From 62374bde751f6bbef2673ca2a3b7cf0293e2be3a Mon Sep 17 00:00:00 2001 From: ?? ? <ulysseskao@ximple.com.tw> Date: Thu, 26 Jun 2008 16:08:47 +0800 Subject: [PATCH] tag 0.6 --- xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatcher.java | 91 .gitattributes | 138 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateShapeStrategy.java | 135 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/OracleConvertMySQLJobContext.java | 311 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/OracleConvertPostGISJobContext.java | 390 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java | 323 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java | 509 xdgnjobs/ximple-spatialjob/pom.xml | 158 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java | 762 + xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateEllipseShapeStrategy.java | 117 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ColorTableMapping.java | 15 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java | 363 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateArcLineStringStrategy.java | 116 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractOracleToOraSDOJobContext.java | 72 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWD97GeometryConverterDecorator.java | 68 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2MySQLJob.java | 1107 + xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateTextStrategy.java | 161 xdgnjobs/ximple-build/maven/jar-collector/src/main/java/com/ximple/eofms/maven/JarCollector.java | 177 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java | 469 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileException.java | 24 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextElement.java | 352 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractFLinkageDispatchableFilter.java | 26 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/FeatureDgnConvertOraSDOJobContext.java | 267 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java | 189 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/AbstractDgnToShapefileJobContext.java | 13 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractDgnFileJobContext.java | 83 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java | 237 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractOracleToMySQLJobContext.java | 70 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/OracleConvertShapefilesJobContext.java | 371 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/FeatureDgnConvertMySQLJobContext.java | 268 xdgnjobs/ximple-jobcarrier/pom.xml | 242 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextNodeElement.java | 387 xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88494_0.dgn | 0 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/UserAttributeData.java | 34 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/FrammeAttributeData.java | 71 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java | 521 xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7TextElementReaderTest.java | 180 xdgnjobs/ximple-build/maven/pom.xml | 70 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/GeometryConverter.java | 18 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java | 758 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementLevelCriterion.java | 48 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7OracleReader.java | 243 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileHeader.java | 58 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java | 613 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/OracleUpgradeJobContext.java | 23 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java | 30 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexElement.java | 16 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineElement.java | 130 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java | 201 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/DummyFeatureConvertJobContext.java | 305 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java | 187 xdgnjobs/ximple-jobcarrier/src/main/resources/quartz.properties | 28 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeStrategy.java | 17 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/FeatureTypeEvent.java | 28 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeIdDispatchableFilter.java | 120 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompLevelIdDispatchableFilter.java | 148 xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491-1.dgn | 0 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementTypeCriterion.java | 48 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/DummyFeatureConvertPostGISJobContext.java | 284 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractDgnToOraSDOJobContext.java | 65 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java | 4830 ++++++ xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/DgnUtility.java | 259 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java | 173 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java | 97 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java | 2885 +++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java | 414 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java | 180 xdgnjobs/ximple-spatialjob/src/test/java/com/ximple/eofms/filter/ElementDispatcherTest.java | 69 xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491_0888888.dgn | 0 xdgnjobs/ximple-build/maven/jar-collector/pom.xml | 46 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/GeneralDgnConvertShpJobContext.java | 556 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Element.java | 334 xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs_shapefiles.xml | 99 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/NIOUtilities.java | 127 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/GeneralDgnConvertOraSDOJobContext.java | 522 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/FeatureDgnConvertShpJobContext.java | 303 xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testElementFilter.xml | 1406 + xdgnjobs/ximple-jobcarrier/src/main/java/com/ximple/eofms/XQuartzJobCarrier.java | 95 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ShapeElement.java | 62 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateComplexChainStrategy.java | 188 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java | 104 xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml | 17 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/OracleConvertOraSDOJobContext.java | 310 xdgnjobs/ximple-jobcarrier/src/test/java/com/ximple/eofms/XQuartzJobCarrierTest.java | 19 xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/OracleTarget.java | 163 xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/testHV.dgn | 0 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ElementType.java | 385 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/EllipseElement.java | 211 xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultMapGroups.xml | 91 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/IndexDgnConvertShpJobContext.java | 343 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2OraSDOJob.java | 1108 + xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultConvertShpFilter.xml | 1465 + xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java | 958 + xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/FeatureDgnConvertPostGISJobContext.java | 266 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/DefaultColorTable.java | 368 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/DummyFeatureConvertOraSDOJobContext.java | 303 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2PostGISJob.java | 1118 + xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/IndexDgnConvertMySQLJobContext.java | 320 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/IndexDgnConvertOraSDOJobContext.java | 320 xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/FeatureClassificationRules.xml | 16 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ArcElement.java | 231 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatchableFilter.java | 18 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java | 760 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Lock.java | 263 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/PrintfFormat.java | 4830 ++++++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractDgnToMySQLJobContext.java | 66 xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties | 28 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractOracleJobContext.java | 286 xdgnjobs/ximple-dgnio/pom.xml | 79 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/IElementHandler.java | 25 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureTypeCollector.java | 48 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java | 551 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java | 468 xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml | 176 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractDispatchableFilter.java | 101 xdgnjobs/pom.xml | 763 + xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7fileReaderTest.java | 118 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/StreamLogging.java | 45 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/DummyFeatureConvertMySQlJobContext.java | 304 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileReader.java | 722 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java | 287 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7Exception.java | 24 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/DummyFeatureConvertShpJobContext.java | 320 xdgnjobs/ximple-build/pom.xml | 50 xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7OracleReaderTest.java | 127 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java | 73 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleElementLogger.java | 420 xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/Demo.dgn | 0 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TcbElement.java | 94 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java | 222 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java | 339 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateSymbolStrategy.java | 143 xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml | 131 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeEventListener.java | 8 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineStringElement.java | 171 xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testRules.xml | 161 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexShapeElement.java | 215 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureClassification.java | 28 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompIdDispatchableFilter.java | 139 139 files changed, 45,619 insertions(+), 0 deletions(-) diff --git a/.gitattributes b/.gitattributes index 8e948c5..8aac53f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,139 @@ * text=auto !eol +xdgnjobs/pom.xml svneol=native#text/xml +xdgnjobs/ximple-build/maven/jar-collector/pom.xml svneol=native#text/xml +xdgnjobs/ximple-build/maven/jar-collector/src/main/java/com/ximple/eofms/maven/JarCollector.java svneol=native#text/plain +xdgnjobs/ximple-build/maven/pom.xml svneol=native#text/xml +xdgnjobs/ximple-build/pom.xml svneol=native#text/xml +xdgnjobs/ximple-dgnio/pom.xml svneol=native#text/xml +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ArcElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexShapeElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7Exception.java -text +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7OracleReader.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileException.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileHeader.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileReader.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Element.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ElementType.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/EllipseElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/FrammeAttributeData.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/GeometryConverter.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/IElementHandler.java -text +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineStringElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Lock.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/NIOUtilities.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ShapeElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/StreamLogging.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TcbElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextNodeElement.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/UserAttributeData.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/DgnUtility.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/PrintfFormat.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7OracleReaderTest.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7TextElementReaderTest.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7fileReaderTest.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/OracleTarget.java svneol=native#text/plain +xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/Demo.dgn -text +xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491-1.dgn -text +xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491_0888888.dgn -text +xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88494_0.dgn -text +xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/testHV.dgn -text +xdgnjobs/ximple-jobcarrier/pom.xml svneol=native#text/xml +xdgnjobs/ximple-jobcarrier/src/main/java/com/ximple/eofms/XQuartzJobCarrier.java svneol=native#text/plain +xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties svneol=native#text/plain +xdgnjobs/ximple-jobcarrier/src/main/resources/quartz.properties svneol=native#text/plain +xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml svneol=native#text/xml +xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs_shapefiles.xml svneol=native#text/xml +xdgnjobs/ximple-jobcarrier/src/test/java/com/ximple/eofms/XQuartzJobCarrierTest.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/pom.xml svneol=native#text/xml +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureClassification.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureTypeCollector.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractDispatchableFilter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractFLinkageDispatchableFilter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateArcLineStringStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateComplexChainStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateEllipseShapeStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeEventListener.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateShapeStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateSymbolStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateTextStrategy.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatchableFilter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatcher.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementLevelCriterion.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementTypeCriterion.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/FeatureTypeEvent.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompIdDispatchableFilter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompLevelIdDispatchableFilter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeIdDispatchableFilter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/DummyFeatureConvertJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2MySQLJob.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2OraSDOJob.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2PostGISJob.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleElementLogger.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractDgnFileJobContext.java -text +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractOracleJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/OracleUpgradeJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractDgnToMySQLJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractOracleToMySQLJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/DummyFeatureConvertMySQlJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/FeatureDgnConvertMySQLJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/IndexDgnConvertMySQLJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/OracleConvertMySQLJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractDgnToOraSDOJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractOracleToOraSDOJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/DummyFeatureConvertOraSDOJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/FeatureDgnConvertOraSDOJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/GeneralDgnConvertOraSDOJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/IndexDgnConvertOraSDOJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/OracleConvertOraSDOJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/DummyFeatureConvertPostGISJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/FeatureDgnConvertPostGISJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/OracleConvertPostGISJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/AbstractDgnToShapefileJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/DummyFeatureConvertShpJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/FeatureDgnConvertShpJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/GeneralDgnConvertShpJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/IndexDgnConvertShpJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/OracleConvertShapefilesJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ColorTableMapping.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/DefaultColorTable.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWD97GeometryConverterDecorator.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml svneol=native#text/xml +xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/FeatureClassificationRules.xml svneol=native#text/xml +xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml svneol=native#text/xml +xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultConvertShpFilter.xml svneol=native#text/xml +xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultMapGroups.xml svneol=native#text/xml +xdgnjobs/ximple-spatialjob/src/test/java/com/ximple/eofms/filter/ElementDispatcherTest.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testElementFilter.xml svneol=native#text/xml +xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testRules.xml svneol=native#text/xml diff --git a/xdgnjobs/pom.xml b/xdgnjobs/pom.xml new file mode 100644 index 0000000..73d417d --- /dev/null +++ b/xdgnjobs/pom.xml @@ -0,0 +1,763 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- ======================================================================= + Maven Project Configuration File + + The Ximple DgnIO Project + http://www.ximple.com.tw/ + + Version: $Id$ + ======================================================================= --> +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <properties> + <oracle.jdbc>true</oracle.jdbc> + <test.maxHeapSize>512M</test.maxHeapSize> + <src.output>${basedir}/target</src.output> + <java5>1.5</java5> + <xdgnio.version>0.6.0</xdgnio.version> + <gt.version>2.4.4</gt.version> + <failIfNoTests>false</failIfNoTests> + </properties> + + <profiles> + <profile> + <id>java5</id> + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <source>1.5</source> + </configuration> + </plugin> + </plugins> + </reporting> + </profile> + <profile> + <id>site.ximple.tw</id> + <distributionManagement> + <site> + <id>artifactorysite-ximple-tw</id> + <name>Artifactory Web site for Maven reports</name> + <url>scp://www.ximple.com.tw/home/www/artfactory/libs-releases@repo</url> + </site> + </distributionManagement> + </profile> + </profiles> + + <scm> + <connection> + scm:svn:http://www.ximple.com.tw/svn/xeofms/xspatialjob/truck/ + </connection> + <url>http://www.ximple.com.tw/svn/xeofms/xspatialjob/truck/</url> + </scm> + + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-dgnjobs</artifactId> + <packaging>pom</packaging> + <version>0.6.0</version> + <name>ximple-dgnjobs</name> + <url>http://www.ximple.com.tw</url> + + <description>Ximple Spatial Data Job for Quartz</description> + + <organization> + <name>Ximple</name> + <url>http://www.ximple.com.tw</url> + </organization> + + <inceptionYear>2008</inceptionYear> + + <!-- =========================================================== --> + <!-- Issue managements and mailing lists. --> + <!-- =========================================================== --> + <issueManagement> + <system>JIRA</system> + <url>http://www.ximple.com.tw/jira/browse/EOFMS</url> + </issueManagement> + + <!-- =========================================================== --> + <!-- Continuous Integration --> + <!-- =========================================================== --> + <ciManagement> + <system>continuum</system> + </ciManagement> + + <mailingLists> + <mailingList> + </mailingList> + </mailingLists> + + <developers> + <developer> + </developer> + </developers> + + <contributors> + </contributors> + + <!-- =========================================================== --> + <!-- Dependency Management --> + <!-- If a POM declares one of those dependencies, then it --> + <!-- will use the version specified here. Otherwise, those --> + <!-- dependencies are ignored. --> + <!-- =========================================================== --> + <dependencyManagement> + <dependencies> + <!-- GeoAPI and its dependencies --> + <dependency> + <groupId>org.opengis</groupId> + <artifactId>geoapi-nogenerics</artifactId> + <version>2.1.0</version> + </dependency> + <dependency> + <groupId>javax.units</groupId> + <artifactId>jsr108</artifactId> + <version>0.01</version> + </dependency> + + <dependency> + <groupId>com.vividsolutions</groupId> + <artifactId>jts</artifactId> + <version>1.9</version> + </dependency> + + <!-- Apache --> + <!-- + <dependency> + <groupId>commons-beanutils</groupId> + <artifactId>commons-beanutils</artifactId> + <version>1.7</version> + </dependency> + --> + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + <version>3.2.1</version> + </dependency> + <dependency> + <groupId>commons-digester</groupId> + <artifactId>commons-digester</artifactId> + <version>1.8</version> + </dependency> + <dependency> + <groupId>commons-pool</groupId> + <artifactId>commons-pool</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + </dependency> + <dependency> + <groupId>commons-transaction</groupId> + <artifactId>commons-transaction</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>1.2.15</version> + <!-- Same as the dependency in commons-logging --> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-contrib</artifactId> + <version>3.0.2-FINAL</version> + </dependency> + + <!-- geotools --> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-api</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-main</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-shapefile</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-sample-data</artifactId> + <version>${gt.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-data</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-jdbc</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-oracle-spatial</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-postgis</artifactId> + <version>${gt.version}</version> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-mysql</artifactId> + <version>${gt.version}</version> + </dependency> + + <!-- because main and sample-data depend on referencing we need a tie breaker --> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-referencing</artifactId> + <version>${gt.version}</version> + </dependency> + + <dependency> + <groupId>jdom</groupId> + <artifactId>jdom</artifactId> + <version>1.0</version> + </dependency> + + <dependency> + <groupId>velocity</groupId> + <artifactId>velocity</artifactId> + <version>1.4</version> + </dependency> + + <!-- We need this to make the referencing module useful --> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-epsg-hsql</artifactId> + <version>${gt.version}</version> + <scope>test</scope> + </dependency> + + <!-- ORACLE --> + <!-- Download and install into your own repo --> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc5</artifactId> + <version>11.1.0</version> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdoapi</artifactId> + <version>11.1.0</version> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdotype</artifactId> + <version>11.1.0</version> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdoutl</artifactId> + <version>11.1.0</version> + </dependency> + + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + <version>8.3-603.jdbc3</version> + </dependency> + <dependency> + <groupId>org.postgis</groupId> + <artifactId>postgis-driver</artifactId> + <version>1.3.3</version> + </dependency> + + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + <version>5.1.6</version> + </dependency> + + <!-- opensymphony --> + <dependency> + <groupId>opensymphony</groupId> + <artifactId>quartz</artifactId> + <version>1.6.0</version> + </dependency> + + <!-- Ximple Library --> + <dependency> + <artifactId>ximple-dgnio</artifactId> + <groupId>com.ximple</groupId> + <version>${xdgnio.version}</version> + </dependency> + + <!-- Tests or legacy --> + <dependency> + <groupId>org.testng</groupId> + <artifactId>testng</artifactId> + <version>5.7</version> + <scope>test</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <!-- =========================================================== --> + <!-- Dependencies to be inherited by all modules. --> + <!-- =========================================================== --> + <dependencies> + <dependency> + <artifactId>geoapi-nogenerics</artifactId> + <groupId>org.opengis</groupId> + </dependency> + + <dependency> + <artifactId>jsr108</artifactId> + <groupId>javax.units</groupId> + </dependency> + + <dependency> + <groupId>com.vividsolutions</groupId> + <artifactId>jts</artifactId> + </dependency> + + <!-- Apache --> + <dependency> + <artifactId>commons-collections</artifactId> + <groupId>commons-collections</groupId> + </dependency> + <dependency> + <groupId>commons-digester</groupId> + <artifactId>commons-digester</artifactId> + </dependency> + <dependency> + <groupId>commons-pool</groupId> + <artifactId>commons-pool</artifactId> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </dependency> + <dependency> + <groupId>commons-transaction</groupId> + <artifactId>commons-transaction</artifactId> + </dependency> + <dependency> + <artifactId>log4j</artifactId> + <groupId>log4j</groupId> + </dependency> + + <dependency> + <artifactId>gt2-api</artifactId> + <groupId>org.geotools</groupId> + </dependency> + <dependency> + <artifactId>gt2-main</artifactId> + <groupId>org.geotools</groupId> + </dependency> + + <dependency> + <artifactId>testng</artifactId> + <groupId>org.testng</groupId> + <scope>test</scope> + </dependency> + </dependencies> + + <!-- =========================================================== --> + <!-- Build Configuration --> + <!-- =========================================================== --> + <build> + <!-- ========================================================= --> + <!-- Maven plugins dependencies management. --> + <!-- It should not be needed since Maven select by default --> + <!-- the latest plugins. Unfortunatly, experience shows that --> + <!-- new plugin releases sometime introduce new bugs that --> + <!-- break our build. So it is saferto specify plugin --> + <!-- versions that are known to work. This list is in --> + <!-- alphabetical order for easier comparaison with latest --> + <!-- plugins at --> + <!-- http://www.ibiblio.org/maven2/org/apache/maven/plugins/ --> + <!-- ========================================================= --> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.1</version> + <configuration> + <descriptors> + <descriptor>build/maven/assembly/binaryDist.xml</descriptor> + <descriptor>build/maven/assembly/sourceDist.xml</descriptor> + </descriptors> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-clean-plugin</artifactId> + <version>2.1.1</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-clover-plugin</artifactId> + <version>2.3</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>2.0.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-install-plugin</artifactId> + <version>2.1</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.1</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-plugin-plugin</artifactId> + <version>2.3</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <version>2.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-project-info-reports-plugin</artifactId> + <version>2.0.1</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>2.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-site-plugin</artifactId> + <version>2.0-beta-5</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.4.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-report-plugin</artifactId> + <version>2.3</version> + </plugin> + + <!-- http://www.ibiblio.org/maven2/org/codehaus/mojo/ --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>changelog-maven-plugin</artifactId> + <version>2.0-beta-1</version> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>changes-maven-plugin</artifactId> + <version>2.0-beta-1</version> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jxr-maven-plugin</artifactId> + <version>2.0-beta-1</version> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>taglist-maven-plugin</artifactId> + <version>2.0</version> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jalopy-maven-plugin</artifactId> + <version>1.0-SNAPSHOT</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <configuration> + <outputDirectory>${src.output}</outputDirectory> + <attach>false</attach> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-eclipse-plugin</artifactId> + <version>2.4</version> + </plugin> + </plugins> + </pluginManagement> + + <!-- http://www.ibiblio.org/maven2/org/apache/maven/wagon/ --> + <!-- + <extensions> + <extension> + <groupId>org.apache.maven.wagon</groupId> + <artifactId>wagon-webdav</artifactId> + <version>1.0-beta-2</version> + </extension> + </extensions> + --> + + <plugins> + <!-- ======================================================= --> + <!-- Source reformat --> + <!-- (activated only on request, jalopy:format) --> + <!-- See developer's guide for automated activation --> + <!-- ======================================================= --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jalopy-maven-plugin</artifactId> + <configuration> + <convention>gt2/jalopygeotools.xml</convention> + <failOnError>false</failOnError> + </configuration> + <dependencies> + <dependency> + <groupId>org.geotools.maven</groupId> + <artifactId>gt2-build-configs</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </plugin> + + + <!-- ======================================================= --> + <!-- Compilation. --> + <!-- ======================================================= --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.5</source> + <!-- The -source argument for the Java compiler. --> + <target>1.5</target> + <!-- The -target argument for the Java compiler. --> + <debug>true</debug> + <!-- Whether to include debugging information. --> + <encoding>ISO-8859-1</encoding> + <!-- The -encoding argument for the Java compiler. --> + </configuration> + </plugin> + + + <!-- ======================================================= --> + <!-- Tests. --> + <!-- ======================================================= --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <includes> + <include>**/*Test.java</include> + </includes> + <excludes> + <exclude>${online.skip.pattern}</exclude> + <exclude>${stress.skip.pattern}</exclude> + </excludes> + <argLine>-Xmx${test.maxHeapSize} -Djava.awt.headless=${java.awt.headless} + </argLine> + <!-- Ignores test failure only if we are generating a --> + <!-- report for publication on the web site. See the --> + <!-- profiles section at the begining of this pom.xml file. --> + <testFailureIgnore> + ${allow.test.failure.ignore} + </testFailureIgnore> + + <!-- Option to print summary of test suites or just print the test cases that has errors. --> + <printSummary>true</printSummary> + <!-- Redirect the unit test standard output to a file. --> + <redirectTestOutputToFile>false</redirectTestOutputToFile> + </configuration> + </plugin> + + + <!-- ======================================================= --> + <!-- Code coverage --> + <!-- ======================================================= --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-clover-plugin</artifactId> + <configuration> + <jdk>1.5</jdk> + <licenseLocation> + http://svn.geotools.org/geotools/branches/2.4.x/build/maven/build-configs/src/main/resources/gt2/clover.license + </licenseLocation> + <flushPolicy>directed</flushPolicy> + </configuration> + <executions> + <execution> + <phase>pre-site</phase> + <goals> + <goal>instrument</goal> + <!-- aggregation is disabled due to the bug: --> + <!-- http://jira.codehaus.org/browse/MCLOVER-34 --> + </goals> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.geotools.maven</groupId> + <artifactId>gt2-build-configs</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </plugin> + + + <!-- ======================================================= --> + <!-- JAR packaging. --> + <!-- ======================================================= --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <addClasspath>true</addClasspath> + </manifest> + </archive> + </configuration> + </plugin> + + <!-- ======================================================= --> + <!-- Source packaging. --> + <!-- ======================================================= --> + <plugin> + <inherited>true</inherited> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <configuration> + <attach>true</attach> + </configuration> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + <resources> + <!-- + <resource> + <targetPath>conf</targetPath> + <filtering>false</filtering> + <directory>${basedir}/src/main/resources/conf</directory> + <includes> + <include>configuration.xml</include> + </includes> + <excludes> + <exclude>**/*.properties</exclude> + </excludes> + </resource> + --> + </resources> + </build> + + <distributionManagement> + <repository> + <uniqueVersion>false</uniqueVersion> + <id>ximple</id> + <name>Ximple - Artifactory lib repo</name> + <url>dav:http://www.ximple.com.tw/artifactory/libs-releases</url> + </repository> + <snapshotRepository> + <uniqueVersion>false</uniqueVersion> + <id>ximple-snapshots</id> + <name>Ximple - Artifactory lib-snapshots repo</name> + <url>dav:http://www.ximple.com.tw/artifactory/libs-snapshots</url> + </snapshotRepository> + </distributionManagement> + + <!-- =========================================================== --> + <!-- Repositories (ibiblio, refractions...). --> + <!-- This is where Maven looks for dependencies. --> + <!-- =========================================================== --> + <repositories> + <repository> + <snapshots> + <enabled>false</enabled> + </snapshots> + <id>central</id> + <name>Ximple Artifactory Maven Repository Switchboard</name> + <url>http://www.ximple.com.tw/artifactory/repo</url> + </repository> + + <repository> + <releases> + <enabled>false</enabled> + </releases> + <id>snapshots</id> + <name>Ximple Artifactory Maven Repository Switchboard</name> + <url>http://www.ximple.com.tw/artifactory/repo</url> + </repository> + </repositories> + + + <!-- =========================================================== --> + <!-- Plugin repositories. --> + <!-- This is where Maven looks for plugin dependencies. --> + <!-- =========================================================== --> + <pluginRepositories> + <pluginRepository> + <id>ximple-snapshots</id> + <name>ximple-shapshots</name> + <url>http://www.ximple.com.tw/artifactory/vplugins-snapshots</url> + <snapshots> + <enabled>true</enabled> + </snapshots> + <releases> + <enabled>false</enabled> + </releases> + </pluginRepository> + <pluginRepository> + <id>ximple</id> + <name>Ximple Maven 2 Repository</name> + <url>http://www.ximple.com.tw/artifactory/vplugins-releases</url> + <snapshots> + <enabled>false</enabled> + </snapshots> + <releases> + <enabled>true</enabled> + </releases> + </pluginRepository> + </pluginRepositories> + + <!-- =========================================================== --> + <!-- Modules for the build in approximate dependency order --> + <!-- =========================================================== --> + <modules> + <module>ximple-build</module> + <module>ximple-dgnio</module> + <module>ximple-spatialjob</module> + <module>ximple-jobcarrier</module> + </modules> +</project> \ No newline at end of file diff --git a/xdgnjobs/ximple-build/maven/jar-collector/pom.xml b/xdgnjobs/ximple-build/maven/jar-collector/pom.xml new file mode 100644 index 0000000..ca14767 --- /dev/null +++ b/xdgnjobs/ximple-build/maven/jar-collector/pom.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.ximple.eofms.maven</groupId> + <artifactId>ximple-maven</artifactId> + <version>0.6.0</version> + </parent> + + + <!-- =========================================================== --> + <!-- Module Description --> + <!-- =========================================================== --> + <groupId>com.ximple.eofms.maven</groupId> + <artifactId>ximple-jar-collector</artifactId> + <packaging>maven-plugin</packaging> + <name>JAR files collector</name> + + <scm> + <connection> + scm:svn:http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/ + </connection> + <url>http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/</url> + </scm> + + <description> + Copy all JAR files (including dependencies) in the target directory + of the parent project descriptor. + </description> + + <licenses> + <license> + <name>Lesser General Public License (LGPL)</name> + <url>http://www.gnu.org/copyleft/lesser.txt</url> + <distribution>repo</distribution> + </license> + </licenses> + + <!-- =========================================================== --> + <!-- Developers and Contributors --> + <!-- =========================================================== --> + +</project> diff --git a/xdgnjobs/ximple-build/maven/jar-collector/src/main/java/com/ximple/eofms/maven/JarCollector.java b/xdgnjobs/ximple-build/maven/jar-collector/src/main/java/com/ximple/eofms/maven/JarCollector.java new file mode 100644 index 0000000..c76d6ae --- /dev/null +++ b/xdgnjobs/ximple-build/maven/jar-collector/src/main/java/com/ximple/eofms/maven/JarCollector.java @@ -0,0 +1,177 @@ +package org.ximple.eofms.maven; + +import org.apache.maven.artifact.Artifact; + +// Maven and Plexus dependencies +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.FileUtils; + +// J2SE dependencies +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.Set; + + +// Note: javadoc in class and fields descriptions must be XHTML. +/** + * Copies <code>.jar</code> files in a single directory. Dependencies are copied as well, + * except if already presents. + * + * @goal collect + * @phase package + * @source $URL$ + * @version $Id$ + * @author Martin Desruisseaux + */ +public class JarCollector extends AbstractMojo { + /** + * The sub directory to create inside the "target" directory. + */ + private static final String SUB_DIRECTORY = "binaries"; + + /** + * The directory where JARs are to be copied. It should + * be the "target" directory of the parent {@code pom.xml}. + */ + private String collectDirectory; + + /** + * Directory containing the generated JAR. + * + * @parameter expression="${project.build.directory}" + * @required + */ + private String outputDirectory; + + /** + * Name of the generated JAR. + * + * @parameter expression="${project.build.finalName}" + * @required + */ + private String jarName; + + /** + * Project dependencies. + * + * @parameter expression="${project.artifacts}" + * @required + */ + private Set /*<Artifact>*/ dependencies; + + /** + * The Maven project running this plugin. + * + * @parameter expression="${project}" + * @required + */ + private MavenProject project; + + /** + * Copies the {@code .jar} files to the collect directory. + * + * @throws MojoExecutionException if the plugin execution failed. + */ + public void execute() throws MojoExecutionException { + /* + * Gets the parent "target" directory. + */ + MavenProject parent = project; + + while (parent.hasParent()) { + parent = parent.getParent(); + } + + collectDirectory = parent.getBuild().getDirectory(); + + /* + * Now collects the JARs. + */ + try { + collect(); + } catch (IOException e) { + throw new MojoExecutionException("Error collecting the JAR file.", e); + } + } + + /** + * Implementation of the {@link #execute} method. + */ + private void collect() throws MojoExecutionException, IOException { + /* + * Make sure that we are collecting the JAR file from a module which produced + * such file. Some modules use pom packaging, which do not produce any JAR file. + */ + final File jarFile = new File(outputDirectory, jarName + ".jar"); + + if (!jarFile.isFile()) { + return; + } + + /* + * Get the "target" directory of the parent pom.xml and make sure it exists. + */ + File collect = new File(collectDirectory); + + if (!collect.exists()) { + if (!collect.mkdir()) { + throw new MojoExecutionException("Failed to create target directory."); + } + } + + if (collect.getCanonicalFile().equals(jarFile.getParentFile().getCanonicalFile())) { + /* + * The parent's directory is the same one than this module's directory. + * In other words, this plugin is not executed from the parent POM. Do + * not copy anything, since this is not the place where we want to + * collect the JAR files. + */ + return; + } + + /* + * Creates a "binaries" subdirectory inside the "target" directory. + */ + collect = new File(collect, SUB_DIRECTORY); + + if (!collect.exists()) { + if (!collect.mkdir()) { + throw new MojoExecutionException("Failed to create binaries directory."); + } + } + + int count = 1; + FileUtils.copyFileToDirectory(jarFile, collect); + + if (dependencies != null) { + for (final Iterator it = dependencies.iterator(); it.hasNext();) { + final Artifact artifact = (Artifact) it.next(); + final String scope = artifact.getScope(); + + if ((scope != null) // Maven 2.0.6 bug? + && (scope.equalsIgnoreCase(Artifact.SCOPE_COMPILE) + || scope.equalsIgnoreCase(Artifact.SCOPE_RUNTIME))) { + final File file = artifact.getFile(); + final File copy = new File(collect, file.getName()); + + if (!copy.exists()) { + /* + * Copies the dependency only if it was not already copied. Note that + * the module's JAR was copied inconditionnaly above (because it may + * be the result of a new compilation). If a Geotools JAR from the + * dependencies list changed, it will be copied inconditionnaly when + * the module for this JAR will be processed by Maven. + */ + FileUtils.copyFileToDirectory(file, collect); + count++; + } + } + } + } + + getLog().info("Copied " + count + " JAR to parent directory."); + } +} diff --git a/xdgnjobs/ximple-build/maven/pom.xml b/xdgnjobs/ximple-build/maven/pom.xml new file mode 100644 index 0000000..af14632 --- /dev/null +++ b/xdgnjobs/ximple-build/maven/pom.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.ximple.eofms.maven</groupId> + <artifactId>ximple-build</artifactId> + <version>0.6.0</version> + </parent> + + + <!-- =========================================================== --> + <!-- Module Description --> + <!-- =========================================================== --> + <groupId>com.ximple.eofms.maven</groupId> + <artifactId>ximple-maven</artifactId> + <packaging>pom</packaging> + <name>Maven plugins for Ximple</name> + + <scm> + <connection> + scm:svn:http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/ + </connection> + <url>http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/</url> + </scm> + + <description> + Maven plugins specific to the the Ximple Dgn IO Library. + </description> + + <licenses> + <license> + <name>Lesser General Public License (LGPL)</name> + <url>http://www.gnu.org/copyleft/lesser.txt</url> + <distribution>repo</distribution> + </license> + </licenses> + + + <!-- =========================================================== --> + <!-- Dependency Management --> + <!-- =========================================================== --> + <dependencies> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>2.0.4</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + <version>2.0.4</version> + </dependency> + <dependency> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-utils</artifactId> + <version>1.2</version> + </dependency> + </dependencies> + + + <!-- =========================================================== --> + <!-- Modules included in the build --> + <!-- =========================================================== --> + <modules> + <module>jar-collector</module> + </modules> +</project> diff --git a/xdgnjobs/ximple-build/pom.xml b/xdgnjobs/ximple-build/pom.xml new file mode 100644 index 0000000..8208e70 --- /dev/null +++ b/xdgnjobs/ximple-build/pom.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-dgnjobs</artifactId> + <version>0.6.0</version> + </parent> + + + <!-- =========================================================== --> + <!-- Module Description --> + <!-- =========================================================== --> + <groupId>com.ximple.eofms.maven</groupId> + <artifactId>ximple-build</artifactId> + <packaging>pom</packaging> + <name>Build tools for Ximple DgnJobs</name> + + <scm> + <connection> + scm:svn:http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/ + </connection> + <url>http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/</url> + </scm> + + <description> + Build tools for the the Ximple Dgn IO Library. + </description> + + <licenses> + <license> + <name>Lesser General Public License (LGPL)</name> + <url>http://www.gnu.org/copyleft/lesser.txt</url> + <distribution>repo</distribution> + </license> + </licenses> + + + <!-- =========================================================== --> + <!-- Modules included in the build --> + <!-- =========================================================== --> + <modules> + <module>maven</module> + </modules> + + +</project> diff --git a/xdgnjobs/ximple-dgnio/pom.xml b/xdgnjobs/ximple-dgnio/pom.xml new file mode 100644 index 0000000..5916a17 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/pom.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-dgnjobs</artifactId> + <version>0.6.0</version> + </parent> + + <!-- =========================================================== --> + <!-- Module Description --> + <!-- =========================================================== --> + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-dgnio</artifactId> + <version>0.6.0</version> + <packaging>jar</packaging> + <name>ximple-dgnio</name> + <url>http://www.ximple.com.tw</url> + + <scm> + <connection> + scm:svn:http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/ + </connection> + <url>http://www.ximple.com.tw/svn/xeofms/xdgnio/truck/</url> + </scm> + + <description> + Ximple Dgn IO Library + </description> + + <organization> + <name>Ximple</name> + <url>http://www.ximple.com.tw</url> + </organization> + + <inceptionYear>2008</inceptionYear> + + <developers> + <developer> + <name>Kuo-Feng Kao</name> + <id>ulysseskao</id> + <email>ulysseskao@ximple.com.tw</email> + <organization>Ximple</organization> + <roles> + <role>Java Developer</role> + </roles> + </developer> + </developers> + + <contributors> + </contributors> + + + <!-- =========================================================== --> + <!-- Dependencies to be inherited by all modules. --> + <!-- =========================================================== --> + <dependencies> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-sample-data</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc5</artifactId> + </dependency> + </dependencies> + + <!-- =========================================================== --> + <!-- Build Configuration --> + <!-- =========================================================== --> + <build> + <plugins> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ArcElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ArcElement.java new file mode 100644 index 0000000..bd452df --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ArcElement.java @@ -0,0 +1,231 @@ +package com.ximple.io.dgn7; + +import java.nio.ByteOrder; +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.util.DgnUtility; + +/** + * ArcElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/26 �U�� 06:41:45 + */ +public class ArcElement extends Element implements GeometryConverter +{ + private static final Logger logger = Logger.getLogger(ArcElement.class); + + public ArcElement(byte[] raw) + { + super(raw); + } + + public double getStartAngle() + { + int angle = (raw[18] & 0x0000ffff) << 16 | (raw[19] & 0x0000ffff); + return DgnUtility.converIntToRotation(angle); + } + + public void setStartAngle(double value) + { + int angle = DgnUtility.converRotatioToInt(value); + + raw[18] = (short) (angle >>> 16 & 0x0000ffff); + raw[19] = (short) (angle & 0x0000ffff); + } + + public double getSweepAngle() + { + int angle = (raw[20] & 0x0000ffff) << 16 | (raw[21] & 0x0000ffff); + if (angle < 0) + angle = -1 * (angle & 0x7fffffff); + + return DgnUtility.converIntToRotation(angle); + } + + public void setSweepAngle(double value) + { + int angle = DgnUtility.converRotatioToInt(value); + if (angle < 0) + { + angle &= 0x7fffffff; + angle |= 0x80000000; + } + + raw[20] = (short) (angle >> 16 & 0x0000ffff); + raw[21] = (short) (angle & 0x0000ffff); + } + + public double getPrimary() + { + rawBuffer.position(22 * 2); + ByteOrder bo = rawBuffer.order(); + rawBuffer.order(ByteOrder.BIG_ENDIAN); + byte[] primary = new byte[8]; + rawBuffer.get(primary); + rawBuffer.order(bo); + return DgnUtility.convertDGNToIEEEDouble(primary) / 1000.0; + } + + public void setPrimary(double value) + { + double temp = value * 1000.0; + short[] primary = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(primary, 0, raw, 22, 4); + } + + public double getSecondary() + { + rawBuffer.position(26 * 2); + ByteOrder bo = rawBuffer.order(); + rawBuffer.order(ByteOrder.BIG_ENDIAN); + byte[] secondary = new byte[8]; + rawBuffer.get(secondary); + rawBuffer.order(bo); + return DgnUtility.convertDGNToIEEEDouble(secondary) / 1000.0; + } + + public void setSecondary(double value) + { + double temp = value * 1000.0; + short[] secondary = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(secondary, 0, raw, 26, 4); + } + + public double getRotationAngle() + { + int rotation = (raw[30] << 16 & 0xffff0000); + rotation |= raw[31] & 0x0000ffff; + + return DgnUtility.converIntToRotation(rotation); + } + + public void setRotationAngle(double value) + { + int angle = DgnUtility.converRotatioToInt(value); + + raw[30] = (short) (angle >> 16 & 0x0000ffff); + raw[31] = (short) (angle & 0x0000ffff); + } + + public Coordinate getOrigin() + { + rawBuffer.position(32 * 2); + ByteOrder bo = rawBuffer.order(); + rawBuffer.order(ByteOrder.BIG_ENDIAN); + byte[] rawValue = new byte[8]; + + rawBuffer.get(rawValue); // x + double dx = DgnUtility.converUnitToCoord(DgnUtility.convertDGNToIEEEDouble(rawValue)); + + rawBuffer.get(rawValue); // y + double dy = DgnUtility.converUnitToCoord(DgnUtility.convertDGNToIEEEDouble(rawValue)); + + rawBuffer.order(bo); + + return new Coordinate(dx, dy); + } + + public void setOrigin(Coordinate value) + { + double temp = DgnUtility.converCoordToUnit(value.x); + short[] x = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(x, 0, raw, 32, 4); + temp = DgnUtility.converCoordToUnit(value.y); + + short[] y = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(y, 0, raw, 36, 4); + } + + public Geometry toGeometry(GeometryFactory factory) + { + double sweep = getSweepAngle(); + double temp = Math.abs(sweep); + temp /= 4; + int pts = (temp < 3) ? 3 : (int) temp; + return factory.createLineString(convertToLineString(pts)); + } + + private Coordinate[] convertToLineString(int pts) + { + ArrayList<Coordinate> result = new ArrayList<Coordinate>(); + double beta = DgnUtility.converRotationToRadian(-getRotationAngle()); + double startAngle = getStartAngle(); + double sweepAngle = getSweepAngle(); + double endAngle = startAngle + sweepAngle; + double steps = sweepAngle / pts; + double current; + if (sweepAngle < 0) + { + for (current = startAngle; current > endAngle; current += steps) + { + Coordinate pt = computePointOnArcByAngle(beta, current); + result.add(pt); + } + + } else + { + for (current = startAngle; current < endAngle; current += steps) + { + Coordinate pt = computePointOnArcByAngle(beta, current); + result.add(pt); + } + } + + Coordinate pt = computePointOnArcByAngle(beta, endAngle); + result.add(pt); + + return result.toArray(new Coordinate[result.size()]); + } + + private Coordinate computePointOnArcByAngle(double beta, double current) + { + double sinbeta = Math.sin(beta); + double cosbeta = Math.cos(beta); + Coordinate pt = new Coordinate(); + double alpha = DgnUtility.converRotationToRadian(current); + double sinalpha = Math.sin(alpha); + double cosalpha = Math.cos(alpha); + pt.x = getOrigin().x + (getPrimary() * cosalpha * cosbeta - + getSecondary() * sinalpha * sinbeta); + pt.y = getOrigin().y + (getPrimary() * cosalpha * sinbeta + + getSecondary() * sinalpha * cosbeta); + return pt; + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.ARC); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new ArcElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java new file mode 100644 index 0000000..9b722d7 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java @@ -0,0 +1,222 @@ +package com.ximple.io.dgn7; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; + +/** + * ComplexChainElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 03:44:56 + */ +public class ComplexChainElement extends Element implements ComplexElement, GeometryConverter +{ + private static final Logger logger = Logger.getLogger(ComplexChainElement.class); + + protected ArrayList<Element> list = new ArrayList<Element>(); + + public ComplexChainElement(byte[] raw) + { + super(raw); + attrOffset = 4; + } + + public int size() + { + return list.size(); + } + + public boolean isEmpty() + { + return list.isEmpty(); + } + + public boolean contains(Object o) + { + return list.contains(o); + } + + public Iterator iterator() + { + return list.iterator(); + } + + public Object[] toArray() + { + return list.toArray(); + } + + public boolean add(Object o) + { + return list.add((Element) o); + } + + public boolean remove(Object o) + { + return list.remove(o); + } + + public boolean addAll(Collection c) + { + return list.addAll(c); + } + + public boolean addAll(int index, Collection c) + { + return list.addAll(index, c); + } + + public void clear() + { + list.clear(); + } + + public Object get(int index) + { + return list.get(index); + } + + public Object set(int index, Object element) + { + return list.set(index, (Element) element); + } + + public void add(int index, Object element) + { + list.add(index, (Element) element); + } + + public Object remove(int index) + { + return list.remove(index); + } + + public int indexOf(Object o) + { + return list.indexOf(o); + } + + public int lastIndexOf(Object o) + { + return list.lastIndexOf(o); + } + + public ListIterator listIterator() + { + return list.listIterator(); + } + + public ListIterator listIterator(int index) + { + return list.listIterator(index); + } + + public List subList(int fromIndex, int toIndex) + { + return list.subList(fromIndex, toIndex); + } + + public boolean retainAll(Collection c) + { + return list.retainAll(c); + } + + public boolean removeAll(Collection c) + { + return list.removeAll(c); + } + + public boolean containsAll(Collection c) + { + return list.containsAll(c); + } + + public Object[] toArray(Object[] a) + { + return list.toArray(a); + } + + public Geometry toGeometry(GeometryFactory factory) + { + ArrayList<LineString> lineStrings = new ArrayList<LineString>(); + + for (ListIterator it = listIterator(); it.hasNext();) + { + Element element = (Element) it.next(); + + if (element instanceof LineStringElement) + { + if (((LineStringElement) element).getVerticeSize() == 0 || ((LineStringElement) element).getVerticeSize() > 1) + { + lineStrings.add((LineString) ((LineStringElement) element).toGeometry(factory)); + } + + } else if (element instanceof LineElement) + { + + if (((LineElement) element).getVertices().length == 0 || ((LineElement) element).getVertices().length > 1) + { + lineStrings.add((LineString) ((LineElement) element).toGeometry(factory)); + } + } else if (element instanceof ArcElement) + { + lineStrings.add((LineString) ((ArcElement) element).toGeometry(factory)); + } + } + + LineString[] lines = lineStrings.toArray(new LineString[lineStrings.size()]); + if ((lines == null) || (lines.length == 0)) + return null; + return factory.createMultiLineString(lines); + } + + public double getElementSize() + { + return raw[18]; + } + + public boolean isClosed() + { + if (isEmpty()) + { + return false; + } + + return false; + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.COMPLEXCHAIN); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new ComplexChainElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexElement.java new file mode 100644 index 0000000..08fa5ae --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexElement.java @@ -0,0 +1,16 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.List; + +/** + * ComplexElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 04:17:37 + */ +public interface ComplexElement extends List +{ +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexShapeElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexShapeElement.java new file mode 100644 index 0000000..f34dc57 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexShapeElement.java @@ -0,0 +1,215 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.CoordinateList; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +/** + * ComplexShapeElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 03:45:15 + */ +public class ComplexShapeElement extends Element implements ComplexElement, GeometryConverter +{ + private static final Logger logger = Logger.getLogger(ComplexShapeElement.class); + + ArrayList<Element> list = new ArrayList<Element>(); + + public ComplexShapeElement(byte[] raw) + { + super(raw); + } + + public int size() + { + return list.size(); + } + + public boolean isEmpty() + { + return list.isEmpty(); + } + + public boolean contains(Object o) + { + return list.contains(o); + } + + public Iterator iterator() + { + return list.iterator(); + } + + public Object[] toArray() + { + return list.toArray(); + } + + public boolean add(Object o) + { + return list.add((Element) o); + } + + public boolean remove(Object o) + { + return list.remove(o); + } + + public boolean addAll(Collection c) + { + return list.addAll(c); + } + + public boolean addAll(int index, Collection c) + { + return list.addAll(index, c); + } + + public void clear() + { + list.clear(); + } + + public Object get(int index) + { + return list.get(index); + } + + public Object set(int index, Object element) + { + return list.set(index, (Element) element); + } + + public void add(int index, Object element) + { + list.add(index, (Element) element); + } + + public Object remove(int index) + { + return list.remove(index); + } + + public int indexOf(Object o) + { + return list.indexOf(o); + } + + public int lastIndexOf(Object o) + { + return list.lastIndexOf(o); + } + + public ListIterator listIterator() + { + return list.listIterator(); + } + + public ListIterator listIterator(int index) + { + return list.listIterator(index); + } + + public List subList(int fromIndex, int toIndex) + { + return list.subList(fromIndex, toIndex); + } + + public boolean retainAll(Collection c) + { + return list.retainAll(c); + } + + public boolean removeAll(Collection c) + { + return list.removeAll(c); + } + + public boolean containsAll(Collection c) + { + return list.containsAll(c); + } + + public Object[] toArray(Object[] a) + { + return list.toArray(a); + } + + public Geometry toGeometry(GeometryFactory factory) + { + ArrayList<Geometry> list = new ArrayList<Geometry>(); + + for (ListIterator it = listIterator(); it.hasNext();) + { + Element element = (Element) it.next(); + + if (element instanceof ShapeElement) + { + if (((ShapeElement) element).getVerticeSize() == 0 || ((ShapeElement) element).getVerticeSize() > 1) + { + list.add(((ShapeElement) element).toGeometry(factory)); + } + } else if (element instanceof LineStringElement) + { + if (((LineStringElement) element).getVerticeSize() == 0 || ((LineStringElement) element).getVerticeSize() > 1) + { + list.add(((LineStringElement) element).toGeometry(factory)); + } + } else if (element instanceof LineElement) + { + if (((LineElement) element).getVertices().length == 0 || ((LineElement) element).getVertices().length > 1) + { + list.add(((LineElement) element).toGeometry(factory)); + } + } else if (element instanceof ArcElement) + { + } + } + + + CoordinateList pts = new CoordinateList(); + for (Geometry geom : list) + { + pts.add(geom.getCoordinates(), true); + } + + return factory.createLinearRing(pts.toCoordinateArray()); + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.COMPLEXSHAPE); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new ComplexShapeElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7Exception.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7Exception.java new file mode 100644 index 0000000..0f2cd91 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7Exception.java @@ -0,0 +1,24 @@ +package com.ximple.io.dgn7; + + +public class Dgn7Exception extends Exception +{ + public Dgn7Exception() + { + } + + public Dgn7Exception(String s) + { + super(s); + } + + public Dgn7Exception(String s, Throwable throwable) + { + super(s, throwable); + } + + public Dgn7Exception(Throwable throwable) + { + super(throwable); + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7OracleReader.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7OracleReader.java new file mode 100644 index 0000000..b8908cf --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7OracleReader.java @@ -0,0 +1,243 @@ +package com.ximple.io.dgn7; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Iterator; + +import org.apache.log4j.Logger; + +import oracle.jdbc.OracleConnection; +import oracle.sql.BLOB; + +/** + * Dgn7OracleReader + * User: Ulysses + * Date: 2007/10/24 + * Time: �U�� 01:01:08 + */ +public class Dgn7OracleReader implements Iterator<Element> +{ + private final static Logger logger = Logger.getLogger(Dgn7OracleReader.class); + + private String _sql; + private String _fieldName; + private Connection _connection; + private ResultSet _resultSet; + private static final int FETCHSIZE = 20; + private Element _element; + + public Dgn7OracleReader(String sql, String fieldName, OracleConnection connection) + { + this._sql = sql; + this._fieldName = fieldName; + this._connection = connection; + } + + public String getSql() + { + return _sql; + } + + public void setSql(String sql) + { + this._sql = sql; + } + + public String getFieldName() + { + return _fieldName; + } + + public void setFieldName(String fieldName) + { + this._fieldName = fieldName; + } + + public boolean hasNext() + { + if (_resultSet == null) + { + try + { + initializeReader(); + } catch (SQLException e) + { + throw new RuntimeException("initialize oralce error.", e); + } catch (Dgn7Exception e) + { + throw new RuntimeException("initialize oralce error.", e); + } + } + return _element != null; + } + + public Element next() + { + Element result = _element; + + try + { + fetchElement(); + } catch (SQLException e) + { + throw new RuntimeException("Error:" + e.getMessage(), e); + } catch (Dgn7Exception e) + { + throw new RuntimeException("Error:" + e.getMessage(), e); + } + + return result; + } + + public void remove() + { + throw new RuntimeException("Not Support this method."); + } + + private boolean initializeReader() throws SQLException, Dgn7Exception + { + if (_resultSet != null) return true; + Statement stmtSrc = _connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtSrc.setFetchSize(FETCHSIZE); + _resultSet = stmtSrc.executeQuery(_sql); + + fetchElement(); + + return true; + } + + private boolean fetchElement() throws SQLException, Dgn7Exception + { + if (_resultSet.next()) + { + byte[] raw = null; + Object value = _resultSet.getObject(this._fieldName); + + if (value instanceof BLOB) + { + BLOB blob = (BLOB) value; + + try + { + raw = getBytesFromBLOB(blob); + } catch (IOException e) + { + throw new Dgn7Exception("IOError", e); + } + blob.close(); + } else if (value instanceof byte[]) + { + raw = (byte[]) value; + } + if (raw == null) + { + _element = null; + return false; + } + + ByteBuffer buffer = ByteBuffer.wrap(raw); + buffer.order(ByteOrder.LITTLE_ENDIAN); + short signature = buffer.getShort(); + + // byte type = (byte) (buffer.get() & 0x7f); + byte type = (byte) ((signature >>> 8) & 0x007f); + + // silly Bentley say contentLength is in 2-byte words + // and ByteByffer uses bytes. + // track the record location + int elementLength = (buffer.getShort() * 2) + 4; + ElementType recordType = ElementType.forID(type); + IElementHandler handler = recordType.getElementHandler(); + _element = (Element) handler.read(buffer, signature, elementLength); + if (recordType.isComplexElement() && (elementLength < raw.length)) + { + int offset = elementLength; + while (offset < (raw.length - 4)) + { + buffer.position(offset); + signature = buffer.getShort(); + type = (byte) ((signature >>> 8) & 0x007f); + elementLength = (buffer.getShort() * 2) + 4; + if (raw.length < (offset + elementLength)) + { + System.out.println("Length not match:" + offset + ":" + buffer.position() + ":" + buffer.limit()); + break; + } + recordType = ElementType.forID(type); + handler = recordType.getElementHandler(); + if (handler != null) + { + Element subElement = (Element) handler.read(buffer, signature, elementLength); + ((ComplexElement) _element).add(subElement); + offset += elementLength; + } else + { + byte[] remain = new byte[buffer.remaining()]; + System.arraycopy(raw, offset, remain, 0, buffer.remaining()); + for (int i = 0; i < remain.length; i++) + { + if (remain[i] != 0) + { + logger.info("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + System.out.println("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + } + } + break; + } + } + } + + } else + { + _element = null; + return false; + } + return true; + } + + protected static byte[] getBytesFromBLOB(BLOB blob) throws SQLException, IOException + { + byte[] raw; + + // BLOB blob = (BLOB) rs.getBlob(1); + int optimalSize = blob.getChunkSize(); + byte[] chunk = new byte[optimalSize]; + InputStream is = blob.getBinaryStream(0); + ByteBuffer buffer = null; // ByteBuffer.allocate(optimalSize); + int len; + + try + { + while ((len = (is.read(chunk))) != -1) + { + if (buffer != null) + { + buffer.limit(buffer.limit() + len); + } else + { + buffer = ByteBuffer.allocate(len); + } + + buffer.put(chunk); + } + + is.close(); + assert buffer != null; + buffer.position(0); + raw = buffer.array(); + } catch (IOException e) + { + e.printStackTrace(); + throw e; + } + + return raw; + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileException.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileException.java new file mode 100644 index 0000000..54741e5 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileException.java @@ -0,0 +1,24 @@ +package com.ximple.io.dgn7; + +public class Dgn7fileException extends Dgn7Exception +{ + + public Dgn7fileException() + { + } + + public Dgn7fileException(String message) + { + super(message); + } + + public Dgn7fileException(String message, Throwable cause) + { + super(message, cause); + } + + public Dgn7fileException(Throwable cause) + { + super(cause); + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileHeader.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileHeader.java new file mode 100644 index 0000000..33f3a1c --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileHeader.java @@ -0,0 +1,58 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import com.vividsolutions.jts.util.Assert; + +/** + * Dgn7fileHeader + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/17 �U�� 01:21:00 + */ +public class Dgn7fileHeader +{ + private short elmtype; + private byte[] raw; + + public Dgn7fileHeader() + { + } + + public void read(ByteBuffer file, boolean strict) throws IOException + { + file.order(ByteOrder.LITTLE_ENDIAN); + elmtype = file.getShort(); + + short wtf = file.getShort(); + int length = (wtf * 2); + + if (file.remaining() != (length)) + { + Assert.shouldNeverReachHere(); + } + + raw = new byte[length]; + file.get(raw, 0, file.remaining()); + } + + public String toString() + { + return "Dgn7fileHeader{" + "raw=" + ((raw == null) ? "null" : raw.length) + '}'; + } + + public int size() + { + if (raw == null) + { + return 0; + } + + return raw.length + 4; + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileReader.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileReader.java new file mode 100644 index 0000000..35a3156 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileReader.java @@ -0,0 +1,722 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import javax.swing.JFileChooser; +import javax.swing.JFrame; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.util.DgnUtility; + + +/** + * Dgn7fileReader + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/17 �U�� 01:24:10 + */ +public class Dgn7fileReader +{ + private static final Logger logger = LogManager.getLogger(Dgn7fileReader.class); + + private Dgn7fileHeader header; + private ReadableByteChannel channel; + ByteBuffer buffer; + private ElementType fileElementType = ElementType.UNDEFINED; + private ByteBuffer headerTransfer; + private final Record record = new Record(); + private final boolean randomAccessEnabled; + private Lock lock; + private boolean useMemoryMappedBuffer; + private long currentOffset = 0L; + private StreamLogging streamLogger = new StreamLogging("Shapefile Reader"); + private int maxElementId = 0; + + public Dgn7fileReader(ReadableByteChannel channel, boolean strict, boolean useMemoryMapped, Lock lock) + throws IOException, Dgn7fileException + { + this.channel = channel; + this.useMemoryMappedBuffer = useMemoryMapped; + streamLogger.open(); + randomAccessEnabled = channel instanceof FileChannel; + this.lock = lock; + lock.lockRead(); + init(strict); + } + + public Dgn7fileReader(ReadableByteChannel channel, Lock lock) throws IOException, Dgn7fileException + { + this(channel, true, true, lock); + } + + // ensure the capacity of the buffer is of size by doubling the original + // capacity until it is big enough + // this may be naiive and result in out of MemoryError as implemented... + public static ByteBuffer ensureCapacity(ByteBuffer buffer, int size, boolean useMemoryMappedBuffer) + { + // This sucks if you accidentally pass is a MemoryMappedBuffer of size + // 80M + // like I did while messing around, within moments I had 1 gig of + // swap... + if (buffer.isReadOnly() || useMemoryMappedBuffer) + { + return buffer; + } + + int limit = buffer.limit(); + + while (limit < size) + { + limit *= 2; + } + + if (limit != buffer.limit()) + { + // if (record.ready) { + buffer = ByteBuffer.allocateDirect(limit); + + // } + // else { + // throw new IllegalArgumentException("next before hasNext"); + // } + } + + return buffer; + } + + // for filling a ReadableByteChannel + public static int fill(ByteBuffer buffer, ReadableByteChannel channel) throws IOException + { + int r = buffer.remaining(); + + // channel reads return -1 when EOF or other error + // because they a non-blocking reads, 0 is a valid return value!! + while ((buffer.remaining() > 0) && (r != -1)) + { + r = channel.read(buffer); + } + + if (r == -1) + { + buffer.limit(buffer.position()); + } + + return r; + } + + public static Dgn7fileHeader readHeader(ReadableByteChannel channel, boolean strict) throws IOException + { + ByteBuffer buffer = ByteBuffer.allocateDirect(4); + + if (fill(buffer, channel) == -1) + { + throw new EOFException("Premature end of header"); + } + + buffer.order(ByteOrder.LITTLE_ENDIAN); + + int length = buffer.getShort(2) * 2; + ByteBuffer old = buffer; + + old.position(0); + + // ensure enough capacity for one more record header + buffer = ByteBuffer.allocateDirect(length + 4); + buffer.put(old); + + if (fill(buffer, channel) == -1) + { + throw new EOFException("Premature end of header"); + } + + buffer.position(0); + + Dgn7fileHeader header = new Dgn7fileHeader(); + + header.read(buffer, strict); + + return header; + } + + public Dgn7fileHeader getHeader() + { + return header; + } + + public void close() throws IOException + { + lock.unlockRead(); + + if (channel.isOpen()) + { + channel.close(); + streamLogger.close(); + } + + if (buffer instanceof MappedByteBuffer) + { + NIOUtilities.clean(buffer); + } + + channel = null; + header = null; + } + + public boolean supportsRandomAccess() + { + return randomAccessEnabled; + } + + public Record nextElement() throws IOException, Dgn7fileException + { + // need to update position + buffer.position(this.toBufferOffset(record.end)); + + // record header is big endian + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // read shape record header + int recordNumber = ++maxElementId; + short signature = buffer.getShort(); + + // byte type = (byte) (buffer.get() & 0x7f); + byte type = (byte) ((signature >>> 8) & 0x007f); + + // silly Bentley say contentLength is in 2-byte words + // and ByteByffer uses bytes. + // track the record location + int elementLength = (buffer.getShort() * 2) + 4; + + if (!buffer.isReadOnly() && !useMemoryMappedBuffer) + { + // capacity is less than required for the record + // copy the old into the newly allocated + if (buffer.capacity() < elementLength) + { + this.currentOffset += buffer.position(); + + ByteBuffer old = buffer; + + // ensure enough capacity for one more record header + buffer = ensureCapacity(buffer, elementLength, useMemoryMappedBuffer); + buffer.put(old); + fill(buffer, channel); + buffer.position(0); + } else + + // remaining is less than record length + // compact the remaining data and read again, + // allowing enough room for one more record header + if (buffer.remaining() < elementLength) + { + this.currentOffset += buffer.position(); + buffer.compact(); + fill(buffer, channel); + buffer.position(0); + } + } + + // shape record is all little endian + // buffer.order(ByteOrder.LITTLE_ENDIAN); + // read the type, handlers don't need it + ElementType recordType = ElementType.forID(type); + + logger.debug("nextElement at " + this.toBufferOffset(record.end) + ":type=" + type); + + // this usually happens if the handler logic is bunk, + // but bad files could exist as well... + + /* + * if (recordType != ElementType.NULL && recordType != fileElementType) + * { + * throw new IllegalStateException("ShapeType changed illegally from " + fileElementType + " to " + recordType); + * } + */ + + // peek at bounds, then reset for handler + // many handler's may ignore bounds reading, but we don't want to + // second guess them... + buffer.mark(); + + if (recordType.isMultiPoint()) + { + int lowCoorX = buffer.getInt(); + + lowCoorX = DgnUtility.convertFromDGN(lowCoorX); + record.minX = DgnUtility.converUnitToCoord(lowCoorX); + + int lowCoorY = buffer.getInt(); + + lowCoorY = DgnUtility.convertFromDGN(lowCoorY); + record.minY = DgnUtility.converUnitToCoord(lowCoorY); + + int lowCoorZ = buffer.getInt(); + + lowCoorZ = DgnUtility.convertFromDGN(lowCoorZ); + record.minZ = DgnUtility.converUnitToCoord(lowCoorZ); + + int highCoorX = buffer.getInt(); + + highCoorX = DgnUtility.convertFromDGN(highCoorX); + record.maxX = DgnUtility.converUnitToCoord(highCoorX); + + int highCoorY = buffer.getInt(); + + highCoorY = DgnUtility.convertFromDGN(highCoorY); + record.maxY = DgnUtility.converUnitToCoord(highCoorY); + + int highCoorZ = buffer.getInt(); + + highCoorZ = DgnUtility.convertFromDGN(highCoorZ); + record.maxZ = DgnUtility.converUnitToCoord(highCoorZ); + } + + buffer.reset(); + record.offset = record.end; + + // update all the record info. + record.length = elementLength; + record.signature = signature; + record.number = recordNumber; + + // remember, we read one int already... + record.end = this.toFileOffset(buffer.position()) + elementLength - 4; + // record.end = this.toFileOffset(buffer.position()) + elementLength; + + // mark this position for the reader + record.start = buffer.position(); + + // clear any cached record + record.handler = recordType.getElementHandler(); + record.element = null; + + return record; + } + + public void goTo(int offset) throws IOException, UnsupportedOperationException + { + if (randomAccessEnabled) + { + if (this.useMemoryMappedBuffer) + { + buffer.position(offset); + } else + { + /* + * Check to see if requested offset is already loaded; ensure + * that record header is in the buffer + */ + if ((this.currentOffset <= offset) && (this.currentOffset + buffer.limit() >= offset + 4)) + { + buffer.position(this.toBufferOffset(offset)); + } else + { + FileChannel fc = (FileChannel) this.channel; + + fc.position(offset); + this.currentOffset = offset; + buffer.position(0); + fill(buffer, fc); + buffer.position(0); + } + } + + int oldRecordOffset = record.end; + + record.end = offset; + + try + { + hasNext(); + } catch (IOException ioe) + { + record.end = oldRecordOffset; + + throw ioe; + } + } else + { + throw new UnsupportedOperationException("Random Access not enabled"); + } + } + + public Record elementAt(int offset) throws IOException, UnsupportedOperationException, Dgn7fileException + { + if (randomAccessEnabled) + { + this.goTo(offset); + + return nextElement(); + } + + throw new UnsupportedOperationException("Random Access not enabled"); + } + + public boolean hasNext() throws IOException + { + // mark current position + int position = buffer.position(); + + // ensure the proper position, regardless of read or handler behavior + try + { + buffer.position(this.toBufferOffset(record.end)); + } catch (IllegalArgumentException e) + { + logger.warn("position=" + this.toBufferOffset(record.end), e); + + return false; + } + + // no more data left + if (buffer.remaining() < 4) + { + return false; + } + + // looks good + boolean hasNext = true; + short type = buffer.getShort(); + + if (type == -1) + { + hasNext = false; + } + + // reset things to as they were + buffer.position(position); + + return hasNext; + } + + private void init(boolean strict) throws IOException, Dgn7fileException + { + header = readHeader(channel, strict); + + // fileElementType = header.getElementType(); + // handler = fileElementType.getElementHandler(); + + // recordHeader = ByteBuffer.allocateDirect(4); + // recordHeader.order(ByteOrder.BIG_ENDIAN); + // if (handler == null) + // { + // throw new IOException("Unsuported shape type:" + fileElementType); + // } + if ((channel instanceof FileChannel) && useMemoryMappedBuffer) + { + FileChannel fc = (FileChannel) channel; + + buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); + + // buffer.position(100); + buffer.position(header.size()); + this.currentOffset = 0; + } else + { + // force useMemoryMappedBuffer to false + this.useMemoryMappedBuffer = false; + + // start with 8K buffer + buffer = ByteBuffer.allocateDirect(8 * 1024); + fill(buffer, channel); + buffer.flip(); + this.currentOffset = header.size(); + } + + headerTransfer = ByteBuffer.allocate(4); + headerTransfer.order(ByteOrder.LITTLE_ENDIAN); + + // make sure the record end is set now... + record.end = toFileOffset(buffer.position()); + } + + private int toBufferOffset(int offset) + { + return (int) (offset - currentOffset); + } + + private int toFileOffset(int offset) + { + return (int) (currentOffset + offset); + } + + public int getCount(int count) throws Dgn7fileException + { + try + { + if (channel == null) + { + return -1; + } + + count = 0; + + for (int tmp = readElement(); tmp != -1; tmp = readElement()) + { + count += tmp; + } + } catch (IOException ioe) + { + count = -1; + + // What now? This seems arbitrarily appropriate ! + throw new Dgn7fileException("Problem reading dgnfile record", ioe); + } + + return count; + } + + public int getCount() throws Dgn7fileException + { + return getCount(0); + } + + private int readElement() throws IOException + { + if (!fillBuffer()) + { + return -1; + } + + // burn the record number + buffer.getInt(); + + if (!fillBuffer()) + { + return -1; + } + + int recordlength = buffer.getInt() * 2; + + // Going to read the first 4 bytes of the record so + // subtract that from the record length + recordlength -= 4; + + if (!fillBuffer()) + { + return -1; + } + + // read record type (used to determine if record is a null record) + int type = buffer.getInt(); + + // go to end of record + while (buffer.limit() < buffer.position() + recordlength) + { + recordlength -= buffer.limit() - buffer.position(); + buffer.clear(); + + if (channel.read(buffer) < 1) + { + return -1; + } + } + + buffer.position(buffer.position() + recordlength); + + // return 0 if record is null. Null records should be counted. + if (type == 0) + { + // this is a null feature + return 0; + } + + return 1; + } + + private boolean fillBuffer() throws IOException + { + int result = 1; + + if (buffer.limit() <= buffer.position() + 4) + { + result = fill(buffer, channel); + } + + return result > 0; + } + + public static void main(String[] args) + { + JFileChooser jfc = new JFileChooser("D:/TEMP"); + File f = null; + int r = jfc.showOpenDialog(new JFrame()); + + if (r == JFileChooser.APPROVE_OPTION) + { + try + { + f = jfc.getSelectedFile(); + + FileChannel channel = new FileInputStream(f).getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(channel, new Lock()); + + System.out.println(reader.getHeader().toString()); + + GeometryFactory factory = new GeometryFactory(); + int count, size; + + count = 0; + size = 0; + + try + { + Element lastComplex = null; + + while (reader.hasNext()) + { + size++; + + Dgn7fileReader.Record record = reader.nextElement(); + + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + // @todo add process in here + count++; + lastComplex = null; + } + + // @todo add process in here + count++; + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex == null) + { + lastComplex = element; + } else + { + // @todo add process in here + count++; + lastComplex = element; + } + } + } + } + } catch (IOException e) + { + logger.warn("Stop read dgn file", e); + } catch (Dgn7fileException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } finally + { + reader.close(); + } + + System.out.println("count=" + count + " size=" + size); + // reader.close(); + } catch (IOException ioe) + { + System.out.println(ioe); + ioe.printStackTrace(); + } catch (Dgn7fileException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + + System.exit(0); + } + + public final class Record + { + int length; + int number = 0; + int offset; // Relative to the whole file + int start = 0; // Relative to the current loaded buffer + short signature = 0; + + /** + * The minimum X value. + */ + public double minX; + + /** + * The minimum Y value. + */ + public double minY; + + /** + * The minimum Z value. + */ + public double minZ; + + /** + * The maximum X value. + */ + public double maxX; + + /** + * The maximum Y value. + */ + public double maxY; + + /** + * The maximum Z value. + */ + public double maxZ; + + // ElementType type; + int end = 0; // Relative to the whole file + Object element = null; + IElementHandler handler; + + public Object element() + { + if (element == null) + { + buffer.position(start); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + if (handler == null) + { + return null; + } + + element = handler.read(buffer, signature, length); + } + + return element; + } + + public int offset() + { + return offset; + } + + /** + * A summary of the record. + */ + public String toString() + { + return "Record " + number + " length " + length + " bounds " + minX + "," + minY + " " + maxX + "," + maxY; + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Element.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Element.java new file mode 100644 index 0000000..030b950 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Element.java @@ -0,0 +1,334 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.ShortBuffer; +import java.util.ArrayList; +import java.util.List; + +import com.vividsolutions.jts.geom.Envelope; + +import com.ximple.util.DgnUtility; + +/** + * Record + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �W�� 11:14:50 + */ +public class Element +{ + public static final int CONSTRUCTION_CLASS = 0; + public static final int CONSTRUCTION_RULE_CLASS = 0; + public static final int DIMENSION_CLASS = 0; + public static final int LINEAR_PATTERNED_CLASS = 0; + public static final int MAX_ELEMENT_SIZE = 0; + public static final int MAX_VERTICES = 100; + public static final int PATTERN_AREA = 0; + public static final int PATTERN_COMPONENT_CLASS = 0; + public static final int PATTERN_CROSSHATCH = 0; + public static final int PATTERN_HATCH = 0; + public static final int PRIMARY_CLASS = 0; + public static final int PRIMARY_RULE_CLASS = 0; + + protected short[] raw; + protected byte attrOffset = 0; + protected ByteBuffer rawBuffer; + + public Element(byte[] raw) + { + // this.raw = raw; + this.raw = new short[raw.length / 2]; + rawBuffer = ByteBuffer.wrap(raw); + rawBuffer.order(ByteOrder.LITTLE_ENDIAN); + rawBuffer.asShortBuffer().get(this.raw); + } + + public int getLineStyle() + { + return 0; + } + + public Envelope getRange() + { + int lowCoorX = ((raw[3] << 16) & 0xffff0000) + (raw[2] & 0x0000ffff); + lowCoorX = DgnUtility.convertFromDGN(lowCoorX); + + int lowCoorY = ((raw[5] << 16) & 0xffff0000) + (raw[4] & 0x0000ffff); + lowCoorY = DgnUtility.convertFromDGN(lowCoorY); + + int highCoorX = ((raw[9] << 16) & 0xffff0000) + (raw[8] & 0x0000ffff); + highCoorX = DgnUtility.convertFromDGN(highCoorX); + + int highCoorY = ((raw[11] << 16) & 0xffff0000) + (raw[10] & 0x0000ffff); + highCoorY = DgnUtility.convertFromDGN(highCoorY); + + return new Envelope(DgnUtility.converUnitToCoord(lowCoorX), DgnUtility.converUnitToCoord(highCoorX), + DgnUtility.converUnitToCoord(lowCoorY), DgnUtility.converUnitToCoord(highCoorY)); + } + + public void setRange(Envelope bbox) + { + int lowCoordX = DgnUtility.converCoordToUnit(bbox.getMinX()); + int temp = DgnUtility.converToDGN(lowCoordX); + raw[3] = (short) (temp >> 16 & 0x0000ffff); + raw[2] = (short) (temp & 0x0000ffff); + + int lowCoordY = DgnUtility.converCoordToUnit(bbox.getMinY()); + temp = DgnUtility.converToDGN(lowCoordY); + raw[5] = (short) (temp >> 16 & 0x0000ffff); + raw[4] = (short) (temp & 0x0000ffff); + + int highCoorX = DgnUtility.converCoordToUnit(bbox.getMaxX()); + temp = DgnUtility.converToDGN(highCoorX); + raw[9] = (short) (temp >> 16 & 0x0000ffff); + raw[8] = (short) (temp & 0x0000ffff); + + int highCoorY = DgnUtility.converCoordToUnit(bbox.getMaxY()); + temp = DgnUtility.converToDGN(highCoorY); + raw[11] = (short) (temp >> 16 & 0x0000ffff); + raw[10] = (short) (temp & 0x0000ffff); + } + + public boolean isComponentElement() + { + return (short) ((raw[0] >>> 7) & 0x0001) == 1; + } + + public boolean removeUserAttributeData(int iLinkageId) + { + return true; + } + + public boolean removeUserAttributeData(int iLinkageId, int iLinkageIndex) + { + return true; + } + + public boolean isDeleted() + { + return (short) ((raw[0] >>> 15) & 0x0001) == 1; + } + + public int getColorIndex() + { + return ((raw[17] >>> 8) & 0x00ff); + } + + public int getType() + { + return ((raw[0] >>> 8) & 0x007f); + } + + public ElementType getElementType() + { + return ElementType.forID(getType()); + } + + public int getLevelIndex() + { + return (raw[0] & 0x003f); + } + + public void setLevelIndex(int value) + { + raw[0] = (short) ((raw[0] & 0xffc0) | (value & 0x003f)); + } + + public int getWeight() + { + return ((raw[17] >>> 3) & 0x001f); + } + + public void addUserAttributeData(byte[] pDataBlock, Class dataClass, int iLinkageId) throws Element.Exception + { + } + + public void addUserAttributeData(byte[] pDataBlock, int iLinkageId, Object oDataDef) throws Element.Exception + { + } + + public boolean hasUserAttributeData() + { + if (raw[15] <= 0) + { + return false; + } + + short index = (short) (raw[15] + 16); + + if (index == -1) + { + return false; + } + + return true; + } + + public List<UserAttributeData> getUserAttributeData() + { + short[] data; + short length, nextAttribute; + + if (raw[15] <= 0) + { + return new ArrayList<UserAttributeData>(); + } + + short index = (short) (raw[15] + 16 + attrOffset); + + if (index == -1) + { + return null; + } + + ArrayList<UserAttributeData> aLinkageSet = new ArrayList<UserAttributeData>(); + + while (index < raw.length) + { + length = (short) (raw[index] & (short) 0x00ff); + + if (length == 0) + { + break; + } + + nextAttribute = (short) (index + length + 1); + data = new short[length]; + System.arraycopy(raw, index + 1, data, 0, length); + + if (data[0] == (short) 0x0020) + { + aLinkageSet.add(new FrammeAttributeData(data)); + } else + { + aLinkageSet.add(new UserAttributeData(data)); + } + + index = nextAttribute; + } + + return aLinkageSet; + } + + public void getUserAttributeData(byte[] pDataBlock, Class dataClass, int iLinkageId, int iLinkageIndex) + { + } + + public void getUserAttributeData(byte[] pDataBlock, int iLinkageId, Object oDataDef) + { + } + + + public ByteBuffer getRawBuffer() + { + return rawBuffer.asReadOnlyBuffer(); + } + + public short[] getRawArray() + { + if (raw == null) return null; + short[] result = new short[raw.length]; + System.arraycopy(raw, 0, result, 0, raw.length); + return result; + } + + public static class Exception extends java.lang.Exception + { + public Exception() + { + } + + // Constructs an Record.Exception with no detail message. + public Exception(String oStrMessage) + { + super(oStrMessage); + } + } + + protected static int getOffsetPosition(int offset) + { + return offset * 2; + } + + public void resyncBuffer() + { + byte[] tempRaw = new byte[this.raw.length * 2]; + ByteBuffer tempBuffer = ByteBuffer.wrap(tempRaw); + tempBuffer.order(ByteOrder.LITTLE_ENDIAN); + tempBuffer.asShortBuffer().put(this.raw); + + int pos = rawBuffer.position(); + rawBuffer = tempBuffer; + rawBuffer.position(pos); + } + + public static class ElementHandler implements IElementHandler + { + ElementType elementType; + + public ElementHandler(ElementType elementType) + { + this.elementType = elementType; + } + + public ElementType getElementType() + { + return elementType; + } + + public Object read(ByteBuffer buffer, short signature, int length) + { + byte[] dst = new byte[length]; + try + { + buffer.get(dst, 4, dst.length - 4); + } catch (BufferUnderflowException exception) + { + throw exception; + } + + ByteBuffer tmpBuffer = ByteBuffer.wrap(dst); + tmpBuffer.order(ByteOrder.LITTLE_ENDIAN); + tmpBuffer.position(0); + tmpBuffer.putShort(signature); + tmpBuffer.putShort((short) ((length / 2) - 2)); + + /* + ShortBuffer sbuffer = tmpBuffer.asShortBuffer(); + + short[] rawMem = new short[(length / 2)]; + sbuffer.get(rawMem, 2, rawMem.length - 2); + rawMem[0] = signature; + rawMem[1] = (short) ((length / 2) - 2); + */ + Element elm = createElement(dst); + + return elm; + } + + public void write(ByteBuffer buffer, Object element) + { + buffer.put(((Element) element).rawBuffer); + } + + public int getLength(Object element) + { + return ((Element) element).raw.length; + } + + public int getBufferLength(Object element) + { + return ((Element) element).rawBuffer.limit(); + } + + protected Element createElement(byte[] raw) + { + return new Element(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ElementType.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ElementType.java new file mode 100644 index 0000000..5612e7a --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ElementType.java @@ -0,0 +1,385 @@ +package com.ximple.io.dgn7; + +//~--- non-JDK imports -------------------------------------------------------- + +/*----------------------------------------------------------------------+ +| | +| Type Description | +| 1 Cell Library Header | +| 2 Cell (complex) | +| 3 Line | +| 4 Line String | +| 5 Group Data | +| 6 Shape | +| 7 Text Node (complex) | +| 8 Digitizer Setup Data | +| 9 Design File Header if level 8 | +| 10 Level Symbology | +| 11 Curve | +| 12 Complex String (complex) | +| 13 Conic | +| 14 Complex Shape (complex) | +| 15 Ellipse | +| 16 Arc | +| 17 Text | +| 18 Surface (complex) | +| 19 Solid (complex) | +| 20 not used | +| 21 B-Spline Pole | +| 22 Point String | +| 23 Circular Truncated Cone | +| 24 B-Spline Surface (complex) | +| 25 B-Spline Surface boundary | +| 26 B-Spline Knot Record | +| 27 B-Spline Curve (complex) | +| 28 B-Spline Weight Factor | +| 33 Dimension Record | +| 34 Shared Cell Definition Record | +| 35 Shared Cell Record | +| 36 Multiline Record | +| 37 Attribute Record | +| 38 DgnStore Component | +| 39 DgnStore Header | +| 66 MicroStation Application | +| 87 Raster Header | +| 88 Raster Component | +| 90 Raster Reference Attachment | +| 91 Raster Reference Component | +| 92 Raster Hierarchy Record | +| 93 Raster Hierarchy Component | +| 94 Raster Frame Record | +| 95 Table Entry Record | +| 96 Table Header Record | +| 97 View Group Record | +| 98 View Record | +| 99 Level Mask Record | +| 100 Reference Attach Record | +| 101 Matrix Header | +| 102 Matrix Int Data | +| 103 Matrix Double Data | +| 105 Mesh Header | +| 106 Extended Record (graphic) (complex) | +| 107 Extended Record (non-graphic) (complex) | +| 108 Reference Override Record | +| 110 Named Group Header | +| 111 Named Group Component | +| | ++----------------------------------------------------------------------*/ + +/** + * ElementType + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/17 �U�� 01:26:49 + */ +public final class ElementType +{ + /** + * Represents a Null shape (id = 0). + */ + public static final ElementType NULL = new ElementType(0, "Null"); + + /** + * Represents a Line shape (id = 3). + */ + public static final ElementType LINE = new ElementType(3, "Line"); + + /** + * Represents a LineString shape (id = 4). + */ + public static final ElementType LINESTRING = new ElementType(4, "LineString"); + + /** + * Represents a Shape shape (id = 6). + */ + public static final ElementType SHAPE = new ElementType(6, "Shape"); + + /** + * Represents an TextNode shape (id = 7). + */ + public static final ElementType TEXTNODE = new ElementType(7, "TextNode"); + + /** + * Represents an IGDSDIGITIZER shape (id = 8). + */ + public static final ElementType IGDSDIGITIZER = new ElementType(8, "IGDSDigitizer"); + + /** + * Represents an TCB shape (id = 9). + */ + public static final ElementType TCB = new ElementType(9, "Tcb"); + + /** + * Represents a LevelSymbology shape (id = 5). + */ + public static final ElementType LEVELSYMBOLOGY = new ElementType(10, "LevelSymbology"); + + /** + * Represents a ComplexChain shape (id = 15). + */ + public static final ElementType COMPLEXCHAIN = new ElementType(12, "ComplexChain"); + + /** + * Represents a ComplexShape shape (id = 25). + */ + public static final ElementType COMPLEXSHAPE = new ElementType(14, "ComplexShape"); + + /** + * Represents a Ellipse shape (id = 8). + */ + public static final ElementType ELLIPSE = new ElementType(15, "Ellipse"); + + /** + * Represents a Arc shape (id = 28). + */ + public static final ElementType ARC = new ElementType(16, "Arc"); + + /** + * Represents a Arc shape (id = 28). + */ + public static final ElementType TEXT = new ElementType(17, "Text"); + + /** + * Represents a Arc shape (id = 28). + */ + public static final ElementType POINTSTRING = new ElementType(22, "PointString"); + + /** + * Represents an Undefined shape (id = -1). + */ + public static final ElementType UNDEFINED = new ElementType(-1, "Undefined"); + + /** + * The integer id of this ElementType. + */ + public final int id; + + /** + * The human-readable name for this ElementType.<br> + * Could easily use ResourceBundle for internationialization. + */ + public final String name; + + /** + * Creates a new instance of ElementType. Hidden on purpose. + * + * @param id The id. + * @param name The name. + */ + protected ElementType(int id, String name) + { + this.id = id; + this.name = name; + } + + /** + * Get the name of this ElementType. + * + * @return The name. + */ + public String toString() + { + return name; + } + + /** + * Is this a multipoint shape? Hint- all shapes are multipoint except NULL, + * UNDEFINED, and the POINTs. + * + * @return true if multipoint, false otherwise. + */ + public boolean isMultiPoint() + { + boolean mp = true; + + if (this == UNDEFINED) + { + mp = false; + } else if (this == NULL) + { + mp = false; + } else if (this == IGDSDIGITIZER) + { + mp = false; + } else if (this == TCB) + { + mp = false; + } else if (this == LEVELSYMBOLOGY) + { + mp = false; + } + + return mp; + } + + public boolean isComplexElement() + { + return id == 2 || id == 7 || id == 12 || id == 14 || id == 18 || + id == 19 || id == 106 || id == 107; + + } + + public boolean isPointType() + { + return id == 7 || id == 17; + + } + + public boolean isLineType() + { + return id == 3 || id == 4 || id == 11 || id == 12 || id == 16; + + } + + public boolean isPolygonType() + { + return id == 6 || id == 14; + + } + + public boolean isMultiPointType() + { + return id == 3 || id == 4 || id == 6 || id == 11 || id == 12 || + id == 13 || id == 14 || id == 15 || id == 16 || id == 22; + + } + + public boolean isArcType() + { + return id == 15 || (id == 16); + } + + /** + * Determine the ElementType for the id. + * + * @param id The id to search for. + * @return The ElementType for the id. + */ + public static ElementType forID(int id) + { + ElementType t; + + switch (id) + { + case 0: + t = NULL; + break; + + case 3: + t = LINE; + break; + + case 4: + t = LINESTRING; + break; + + case 6: + t = SHAPE; + break; + + case 7: + t = TEXTNODE; + break; + + case 8: + t = IGDSDIGITIZER; + break; + + case 9: + t = TCB; + break; + + case 10: + t = LEVELSYMBOLOGY; + break; + + case 12: + t = COMPLEXCHAIN; + break; + + case 14: + t = COMPLEXSHAPE; + break; + + case 15: + t = ELLIPSE; + break; + + case 16: + t = ARC; + break; + + case 17: + t = TEXT; + break; + + default: + t = UNDEFINED; + break; + } + + return t; + } + + public IElementHandler getElementHandler() throws Dgn7fileException + { + IElementHandler handler; + + switch (id) + { + case 3: + handler = LineElement.ElementHandler.getInstance(); + break; + + case 4: + handler = LineStringElement.ElementHandler.getInstance(); + break; + + case 6: + handler = ShapeElement.ElementHandler.getInstance(); + break; + + case 7: + handler = TextNodeElement.ElementHandler.getInstance(); + break; + + case 8: + handler = new Element.ElementHandler(this); + break; + + case 9: + handler = new Element.ElementHandler(this); + break; + + case 10: + handler = new Element.ElementHandler(this); + break; + + case 12: + handler = ComplexChainElement.ElementHandler.getInstance(); + break; + + case 14: + handler = ComplexShapeElement.ElementHandler.getInstance(); + break; + + case 15: + handler = EllipseElement.ElementHandler.getInstance(); + break; + + case 16: + handler = ArcElement.ElementHandler.getInstance(); + break; + + case 17: + handler = TextElement.ElementHandler.getInstance(); + break; + + default: + handler = null; + } + + return handler; + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/EllipseElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/EllipseElement.java new file mode 100644 index 0000000..044d57a --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/EllipseElement.java @@ -0,0 +1,211 @@ +package com.ximple.io.dgn7; + +import java.nio.ByteOrder; +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.util.DgnUtility; + +public class EllipseElement extends Element implements GeometryConverter +{ + private static final Logger logger = Logger.getLogger(EllipseElement.class); + + public EllipseElement(byte[] raw) + { + super(raw); + } + + public double getStartAngle() + { + return 0.0; + } + + public void setStartAngle(double value) + { + } + + public double getSweepAngle() + { + return 360.0; + } + + public void setSweepAngle(double value) + { + } + + public double getPrimary() + { + rawBuffer.position(18 * 2); + ByteOrder bo = rawBuffer.order(); + rawBuffer.order(ByteOrder.BIG_ENDIAN); + byte[] primary = new byte[8]; + rawBuffer.get(primary); + rawBuffer.order(bo); + return DgnUtility.convertDGNToIEEEDouble(primary) / 1000.0; + } + + public void setPrimary(double value) + { + double temp = value * 1000.0; + short[] primary = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(primary, 0, raw, 18, 4); + } + + public double getSecondary() + { + rawBuffer.position(22 * 2); + ByteOrder bo = rawBuffer.order(); + rawBuffer.order(ByteOrder.BIG_ENDIAN); + byte[] secondary = new byte[8]; + rawBuffer.get(secondary); + rawBuffer.order(bo); + return DgnUtility.convertDGNToIEEEDouble(secondary) / 1000.0; + } + + public void setSecondary(double value) + { + double temp = value * 1000.0; + short[] secondary = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(secondary, 0, raw, 22, 4); + } + + public double getRotationAngle() + { + int rotation = (raw[26] << 16 & 0xffff0000); + rotation |= raw[27] & 0x0000ffff; + + return DgnUtility.converIntToRotation(rotation); + } + + public void setRotationAngle(double value) + { + int angle = DgnUtility.converRotatioToInt(value); + + raw[26] = (short) (angle >> 16 & 0x0000ffff); + raw[27] = (short) (angle & 0x0000ffff); + } + + public Coordinate getOrigin() + { + rawBuffer.position(28 * 2); + ByteOrder bo = rawBuffer.order(); + rawBuffer.order(ByteOrder.BIG_ENDIAN); + byte[] rawValue = new byte[8]; + + rawBuffer.get(rawValue); // x + double dx = DgnUtility.converUnitToCoord(DgnUtility.convertDGNToIEEEDouble(rawValue)); + + rawBuffer.get(rawValue); // y + double dy = DgnUtility.converUnitToCoord(DgnUtility.convertDGNToIEEEDouble(rawValue)); + + rawBuffer.order(bo); + + return new Coordinate(dx, dy); + } + + public void setOrigin(Coordinate value) + { + double temp = DgnUtility.converCoordToUnit(value.x); + short[] x = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(x, 0, raw, 28, 4); + temp = DgnUtility.converCoordToUnit(value.y); + + short[] y = DgnUtility.convertIEEEDoubleToDGN(temp); + + System.arraycopy(y, 0, raw, 32, 4); + } + + public Geometry toGeometry(GeometryFactory factory) + { + double temp = Math.abs(getStartAngle() - getSweepAngle()); + temp /= 4; + int pts = (temp < 3) ? 3 : (int) temp; + return factory.createPolygon(factory.createLinearRing(convertToLineString(pts)), null); + } + + private Coordinate[] convertToLineString(int pts) + { + ArrayList<Coordinate> result = new ArrayList<Coordinate>(); + double beta = DgnUtility.converRotationToRadian(-getRotationAngle()); + double startAngle = getStartAngle(); + double sweepAngle = getSweepAngle(); + double endAngle = startAngle + sweepAngle; + double steps = sweepAngle / pts; + double current; + if (sweepAngle < 0) + { + for (current = startAngle; current > endAngle; current += steps) + { + Coordinate pt = computePointOnArcByAngle(beta, current); + result.add(pt); + } + + } else + { + for (current = startAngle; current < endAngle; current += steps) + { + Coordinate pt = computePointOnArcByAngle(beta, current); + result.add(pt); + } + } + + Coordinate pt = computePointOnArcByAngle(beta, endAngle); + result.add(pt); + + if (!result.get(0).equals(result.get(result.size() - 1))) + { + result.add(result.get(0)); + } + + return result.toArray(new Coordinate[result.size()]); + } + + + private Coordinate computePointOnArcByAngle(double beta, double current) + { + double sinbeta = Math.sin(beta); + double cosbeta = Math.cos(beta); + Coordinate pt = new Coordinate(); + double alpha = DgnUtility.converRotationToRadian(current); + double sinalpha = Math.sin(alpha); + double cosalpha = Math.cos(alpha); + pt.x = getOrigin().x + (getPrimary() * cosalpha * cosbeta - + getSecondary() * sinalpha * sinbeta); + pt.y = getOrigin().y + (getPrimary() * cosalpha * sinbeta + + getSecondary() * sinalpha * cosbeta); + return pt; + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.ELLIPSE); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new EllipseElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/FrammeAttributeData.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/FrammeAttributeData.java new file mode 100644 index 0000000..2a9840e --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/FrammeAttributeData.java @@ -0,0 +1,71 @@ +package com.ximple.io.dgn7; + +/** + * FrammeAttributeData + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 06:36:55 + */ +public class FrammeAttributeData extends UserAttributeData +{ + public FrammeAttributeData(short id) + { + super(id, 7); + } + + public FrammeAttributeData(short[] src) + { + super(src); + } + + public short getFsc() + { + int fsc = _src[3] & 0x0000ffff; + + return (short) fsc; + } + + public int getUfid() + { + int ufid = (int) (_src[2] << 16 & 0xffff0000); + + ufid += _src[1] & 0x0000ffff; + + return ufid; + } + + public byte getComponentID() + { + int cmpid = (int) (_src[5] & 0x000000ff); + + return (byte) cmpid; + } + + public byte getRuleNo() + { + int no = (int) ((_src[5] >> 8) & 0x000000ff); + + return (byte) no; + } + + public short getStatus() + { + int status = (int) (_src[4] & 0x0000ffff); + + return (short) status; + } + + public short getOccID() + { + int occid = (int) (_src[6] & 0x0000ffff); + + return (short) occid; + } + + public String toString() + { + return "FrammeData{" + getFsc() + "," + getUfid() + "," + getComponentID() + "," + getRuleNo() + "," + getStatus() + "," + + getOccID() + "}"; + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/GeometryConverter.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/GeometryConverter.java new file mode 100644 index 0000000..2ac6fdc --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/GeometryConverter.java @@ -0,0 +1,18 @@ +package com.ximple.io.dgn7; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +/** + * GeometryConverter + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �W�� 11:38:57 + */ +public interface GeometryConverter +{ + public Geometry toGeometry(GeometryFactory factory); +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/IElementHandler.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/IElementHandler.java new file mode 100644 index 0000000..37af5e9 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/IElementHandler.java @@ -0,0 +1,25 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.nio.ByteBuffer; + +/** + * IElementHandler + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/17 �U�� 01:50:26 + */ +public interface IElementHandler +{ + public ElementType getElementType(); + + public Object read(ByteBuffer buffer, short signature, int length); + + public void write(ByteBuffer buffer, Object element); + + public int getLength(Object element); + + public int getBufferLength(Object element); +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineElement.java new file mode 100644 index 0000000..2996936 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineElement.java @@ -0,0 +1,130 @@ +package com.ximple.io.dgn7; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.util.DgnUtility; + +/** + * LineElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �W�� 11:34:59 + */ +public class LineElement extends Element implements GeometryConverter +{ + private static final Logger logger = Logger.getLogger(LineElement.class); + + public LineElement(byte[] raw) + { + super(raw); + } + + public Coordinate getCentroid(double dTolerance) + { + return null; + } + + public Coordinate getEndPoint() + { + int endX = ((raw[22] << 16) & 0xffff0000) | (raw[23] & 0x0000ffff); + int endY = ((raw[24] << 16) & 0xffff0000) | (raw[25] & 0x0000ffff); + + + double x = DgnUtility.converUnitToCoord(endX); + double y = DgnUtility.converUnitToCoord(endY); + + return new Coordinate(x, y); + } + + public Coordinate getNormal() + { + return null; + } + + public Coordinate getOrigin() + { + return null; + } + + public Coordinate getStartPoint() + { + int startX = ((raw[18] << 16) & 0xffff0000); + startX = startX + (raw[19] & 0x0000ffff); + + double x = DgnUtility.converUnitToCoord(startX); + int startY = ((raw[20] << 16) & 0xffff0000); + + startY = startY + (raw[21] & 0x0000ffff); + + double y = DgnUtility.converUnitToCoord(startY); + + return new Coordinate(x, y); + } + + public Coordinate getVertex(int index) + { + return (index == 0) + ? getStartPoint() + : getEndPoint(); + } + + public double getLength() + { + Coordinate p1 = getStartPoint(); + Coordinate p2 = getEndPoint(); + + return DgnUtility.getLength(p1.x, p1.y, p2.x, p2.y); + } + + public Coordinate pointAtDistance(double dDistance, double dTolerance) + { + return null; + } + + public Coordinate[] getVertices() + { + Coordinate[] result = new Coordinate[2]; + + result[0] = getStartPoint(); + result[1] = getEndPoint(); + + return result; + } + + public Geometry toGeometry(GeometryFactory factory) + { + return factory.createLineString(getVertices()); + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.LINE); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new LineElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineStringElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineStringElement.java new file mode 100644 index 0000000..ce09145 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/LineStringElement.java @@ -0,0 +1,171 @@ +package com.ximple.io.dgn7; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.util.DgnUtility; + +/** + * LineStringElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 02:48:58 + */ +public class LineStringElement extends Element implements GeometryConverter +{ + private static final Logger logger = Logger.getLogger(LineStringElement.class); + + public LineStringElement(byte[] raw) + { + super(raw); + } + + public Coordinate getCentroid(double dTolerance) + { + return null; + } + + public Coordinate getEndPoint() + { + return new Coordinate(getX(getVerticeSize() - 1), getY(getVerticeSize() - 1)); + } + + public Coordinate getNormal() + { + return null; + } + + public Coordinate getOrigin() + { + return null; + } + + public Coordinate getStartPoint() + { + return new Coordinate(getX(0), getY(0)); + } + + public Coordinate getVertex(int index) + { + return (index == 0) + ? getStartPoint() + : getEndPoint(); + } + + public int getVerticeSize() + { + return raw[18] & 0x0000ffff; + } + + public double getLength() + { + double result = 0.0; + Coordinate[] vset = getVertices(); + + for (int i = 1; i < getVerticeSize(); i++) + { + Coordinate p1 = vset[i - 1]; + Coordinate p2 = vset[i]; + + result += DgnUtility.getLength(p1.x, p1.y, p2.x, p2.y); + } + + return result; + } + + public Coordinate pointAtDistance(double dDistance, double dTolerance) + { + return null; + } + + public Coordinate[] getVertices() + { + Coordinate[] result = new Coordinate[getVerticeSize()]; + + for (int i = 0; i < getVerticeSize(); i++) + { + result[i] = new Coordinate(getX(i), getY(i)); + } + + return result; + } + + public Geometry toGeometry(GeometryFactory factory) + { + return factory.createLineString(getVertices()); + } + + protected double getX(int index) + { + if ((index < 0) || (index > getVerticeSize())) + { + return -1; + } + + int x = ((raw[19 + (4 * index)] << 16) & 0xffff0000); + + x += (raw[20 + (4 * index)] & 0x0000ffff); + + return DgnUtility.converUnitToCoord(x); + } + + protected void setX(int index, double dx) + { + int newVal = DgnUtility.converCoordToUnit(dx); + + raw[19 + (4 * index)] = (short) (newVal >> 16 & 0x0000ffff); + raw[20 + (4 * index)] = (short) (newVal & 0x0000ffff); + } + + protected double getY(int index) + { + if ((index < 0) || (index > getVerticeSize())) + { + return -1; + } + + int y = ((raw[21 + (4 * index)] << 16) & 0xffff0000); + y = y + (raw[22 + (4 * index)] & 0x0000ffff); + + return DgnUtility.converUnitToCoord(y); + } + + protected void setY(int index, double dy) + { + int newVal = DgnUtility.converCoordToUnit(dy); + + raw[21 + (4 * index)] = (short) ((newVal >> 16) & 0x0000ffff); + raw[22 + (4 * index)] = (short) (newVal & 0x0000ffff); + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.LINESTRING); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new LineStringElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Lock.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Lock.java new file mode 100644 index 0000000..58f9f73 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Lock.java @@ -0,0 +1,263 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +/** + * Lock + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �W�� 10:27:24 + */ +public class Lock +{ + Logger logger = LogManager.getLogger("com.ximple.io.dgn7"); + + /** + * indicates a write is occurring + */ + int writeLocks = 0; + + /** + * if not null a writer is waiting for the lock or is writing. + */ + Thread writer; + + /** + * Thread->Owner map. If empty no read locks exist. + */ + Map owners = new HashMap(); + + /** + * If the lock can be read locked the lock will be read and default + * visibility for tests + * + * @return + * @throws java.io.IOException + */ + synchronized boolean canRead() throws IOException + { + if ((writer != null) && (writer != Thread.currentThread())) + { + return false; + } + + if (writer == null) + { + return true; + } + + if (owners.size() > 1) + { + return false; + } + + return true; + } + + /** + * If the lock can be read locked the lock will be read and default + * visibility for tests + * + * @return + * @throws IOException + */ + synchronized boolean canWrite() throws IOException + { + if (owners.size() > 1) + { + return false; + } + + if ((canRead()) && ((writer == Thread.currentThread()) || (writer == null))) + { + if (owners.isEmpty()) + { + return true; + } + + if (owners.containsKey(Thread.currentThread())) + { + return true; + } + } + + return false; + } + + /** + * Called by shapefileReader before a read is started and before an IOStream + * is openned. + * + * @throws IOException + */ + public synchronized void lockRead() throws IOException + { + if (!canRead()) + { + while ((writeLocks > 0) || (writer != null)) + { + try + { + wait(); + } catch (InterruptedException e) + { + throw (IOException) new IOException().initCause(e); + } + } + } + + assertTrue("A write lock exists that is owned by another thread", canRead()); + + Thread current = Thread.currentThread(); + Owner owner = (Owner) owners.get(current); + + if (owner != null) + { + owner.timesLocked++; + } else + { + owner = new Owner(current); + owners.put(current, owner); + } + + logger.debug("Start Read Lock:" + owner); + } + + private void assertTrue(String message, boolean b) + { + if (!b) + { + throw new AssertionError(message); + } + } + + /** + * Called by ShapefileReader after a read is complete and after the IOStream + * is closed. + */ + public synchronized void unlockRead() + { + assertTrue("Current thread does not have a readLock", owners.containsKey(Thread.currentThread())); + + Owner owner = (Owner) owners.get(Thread.currentThread()); + + assertTrue("Current thread has " + owner.timesLocked + "negative number of locks", owner.timesLocked > 0); + owner.timesLocked--; + + if (owner.timesLocked == 0) + { + owners.remove(Thread.currentThread()); + } + + notifyAll(); + logger.debug("unlock Read:" + owner); + } + + /** + * Called by ShapefileDataStore before a write is started and before an + * IOStream is openned. + * + * @throws IOException + */ + public synchronized void lockWrite() throws IOException + { + Thread currentThread = Thread.currentThread(); + + if (writer == null) + { + writer = currentThread; + } + + while (!canWrite()) + { + try + { + wait(); + } catch (InterruptedException e) + { + throw (IOException) new IOException().initCause(e); + } + + if (writer == null) + { + writer = currentThread; + } + } + + if (writer == null) + { + writer = currentThread; + } + + assertTrue("The current thread is not the writer", writer == currentThread); + assertTrue("There are read locks not belonging to the current thread.", canRead()); + writeLocks++; + logger.debug(currentThread.getName() + " is getting write lock:" + writeLocks); + } + + /** + * default visibility for tests + */ + synchronized int getReadLocks(Thread thread) + { + Owner owner = (Owner) owners.get(thread); + + if (owner == null) + { + return -1; + } + + return owner.timesLocked; + } + + public synchronized void unlockWrite() + { + if (writeLocks > 0) + { + assertTrue("current thread does not own the write lock", writer == Thread.currentThread()); + assertTrue("writeLock has already been unlocked", writeLocks > 0); + writeLocks--; + + if (writeLocks == 0) + { + writer = null; + } + } + + logger.debug("unlock write:" + Thread.currentThread().getName()); + notifyAll(); + } + + /** + * default visibility for tests + */ + synchronized boolean ownWriteLock(Thread thread) + { + return (writer == thread) && (writeLocks > 0); + } + + private class Owner + { + final Thread owner; + int timesLocked; + + Owner(Thread owner) + { + this.owner = owner; + timesLocked = 1; + } + + public String toString() + { + return owner.getName() + " has " + timesLocked + " locks"; + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/NIOUtilities.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/NIOUtilities.java new file mode 100644 index 0000000..84c14af --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/NIOUtilities.java @@ -0,0 +1,127 @@ +package com.ximple.io.dgn7; + +/* + * GeoTools - OpenSource mapping toolkit + * http://geotools.org + * (C) 2003-2006, Geotools Project Managment Committee (PMC) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +// J2SE dependencies + +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Utility class for managing memory mapped buffers. + * + * @author Andres Aimes + * @version $Id$ + * @source $URL$ + * @since 2.0 + */ +public class NIOUtilities +{ + /** + * {@code true} if a warning has already been logged. + */ + private static boolean warned = false; + + /** + * Do not allows instantiation of this class. + * + * @todo This constructor will become private when {@code NIOBufferUtils} + * will have been removed. + */ + protected NIOUtilities() + { + } + + /** + * Really closes a {@code MappedByteBuffer} without the need to wait for garbage + * collection. Any problems with closing a buffer on Windows (the problem child in this + * case) will be logged as {@code SEVERE} to the logger of the package name. To + * force logging of errors, set the System property "org.geotools.io.debugBuffer" to "true". + * + * @param buffer The buffer to close. + * @return true if the operation was successful, false otherwise. + * @see java.nio.MappedByteBuffer + */ + public static boolean clean(final ByteBuffer buffer) + { + if (buffer == null || !buffer.isDirect()) + { + return false; + } + Boolean b = (Boolean) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + Boolean success = Boolean.FALSE; + try + { + Method getCleanerMethod = buffer.getClass().getMethod("cleaner", (Class[]) null); + getCleanerMethod.setAccessible(true); + Object cleaner = getCleanerMethod.invoke(buffer, (Object[]) null); + Method clean = cleaner.getClass().getMethod("clean", (Class[]) null); + clean.invoke(cleaner, (Object[]) null); + success = Boolean.TRUE; + } catch (Exception e) + { + // This really is a show stopper on windows + if (isLoggable()) + { + log(e, buffer); + } + } + return success; + } + }); + + return b.booleanValue(); + } + + /** + * Check if a warning message should be logged. + */ + private static synchronized boolean isLoggable() + { + try + { + return !warned && ( + System.getProperty("org.geotools.io.debugBuffer", "false").equalsIgnoreCase("true") || + System.getProperty("os.name").indexOf("Windows") >= 0); + } catch (SecurityException exception) + { + // The utilities may be running in an Applet, in which case we + // can't read properties. Assumes we are not in debugging mode. + return false; + } + } + + /** + * Log a warning message. + */ + private static synchronized void log(final Exception e, final ByteBuffer buffer) + { + warned = true; + String message = "Error attempting to close a mapped byte buffer : " + buffer.getClass().getName() + + "\n JVM : " + System.getProperty("java.version") + + ' ' + System.getProperty("java.vendor"); + Logger.getLogger("org.geotools.io").log(Level.SEVERE, message, e); + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ShapeElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ShapeElement.java new file mode 100644 index 0000000..945d11e --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ShapeElement.java @@ -0,0 +1,62 @@ +package com.ximple.io.dgn7; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LinearRing; + +/** + * ShapeElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 03:08:43 + */ +public class ShapeElement extends LineStringElement implements GeometryConverter +{ + private static final Logger logger = Logger.getLogger(ShapeElement.class); + + public ShapeElement(byte[] raw) + { + super(raw); + } + + public Geometry toGeometry(GeometryFactory factory) + { + try + { + LinearRing ring = factory.createLinearRing(this.getVertices()); + return factory.createPolygon(ring, null); + } catch (IllegalArgumentException e) + { + logger.warn(e.getMessage(), e); + return null; + } + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.SHAPE); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new ShapeElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/StreamLogging.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/StreamLogging.java new file mode 100644 index 0000000..8000b5c --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/StreamLogging.java @@ -0,0 +1,45 @@ +package com.ximple.io.dgn7; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +/** + * StreamLogging + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �W�� 10:31:08 + */ +public class StreamLogging +{ + private static final Logger LOGGER = LogManager.getLogger("com.ximple.io.dgn7"); + private String name; + private int open = 0; + + /** + * The name that will appear in the debug message + * + * @param name + */ + public StreamLogging(String name) + { + this.name = name; + } + + /** + * Call when reader or writer is opened + */ + public synchronized void open() + { + open++; + LOGGER.debug(name + " has been opened. Number open: " + open); + } + + public synchronized void close() + { + open--; + LOGGER.debug(name + " has been closed. Number open: " + open); + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TcbElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TcbElement.java new file mode 100644 index 0000000..2a2e165 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TcbElement.java @@ -0,0 +1,94 @@ +package com.ximple.io.dgn7; + +import org.apache.log4j.Logger; + +/** + * TcbElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 05:03:46 + */ +public class TcbElement extends Element +{ + private static final Logger logger = Logger.getLogger(TcbElement.class); + + public TcbElement(byte[] raw) + { + super(raw); + } + + public boolean is2D() + { + int dimension = (int) (raw[607] & 0x00000004); + + if (dimension == 0) + { + return true; + } else + { + return false; + } + } + + public String getMasterUnitName() + { + byte[] master = new byte[1]; + + master[0] = (byte) (raw[560] & 0x00ff); + java.nio.charset.Charset.forName("US-ASCII"); + + // ASCIIEncoding encode = new ASCIIEncoding(); + StringBuffer sb = new StringBuffer(); + + sb.append((char) master[0]); + + // return encode.GetString(master); + return sb.toString(); + } + + public String getSubUnitName() + { + byte[] sub = new byte[2]; + + sub[0] = (byte) (raw[561] & 0x00ff); + sub[1] = (byte) (raw[561] >> 8 & 0x00ff); + + StringBuffer sb = new StringBuffer(); + + sb.append((char) sub[0]); + sb.append((char) sub[0]); + + return sb.toString(); + } + + public int getGraphicGroup() + { + return (int) (raw[594] & 0x0000ffff); + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.TCB); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new TcbElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextElement.java new file mode 100644 index 0000000..79ca5eb --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextElement.java @@ -0,0 +1,352 @@ +package com.ximple.io.dgn7; + +import java.awt.geom.AffineTransform; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.util.DgnUtility; + +/** + * TextElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �W�� 11:45:29 + */ +public class TextElement extends Element implements GeometryConverter +{ + private static final Logger logger = Logger.getLogger(TextElement.class); + + public static final int ED_CENTERJUSTIFICATION = 0; + + // Enter data field center justification + public static final int ED_LEFTJUSTIFICATION = 0; + + // Enter data field left justification + public static final int ED_RIGHTJUSTIFICATION = 0; + + public static final int TXTJUST_LT = 0; /* Left Top */ + public static final int TXTJUST_LC = 1; /* Left Center */ + public static final int TXTJUST_LB = 2; /* Left Bottom */ + public static final int TXTJUST_LMT = 3; /* Left Margin Top */ + public static final int TXTJUST_LMC = 4; /* Left Margin Center */ + public static final int TXTJUST_LMB = 5; /* Left Margin Bottom */ + public static final int TXTJUST_CT = 6; /* Center Top */ + public static final int TXTJUST_CC = 7; /* Center Center */ + public static final int TXTJUST_CB = 8; /* Center Bottom */ + public static final int TXTJUST_RMT = 9; /* Right Margin Top */ + public static final int TXTJUST_RMC = 10; /* Right Margin Center */ + public static final int TXTJUST_RMB = 11; /* Right Margin Bottom */ + public static final int TXTJUST_RT = 12; /* Right Top */ + public static final int TXTJUST_RC = 13; /* Right Center */ + public static final int TXTJUST_RB = 14; /* Right Bottom */ + + public static final int TXTJUST_LU = 15; /* Left Cap */ + public static final int TXTJUST_LD = 16; /* Left Descender */ + public static final int TXTJUST_LMU = 17; /* Left Margin Cap */ + public static final int TXTJUST_LMD = 18; /* Left Margin Descender */ + public static final int TXTJUST_CU = 19; /* Center Cap */ + public static final int TXTJUST_CD = 20; /* Center Descender */ + public static final int TXTJUST_RMU = 21; /* Right Margin Cap */ + public static final int TXTJUST_RMD = 22; /* Right Margin Descender */ + public static final int TXTJUST_RU = 23; /* Right Cap */ + public static final int TXTJUST_RD = 24; /* Right Descender */ + public static final int TXTJUST_NONE = 127;/* no justfication */ + + public TextElement(byte[] raw) + { + super(raw); + } + + public Coordinate getOrigin() + { + int x = (raw[25] << 16 & 0xffff0000); + + x += raw[26] & 0x0000ffff; + + double dx = DgnUtility.converUnitToCoord(x); + int y = (raw[27] << 16 & 0xffff0000); + + y += raw[28] & 0x0000ffff; + + double dy = DgnUtility.converUnitToCoord(y); + + return new Coordinate(dx, dy); + } + + public int getFontIndex() + { + return (int) raw[18] & 0x00000000ff; + } + + public boolean hasSlant() + { + return true; + } + + public boolean hasUnderline() + { + return true; + } + + public boolean isFixedWidthSpacing() + { + return true; + } + + public boolean isPlanar() + { + return true; + } + + public boolean isVertical() + { + return true; + } + + public double getTextHeight() + { + int height = ((raw[21] << 16) & 0xffff0000); + + height += raw[22] & 0x0000ffff; + + return DgnUtility.converIntToDouble(height); + } + + public double getTextWidth() + { + int length = (raw[19] << 16 & 0xffff0000); + + length += raw[20] & 0x0000ffff; + + return DgnUtility.converIntToDouble(length); + } + + public int getJustification() + { + return ((raw[18] >>> 8) & 0x00000000ff); + } + + public double getRotationAngle() + { + int totation = ((raw[23] & 0x0000ffff) << 16) | (raw[24] & 0x0000ffff); + return DgnUtility.converIntToRotation(totation); + } + + public boolean isChinese() + { + int isChinese = raw[30] & 0x0000ffff; + + return (isChinese == 0xfdff); + } + + public int getTextLength() + { + int num = raw[29]; + + if (isChinese()) + { + num = (num / 2) - 1; + } + + return num; + } + + public String getText() + { + StringBuffer val = new StringBuffer(); + char[] temp; + int num = getTextLength(); + + if (!isChinese()) + { + temp = new char[num]; + + for (int i = 0; i < temp.length; i++) + { + if ((i % 2) == 0) + { + temp[i] = (char) (raw[30 + (int) (i / 2)] & (short) 0x00ff); + } else + { + temp[i] = (char) ((raw[30 + (int) (i / 2)] >> 8) & (short) 0x00ff); + } + + val.append(temp[i]); + } + } else + { + byte[] strRaw = new byte[num * 2]; + for (int i = 0; i < num; i++) + { + short charValue = raw[i + 31]; + byte hi = (byte) (charValue >>> 8); + byte lo = (byte) charValue; + strRaw[i * 2] = hi; + strRaw[i * 2 + 1] = lo; + } + + try + { + Charset charsetBig5 = Charset.forName("Big5"); + CharsetDecoder decoder = charsetBig5.newDecoder(); + CharBuffer cb = decoder.decode(ByteBuffer.wrap(strRaw)); + val.append(cb); + } catch (CharacterCodingException e) + { + logger.warn(e.getMessage(), e); + return val.toString(); + } finally + { + // rawBuffer.position(pos); + // rawBuffer.order(order); + } + } + + return val.toString(); + } + + protected byte[] convertDBCSToUnicode(byte[] buffer) + { + byte[] charBuffer = new byte[4]; + charBuffer[0] = (byte) ((byte) ((buffer[1] & 0xc0) >>> 6) | 0xc0); + charBuffer[1] = (byte) (buffer[1] & 0x3f | 0x80); + charBuffer[2] = (byte) ((byte) ((buffer[0] & 0xc0) >>> 6) | 0xc0); + charBuffer[3] = (byte) (buffer[0] & 0x3f | 0x80); + return charBuffer; + } + + public Geometry toGeometry(GeometryFactory factory) + { + return factory.createPoint(getUserOrigin()); + } + + private double getUserWidth() + { + int just = getJustification(); + // Envelope range = getRange(); // case -1 + // double width = (range.getWidth()); // case -1 + // double width = this.getTextWidth() * this.getTextLength() * 1000.0; // case -2 + double width = (this.getTextWidth() * this.getTextLength()); + + switch (just) + { + case TXTJUST_LT: + case TXTJUST_LC: + case TXTJUST_LB: + width = 0; + break; + + case TXTJUST_CT: + case TXTJUST_CC: + case TXTJUST_CB: + width = width / 2; + break; + + case TXTJUST_RT: + case TXTJUST_RC: + case TXTJUST_RB: + break; + } + + return width; + } + + private double getUserHeight() + { + int just = getJustification(); + double height = getTextHeight(); + + switch (just) + { + case TXTJUST_LB: + case TXTJUST_CB: + case TXTJUST_RB: // bottom + height = 0; + break; + + case TXTJUST_LC: + case TXTJUST_CC: + case TXTJUST_RC: // center + height = height / 2; + break; + + case TXTJUST_LT: + case TXTJUST_CT: + case TXTJUST_RT: // height + break; + } + + return height; + } + + public Coordinate getUserOrigin() + { + double width = getUserWidth(); + double height = getUserHeight(); + double angle = Math.toRadians(getRotationAngle()); + + AffineTransform at = new AffineTransform(); + at.translate(width, height); + Coordinate p = getOrigin(); + at.setToRotation(angle, p.x, p.y); + at.scale(1, 1); + + double[] srcPt = new double[2]; + double[] dstPt = new double[2]; + + srcPt[0] = p.x + width; + srcPt[1] = p.y + height; + + at.transform(srcPt, 0, dstPt, 0, 1); + + return new Coordinate(dstPt[0], dstPt[1]); + } + + public Object clone() throws CloneNotSupportedException + { + int pos = this.rawBuffer.position(); + this.rawBuffer.position(0); + byte[] rawBytes = this.rawBuffer.array(); + byte[] otherRaw = new byte[rawBytes.length]; + System.arraycopy(rawBytes, 0, otherRaw, 0, rawBytes.length); + this.rawBuffer.position(pos); + + TextElement other = new TextElement(otherRaw); + return other; + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.TEXT); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new TextElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextNodeElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextNodeElement.java new file mode 100644 index 0000000..fbab7cd --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/TextNodeElement.java @@ -0,0 +1,387 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.util.DgnUtility; + +/** + * TextNodeElement + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 04:02:58 + */ +public class TextNodeElement extends Element implements ComplexElement, GeometryConverter +{ + private static final Logger logger = Logger.getLogger(TextElement.class); + + private ArrayList list = new ArrayList(); + + public TextNodeElement(byte[] raw) + { + super(raw); + } + + public int size() + { + return list.size(); + } + + public boolean isEmpty() + { + return list.isEmpty(); + } + + public boolean contains(Object o) + { + return list.contains(o); + } + + public Iterator iterator() + { + return list.iterator(); + } + + public Object[] toArray() + { + return list.toArray(); + } + + public boolean add(Object o) + { + return list.add(o); + } + + public boolean remove(Object o) + { + return list.remove(o); + } + + public boolean addAll(Collection c) + { + return list.addAll(c); + } + + public boolean addAll(int index, Collection c) + { + return list.addAll(index, c); + } + + public void clear() + { + list.clear(); + } + + public Object get(int index) + { + return list.get(index); + } + + public Object set(int index, Object element) + { + return list.set(index, element); + } + + public void add(int index, Object element) + { + list.add(index, element); + } + + public Object remove(int index) + { + return list.remove(index); + } + + public int indexOf(Object o) + { + return list.indexOf(o); + } + + public int lastIndexOf(Object o) + { + return list.lastIndexOf(o); + } + + public ListIterator listIterator() + { + return list.listIterator(); + } + + public ListIterator listIterator(int index) + { + return list.listIterator(index); + } + + public List subList(int fromIndex, int toIndex) + { + return list.subList(fromIndex, toIndex); + } + + public boolean retainAll(Collection c) + { + return list.retainAll(c); + } + + public boolean removeAll(Collection c) + { + return list.removeAll(c); + } + + public boolean containsAll(Collection c) + { + return list.containsAll(c); + } + + public Object[] toArray(Object[] a) + { + return list.toArray(a); + } + + public String[] getTextArray() + { + ArrayList list = new ArrayList(); + + for (ListIterator it = listIterator(); it.hasNext();) + { + Element element = (Element) it.next(); + + if (element instanceof TextElement) + { + list.add(((TextElement) element).getText()); + } + } + + return (String[]) list.toArray(new String[list.size()]); + } + + public Geometry toGeometry(GeometryFactory factory) + { + /* + * CoordinateList coords = new CoordinateList(); + * for (ListIterator it = listIterator(); it.hasNext(); ) + * { + * Element element = (Element) it.next(); + * if (element instanceof TextElement) + * { + * coords.add(((TextElement) element).getUserOrigin()); + * } + * } + */ + return factory.createPoint(getOrigin()); + + // return factory.createMultiPoint(coords.toCoordinateArray()); + } + + public int getTotalWords() + { + return (raw[18] & 0x0000ffff); + } + + public void setTotalWords(int value) + { + raw[18] = (short) (value & 0x0000ffff); + } + + public int getNumString() + { + return (raw[19] & 0x0000ffff); + } + + public void setNumString(int value) + { + raw[19] = (short) (value & 0x0000ffff); + } + + public int getNodeNumber() + { + return (raw[20] & 0x0000ffff); + } + + public void setNodeNumber(int value) + { + raw[20] = (short) (value & 0x0000ffff); + } + + public int getMaxLength() + { + return (raw[21] & 0x00ff); + } + + public void setMaxLength(int value) + { + raw[21] = (short) ((value & 0x00ff) | (raw[21] & 0xff00)); + } + + public int getMaxUsed() + { + return ((raw[21] >> 8) & 0x00ff); + } + + public void setMaxUsed(int value) + { + raw[21] = (short) (((value << 8) & 0xff00) | (raw[21] & 0x00ff)); + } + + public int getJustification() + { + return ((raw[22] >> 8) & 0x00ff); + } + + public void setJustification(int value) + { + raw[22] = (short) (((value << 8) & 0xff00) | (raw[22] & 0x00ff)); + } + + public int getFontIndex() + { + return (raw[22] & 0x00ff); + } + + public void setFontIndex(int value) + { + raw[22] = (short) ((value & 0x00ff) | (raw[22] & 0xff00)); + } + + public double getLineSpacing() + { + int lineSpace; + lineSpace = ((raw[23] & 0x0000ffff) << 16) | (raw[24] & 0x0000ffff); + + return lineSpace; + } + + public void setLineSpacing(double value) + { + int temp = (int) (value*1000.0); + raw[23] = (short) ((temp >> 16) & 0x0000ffff); + raw[24] = (short) (temp & 0x0000ffff); + } + + public double getTextNodeLength() + { + int lengthMult; + + lengthMult = ((raw[25] << 16) & 0xffff0000); + lengthMult += (raw[26] & 0x0000ffff); + + return DgnUtility.converIntToDouble(lengthMult); + } + + public void setTextNodeLength(double value) + { + int temp = DgnUtility.converDoubleToInt(value); + raw[25] = (short) ((temp >> 16) & 0x0000ffff); + raw[26] = (short) (temp & 0x0000ffff); + } + + public double getTextNodeHeight() + { + int heightMult; + + heightMult = ((raw[27] << 16) & 0xffff0000); + heightMult += (raw[28] & 0x0000ffff); + + return DgnUtility.converIntToDouble(heightMult); + } + + public void setTextNodeHeight(double value) + { + int temp = DgnUtility.converDoubleToInt(value); + raw[27] = (short) ((temp >> 16) & 0x0000ffff); + raw[28] = (short) (temp & 0x0000ffff); + } + + public double getRotationAngle() + { + int rotation = (raw[29] << 16 & 0xffff0000); + rotation += raw[30]; + + return DgnUtility.converIntToRotation(rotation); + } + + public void setRotationAngle(double value) + { + int temp = DgnUtility.converRotatioToInt(value); + raw[29] = (short) (temp >> 16 & 0x0000ffff); + raw[30] = (short) (temp & 0x0000ffff); + } + + public Coordinate getOrigin() + { + int x = ((raw[31] << 16) & 0xffff0000) | (raw[32] & 0x0000ffff); + double dx = DgnUtility.converUnitToCoord(x); + // return DgnUtility.convertFromDGN(x); + + int y = ((raw[33] << 16) & 0xffff0000) | (raw[34] & 0x0000ffff); + double dy = DgnUtility.converUnitToCoord(y); + + return new Coordinate(dx, dy); + } + + public void setOrigin(Coordinate value) + { + int x = DgnUtility.converCoordToUnit(value.x); + raw[31] = (short) (x >> 16 & 0x0000ffff); + raw[32] = (short) (x & 0x0000ffff); + + int y = DgnUtility.converCoordToUnit(value.y); + raw[33] = (short) (y >> 16 & 0x0000ffff); + raw[34] = (short) (y & 0x0000ffff); + } + + public Object clone() throws CloneNotSupportedException + { + int pos = this.rawBuffer.position(); + this.rawBuffer.position(0); + byte[] rawBytes = this.rawBuffer.array(); + byte[] otherRaw = new byte[rawBytes.length]; + System.arraycopy(rawBytes, 0, otherRaw, 0, rawBytes.length); + this.rawBuffer.position(pos); + + TextNodeElement other = new TextNodeElement(otherRaw); + for (Object o : this) + { + TextElement textElm = (TextElement) o; + other.add(textElm.clone()); + } + + return other; + } + + public static class ElementHandler extends Element.ElementHandler + { + private static ElementHandler instance = null; + + public ElementHandler() + { + super(ElementType.TEXTNODE); + } + + public static IElementHandler getInstance() + { + if (instance == null) + { + instance = new ElementHandler(); + } + + return instance; + } + + protected Element createElement(byte[] raw) + { + return new TextNodeElement(raw); + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/UserAttributeData.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/UserAttributeData.java new file mode 100644 index 0000000..2b87fe1 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/UserAttributeData.java @@ -0,0 +1,34 @@ +package com.ximple.io.dgn7; + +/** + * UserAttributeData + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 02:29:29 + */ +public class UserAttributeData +{ + protected short[] _src; + + public UserAttributeData(short id, int attributeCount) + { + _src = new short[attributeCount]; + _src[0] = id; + } + + public UserAttributeData(short[] src) + { + _src = src; + } + + public short getID() + { + return _src[0]; + } + + public void setID(short value) + { + _src[0] = value; + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/DgnUtility.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/DgnUtility.java new file mode 100644 index 0000000..0009270 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/DgnUtility.java @@ -0,0 +1,259 @@ +package com.ximple.util; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.geom.Envelope; + +/** + * Utility + * + * @author Ulysses + * @version 0.1 + * @since 2006/5/18 �U�� 01:33:00 + */ +public final class DgnUtility +{ + private static final Logger logger = Logger.getLogger(DgnUtility.class); + + public static double converIntToDouble(int src) + { + return (double) ((long) ((src * 6) / 1000.0 + 0.5)) / 1000.0; + } + + public static int converDoubleToInt(double src) + { + + return (int) (src / 6 * 1000000.0); + } + + public static int convertFromDGN(int aValue) + { + int newVal; + + newVal = (((aValue ^ 0x00008000) << 16) & 0xffff0000); + newVal |= (aValue >>> 16) & 0x0000ffff; + + return newVal; + } + + public static int converToDGN(int aValue) + { + int newVal; + + newVal = (aValue << 16 & 0xffff0000); + newVal |= (((aValue ^ 0x80000000) >>> 16) & 0x0000ffff); + + return newVal; + } + + public static double converIntToRotation(int aValue) + { + + return aValue / 360000.0; + } + + public static int converRotatioToInt(double aValue) + { + + return (int) (aValue * 360000.0); + } + + public static double converRotationToRadian(double aValue) + { + + return aValue * Math.PI / 180; + } + + public static double converUnitToCoord(int aValue) + { + double newVal; + + newVal = aValue / 1000.0; + newVal += 2147483.648; // 2147483.648 = 2 ^ 31 + + return newVal; + } + + public static double converUnitToCoord(double aValue) + { + double newVal; + + newVal = aValue / 1000.0; + newVal += 2147483.648; // 2147483.648 = 2 ^ 31 + + return newVal; + } + + public static int converCoordToUnit(double aValue) + { + double newVal = aValue; + + newVal -= 2147483.648; + newVal = newVal * 1000.0; + + return (int) newVal; + } + + public static Envelope converUnitToCoord(Envelope range) + { + if (range == null) + { + return null; + } + + return new Envelope(converUnitToCoord((int) range.getMinX()), converUnitToCoord((int) range.getMaxX()), + converUnitToCoord((int) range.getMinY()), converUnitToCoord((int) range.getMaxY())); + } + + public static Envelope converCoordToUnit(Envelope range) + { + if (range == null) + { + return null; + } + + return new Envelope(converCoordToUnit(range.getMinX()), converCoordToUnit(range.getMaxX()), + converCoordToUnit(range.getMinY()), converCoordToUnit(range.getMaxY())); + } + + public static long convertDGNToRAWIEEEDouble(byte[] org) + { + ByteBuffer buf = ByteBuffer.allocate(8); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.mark(); + buf.put(org[2]); + buf.put(org[3]); + buf.put(org[0]); + buf.put(org[1]); + buf.put(org[6]); + buf.put(org[7]); + buf.put(org[4]); + buf.put(org[5]); + buf.position(0); + + int[] tmp = new int[2]; + + tmp[0] = buf.getInt(); + tmp[1] = buf.getInt(); + + int exponent; + + int sign = (tmp[0] & 0x80000000); + exponent = (tmp[0] >>> 23) & 0x000000ff; + + if (exponent != 0) + { + exponent = exponent - 129 + 1023; + } + + int rndbits = tmp[1] & 0x00000007; + tmp[1] = tmp[1] >>> 3; + tmp[1] = (tmp[1] & 0x1fffffff) | (tmp[0] << 29); + + if (rndbits != 0) + { + tmp[1] = tmp[1] | 0x00000001; + } + + tmp[0] = (tmp[0] >>> 3) & 0x000fffff; + tmp[0] = tmp[0] | (exponent << 20) | sign; + + buf.position(0); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putInt(tmp[0]); + buf.putInt(tmp[1]); + buf.position(0); + byte[] tmpRaw = new byte[8]; + buf.get(tmpRaw); + buf.position(0); + buf.order(ByteOrder.LITTLE_ENDIAN); + for (int i = tmpRaw.length; i > 0; i--) + { + buf.put(tmpRaw[i - 1]); + } + buf.position(0); + long result = buf.getLong(); + return result; + } + + public static double convertDGNToIEEEDouble(byte[] src) + { + return Double.longBitsToDouble(convertDGNToRAWIEEEDouble(src)); + } + + public static short[] convertIEEEDoubleToDGN(double src) + { + long newVal = Double.doubleToLongBits(src); + + // uint[] tmp = new int[ 2 ]; + // ushort[] des = new short[ 4 ]; + int[] tmp = new int[2]; + short[] des = new short[4]; + int sign; + int exponent; + + tmp[0] = (int) ((newVal >>> 32)); + tmp[1] = (int) (newVal); + + // sign = ( int ) ( ( uint ) tmp[ 0 ] & 0x80000000 ); + sign = tmp[0] & 0x80000000; + exponent = (tmp[0] >>> 20) & 0x07ff; + + if (exponent != 0) + { + exponent = exponent - 1023 + 129; + } + + if (exponent > 255) + { + if (sign != 0) + { + des[0] = -1; + } else + { + des[0] = 0x7fff; + } + + des[1] = -1; + des[2] = -1; + des[3] = -1; + + return des; + } else if ((exponent < 0) || ((exponent == 0) && (sign == 0))) + { + des[0] = 0x0; + des[1] = 0x0; + des[2] = 0x0; + des[3] = 0x0; + + return des; + } else + { + tmp[0] = (tmp[0] << 3) | (tmp[1] >> 29); + tmp[0] = tmp[0] & 0x007fffff; + tmp[0] = tmp[0] | (exponent << 23) | sign; + + // changed by phil 07/05/2004 + // tmp[ 1 ] = tmp[ 1 ] >> 3; + tmp[1] = tmp[1] << 3; + } + + des[0] = (short) ((tmp[0] >>> 16) & 0x0000ffff); + des[1] = (short) (tmp[0] & 0x0000ffff); + des[2] = (short) ((tmp[1] >>> 16) & 0x0000ffff); + des[3] = (short) (tmp[1] & 0x0000ffff); + + return des; + } + + public static double getLength(double x1, double y1, double x2, double y2) + { + double dx = x1 - x2; + double dy = y1 - y2; + + return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); + } +} diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/PrintfFormat.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/PrintfFormat.java new file mode 100644 index 0000000..5ec015f --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/util/PrintfFormat.java @@ -0,0 +1,4830 @@ +// +//(c) 2000 Sun Microsystems, Inc. +//ALL RIGHTS RESERVED +// +//License Grant- +// +// +//Permission to use, copy, modify, and distribute this Software and its +//documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is +//hereby granted. +// +//This Software is provided "AS IS". All express warranties, including any +//implied warranty of merchantability, satisfactory quality, fitness for a +//particular purpose, or non-infringement, are disclaimed, except to the extent +//that such disclaimers are held to be legally invalid. +// +//You acknowledge that Software is not designed, licensed or intended for use in +//the design, construction, operation or maintenance of any nuclear facility +//("High Risk Activities"). Sun disclaims any express or implied warranty of +//fitness for such uses. +// +//Please refer to the file http://www.sun.com/policies/trademarks/ for further +//important trademark information and to +//http://java.sun.com/nav/business/index.html for further important licensing +//information for the Java Technology. +// + +package com.ximple.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.text.DecimalFormatSymbols; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +/** + * PrintfFormat allows the formatting of an array of + * objects embedded within a string. Primitive types + * must be passed using wrapper types. The formatting + * is controlled by a control string. + * <p> + * A control string is a Java string that contains a + * control specification. The control specification + * starts at the first percent sign (%) in the string, + * provided that this percent sign + * <ol> + * <li>is not escaped protected by a matching % or is + * not an escape % character, + * <li>is not at the end of the format string, and + * <li>precedes a sequence of characters that parses as + * a valid control specification. + * </ol> + * </p><p> + * A control specification usually takes the form: + * <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ + * { [hlL] }+ [idfgGoxXeEcs] + * </pre> + * There are variants of this basic form that are + * discussed below.</p> + * <p> + * The format is composed of zero or more directives + * defined as follows: + * <ul> + * <li>ordinary characters, which are simply copied to + * the output stream; + * <li>escape sequences, which represent non-graphic + * characters; and + * <li>conversion specifications, each of which + * results in the fetching of zero or more arguments. + * </ul></p> + * <p> + * The results are undefined if there are insufficient + * arguments for the format. Usually an unchecked + * exception will be thrown. If the format is + * exhausted while arguments remain, the excess + * arguments are evaluated but are otherwise ignored. + * In format strings containing the % form of + * conversion specifications, each argument in the + * argument list is used exactly once.</p> + * <p> + * Conversions can be applied to the <code>n</code>th + * argument after the format in the argument list, + * rather than to the next unused argument. In this + * case, the conversion characer % is replaced by the + * sequence %<code>n</code>$, where <code>n</code> is + * a decimal integer giving the position of the + * argument in the argument list.</p> + * <p> + * In format strings containing the %<code>n</code>$ + * form of conversion specifications, each argument + * in the argument list is used exactly once.</p> + * <p/> + * <h4>Escape Sequences</h4> + * <p> + * The following table lists escape sequences and + * associated actions on display devices capable of + * the action. + * <table> + * <tr><th align=left>Sequence</th> + * <th align=left>Name</th> + * <th align=left>Description</th></tr> + * <tr><td>\\</td><td>backlash</td><td>None. + * </td></tr> + * <tr><td>\a</td><td>alert</td><td>Attempts to alert + * the user through audible or visible + * notification. + * </td></tr> + * <tr><td>\b</td><td>backspace</td><td>Moves the + * printing position to one column before + * the current position, unless the + * current position is the start of a line. + * </td></tr> + * <tr><td>\f</td><td>form-feed</td><td>Moves the + * printing position to the initial + * printing position of the next logical + * page. + * </td></tr> + * <tr><td>\n</td><td>newline</td><td>Moves the + * printing position to the start of the + * next line. + * </td></tr> + * <tr><td>\r</td><td>carriage-return</td><td>Moves + * the printing position to the start of + * the current line. + * </td></tr> + * <tr><td>\t</td><td>tab</td><td>Moves the printing + * position to the next implementation- + * defined horizontal tab position. + * </td></tr> + * <tr><td>\v</td><td>vertical-tab</td><td>Moves the + * printing position to the start of the + * next implementation-defined vertical + * tab position. + * </td></tr> + * </table></p> + * <h4>Conversion Specifications</h4> + * <p> + * Each conversion specification is introduced by + * the percent sign character (%). After the character + * %, the following appear in sequence:</p> + * <p> + * Zero or more flags (in any order), which modify the + * meaning of the conversion specification.</p> + * <p> + * An optional minimum field width. If the converted + * value has fewer characters than the field width, it + * will be padded with spaces by default on the left; + * t will be padded on the right, if the left- + * adjustment flag (-), described below, is given to + * the field width. The field width takes the form + * of a decimal integer. If the conversion character + * is s, the field width is the the minimum number of + * characters to be printed.</p> + * <p> + * An optional precision that gives the minumum number + * of digits to appear for the d, i, o, x or X + * conversions (the field is padded with leading + * zeros); the number of digits to appear after the + * radix character for the e, E, and f conversions, + * the maximum number of significant digits for the g + * and G conversions; or the maximum number of + * characters to be written from a string is s and S + * conversions. The precision takes the form of an + * optional decimal digit string, where a null digit + * string is treated as 0. If a precision appears + * with a c conversion character the precision is + * ignored. + * </p> + * <p> + * An optional h specifies that a following d, i, o, + * x, or X conversion character applies to a type + * short argument (the argument will be promoted + * according to the integral promotions and its value + * converted to type short before printing).</p> + * <p> + * An optional l (ell) specifies that a following + * d, i, o, x, or X conversion character applies to a + * type long argument.</p> + * <p> + * A field width or precision may be indicated by an + * asterisk (*) instead of a digit string. In this + * case, an integer argument supplised the field width + * precision. The argument that is actually converted + * is not fetched until the conversion letter is seen, + * so the the arguments specifying field width or + * precision must appear before the argument (if any) + * to be converted. If the precision argument is + * negative, it will be changed to zero. A negative + * field width argument is taken as a - flag, followed + * by a positive field width.</p> + * <p> + * In format strings containing the %<code>n</code>$ + * form of a conversion specification, a field width + * or precision may be indicated by the sequence + * *<code>m</code>$, where m is a decimal integer + * giving the position in the argument list (after the + * format argument) of an integer argument containing + * the field width or precision.</p> + * <p> + * The format can contain either numbered argument + * specifications (that is, %<code>n</code>$ and + * *<code>m</code>$), or unnumbered argument + * specifications (that is % and *), but normally not + * both. The only exception to this is that %% can + * be mixed with the %<code>n</code>$ form. The + * results of mixing numbered and unnumbered argument + * specifications in a format string are undefined.</p> + * <p/> + * <h4>Flag Characters</h4> + * <p> + * The flags and their meanings are:</p> + * <dl> + * <dt>'<dd> integer portion of the result of a + * decimal conversion (%i, %d, %f, %g, or %G) will + * be formatted with thousands' grouping + * characters. For other conversions the flag + * is ignored. The non-monetary grouping + * character is used. + * <dt>-<dd> result of the conversion is left-justified + * within the field. (It will be right-justified + * if this flag is not specified).</td></tr> + * <dt>+<dd> result of a signed conversion always + * begins with a sign (+ or -). (It will begin + * with a sign only when a negative value is + * converted if this flag is not specified.) + * <dt><space><dd> If the first character of a + * signed conversion is not a sign, a space + * character will be placed before the result. + * This means that if the space character and + + * flags both appear, the space flag will be + * ignored. + * <dt>#<dd> value is to be converted to an alternative + * form. For c, d, i, and s conversions, the flag + * has no effect. For o conversion, it increases + * the precision to force the first digit of the + * result to be a zero. For x or X conversion, a + * non-zero result has 0x or 0X prefixed to it, + * respectively. For e, E, f, g, and G + * conversions, the result always contains a radix + * character, even if no digits follow the radix + * character (normally, a decimal point appears in + * the result of these conversions only if a digit + * follows it). For g and G conversions, trailing + * zeros will not be removed from the result as + * they normally are. + * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G + * conversions, leading zeros (following any + * indication of sign or base) are used to pad to + * the field width; no space padding is + * performed. If the 0 and - flags both appear, + * the 0 flag is ignored. For d, i, o, x, and X + * conversions, if a precision is specified, the + * 0 flag will be ignored. For c conversions, + * the flag is ignored. + * </dl> + * <p/> + * <h4>Conversion Characters</h4> + * <p> + * Each conversion character results in fetching zero + * or more arguments. The results are undefined if + * there are insufficient arguments for the format. + * Usually, an unchecked exception will be thrown. + * If the format is exhausted while arguments remain, + * the excess arguments are ignored.</p> + * <p/> + * <p> + * The conversion characters and their meanings are: + * </p> + * <dl> + * <dt>d,i<dd>The int argument is converted to a + * signed decimal in the style [-]dddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + * <dt>o<dd> The int argument is converted to unsigned + * octal format in the style ddddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + * <dt>x<dd> The int argument is converted to unsigned + * hexadecimal format in the style dddd; the + * letters abcdef are used. The precision + * specifies the minimum numberof digits to + * appear; if the value being converted can be + * represented in fewer digits, it will be + * expanded with leading zeros. The default + * precision is 1. The result of converting 0 + * with an explicit precision of 0 is no + * characters. + * <dt>X<dd> Behaves the same as the x conversion + * character except that letters ABCDEF are + * used instead of abcdef. + * <dt>f<dd> The floating point number argument is + * written in decimal notation in the style + * [-]ddd.ddd, where the number of digits after + * the radix character (shown here as a decimal + * point) is equal to the precision + * specification. A Locale is used to determine + * the radix character to use in this format. + * If the precision is omitted from the + * argument, six digits are written after the + * radix character; if the precision is + * explicitly 0 and the # flag is not specified, + * no radix character appears. If a radix + * character appears, at least 1 digit appears + * before it. The value is rounded to the + * appropriate number of digits. + * <dt>e,E<dd>The floating point number argument is + * written in the style [-]d.ddde{+-}dd + * (the symbols {+-} indicate either a plus or + * minus sign), where there is one digit before + * the radix character (shown here as a decimal + * point) and the number of digits after it is + * equal to the precision. A Locale is used to + * determine the radix character to use in this + * format. When the precision is missing, six + * digits are written after the radix character; + * if the precision is 0 and the # flag is not + * specified, no radix character appears. The + * E conversion will produce a number with E + * instead of e introducing the exponent. The + * exponent always contains at least two digits. + * However, if the value to be written requires + * an exponent greater than two digits, + * additional exponent digits are written as + * necessary. The value is rounded to the + * appropriate number of digits. + * <dt>g,G<dd>The floating point number argument is + * written in style f or e (or in sytle E in the + * case of a G conversion character), with the + * precision specifying the number of + * significant digits. If the precision is + * zero, it is taken as one. The style used + * depends on the value converted: style e + * (or E) will be used only if the exponent + * resulting from the conversion is less than + * -4 or greater than or equal to the precision. + * Trailing zeros are removed from the result. + * A radix character appears only if it is + * followed by a digit. + * <dt>c,C<dd>The integer argument is converted to a + * char and the result is written. + * <p/> + * <dt>s,S<dd>The argument is taken to be a string and + * bytes from the string are written until the + * end of the string or the number of bytes + * indicated by the precision specification of + * the argument is reached. If the precision + * is omitted from the argument, it is taken to + * be infinite, so all characters up to the end + * of the string are written. + * <dt>%<dd>Write a % character; no argument is + * converted. + * </dl> + * <p> + * If a conversion specification does not match one of + * the above forms, an IllegalArgumentException is + * thrown and the instance of PrintfFormat is not + * created.</p> + * <p> + * If a floating point value is the internal + * representation for infinity, the output is + * [+]Infinity, where Infinity is either Infinity or + * Inf, depending on the desired output string length. + * Printing of the sign follows the rules described + * above.</p> + * <p> + * If a floating point value is the internal + * representation for "not-a-number," the output is + * [+]NaN. Printing of the sign follows the rules + * described above.</p> + * <p> + * In no case does a non-existent or small field width + * cause truncation of a field; if the result of a + * conversion is wider than the field width, the field + * is simply expanded to contain the conversion result. + * </p> + * <p> + * The behavior is like printf. One exception is that + * the minimum number of exponent digits is 3 instead + * of 2 for e and E formats when the optional L is used + * before the e, E, g, or G conversion character. The + * optional L does not imply conversion to a long long + * double. </p> + * <p> + * The biggest divergence from the C printf + * specification is in the use of 16 bit characters. + * This allows the handling of characters beyond the + * small ASCII character set and allows the utility to + * interoperate correctly with the rest of the Java + * runtime environment.</p> + * <p> + * Omissions from the C printf specification are + * numerous. All the known omissions are present + * because Java never uses bytes to represent + * characters and does not have pointers:</p> + * <ul> + * <li>%c is the same as %C. + * <li>%s is the same as %S. + * <li>u, p, and n conversion characters. + * <li>%ws format. + * <li>h modifier applied to an n conversion character. + * <li>l (ell) modifier applied to the c, n, or s + * conversion characters. + * <li>ll (ell ell) modifier to d, i, o, u, x, or X + * conversion characters. + * <li>ll (ell ell) modifier to an n conversion + * character. + * <li>c, C, d,i,o,u,x, and X conversion characters + * apply to Byte, Character, Short, Integer, Long + * types. + * <li>f, e, E, g, and G conversion characters apply + * to Float and Double types. + * <li>s and S conversion characters apply to String + * types. + * <li>All other reference types can be formatted + * using the s or S conversion characters only. + * </ul> + * <p> + * Most of this specification is quoted from the Unix + * man page for the sprintf utility.</p> + * + * @author Allan Jacobs + * @version 1 + * Release 1: Initial release. + * Release 2: Asterisk field widths and precisions + * %n$ and *m$ + * Bug fixes + * g format fix (2 digits in e form corrupt) + * rounding in f format implemented + * round up when digit not printed is 5 + * formatting of -0.0f + * round up/down when last digits are 50000... + */ +public final class PrintfFormat +{ + /** + * Vector of control strings and format literals. + */ + private Vector vFmt = new Vector(); + + /** + * Character position. Used by the constructor. + */ + private int cPos = 0; + + /** + * Character position. Used by the constructor. + */ + private DecimalFormatSymbols dfs = null; + + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * + * @param fmtArg Control string. + * @throws IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(String fmtArg) throws IllegalArgumentException + { + this(Locale.getDefault(), fmtArg); + } + + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * + * @param fmtArg Control string. + * @throws IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(Locale locale, String fmtArg) throws IllegalArgumentException + { + dfs = new DecimalFormatSymbols(locale); + + int ePos = 0; + ConversionSpecification sFmt = null; + String unCS = this.nonControl(fmtArg, 0); + + if (unCS != null) + { + sFmt = new ConversionSpecification(); + sFmt.setLiteral(unCS); + vFmt.addElement(sFmt); + } + + while ((cPos != -1) && (cPos < fmtArg.length())) + { + for (ePos = cPos + 1; ePos < fmtArg.length(); ePos++) + { + char c = 0; + + c = fmtArg.charAt(ePos); + + if (c == 'i') + { + break; + } + + if (c == 'd') + { + break; + } + + if (c == 'f') + { + break; + } + + if (c == 'g') + { + break; + } + + if (c == 'G') + { + break; + } + + if (c == 'o') + { + break; + } + + if (c == 'x') + { + break; + } + + if (c == 'X') + { + break; + } + + if (c == 'e') + { + break; + } + + if (c == 'E') + { + break; + } + + if (c == 'c') + { + break; + } + + if (c == 's') + { + break; + } + + if (c == '%') + { + break; + } + } + + ePos = Math.min(ePos + 1, fmtArg.length()); + sFmt = new ConversionSpecification(fmtArg.substring(cPos, ePos)); + vFmt.addElement(sFmt); + unCS = this.nonControl(fmtArg, ePos); + + if (unCS != null) + { + sFmt = new ConversionSpecification(); + sFmt.setLiteral(unCS); + vFmt.addElement(sFmt); + } + } + } + + /** + * Return a substring starting at + * <code>start</code> and ending at either the end + * of the String <code>s</code>, the next unpaired + * percent sign, or at the end of the String if the + * last character is a percent sign. + * + * @param s Control string. + * @param start Position in the string + * <code>s</code> to begin looking for the start + * of a control string. + * @return the substring from the start position + * to the beginning of the control string. + */ + private String nonControl(String s, int start) + { + String ret = ""; + + cPos = s.indexOf("%", start); + + if (cPos == -1) + { + cPos = s.length(); + } + + return s.substring(start, cPos); + } + + /** + * Format an array of objects. Byte, Short, + * Integer, Long, Float, Double, and Character + * arguments are treated as wrappers for primitive + * types. + * + * @param o The array of objects to format. + * @return The formatted String. + */ + public String sprintf(Object[] o) + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + int i = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + if (cs.isPositionalSpecification()) + { + i = cs.getArgumentPosition() - 1; + + if (cs.isPositionalFieldWidth()) + { + int ifw = cs.getArgumentPositionForFieldWidth() - 1; + + cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue()); + } + + if (cs.isPositionalPrecision()) + { + int ipr = cs.getArgumentPositionForPrecision() - 1; + + cs.setPrecisionWithArg(((Integer) o[ipr]).intValue()); + } + } else + { + if (cs.isVariableFieldWidth()) + { + cs.setFieldWidthWithArg(((Integer) o[i]).intValue()); + i++; + } + + if (cs.isVariablePrecision()) + { + cs.setPrecisionWithArg(((Integer) o[i]).intValue()); + i++; + } + } + + if (o[i] instanceof Byte) + { + sb.append(cs.internalsprintf(((Byte) o[i]).byteValue())); + } else if (o[i] instanceof Short) + { + sb.append(cs.internalsprintf(((Short) o[i]).shortValue())); + } else if (o[i] instanceof Integer) + { + sb.append(cs.internalsprintf(((Integer) o[i]).intValue())); + } else if (o[i] instanceof Long) + { + sb.append(cs.internalsprintf(((Long) o[i]).longValue())); + } else if (o[i] instanceof Float) + { + sb.append(cs.internalsprintf(((Float) o[i]).floatValue())); + } else if (o[i] instanceof Double) + { + sb.append(cs.internalsprintf(((Double) o[i]).doubleValue())); + } else if (o[i] instanceof Character) + { + sb.append(cs.internalsprintf(((Character) o[i]).charValue())); + } else if (o[i] instanceof String) + { + sb.append(cs.internalsprintf((String) o[i])); + } else + { + sb.append(cs.internalsprintf(o[i])); + } + + if (!cs.isPositionalSpecification()) + { + i++; + } + } + } + + return sb.toString(); + } + + /** + * Format nothing. Just use the control string. + * + * @return the formatted String. + */ + public String sprintf() + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } + } + + return sb.toString(); + } + + /** + * Format an int. + * + * @param x The int to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(int x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format an long. + * + * @param x The long to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(long x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format a double. + * + * @param x The double to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is c, C, s, S, + * d, d, x, X, or o. + */ + public String sprintf(double x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format a String. + * + * @param x The String to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is neither s nor S. + */ + public String sprintf(String x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format an Object. Convert wrapper types to + * their primitive equivalents and call the + * appropriate internal formatting method. Convert + * Strings using an internal formatting method for + * Strings. Otherwise use the default formatter + * (use toString). + * + * @param x the Object to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is inappropriate for + * formatting an unwrapped value. + */ + public String sprintf(Object x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + if (x instanceof Byte) + { + sb.append(cs.internalsprintf(((Byte) x).byteValue())); + } else if (x instanceof Short) + { + sb.append(cs.internalsprintf(((Short) x).shortValue())); + } else if (x instanceof Integer) + { + sb.append(cs.internalsprintf(((Integer) x).intValue())); + } else if (x instanceof Long) + { + sb.append(cs.internalsprintf(((Long) x).longValue())); + } else if (x instanceof Float) + { + sb.append(cs.internalsprintf(((Float) x).floatValue())); + } else if (x instanceof Double) + { + sb.append(cs.internalsprintf(((Double) x).doubleValue())); + } else if (x instanceof Character) + { + sb.append(cs.internalsprintf(((Character) x).charValue())); + } else if (x instanceof String) + { + sb.append(cs.internalsprintf((String) x)); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + } + + return sb.toString(); + } + + /** + * <p/> + * ConversionSpecification allows the formatting of + * a single primitive or object embedded within a + * string. The formatting is controlled by a + * format string. Only one Java primitive or + * object can be formatted at a time. + * <p/> + * A format string is a Java string that contains + * a control string. The control string starts at + * the first percent sign (%) in the string, + * provided that this percent sign + * <ol> + * <li>is not escaped protected by a matching % or + * is not an escape % character, + * <li>is not at the end of the format string, and + * <li>precedes a sequence of characters that parses + * as a valid control string. + * </ol> + * <p/> + * A control string takes the form: + * <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ + * { [hlL] }+ [idfgGoxXeEcs] + * </pre> + * <p/> + * The behavior is like printf. One (hopefully the + * only) exception is that the minimum number of + * exponent digits is 3 instead of 2 for e and E + * formats when the optional L is used before the + * e, E, g, or G conversion character. The + * optional L does not imply conversion to a long + * long double. + */ + private class ConversionSpecification + { + /** + * Default precision. + */ + private final static int defaultDigits = 6; + + /** + * The integer portion of the result of a decimal + * conversion (i, d, u, f, g, or G) will be + * formatted with thousands' grouping characters. + * For other conversions the flag is ignored. + */ + private boolean thousands = false; + + /** + * The result of the conversion will be + * left-justified within the field. + */ + private boolean leftJustify = false; + + /** + * The result of a signed conversion will always + * begin with a sign (+ or -). + */ + private boolean leadingSign = false; + + /** + * Flag indicating that left padding with spaces is + * specified. + */ + private boolean leadingSpace = false; + + /** + * For an o conversion, increase the precision to + * force the first digit of the result to be a + * zero. For x (or X) conversions, a non-zero + * result will have 0x (or 0X) prepended to it. + * For e, E, f, g, or G conversions, the result + * will always contain a radix character, even if + * no digits follow the point. For g and G + * conversions, trailing zeros will not be removed + * from the result. + */ + private boolean alternateForm = false; + + /** + * Flag indicating that left padding with zeroes is + * specified. + */ + private boolean leadingZeros = false; + + /** + * Flag indicating that the field width is *. + */ + private boolean variableFieldWidth = false; + + /** + * If the converted value has fewer bytes than the + * field width, it will be padded with spaces or + * zeroes. + */ + private int fieldWidth = 0; + + /** + * Flag indicating whether or not the field width + * has been set. + */ + private boolean fieldWidthSet = false; + + /** + * The minimum number of digits to appear for the + * d, i, o, u, x, or X conversions. The number of + * digits to appear after the radix character for + * the e, E, and f conversions. The maximum number + * of significant digits for the g and G + * conversions. The maximum number of bytes to be + * printed from a string in s and S conversions. + */ + private int precision = 0; + + /** + * Flag indicating that the precision is *. + */ + private boolean variablePrecision = false; + + /** + * Flag indicating whether or not the precision has + * been set. + */ + private boolean precisionSet = false; + + /* + */ + private boolean positionalSpecification = false; + private int argumentPosition = 0; + private boolean positionalFieldWidth = false; + private int argumentPositionForFieldWidth = 0; + private boolean positionalPrecision = false; + private int argumentPositionForPrecision = 0; + + /** + * Flag specifying that a following d, i, o, u, x, + * or X conversion character applies to a type + * short int. + */ + private boolean optionalh = false; + + /** + * Flag specifying that a following d, i, o, u, x, + * or X conversion character applies to a type lont + * int argument. + */ + private boolean optionall = false; + + /** + * Flag specifying that a following e, E, f, g, or + * G conversion character applies to a type double + * argument. This is a noop in Java. + */ + private boolean optionalL = false; + + /** + * Control string type. + */ + private char conversionCharacter = '\0'; + + /** + * Position within the control string. Used by + * the constructor. + */ + private int pos = 0; + + /** + * Literal or control format string. + */ + private String fmt; + + /** + * Constructor. Used to prepare an instance + * to hold a literal, not a control string. + */ + ConversionSpecification() + { + } + + /** + * Constructor for a conversion specification. + * The argument must begin with a % and end + * with the conversion character for the + * conversion specification. + * + * @param fmtArg String specifying the + * conversion specification. + * @throws IllegalArgumentException if the + * input string is null, zero length, or + * otherwise malformed. + */ + ConversionSpecification(String fmtArg) throws IllegalArgumentException + { + if (fmtArg == null) + { + throw new NullPointerException(); + } + + if (fmtArg.length() == 0) + { + throw new IllegalArgumentException("Control strings must have positive" + " lengths."); + } + + if (fmtArg.charAt(0) == '%') + { + fmt = fmtArg; + pos = 1; + setArgPosition(); + setFlagCharacters(); + setFieldWidth(); + setPrecision(); + setOptionalHL(); + + if (setConversionCharacter()) + { + if (pos == fmtArg.length()) + { + if (leadingZeros && leftJustify) + { + leadingZeros = false; + } + + if (precisionSet && leadingZeros) + { + if ((conversionCharacter == 'd') || (conversionCharacter == 'i') || (conversionCharacter == 'o') + || (conversionCharacter == 'x')) + { + leadingZeros = false; + } + } + } else + { + throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg); + } + } else + { + throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg); + } + } else + { + throw new IllegalArgumentException("Control strings must begin with %."); + } + } + + /** + * Set the String for this instance. + * + * @param s the String to store. + */ + void setLiteral(String s) + { + fmt = s; + } + + /** + * Get the String for this instance. Translate + * any escape sequences. + * + * @return s the stored String. + */ + String getLiteral() + { + StringBuffer sb = new StringBuffer(); + int i = 0; + + while (i < fmt.length()) + { + if (fmt.charAt(i) == '\\') + { + i++; + + if (i < fmt.length()) + { + char c = fmt.charAt(i); + + switch (c) + { + case 'a': + sb.append((char) 0x07); + + break; + + case 'b': + sb.append('\b'); + + break; + + case 'f': + sb.append('\f'); + + break; + + case 'n': + sb.append(System.getProperty("line.separator")); + + break; + + case 'r': + sb.append('\r'); + + break; + + case 't': + sb.append('\t'); + + break; + + case 'v': + sb.append((char) 0x0b); + + break; + + case '\\': + sb.append('\\'); + + break; + } + + i++; + } else + { + sb.append('\\'); + } + } else + { + i++; + } + } + + return fmt; + } + + /** + * Get the conversion character that tells what + * type of control character this instance has. + * + * @return the conversion character. + */ + char getConversionCharacter() + { + return conversionCharacter; + } + + /** + * Check whether the specifier has a variable + * field width that is going to be set by an + * argument. + * + * @return <code>true</code> if the conversion + * uses an * field width; otherwise + * <code>false</code>. + */ + boolean isVariableFieldWidth() + { + return variableFieldWidth; + } + + /** + * Set the field width with an argument. A + * negative field width is taken as a - flag + * followed by a positive field width. + * + * @param fw the field width. + */ + void setFieldWidthWithArg(int fw) + { + if (fw < 0) + { + leftJustify = true; + } + + fieldWidthSet = true; + fieldWidth = Math.abs(fw); + } + + /** + * Check whether the specifier has a variable + * precision that is going to be set by an + * argument. + * + * @return <code>true</code> if the conversion + * uses an * precision; otherwise + * <code>false</code>. + */ + boolean isVariablePrecision() + { + return variablePrecision; + } + + /** + * Set the precision with an argument. A + * negative precision will be changed to zero. + * + * @param pr the precision. + */ + void setPrecisionWithArg(int pr) + { + precisionSet = true; + precision = Math.max(pr, 0); + } + + /** + * Format an int argument using this conversion + * specification. + * + * @param s the int to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(int s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'd': + case 'i': + if (optionalh) + { + s2 = printDFormat((short) s); + } else if (optionall) + { + s2 = printDFormat((long) s); + } else + { + s2 = printDFormat(s); + } + + break; + + case 'x': + case 'X': + if (optionalh) + { + s2 = printXFormat((short) s); + } else if (optionall) + { + s2 = printXFormat((long) s); + } else + { + s2 = printXFormat(s); + } + + break; + + case 'o': + if (optionalh) + { + s2 = printOFormat((short) s); + } else if (optionall) + { + s2 = printOFormat((long) s); + } else + { + s2 = printOFormat(s); + } + + break; + + case 'c': + case 'C': + s2 = printCFormat((char) s); + + break; + + default: + throw new IllegalArgumentException("Cannot format a int with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a long argument using this conversion + * specification. + * + * @param s the long to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(long s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'd': + case 'i': + if (optionalh) + { + s2 = printDFormat((short) s); + } else if (optionall) + { + s2 = printDFormat(s); + } else + { + s2 = printDFormat((int) s); + } + + break; + + case 'x': + case 'X': + if (optionalh) + { + s2 = printXFormat((short) s); + } else if (optionall) + { + s2 = printXFormat(s); + } else + { + s2 = printXFormat((int) s); + } + + break; + + case 'o': + if (optionalh) + { + s2 = printOFormat((short) s); + } else if (optionall) + { + s2 = printOFormat(s); + } else + { + s2 = printOFormat((int) s); + } + + break; + + case 'c': + case 'C': + s2 = printCFormat((char) s); + + break; + + default: + throw new IllegalArgumentException("Cannot format a long with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a double argument using this conversion + * specification. + * + * @param s the double to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is c, C, s, S, i, d, + * x, X, or o. + */ + String internalsprintf(double s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'f': + s2 = printFFormat(s); + + break; + + case 'E': + case 'e': + s2 = printEFormat(s); + + break; + + case 'G': + case 'g': + s2 = printGFormat(s); + + break; + + default: + throw new IllegalArgumentException("Cannot " + "format a double with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a String argument using this conversion + * specification. + * + * @param s the String to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(String s) throws IllegalArgumentException + { + String s2 = ""; + + if ((conversionCharacter == 's') || (conversionCharacter == 'S')) + { + s2 = printSFormat(s); + } else + { + throw new IllegalArgumentException("Cannot " + "format a String with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format an Object argument using this conversion + * specification. + * + * @param s the Object to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(Object s) + { + String s2 = ""; + + if ((conversionCharacter == 's') || (conversionCharacter == 'S')) + { + s2 = printSFormat(s.toString()); + } else + { + throw new IllegalArgumentException("Cannot format a String with a format using" + " a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * For f format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both + * a '+' and a ' ' are specified, the blank flag + * is ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the number of digits + * to appear after the radix character. Padding is + * with trailing 0s. + */ + private char[] fFormatDigits(double x) + { + // int defaultDigits=6; + String sx, sxOut; + int i, j, k; + int n1In, n2In; + int expon = 0; + boolean minusSign = false; + + if (x > 0.0) + { + sx = Double.toString(x); + } else if (x < 0.0) + { + sx = Double.toString(-x); + minusSign = true; + } else + { + sx = Double.toString(x); + + if (sx.charAt(0) == '-') + { + minusSign = true; + sx = sx.substring(1); + } + } + + int ePos = sx.indexOf('E'); + int rPos = sx.indexOf('.'); + + if (rPos != -1) + { + n1In = rPos; + } else if (ePos != -1) + { + n1In = ePos; + } else + { + n1In = sx.length(); + } + + if (rPos != -1) + { + if (ePos != -1) + { + n2In = ePos - rPos - 1; + } else + { + n2In = sx.length() - rPos - 1; + } + } else + { + n2In = 0; + } + + if (ePos != -1) + { + int ie = ePos + 1; + + expon = 0; + + if (sx.charAt(ie) == '-') + { + for (++ie; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = -Integer.parseInt(sx.substring(ie)); + } + } else + { + if (sx.charAt(ie) == '+') + { + ++ie; + } + + for (; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = Integer.parseInt(sx.substring(ie)); + } + } + } + + int p; + + if (precisionSet) + { + p = precision; + } else + { + p = defaultDigits - 1; + } + + char[] ca1 = sx.toCharArray(); + char[] ca2 = new char[n1In + n2In]; + char[] ca3, ca4, ca5; + + for (j = 0; j < n1In; j++) + { + ca2[j] = ca1[j]; + } + + i = j + 1; + + for (k = 0; k < n2In; j++, i++, k++) + { + ca2[j] = ca1[i]; + } + + if (n1In + expon <= 0) + { + ca3 = new char[-expon + n2In]; + + for (j = 0, k = 0; k < (-n1In - expon); k++, j++) + { + ca3[j] = '0'; + } + + for (i = 0; i < (n1In + n2In); i++, j++) + { + ca3[j] = ca2[i]; + } + } else + { + ca3 = ca2; + } + + boolean carry = false; + + if (p < -expon + n2In) + { + if (expon < 0) + { + i = p; + } else + { + i = p + n1In; + } + + carry = checkForCarry(ca3, i); + + if (carry) + { + carry = startSymbolicCarry(ca3, i - 1, 0); + } + } + + if (n1In + expon <= 0) + { + ca4 = new char[2 + p]; + + if (!carry) + { + ca4[0] = '0'; + } else + { + ca4[0] = '1'; + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4[1] = '.'; + + for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++) + { + ca4[j] = ca3[i]; + } + + for (; j < ca4.length; j++) + { + ca4[j] = '0'; + } + } + } else + { + if (!carry) + { + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4 = new char[n1In + expon + p + 1]; + } else + { + ca4 = new char[n1In + expon]; + } + + j = 0; + } else + { + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4 = new char[n1In + expon + p + 2]; + } else + { + ca4 = new char[n1In + expon + 1]; + } + + ca4[0] = '1'; + j = 1; + } + + for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++) + { + ca4[j] = ca3[i]; + } + + for (; i < n1In + expon; i++, j++) + { + ca4[j] = '0'; + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4[j] = '.'; + j++; + + for (k = 0; (i < ca3.length) && (k < p); i++, j++, k++) + { + ca4[j] = ca3[i]; + } + + for (; j < ca4.length; j++) + { + ca4[j] = '0'; + } + } + } + + int nZeros = 0; + + if (!leftJustify && leadingZeros) + { + int xThousands = 0; + + if (thousands) + { + int xlead = 0; + + if ((ca4[0] == '+') || (ca4[0] == '-') || (ca4[0] == ' ')) + { + xlead = 1; + } + + int xdp = xlead; + + for (; xdp < ca4.length; xdp++) + { + if (ca4[xdp] == '.') + { + break; + } + } + + xThousands = (xdp - xlead) / 3; + } + + if (fieldWidthSet) + { + nZeros = fieldWidth - ca4.length; + } + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + nZeros--; + } + + nZeros -= xThousands; + + if (nZeros < 0) + { + nZeros = 0; + } + } + + j = 0; + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + ca5 = new char[ca4.length + nZeros + 1]; + j++; + } else + { + ca5 = new char[ca4.length + nZeros]; + } + + if (!minusSign) + { + if (leadingSign) + { + ca5[0] = '+'; + } + + if (leadingSpace) + { + ca5[0] = ' '; + } + } else + { + ca5[0] = '-'; + } + + for (i = 0; i < nZeros; i++, j++) + { + ca5[j] = '0'; + } + + for (i = 0; i < ca4.length; i++, j++) + { + ca5[j] = ca4[i]; + } + + int lead = 0; + + if ((ca5[0] == '+') || (ca5[0] == '-') || (ca5[0] == ' ')) + { + lead = 1; + } + + int dp = lead; + + for (; dp < ca5.length; dp++) + { + if (ca5[dp] == '.') + { + break; + } + } + + int nThousands = (dp - lead) / 3; + + // Localize the decimal point. + if (dp < ca5.length) + { + ca5[dp] = dfs.getDecimalSeparator(); + } + + char[] ca6 = ca5; + + if (thousands && (nThousands > 0)) + { + ca6 = new char[ca5.length + nThousands + lead]; + ca6[0] = ca5[0]; + + for (i = lead, k = lead; i < dp; i++) + { + if ((i > 0) && (dp - i) % 3 == 0) + { + // ca6[k]=','; + ca6[k] = dfs.getGroupingSeparator(); + ca6[k + 1] = ca5[i]; + k += 2; + } else + { + ca6[k] = ca5[i]; + k++; + } + } + + for (; i < ca5.length; i++, k++) + { + ca6[k] = ca5[i]; + } + } + + return ca6; + } + + /** + * An intermediate routine on the way to creating + * an f format String. The method decides whether + * the input double value is an infinity, + * not-a-number, or a finite double and formats + * each type of input appropriately. + * + * @param x the double value to be formatted. + * @return the converted double value. + */ + private String fFormatString(double x) + { + boolean noDigits = false; + char[] ca6, ca7; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca6 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca6 = " Inf".toCharArray(); + } else + { + ca6 = "Inf".toCharArray(); + } + } else + { + ca6 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca6 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca6 = " NaN".toCharArray(); + } else + { + ca6 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + ca6 = fFormatDigits(x); + } + + ca7 = applyFloatPadding(ca6, false); + + return new String(ca7); + } + + /** + * For e format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear after the radix character. + * Padding is with trailing 0s. + * <p/> + * The behavior is like printf. One (hopefully the + * only) exception is that the minimum number of + * exponent digits is 3 instead of 2 for e and E + * formats when the optional L is used before the + * e, E, g, or G conversion character. The optional + * L does not imply conversion to a long long + * double. + */ + private char[] eFormatDigits(double x, char eChar) + { + char[] ca1, ca2, ca3; + + // int defaultDigits=6; + String sx, sxOut; + int i, j, k, p; + int n1In, n2In; + int expon = 0; + int ePos, rPos, eSize; + boolean minusSign = false; + + if (x > 0.0) + { + sx = Double.toString(x); + } else if (x < 0.0) + { + sx = Double.toString(-x); + minusSign = true; + } else + { + sx = Double.toString(x); + + if (sx.charAt(0) == '-') + { + minusSign = true; + sx = sx.substring(1); + } + } + + ePos = sx.indexOf('E'); + + if (ePos == -1) + { + ePos = sx.indexOf('e'); + } + + rPos = sx.indexOf('.'); + + if (rPos != -1) + { + n1In = rPos; + } else if (ePos != -1) + { + n1In = ePos; + } else + { + n1In = sx.length(); + } + + if (rPos != -1) + { + if (ePos != -1) + { + n2In = ePos - rPos - 1; + } else + { + n2In = sx.length() - rPos - 1; + } + } else + { + n2In = 0; + } + + if (ePos != -1) + { + int ie = ePos + 1; + + expon = 0; + + if (sx.charAt(ie) == '-') + { + for (++ie; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = -Integer.parseInt(sx.substring(ie)); + } + } else + { + if (sx.charAt(ie) == '+') + { + ++ie; + } + + for (; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = Integer.parseInt(sx.substring(ie)); + } + } + } + + if (rPos != -1) + { + expon += rPos - 1; + } + + if (precisionSet) + { + p = precision; + } else + { + p = defaultDigits - 1; + } + + if ((rPos != -1) && (ePos != -1)) + { + ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray(); + } else if (rPos != -1) + { + ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray(); + } else if (ePos != -1) + { + ca1 = sx.substring(0, ePos).toCharArray(); + } else + { + ca1 = sx.toCharArray(); + } + + boolean carry = false; + int i0 = 0; + + if (ca1[0] != '0') + { + i0 = 0; + } else + { + for (i0 = 0; i0 < ca1.length; i0++) + { + if (ca1[i0] != '0') + { + break; + } + } + } + + if (i0 + p < ca1.length - 1) + { + carry = checkForCarry(ca1, i0 + p + 1); + + if (carry) + { + carry = startSymbolicCarry(ca1, i0 + p, i0); + } + + if (carry) + { + ca2 = new char[i0 + p + 1]; + ca2[i0] = '1'; + + for (j = 0; j < i0; j++) + { + ca2[j] = '0'; + } + + for (i = i0, j = i0 + 1; j < p + 1; i++, j++) + { + ca2[j] = ca1[i]; + } + + expon++; + ca1 = ca2; + } + } + + if ((Math.abs(expon) < 100) && !optionalL) + { + eSize = 4; + } else + { + eSize = 5; + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca2 = new char[2 + p + eSize]; + } else + { + ca2 = new char[1 + eSize]; + } + + if (ca1[0] != '0') + { + ca2[0] = ca1[0]; + j = 1; + } else + { + for (j = 1; j < ((ePos == -1) + ? ca1.length + : ePos); j++) + { + if (ca1[j] != '0') + { + break; + } + } + + if (((ePos != -1) && (j < ePos)) || ((ePos == -1) && (j < ca1.length))) + { + ca2[0] = ca1[j]; + expon -= j; + j++; + } else + { + ca2[0] = '0'; + j = 2; + } + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca2[1] = '.'; + i = 2; + } else + { + i = 1; + } + + for (k = 0; (k < p) && (j < ca1.length); j++, i++, k++) + { + ca2[i] = ca1[j]; + } + + for (; i < ca2.length - eSize; i++) + { + ca2[i] = '0'; + } + + ca2[i++] = eChar; + + if (expon < 0) + { + ca2[i++] = '-'; + } else + { + ca2[i++] = '+'; + } + + expon = Math.abs(expon); + + if (expon >= 100) + { + switch (expon / 100) + { + case 1: + ca2[i] = '1'; + + break; + + case 2: + ca2[i] = '2'; + + break; + + case 3: + ca2[i] = '3'; + + break; + + case 4: + ca2[i] = '4'; + + break; + + case 5: + ca2[i] = '5'; + + break; + + case 6: + ca2[i] = '6'; + + break; + + case 7: + ca2[i] = '7'; + + break; + + case 8: + ca2[i] = '8'; + + break; + + case 9: + ca2[i] = '9'; + + break; + } + + i++; + } + + switch ((expon % 100) / 10) + { + case 0: + ca2[i] = '0'; + + break; + + case 1: + ca2[i] = '1'; + + break; + + case 2: + ca2[i] = '2'; + + break; + + case 3: + ca2[i] = '3'; + + break; + + case 4: + ca2[i] = '4'; + + break; + + case 5: + ca2[i] = '5'; + + break; + + case 6: + ca2[i] = '6'; + + break; + + case 7: + ca2[i] = '7'; + + break; + + case 8: + ca2[i] = '8'; + + break; + + case 9: + ca2[i] = '9'; + + break; + } + + i++; + + switch (expon % 10) + { + case 0: + ca2[i] = '0'; + + break; + + case 1: + ca2[i] = '1'; + + break; + + case 2: + ca2[i] = '2'; + + break; + + case 3: + ca2[i] = '3'; + + break; + + case 4: + ca2[i] = '4'; + + break; + + case 5: + ca2[i] = '5'; + + break; + + case 6: + ca2[i] = '6'; + + break; + + case 7: + ca2[i] = '7'; + + break; + + case 8: + ca2[i] = '8'; + + break; + + case 9: + ca2[i] = '9'; + + break; + } + + int nZeros = 0; + + if (!leftJustify && leadingZeros) + { + int xThousands = 0; + + if (thousands) + { + int xlead = 0; + + if ((ca2[0] == '+') || (ca2[0] == '-') || (ca2[0] == ' ')) + { + xlead = 1; + } + + int xdp = xlead; + + for (; xdp < ca2.length; xdp++) + { + if (ca2[xdp] == '.') + { + break; + } + } + + xThousands = (xdp - xlead) / 3; + } + + if (fieldWidthSet) + { + nZeros = fieldWidth - ca2.length; + } + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + nZeros--; + } + + nZeros -= xThousands; + + if (nZeros < 0) + { + nZeros = 0; + } + } + + j = 0; + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + ca3 = new char[ca2.length + nZeros + 1]; + j++; + } else + { + ca3 = new char[ca2.length + nZeros]; + } + + if (!minusSign) + { + if (leadingSign) + { + ca3[0] = '+'; + } + + if (leadingSpace) + { + ca3[0] = ' '; + } + } else + { + ca3[0] = '-'; + } + + for (k = 0; k < nZeros; j++, k++) + { + ca3[j] = '0'; + } + + for (i = 0; (i < ca2.length) && (j < ca3.length); i++, j++) + { + ca3[j] = ca2[i]; + } + + int lead = 0; + + if ((ca3[0] == '+') || (ca3[0] == '-') || (ca3[0] == ' ')) + { + lead = 1; + } + + int dp = lead; + + for (; dp < ca3.length; dp++) + { + if (ca3[dp] == '.') + { + break; + } + } + + int nThousands = dp / 3; + + // Localize the decimal point. + if (dp < ca3.length) + { + ca3[dp] = dfs.getDecimalSeparator(); + } + + char[] ca4 = ca3; + + if (thousands && (nThousands > 0)) + { + ca4 = new char[ca3.length + nThousands + lead]; + ca4[0] = ca3[0]; + + for (i = lead, k = lead; i < dp; i++) + { + if ((i > 0) && (dp - i) % 3 == 0) + { + // ca4[k]=','; + ca4[k] = dfs.getGroupingSeparator(); + ca4[k + 1] = ca3[i]; + k += 2; + } else + { + ca4[k] = ca3[i]; + k++; + } + } + + for (; i < ca3.length; i++, k++) + { + ca4[k] = ca3[i]; + } + } + + return ca4; + } + + /** + * Check to see if the digits that are going to + * be truncated because of the precision should + * force a round in the preceding digits. + * + * @param ca1 the array of digits + * @param icarry the index of the first digit that + * is to be truncated from the print + * @return <code>true</code> if the truncation forces + * a round that will change the print + */ + private boolean checkForCarry(char[] ca1, int icarry) + { + boolean carry = false; + + if (icarry < ca1.length) + { + if ((ca1[icarry] == '6') || (ca1[icarry] == '7') || (ca1[icarry] == '8') || (ca1[icarry] == '9')) + { + carry = true; + } else if (ca1[icarry] == '5') + { + int ii = icarry + 1; + + for (; ii < ca1.length; ii++) + { + if (ca1[ii] != '0') + { + break; + } + } + + carry = ii < ca1.length; + + if (!carry && (icarry > 0)) + { + carry = ((ca1[icarry - 1] == '1') || (ca1[icarry - 1] == '3') || (ca1[icarry - 1] == '5') + || (ca1[icarry - 1] == '7') || (ca1[icarry - 1] == '9')); + } + } + } + + return carry; + } + + /** + * Start the symbolic carry process. The process + * is not quite finished because the symbolic + * carry may change the length of the string and + * change the exponent (in e format). + * + * @param cLast index of the last digit changed + * by the round + * @param cFirst index of the first digit allowed + * to be changed by this phase of the round + * @return <code>true</code> if the carry forces + * a round that will change the print still + * more + */ + private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) + { + boolean carry = true; + + for (int i = cLast; carry && (i >= cFirst); i--) + { + carry = false; + + switch (ca[i]) + { + case '0': + ca[i] = '1'; + + break; + + case '1': + ca[i] = '2'; + + break; + + case '2': + ca[i] = '3'; + + break; + + case '3': + ca[i] = '4'; + + break; + + case '4': + ca[i] = '5'; + + break; + + case '5': + ca[i] = '6'; + + break; + + case '6': + ca[i] = '7'; + + break; + + case '7': + ca[i] = '8'; + + break; + + case '8': + ca[i] = '9'; + + break; + + case '9': + ca[i] = '0'; + carry = true; + + break; + } + } + + return carry; + } + + /** + * An intermediate routine on the way to creating + * an e format String. The method decides whether + * the input double value is an infinity, + * not-a-number, or a finite double and formats + * each type of input appropriately. + * + * @param x the double value to be formatted. + * @param eChar an 'e' or 'E' to use in the + * converted double value. + * @return the converted double value. + */ + private String eFormatString(double x, char eChar) + { + boolean noDigits = false; + char[] ca4, ca5; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca4 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca4 = " Inf".toCharArray(); + } else + { + ca4 = "Inf".toCharArray(); + } + } else + { + ca4 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca4 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca4 = " NaN".toCharArray(); + } else + { + ca4 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + ca4 = eFormatDigits(x, eChar); + } + + ca5 = applyFloatPadding(ca4, false); + + return new String(ca5); + } + + /** + * Apply zero or blank, left or right padding. + * + * @param ca4 array of characters before padding is + * finished + * @param noDigits NaN or signed Inf + * @return a padded array of characters + */ + private char[] applyFloatPadding(char[] ca4, boolean noDigits) + { + char[] ca5 = ca4; + + if (fieldWidthSet) + { + int i, j, nBlanks; + + if (leftJustify) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + + for (i = 0; i < ca4.length; i++) + { + ca5[i] = ca4[i]; + } + + for (j = 0; j < nBlanks; j++, i++) + { + ca5[i] = ' '; + } + } + } else if (!leadingZeros || noDigits) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + + for (i = 0; i < nBlanks; i++) + { + ca5[i] = ' '; + } + + for (j = 0; j < ca4.length; i++, j++) + { + ca5[i] = ca4[j]; + } + } + } else if (leadingZeros) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + i = 0; + j = 0; + + if (ca4[0] == '-') + { + ca5[0] = '-'; + i++; + j++; + } + + for (int k = 0; k < nBlanks; i++, k++) + { + ca5[i] = '0'; + } + + for (; j < ca4.length; i++, j++) + { + ca5[i] = ca4[j]; + } + } + } + } + + return ca5; + } + + /** + * Format method for the f conversion character. + * + * @param x the double to format. + * @return the formatted String. + */ + private String printFFormat(double x) + { + return fFormatString(x); + } + + /** + * Format method for the e or E conversion + * character. + * + * @param x the double to format. + * @return the formatted String. + */ + private String printEFormat(double x) + { + if (conversionCharacter == 'e') + { + return eFormatString(x, 'e'); + } else + { + return eFormatString(x, 'E'); + } + } + + /** + * Format method for the g conversion character. + * <p/> + * For g format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear after the radix character. + * Padding is with trailing 0s. + * + * @param x the double to format. + * @return the formatted String. + */ + private String printGFormat(double x) + { + String sx, sy, sz, ret; + int savePrecision = precision; + int i; + char[] ca4, ca5; + boolean noDigits = false; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca4 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca4 = " Inf".toCharArray(); + } else + { + ca4 = "Inf".toCharArray(); + } + } else + { + ca4 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca4 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca4 = " NaN".toCharArray(); + } else + { + ca4 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + if (!precisionSet) + { + precision = defaultDigits; + } + + if (precision == 0) + { + precision = 1; + } + + int ePos = -1; + + if (conversionCharacter == 'g') + { + sx = eFormatString(x, 'e').trim(); + ePos = sx.indexOf('e'); + } else + { + sx = eFormatString(x, 'E').trim(); + ePos = sx.indexOf('E'); + } + + i = ePos + 1; + + int expon = 0; + + if (sx.charAt(i) == '-') + { + for (++i; i < sx.length(); i++) + { + if (sx.charAt(i) != '0') + { + break; + } + } + + if (i < sx.length()) + { + expon = -Integer.parseInt(sx.substring(i)); + } + } else + { + if (sx.charAt(i) == '+') + { + ++i; + } + + for (; i < sx.length(); i++) + { + if (sx.charAt(i) != '0') + { + break; + } + } + + if (i < sx.length()) + { + expon = Integer.parseInt(sx.substring(i)); + } + } + + // Trim trailing zeros. + // If the radix character is not followed by + // a digit, trim it, too. + if (!alternateForm) + { + if ((expon >= -4) && (expon < precision)) + { + sy = fFormatString(x).trim(); + } else + { + sy = sx.substring(0, ePos); + } + + i = sy.length() - 1; + + for (; i >= 0; i--) + { + if (sy.charAt(i) != '0') + { + break; + } + } + + if ((i >= 0) && (sy.charAt(i) == '.')) + { + i--; + } + + if (i == -1) + { + sz = "0"; + } else if (!Character.isDigit(sy.charAt(i))) + { + sz = sy.substring(0, i + 1) + "0"; + } else + { + sz = sy.substring(0, i + 1); + } + + if ((expon >= -4) && (expon < precision)) + { + ret = sz; + } else + { + ret = sz + sx.substring(ePos); + } + } else + { + if ((expon >= -4) && (expon < precision)) + { + ret = fFormatString(x).trim(); + } else + { + ret = sx; + } + } + + // leading space was trimmed off during + // construction + if (leadingSpace) + { + if (x >= 0) + { + ret = " " + ret; + } + } + + ca4 = ret.toCharArray(); + } + + // Pad with blanks or zeros. + ca5 = applyFloatPadding(ca4, false); + precision = savePrecision; + + return new String(ca5); + } + + /** + * Format method for the d conversion specifer and + * short argument. + * <p/> + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the short to format. + * @return the formatted String. + */ + private String printDFormat(short x) + { + return printDFormat(Short.toString(x)); + } + + /** + * Format method for the d conversion character and + * long argument. + * <p/> + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the long to format. + * @return the formatted String. + */ + private String printDFormat(long x) + { + return printDFormat(Long.toString(x)); + } + + /** + * Format method for the d conversion character and + * int argument. + * <p/> + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the int to format. + * @return the formatted String. + */ + private String printDFormat(int x) + { + return printDFormat(Integer.toString(x)); + } + + /** + * Utility method for formatting using the d + * conversion character. + * + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printDFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0, + n = 0; + int i = 0, + jFirst = 0; + boolean neg = sx.charAt(0) == '-'; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (!neg) + { + if (precisionSet && (sx.length() < precision)) + { + nLeadingZeros = precision - sx.length(); + } + } else + { + if (precisionSet && (sx.length() - 1) < precision) + { + nLeadingZeros = precision - sx.length() + 1; + } + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + + if (!neg && (leadingSign || leadingSpace)) + { + nBlanks--; + } + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + if (leadingSign) + { + n++; + } else if (leadingSpace) + { + n++; + } + + n += nBlanks; + n += nLeadingZeros; + n += sx.length(); + + char[] ca = new char[n]; + + if (leftJustify) + { + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + + char[] csx = sx.toCharArray(); + + jFirst = neg + ? 1 + : 0; + + for (int j = 0; j < nLeadingZeros; i++, j++) + { + ca[i] = '0'; + } + + for (int j = jFirst; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; i++, j++) + { + ca[i] = ' '; + } + } else + { + if (!leadingZeros) + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = ' '; + } + + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + } else + { + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = '0'; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + jFirst = neg + ? 1 + : 0; + + for (int j = jFirst; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + return new String(ca); + } + + /** + * Format method for the x conversion character and + * short argument. + * <p/> + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the short to format. + * @return the formatted String. + */ + private String printXFormat(short x) + { + String sx = null; + + if (x == Short.MIN_VALUE) + { + sx = "8000"; + } else if (x < 0) + { + String t; + + if (x == Short.MIN_VALUE) + { + t = "0"; + } else + { + t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16); + + if ((t.charAt(0) == 'F') || (t.charAt(0) == 'f')) + { + t = t.substring(16, 32); + } + } + + switch (t.length()) + { + case 1: + sx = "800" + t; + + break; + + case 2: + sx = "80" + t; + + break; + + case 3: + sx = "8" + t; + + break; + + case 4: + switch (t.charAt(0)) + { + case '1': + sx = "9" + t.substring(1, 4); + + break; + + case '2': + sx = "a" + t.substring(1, 4); + + break; + + case '3': + sx = "b" + t.substring(1, 4); + + break; + + case '4': + sx = "c" + t.substring(1, 4); + + break; + + case '5': + sx = "d" + t.substring(1, 4); + + break; + + case '6': + sx = "e" + t.substring(1, 4); + + break; + + case '7': + sx = "f" + t.substring(1, 4); + + break; + } + + break; + } + } else + { + sx = Integer.toString((int) x, 16); + } + + return printXFormat(sx); + } + + /** + * Format method for the x conversion character and + * long argument. + * <p/> + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the long to format. + * @return the formatted String. + */ + private String printXFormat(long x) + { + String sx = null; + + if (x == Long.MIN_VALUE) + { + sx = "8000000000000000"; + } else if (x < 0) + { + String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16); + + switch (t.length()) + { + case 1: + sx = "800000000000000" + t; + + break; + + case 2: + sx = "80000000000000" + t; + + break; + + case 3: + sx = "8000000000000" + t; + + break; + + case 4: + sx = "800000000000" + t; + + break; + + case 5: + sx = "80000000000" + t; + + break; + + case 6: + sx = "8000000000" + t; + + break; + + case 7: + sx = "800000000" + t; + + break; + + case 8: + sx = "80000000" + t; + + break; + + case 9: + sx = "8000000" + t; + + break; + + case 10: + sx = "800000" + t; + + break; + + case 11: + sx = "80000" + t; + + break; + + case 12: + sx = "8000" + t; + + break; + + case 13: + sx = "800" + t; + + break; + + case 14: + sx = "80" + t; + + break; + + case 15: + sx = "8" + t; + + break; + + case 16: + switch (t.charAt(0)) + { + case '1': + sx = "9" + t.substring(1, 16); + + break; + + case '2': + sx = "a" + t.substring(1, 16); + + break; + + case '3': + sx = "b" + t.substring(1, 16); + + break; + + case '4': + sx = "c" + t.substring(1, 16); + + break; + + case '5': + sx = "d" + t.substring(1, 16); + + break; + + case '6': + sx = "e" + t.substring(1, 16); + + break; + + case '7': + sx = "f" + t.substring(1, 16); + + break; + } + + break; + } + } else + { + sx = Long.toString(x, 16); + } + + return printXFormat(sx); + } + + /** + * Format method for the x conversion character and + * int argument. + * <p/> + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the int to format. + * @return the formatted String. + */ + private String printXFormat(int x) + { + String sx = null; + + if (x == Integer.MIN_VALUE) + { + sx = "80000000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16); + + switch (t.length()) + { + case 1: + sx = "8000000" + t; + + break; + + case 2: + sx = "800000" + t; + + break; + + case 3: + sx = "80000" + t; + + break; + + case 4: + sx = "8000" + t; + + break; + + case 5: + sx = "800" + t; + + break; + + case 6: + sx = "80" + t; + + break; + + case 7: + sx = "8" + t; + + break; + + case 8: + switch (t.charAt(0)) + { + case '1': + sx = "9" + t.substring(1, 8); + + break; + + case '2': + sx = "a" + t.substring(1, 8); + + break; + + case '3': + sx = "b" + t.substring(1, 8); + + break; + + case '4': + sx = "c" + t.substring(1, 8); + + break; + + case '5': + sx = "d" + t.substring(1, 8); + + break; + + case '6': + sx = "e" + t.substring(1, 8); + + break; + + case '7': + sx = "f" + t.substring(1, 8); + + break; + } + + break; + } + } else + { + sx = Integer.toString(x, 16); + } + + return printXFormat(sx); + } + + /** + * Utility method for formatting using the x + * conversion character. + * + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printXFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (precisionSet) + { + nLeadingZeros = precision - sx.length(); + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + + if (alternateForm) + { + nBlanks = nBlanks - 2; + } + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + int n = 0; + + if (alternateForm) + { + n += 2; + } + + n += nLeadingZeros; + n += sx.length(); + n += nBlanks; + + char[] ca = new char[n]; + int i = 0; + + if (leftJustify) + { + if (alternateForm) + { + ca[i++] = '0'; + ca[i++] = 'x'; + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } else + { + if (!leadingZeros) + { + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } + + if (alternateForm) + { + ca[i++] = '0'; + ca[i++] = 'x'; + } + + if (leadingZeros) + { + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = '0'; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + String caReturn = new String(ca); + + if (conversionCharacter == 'X') + { + caReturn = caReturn.toUpperCase(); + } + + return caReturn; + } + + /** + * Format method for the o conversion character and + * short argument. + * <p/> + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the short to format. + * @return the formatted String. + */ + private String printOFormat(short x) + { + String sx = null; + + if (x == Short.MIN_VALUE) + { + sx = "100000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8); + + switch (t.length()) + { + case 1: + sx = "10000" + t; + + break; + + case 2: + sx = "1000" + t; + + break; + + case 3: + sx = "100" + t; + + break; + + case 4: + sx = "10" + t; + + break; + + case 5: + sx = "1" + t; + + break; + } + } else + { + sx = Integer.toString((int) x, 8); + } + + return printOFormat(sx); + } + + /** + * Format method for the o conversion character and + * long argument. + * <p/> + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the long to format. + * @return the formatted String. + */ + private String printOFormat(long x) + { + String sx = null; + + if (x == Long.MIN_VALUE) + { + sx = "1000000000000000000000"; + } else if (x < 0) + { + String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8); + + switch (t.length()) + { + case 1: + sx = "100000000000000000000" + t; + + break; + + case 2: + sx = "10000000000000000000" + t; + + break; + + case 3: + sx = "1000000000000000000" + t; + + break; + + case 4: + sx = "100000000000000000" + t; + + break; + + case 5: + sx = "10000000000000000" + t; + + break; + + case 6: + sx = "1000000000000000" + t; + + break; + + case 7: + sx = "100000000000000" + t; + + break; + + case 8: + sx = "10000000000000" + t; + + break; + + case 9: + sx = "1000000000000" + t; + + break; + + case 10: + sx = "100000000000" + t; + + break; + + case 11: + sx = "10000000000" + t; + + break; + + case 12: + sx = "1000000000" + t; + + break; + + case 13: + sx = "100000000" + t; + + break; + + case 14: + sx = "10000000" + t; + + break; + + case 15: + sx = "1000000" + t; + + break; + + case 16: + sx = "100000" + t; + + break; + + case 17: + sx = "10000" + t; + + break; + + case 18: + sx = "1000" + t; + + break; + + case 19: + sx = "100" + t; + + break; + + case 20: + sx = "10" + t; + + break; + + case 21: + sx = "1" + t; + + break; + } + } else + { + sx = Long.toString(x, 8); + } + + return printOFormat(sx); + } + + /** + * Format method for the o conversion character and + * int argument. + * <p/> + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the int to format. + * @return the formatted String. + */ + private String printOFormat(int x) + { + String sx = null; + + if (x == Integer.MIN_VALUE) + { + sx = "20000000000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8); + + switch (t.length()) + { + case 1: + sx = "2000000000" + t; + + break; + + case 2: + sx = "200000000" + t; + + break; + + case 3: + sx = "20000000" + t; + + break; + + case 4: + sx = "2000000" + t; + + break; + + case 5: + sx = "200000" + t; + + break; + + case 6: + sx = "20000" + t; + + break; + + case 7: + sx = "2000" + t; + + break; + + case 8: + sx = "200" + t; + + break; + + case 9: + sx = "20" + t; + + break; + + case 10: + sx = "2" + t; + + break; + + case 11: + sx = "3" + t.substring(1); + + break; + } + } else + { + sx = Integer.toString(x, 8); + } + + return printOFormat(sx); + } + + /** + * Utility method for formatting using the o + * conversion character. + * + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printOFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (precisionSet) + { + nLeadingZeros = precision - sx.length(); + } + + if (alternateForm) + { + nLeadingZeros++; + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + int n = nLeadingZeros + sx.length() + nBlanks; + char[] ca = new char[n]; + int i; + + if (leftJustify) + { + for (i = 0; i < nLeadingZeros; i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } else + { + if (leadingZeros) + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = '0'; + } + } else + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = ' '; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + return new String(ca); + } + + /** + * Format method for the c conversion character and + * char argument. + * <p/> + * The only flag character that affects c format is + * the '-', meaning that the output should be left + * justified within the field. The default is to + * pad with blanks on the left. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. Padding is with + * blanks by default. The default width is 1. + * <p/> + * The precision, if set, is ignored. + * + * @param x the char to format. + * @return the formatted String. + */ + private String printCFormat(char x) + { + int nPrint = 1; + int width = fieldWidth; + + if (!fieldWidthSet) + { + width = nPrint; + } + + char[] ca = new char[width]; + int i = 0; + + if (leftJustify) + { + ca[0] = x; + + for (i = 1; i <= width - nPrint; i++) + { + ca[i] = ' '; + } + } else + { + for (i = 0; i < width - nPrint; i++) + { + ca[i] = ' '; + } + + ca[i] = x; + } + + return new String(ca); + } + + /** + * Format method for the s conversion character and + * String argument. + * <p/> + * The only flag character that affects s format is + * the '-', meaning that the output should be left + * justified within the field. The default is to + * pad with blanks on the left. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is the + * smaller of the number of characters in the the + * input and the precision. Padding is with blanks + * by default. + * <p/> + * The precision, if set, specifies the maximum + * number of characters to be printed from the + * string. A null digit string is treated + * as a 0. The default is not to set a maximum + * number of characters to be printed. + * + * @param x the String to format. + * @return the formatted String. + */ + private String printSFormat(String x) + { + int nPrint = x.length(); + int width = fieldWidth; + + if (precisionSet && (nPrint > precision)) + { + nPrint = precision; + } + + if (!fieldWidthSet) + { + width = nPrint; + } + + int n = 0; + + if (width > nPrint) + { + n += width - nPrint; + } + + if (nPrint >= x.length()) + { + n += x.length(); + } else + { + n += nPrint; + } + + char[] ca = new char[n]; + int i = 0; + + if (leftJustify) + { + if (nPrint >= x.length()) + { + char[] csx = x.toCharArray(); + + for (i = 0; i < x.length(); i++) + { + ca[i] = csx[i]; + } + } else + { + char[] csx = x.substring(0, nPrint).toCharArray(); + + for (i = 0; i < nPrint; i++) + { + ca[i] = csx[i]; + } + } + + for (int j = 0; j < width - nPrint; j++, i++) + { + ca[i] = ' '; + } + } else + { + for (i = 0; i < width - nPrint; i++) + { + ca[i] = ' '; + } + + if (nPrint >= x.length()) + { + char[] csx = x.toCharArray(); + + for (int j = 0; j < x.length(); i++, j++) + { + ca[i] = csx[j]; + } + } else + { + char[] csx = x.substring(0, nPrint).toCharArray(); + + for (int j = 0; j < nPrint; i++, j++) + { + ca[i] = csx[j]; + } + } + } + + return new String(ca); + } + + /** + * Check for a conversion character. If it is + * there, store it. + * + * @return <code>true</code> if the conversion + * character is there, and + * <code>false</code> otherwise. + */ + private boolean setConversionCharacter() + { + /* idfgGoxXeEcs */ + boolean ret = false; + + conversionCharacter = '\0'; + + if (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if ((c == 'i') || (c == 'd') || (c == 'f') || (c == 'g') || (c == 'G') || (c == 'o') || (c == 'x') || (c == 'X') + || (c == 'e') || (c == 'E') || (c == 'c') || (c == 's') || (c == '%')) + { + conversionCharacter = c; + pos++; + ret = true; + } + } + + return ret; + } + + /** + * Check for an h, l, or L in a format. An L is + * used to control the minimum number of digits + * in an exponent when using floating point + * formats. An l or h is used to control + * conversion of the input to a long or short, + * respectively, before formatting. If any of + * these is present, store them. + */ + private void setOptionalHL() + { + optionalh = false; + optionall = false; + optionalL = false; + + if (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (c == 'h') + { + optionalh = true; + pos++; + } else if (c == 'l') + { + optionall = true; + pos++; + } else if (c == 'L') + { + optionalL = true; + pos++; + } + } + } + + /** + * Set the precision. + */ + private void setPrecision() + { + int firstPos = pos; + + precisionSet = false; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '.')) + { + pos++; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) + { + pos++; + + if (!setPrecisionArgPosition()) + { + variablePrecision = true; + precisionSet = true; + } + + return; + } else + { + while (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (Character.isDigit(c)) + { + pos++; + } else + { + break; + } + } + + if (pos > firstPos + 1) + { + String sz = fmt.substring(firstPos + 1, pos); + + precision = Integer.parseInt(sz); + precisionSet = true; + } + } + } + } + + /** + * Set the field width. + */ + private void setFieldWidth() + { + int firstPos = pos; + + fieldWidth = 0; + fieldWidthSet = false; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) + { + pos++; + + if (!setFieldWidthArgPosition()) + { + variableFieldWidth = true; + fieldWidthSet = true; + } + } else + { + while (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (Character.isDigit(c)) + { + pos++; + } else + { + break; + } + } + + if ((firstPos < pos) && (firstPos < fmt.length())) + { + String sz = fmt.substring(firstPos, pos); + + fieldWidth = Integer.parseInt(sz); + fieldWidthSet = true; + } + } + } + + /** + * Store the digits <code>n</code> in %n$ forms. + */ + private void setArgPosition() + { + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalSpecification = true; + argumentPosition = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + } + } + } + + /** + * Store the digits <code>n</code> in *n$ forms. + */ + private boolean setFieldWidthArgPosition() + { + boolean ret = false; + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalFieldWidth = true; + argumentPositionForFieldWidth = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + ret = true; + } + } + + return ret; + } + + /** + * Store the digits <code>n</code> in *n$ forms. + */ + private boolean setPrecisionArgPosition() + { + boolean ret = false; + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalPrecision = true; + argumentPositionForPrecision = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + ret = true; + } + } + + return ret; + } + + boolean isPositionalSpecification() + { + return positionalSpecification; + } + + int getArgumentPosition() + { + return argumentPosition; + } + + boolean isPositionalFieldWidth() + { + return positionalFieldWidth; + } + + int getArgumentPositionForFieldWidth() + { + return argumentPositionForFieldWidth; + } + + boolean isPositionalPrecision() + { + return positionalPrecision; + } + + int getArgumentPositionForPrecision() + { + return argumentPositionForPrecision; + } + + /** + * Set flag characters, one of '-+#0 or a space. + */ + private void setFlagCharacters() + { + /* '-+ #0 */ + thousands = false; + leftJustify = false; + leadingSign = false; + leadingSpace = false; + alternateForm = false; + leadingZeros = false; + + for (; pos < fmt.length(); pos++) + { + char c = fmt.charAt(pos); + + if (c == '\'') + { + thousands = true; + } else if (c == '-') + { + leftJustify = true; + leadingZeros = false; + } else if (c == '+') + { + leadingSign = true; + leadingSpace = false; + } else if (c == ' ') + { + if (!leadingSign) + { + leadingSpace = true; + } + } else if (c == '#') + { + alternateForm = true; + } else if (c == '0') + { + if (!leftJustify) + { + leadingZeros = true; + } + } else + { + break; + } + } + } + } +} diff --git a/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7OracleReaderTest.java b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7OracleReaderTest.java new file mode 100644 index 0000000..f01a630 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7OracleReaderTest.java @@ -0,0 +1,127 @@ +package com.ximple.io.dgn7; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.vividsolutions.jts.geom.Coordinate; + +import oracle.jdbc.OracleConnection; + +import com.ximple.util.PrintfFormat; + +/** + * Dgn7OracleReaderTest + * User: Ulysses + * Date: 2007/10/24 + * Time: �W�� 10:49:54 + */ +public class Dgn7OracleReaderTest +{ + @BeforeTest + public void setUp() + { + + } + + @Test + public void testOracleReader() throws SQLException, IOException + { + OracleConnection connection = OracleTarget.getInstance().getOracleConnection(); + // String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" ORDER BY ROWID"; + String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" WHERE TAG_SFSC=106 ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchSrcStmtFmt); + String srcschema = "SPATIALDB"; + String srctable = "IGSET_1"; + String fetchSrcStmt = spf.sprintf(new Object[]{srcschema, srctable}); + + Dgn7OracleReader reader = new Dgn7OracleReader(fetchSrcStmt, "IGDSELM", connection); + int count = 0; + while (reader.hasNext()) + { + Element element = reader.next(); + + if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChain = (ComplexChainElement) element; + FrammeAttributeData frammeLinkage = null; + + List<UserAttributeData> attrs = complexChain.getUserAttributeData(); + for (int k = 0; k < attrs.size(); k++) + { + UserAttributeData userAttr = attrs.get(k); + if (userAttr instanceof FrammeAttributeData) + { + frammeLinkage = (FrammeAttributeData) userAttr; + break; + } + } + + System.out.print("complexChain:"); + if (frammeLinkage != null) + System.out.print(":FSC-" + frammeLinkage.getFsc() + + ":UFID-" + frammeLinkage.getUfid() + + ":COMP-" + frammeLinkage.getComponentID()); + else + System.out.print("Linkage is null"); + + for (int i = 0; i < complexChain.size(); i++) + { + Element elm = (Element) complexChain.get(i); + if (elm instanceof LineStringElement) + { + LineStringElement lineStringElement = (LineStringElement) elm; + int size = lineStringElement.getVerticeSize(); + System.out.print("size=" + size + ":"); + Coordinate[] coords = lineStringElement.getVertices(); + for (int j = 0; j < coords.length; j++) + System.out.print("[" + j + "]" + coords[j].toString()); + } + } + + System.out.println(); + } else if (element instanceof TextNodeElement) + { + TextNodeElement textNode = (TextNodeElement) element; + + FrammeAttributeData frammeLinkage = null; + + List<UserAttributeData> attrs = textNode.getUserAttributeData(); + for (int k = 0; k < attrs.size(); k++) + { + UserAttributeData userAttr = attrs.get(k); + if (userAttr instanceof FrammeAttributeData) + { + frammeLinkage = (FrammeAttributeData) userAttr; + break; + } + } + + Coordinate coord = textNode.getOrigin(); + System.out.print("TextNode:origin=" + coord.toString()); + if (frammeLinkage != null) + System.out.print(":FSC-" + frammeLinkage.getFsc() + + ":UFID-" + frammeLinkage.getUfid() + + ":COMP-" + frammeLinkage.getComponentID()); + else + System.out.print("Linkage is null"); + for (int i = 0; i < textNode.size(); i++) + { + Element elm = (Element) textNode.get(i); + if (elm instanceof TextElement) + { + TextElement textElm = (TextElement) elm; + System.out.print("---"); + String text = textElm.getText(); + System.out.print("'" + text + "'"); + } + } + System.out.println(); + } + } + } + +} diff --git a/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7TextElementReaderTest.java b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7TextElementReaderTest.java new file mode 100644 index 0000000..301255e --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7TextElementReaderTest.java @@ -0,0 +1,180 @@ +package com.ximple.io.dgn7; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; +import org.geotools.TestData; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +/** + * Dgn7TextElementReaderTest + * User: Ulysses + * Date: 2008/1/10 + * Time: �W�� 12:19:14 + */ +public class Dgn7TextElementReaderTest +{ + private final static Logger logger = Logger.getLogger(Dgn7fileReaderTest.class); + + private final static String testFilePathCreated = "demo.dgn"; + private final static String testFilePathExist = "HV88491-1.dgn"; + private final static String testFilePathPostComplete = "HV88494_0.dgn"; + + private FileInputStream _fs; + + @BeforeTest + public void setUp() throws FileNotFoundException + { + } + + @Test + public void testRead() throws Dgn7fileException, IOException + { + File dataFile = TestData.file(this, testFilePathCreated); + if (dataFile.exists()) + { + System.out.println("Output--" + testFilePathCreated); + _fs = new FileInputStream(dataFile); + FileChannel fc = _fs.getChannel(); + dumpElements(fc); + fc.close(); + _fs.close(); + } + + dataFile = TestData.file(this, testFilePathExist); + if (dataFile.exists()) + { + System.out.println("Output--" + testFilePathExist); + _fs = new FileInputStream(dataFile); + FileChannel fc = _fs.getChannel(); + dumpElements(fc); + fc.close(); + _fs.close(); + } + + dataFile = TestData.file(this, testFilePathPostComplete); + if (dataFile.exists()) + { + System.out.println("Output--" + testFilePathPostComplete); + _fs = new FileInputStream(dataFile); + FileChannel fc = _fs.getChannel(); + dumpElements(fc); + fc.close(); + _fs.close(); + } + } + + public void dumpElements(FileChannel fc) throws Dgn7fileException, IOException + { + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + // @todo add process in here + lastComplex = null; + } + + // @todo add process in here + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex == null) + { + lastComplex = element; + } else + { + // @todo add process in here + lastComplex = element; + } + } + + if (element.getElementType().isComplexElement()) + { + if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChain = (ComplexChainElement) element; + int size = complexChain.size(); + for (Object aComplexChain : complexChain) + { + Element subElement = (Element) aComplexChain; + subElement.getType(); + } + } + + if (element instanceof ComplexShapeElement) + { + ComplexShapeElement complexShape = (ComplexShapeElement) element; + } + + if (element instanceof TextNodeElement) + { + TextNodeElement textNode = (TextNodeElement) element; + int size = textNode.size(); + for (int i = 0; i < size; i++) + { + Element subElement = (Element) textNode.get(i); + subElement.getElementType(); + } + } + + } else + { + boolean hasLinkage = false; + if (element instanceof TextElement) + { + TextElement textElm = (TextElement) element; + List<UserAttributeData> usrData = textElm.getUserAttributeData(); + Iterator<UserAttributeData> it = usrData.iterator(); + while (it.hasNext()) + { + UserAttributeData attr = it.next(); + if (attr instanceof FrammeAttributeData) + { + hasLinkage = true; + System.out.println("------------------------------------------"); + System.out.println("FSC=" + ((FrammeAttributeData) attr).getFsc() + ":" + + ((FrammeAttributeData) attr).getUfid()); + } + } + + if (hasLinkage) + { + System.out.println("Text.Font=" + textElm.getFontIndex()); + System.out.println("Text.Just=" + textElm.getJustification()); + System.out.println("usrData.len=" + usrData.size()); + System.out.println("text=" + textElm.getText()); + System.out.println("Origin=" + textElm.getOrigin()); + System.out.println("UserOrigin=" + textElm.getUserOrigin()); + } + } + } + } + count++; + } + + logger.info("ElementRecord Count=" + count); + } +} diff --git a/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7fileReaderTest.java b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7fileReaderTest.java new file mode 100644 index 0000000..40b6d1f --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/Dgn7fileReaderTest.java @@ -0,0 +1,118 @@ +package com.ximple.io.dgn7; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; + +import org.apache.log4j.Logger; +import org.geotools.TestData; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +/** + * Dgn7fileReaderTest + * User: Ulysses + * Date: 2007/10/24 + * Time: �W�� 01:43:41 + * To change this template use File | Settings | File Templates. + */ +public class Dgn7fileReaderTest +{ + private final static Logger logger = Logger.getLogger(Dgn7fileReaderTest.class); + + // private final static String testFilePath = "test-data\\testHV.dgn"; + private final static String testFilePath = "testHV.dgn"; + private FileInputStream _fs; + + @BeforeTest + public void setUp() throws IOException + { + File dataFile = TestData.file(this, testFilePath); + if (!dataFile.exists()) + { + return; + } + + _fs = new FileInputStream(dataFile); + } + + @Test + public void testRead() throws Dgn7fileException, IOException + { + if (_fs == null) return; + FileChannel fc = _fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + // @todo add process in here + lastComplex = null; + } + + // @todo add process in here + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex == null) + { + lastComplex = element; + } else + { + // @todo add process in here + lastComplex = element; + } + } + + if (element.getElementType().isComplexElement()) + { + if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChain = (ComplexChainElement) element; + int size = complexChain.size(); + for (Object aComplexChain : complexChain) + { + Element subElement = (Element) aComplexChain; + subElement.getType(); + } + } + + if (element instanceof ComplexShapeElement) + { + ComplexShapeElement complexShape = (ComplexShapeElement) element; + } + + if (element instanceof TextNodeElement) + { + TextNodeElement textNode = (TextNodeElement) element; + int size = textNode.size(); + for (int i = 0; i < size; i++) + { + Element subElement = (Element) textNode.get(i); + subElement.getElementType(); + } + } + } + } + count++; + } + + logger.info("ElementRecord Count=" + count); + } +} diff --git a/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/OracleTarget.java b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/OracleTarget.java new file mode 100644 index 0000000..11d8fe0 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/java/com/ximple/io/dgn7/OracleTarget.java @@ -0,0 +1,163 @@ +package com.ximple.io.dgn7; + +//~--- JDK imports ------------------------------------------------------------ + +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +import org.apache.log4j.Logger; + +import com.vividsolutions.jts.util.Assert; + +import oracle.jdbc.OracleConnection; + +/** + * OracleTarget + * User: Ulysses + * Date: 2007/6/15 + * Time: ?U?? 03:12:43 + * To change this template use File | Settings | File Templates. + */ +public class OracleTarget +{ + private static final Logger logger = Logger.getLogger(OracleTarget.class); + private static OracleTarget _instance = null; + private static final String ORACLE_URL = "jdbc:oracle:thin:@"; + private static final String _propUsrKey = "user"; + private static final String _propPassKey = "password"; + private static String _oracleHost = "192.168.11.200"; + private static String _oracleInstance = "NNTPC"; + private static String _oraclePort = "1521"; + + static + { + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + } catch (SQLException e) + { + Assert.shouldNeverReachHere(e.getMessage()); + } + } + + private OracleConnection oracleConnection = null; + private Properties properties; + + private OracleTarget() + { + properties = new Properties(); + properties.put(_propUsrKey, "SPATIALDB"); + properties.put(_propPassKey, "SPATIALDB000"); + } + + public static String getOracleHost() + { + return _oracleHost; + } + + public static void setOracleHost(String oracleHost) + { + OracleTarget._oracleHost = oracleHost; + } + + public static String getOracleInstance() + { + return _oracleInstance; + } + + public static void setOracleInstance(String oracleInstance) + { + OracleTarget._oracleInstance = oracleInstance; + } + + public static String getOraclePort() + { + return _oraclePort; + } + + public static void setOraclePort(String oraclePort) + { + OracleTarget._oraclePort = oraclePort; + } + + public static String getCurrentURL() + { + StringBuilder builder = new StringBuilder(); + + builder.append(ORACLE_URL); + builder.append(_oracleHost); + builder.append(":"); + builder.append(_oraclePort); + builder.append(":"); + builder.append(_oracleInstance); + + return builder.toString(); + } + + public String getLoginPass() + { + return (String) properties.get(_propPassKey); + } + + public void setLoginPass(String loginPass) + { + properties.put(_propPassKey, loginPass); + } + + public String getLoginUsr() + { + return (String) properties.get(_propUsrKey); + } + + public void setLoginUsr(String loginUsr) + { + properties.put(_propUsrKey, loginUsr); + } + + public static OracleTarget getInstance() + { + if (_instance == null) + { + _instance = new OracleTarget(); + } + + return _instance; + } + + public OracleConnection getOracleConnection() + { + try + { + if (oracleConnection == null) + { + oracleConnection = (OracleConnection) DriverManager.getConnection(getCurrentURL(), properties); + } + + return oracleConnection; + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + + oracleConnection = null; + + return null; + } + + public void closeConnection() + { + try + { + if (oracleConnection != null) + { + oracleConnection.close(); + oracleConnection = null; + } + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } +} + diff --git a/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/Demo.dgn b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/Demo.dgn new file mode 100644 index 0000000..d749f68 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/Demo.dgn Binary files differ diff --git a/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491-1.dgn b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491-1.dgn new file mode 100644 index 0000000..acbb8a2 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491-1.dgn Binary files differ diff --git a/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491_0888888.dgn b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491_0888888.dgn new file mode 100644 index 0000000..f29f86f --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88491_0888888.dgn Binary files differ diff --git a/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88494_0.dgn b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88494_0.dgn new file mode 100644 index 0000000..4899d19 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/HV88494_0.dgn Binary files differ diff --git a/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/testHV.dgn b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/testHV.dgn new file mode 100644 index 0000000..05fb839 --- /dev/null +++ b/xdgnjobs/ximple-dgnio/src/test/resources/com/ximple/io/dgn7/test-data/testHV.dgn Binary files differ diff --git a/xdgnjobs/ximple-jobcarrier/pom.xml b/xdgnjobs/ximple-jobcarrier/pom.xml new file mode 100644 index 0000000..ae21fcb --- /dev/null +++ b/xdgnjobs/ximple-jobcarrier/pom.xml @@ -0,0 +1,242 @@ +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + + <parent> + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-dgnjobs</artifactId> + <version>0.6.0</version> + </parent> + + + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-jobcarrier</artifactId> + <version>0.6.0</version> + <packaging>jar</packaging> + <name>ximple-jobcarrier</name> + <url>http://maven.apache.org</url> + + <properties> + <xdgnio.version>0.6.0</xdgnio.version> + </properties> + + <scm> + <connection> + scm:svn:http://www.ximple.com.tw/svn/xeofms/xspatialjob/truck/ + </connection> + <url>http://www.ximple.com.tw/svn/xeofms/xspatialjob/truck/</url> + </scm> + + <description> + Ximple Job Carrier for Quartz + </description> + + <organization> + <name>Ximple</name> + <url>http://www.ximple.com.tw</url> + </organization> + + <inceptionYear>2008</inceptionYear> + + <developers> + <developer> + <name>Kuo-Feng Kao</name> + <id>ulysseskao</id> + <email>ulysseskao@ximple.com.tw</email> + <organization>Ximple</organization> + <roles> + <role>Java Developer</role> + </roles> + </developer> + </developers> + + <contributors> + </contributors> + + <!-- =========================================================== --> + <!-- Dependencies to be inherited by all modules. --> + <!-- =========================================================== --> + <dependencies> + <dependency> + <artifactId>quartz</artifactId> + <groupId>opensymphony</groupId> + </dependency> + + <dependency> + <groupId>javax.transaction</groupId> + <artifactId>jta</artifactId> + <version>1.0.1B</version> + </dependency> + + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-shapefile</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-sample-data</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-data</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-jdbc</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-postgis</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-oracle-spatial</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-mysql</artifactId> + </dependency> + + <!-- because main and sample-data depend on referencing we need a tie breaker --> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-referencing</artifactId> + </dependency> + + <!-- We need this to make the referencing module useful --> + <dependency> + <artifactId>gt2-epsg-hsql</artifactId> + <groupId>org.geotools</groupId> + <scope>test</scope> + </dependency> + + <dependency> + <artifactId>jdom</artifactId> + <groupId>jdom</groupId> + </dependency> + + <dependency> + <artifactId>velocity</artifactId> + <groupId>velocity</groupId> + </dependency> + + <!-- ORACLE --> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc5</artifactId> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc5</artifactId> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdoapi</artifactId> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdotype</artifactId> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdoutl</artifactId> + </dependency> + + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + <dependency> + <groupId>org.postgis</groupId> + <artifactId>postgis-driver</artifactId> + </dependency> + + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + + <!-- Ximple Library --> + <dependency> + <artifactId>ximple-dgnio</artifactId> + <groupId>com.ximple.eofms</groupId> + <version>${xdgnio.version}</version> + </dependency> + <dependency> + <artifactId>ximple-spatialjob</artifactId> + <groupId>com.ximple.eofms</groupId> + <version>${xdgnio.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <!-- ======================================================= --> + <!-- JAR packaging. --> + <!-- ======================================================= --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <mainClass>com.ximple.eofms.XQuartzJobCarrier</mainClass> + <addClasspath>true</addClasspath> + </manifest> + </archive> + </configuration> + </plugin> + <!-- ======================================================= --> + <!-- exec jar. --> + <!-- ======================================================= --> + <plugin> + <!-- + Use maven from the command line: + mvn exec:java -Dexec.mainClass="com.ximple.eofms.XQuartzJobCarrier" + --> + <artifactId>exec-maven-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <!-- + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + --> + <configuration> + <mainClass>com.ximple.eofms.XQuartzJobCarrier</mainClass> + </configuration> + <!-- + <dependencies> + <dependency> + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-jobcarrier</artifactId> + <version>0.0.1</version> + <type>jar</type> + </dependency> + </dependencies> + --> + </plugin> + <plugin> + <groupId>com.ximple.eofms.maven</groupId> + <artifactId>ximple-jar-collector</artifactId> + <version>${project.version}</version> + <executions> + <execution> + <goals> + <goal>collect</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + <resources> + </resources> + </build> + +</project> diff --git a/xdgnjobs/ximple-jobcarrier/src/main/java/com/ximple/eofms/XQuartzJobCarrier.java b/xdgnjobs/ximple-jobcarrier/src/main/java/com/ximple/eofms/XQuartzJobCarrier.java new file mode 100644 index 0000000..f2eef84 --- /dev/null +++ b/xdgnjobs/ximple-jobcarrier/src/main/java/com/ximple/eofms/XQuartzJobCarrier.java @@ -0,0 +1,95 @@ +package com.ximple.eofms; + +import java.util.Date; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.quartz.JobDetail; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.Trigger; +import org.quartz.TriggerUtils; +import org.quartz.impl.StdSchedulerFactory; + +import com.ximple.eofms.jobs.OracleConvertDgn2ShpJob; + +/** + * Hello world! + */ +public class XQuartzJobCarrier +{ + static Log logger = LogFactory.getLog(XQuartzJobCarrier.class); + + + public static void main(String[] args) + { + XQuartzJobCarrier instance = new XQuartzJobCarrier(); + instance.startScheduler(); + } + + public void startScheduler() + { + Scheduler scheduler = null; + boolean shutdown = false; + + try + { + // Get a Scheduler instance from the Factory + scheduler = StdSchedulerFactory.getDefaultScheduler(); + + // Start the scheduler + scheduler.start(); + logger.info("Scheduler started at " + new Date()); + + } catch (SchedulerException ex) + { + // deal with any exceptions + logger.error(ex); + shutdown = true; + } catch (Throwable throwable) + { + logger.error(throwable.getMessage(), throwable); + shutdown = true; + } + if (shutdown) + { + try + { + scheduler.shutdown(); + } catch (SchedulerException e) + { + logger.error(e.getMessage(), e); + } + } + } + + /* + * return an instance of the Scheduler from the factory + */ + public Scheduler createScheduler() throws SchedulerException + { + return StdSchedulerFactory.getDefaultScheduler(); + } + + // Create and Schedule a ScanDirectoryJob with the Scheduler + private void scheduleJob(Scheduler scheduler) throws SchedulerException + { + + // Create a JobDetail for the Job + JobDetail jobDetail = new JobDetail("ScanDirectory", Scheduler.DEFAULT_GROUP, + OracleConvertDgn2ShpJob.class); + + // Configure the directory to scan + jobDetail.getJobDataMap().put("SCAN_DIR", "c:\\quartz-book\\input"); + + // Create a trigger that fires every 10 seconds, forever + Trigger trigger = TriggerUtils.makeSecondlyTrigger(10); + trigger.setName("scanTrigger"); + // Start the trigger firing from now + trigger.setStartTime(new Date()); + + // Associate the trigger with the job in the scheduler + scheduler.scheduleJob(jobDetail, trigger); + } + +} diff --git a/xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties b/xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties new file mode 100644 index 0000000..2691982 --- /dev/null +++ b/xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties @@ -0,0 +1,28 @@ +# Create stdout appender +log4j.rootLogger=error, logfile, stdout + +# Configure the stdout appender to go to the Console +log4j.appender.stdout=org.apache.log4j.ConsoleAppender + +# Configure stdout appender to use the PatternLayout +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout + +# Pattern output the caller's filename and line # +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n +#log4j.appender.stdout.encoding=UTF-8 + +log4j.appender.logfile=org.apache.log4j.FileAppender +log4j.appender.logfile.file=xjobcarrier.log +log4j.appender.logfile.layout=org.apache.log4j.PatternLayout +log4j.appender.logfile.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n +#log4j.appender.logfile.encoding=UTF-8 + +log4j.appender.remoteout=com.holub.log4j.RemoteAppender +log4j.appender.remoteout.Port=8011 +log4j.appender.remoteout.layout=org.apache.log4j.PatternLayout +log4j.appender.remoteout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n +#log4j.appender.remoteout.encoding=UTF-8 + +# Print messages of level INFO or above for examples +log4j.logger.org.cavaness.quartzbook=INFO +log4j.logger.com.ximple.eofms=INFO \ No newline at end of file diff --git a/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz.properties b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz.properties new file mode 100644 index 0000000..be35e19 --- /dev/null +++ b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz.properties @@ -0,0 +1,28 @@ +#=============================================================== +#Configure Main Scheduler Properties +#=============================================================== +org.quartz.scheduler.instanceName = QuartzScheduler +org.quartz.scheduler.instanceId = AUTO + +#=============================================================== +#Configure ThreadPool +#=============================================================== +org.quartz.threadPool.threadCount = 5 +org.quartz.threadPool.threadPriority = 5 +org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool + +#=============================================================== +#Configure JobStore +#=============================================================== +org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore + +#=============================================================== +#Configure Plugins +#=============================================================== +org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin + +org.quartz.plugin.jobInitializer.fileName = quartz_jobs.xml + +org.quartz.plugin.jobInitializer.overWriteExistingJobs = true +org.quartz.plugin.jobInitializer.failOnFileNotFound = true +org.quartz.plugin.jobInitializer.validating=false diff --git a/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml new file mode 100644 index 0000000..1bd55fc --- /dev/null +++ b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml @@ -0,0 +1,131 @@ +<?xml version='1.0' encoding='utf-8'?> + +<quartz xmlns="http://www.opensymphony.com/quartz/JobSchedulingData" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.opensymphony.com/quartz/JobSchedulingData + http://www.opensymphony.com/quartz/xml/job_scheduling_data_1_5.xsd" + version="1.5"> + + <job> + <job-detail> + <name>ConvertDgn2PostGisIntoPostgre</name> + <group>DEFAULT</group> + <description>A job that convert dgn to shapefiles</description> + <job-class>com.ximple.eofms.jobs.OracleConvertDgn2PostGISJob</job-class> + <volatility>false</volatility> + <durability>false</durability> + <recover>false</recover> + <job-data-map allows-transient-data="true"> + <entry> + <key>JOBDATA_DIR</key> + <value>g:\temp\data</value> + </entry> + <!-- + <entry> + <key>ELMSFILTER_CONF</key> + <value></value> + </entry> + --> + <entry> + <key>PGHOST</key> + <value>192.168.11.200</value> + </entry> + <entry> + <key>PGDDATBASE</key> + <value>tctpc</value> + </entry> + <entry> + <key>PGPORT</key> + <value>5432</value> + </entry> + <entry> + <key>PGSCHEMA</key> + <value>public</value> + </entry> + <entry> + <key>PGUSER</key> + <value>spatialdb</value> + </entry> + <entry> + <key>PGPASS</key> + <value>spatialdb000</value> + </entry> + <entry> + <key>ORAHOST</key> + <value>192.168.11.200</value> + </entry> + <entry> + <key>ORAINST</key> + <value>tctpc</value> + </entry> + <entry> + <key>ORAPORT</key> + <value>1521</value> + </entry> + <entry> + <key>ORAUSER</key> + <value>spatialdb</value> + </entry> + <entry> + <key>ORAPASS</key> + <value>spatialdb000</value> + </entry> + <entry> + <key>ORGSCHEMA</key> + <value>SPATIALDB, CMMS_SPATIALDB</value> + </entry> + <entry> + <key>CONVERTDB</key> + <value>true</value> + </entry> + <entry> + <key>CONVERTFILE</key> + <value>true</value> + </entry> + <entry> + <key>CONVERTELEMIN</key> + <value>false</value> + </entry> + <entry> + <key>CREATEDUMMY</key> + <value>false</value> + </entry> + <entry> + <key>ELEMLOG</key> + <value>true</value> + </entry> + <entry> + <key>USEWKB</key> + <value>true</value> + </entry> + <entry> + <key>TESTMODE</key> + <value>false</value> + </entry> + <entry> + <key>TESTCOUNT</key> + <value>2</value> + </entry> + <entry> + <key>COPYCONNECTIVITYMODE</key> + <value>true</value> + </entry> + </job-data-map> + </job-detail> + + <trigger> + <simple> + <name>convertTrigger</name> + <group>DEFAULT</group> + <job-name>ConvertDgn2PostGisIntoPostgre</job-name> + <job-group>DEFAULT</job-group> + <start-time>2008-03-01T18:10:00</start-time> + <!-- repeat indefinitely every 10 seconds --> + <repeat-count>0</repeat-count> + <repeat-interval>500</repeat-interval> + <!-- <repeat-interval>72000000</repeat-interval> --> + </simple> + </trigger> + + </job> +</quartz> diff --git a/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs_shapefiles.xml b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs_shapefiles.xml new file mode 100644 index 0000000..f03ace3 --- /dev/null +++ b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs_shapefiles.xml @@ -0,0 +1,99 @@ +<?xml version='1.0' encoding='utf-8'?> + +<quartz xmlns="http://www.opensymphony.com/quartz/JobSchedulingData" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.opensymphony.com/quartz/JobSchedulingData + http://www.opensymphony.com/quartz/xml/job_scheduling_data_1_5.xsd" + version="1.5"> + + <job> + <job-detail> + <name>ConvertDgn2ShpIntoDirectory</name> + <group>DEFAULT</group> + <description>A job that convert dgn to shapefiles</description> + <job-class>com.ximple.eofms.jobs.OracleConvertDgn2ShpJob</job-class> + <volatility>false</volatility> + <durability>false</durability> + <recover>false</recover> + <job-data-map allows-transient-data="true"> + <entry> + <key>SHPDATA_DIR</key> + <value>g:\temp\data</value> + </entry> + <!-- + <entry> + <key>ELMSFILTER_CONF</key> + <value></value> + </entry> + --> + <entry> + <key>ORAHOST</key> + <value>192.168.11.200</value> + </entry> + <entry> + <key>ORAINST</key> + <value>nntpc</value> + </entry> + <entry> + <key>ORAPORT</key> + <value>1521</value> + </entry> + <entry> + <key>ORAUSER</key> + <value>spatialdb</value> + </entry> + <entry> + <key>ORAPASS</key> + <value>spatialdb000</value> + </entry> + <entry> + <key>ORGSCHEMA</key> + <value>SPATIALDB, CMMS_SPATIALDB</value> + </entry> + <entry> + <key>CONVERTDB</key> + <value>false</value> + </entry> + <entry> + <key>CONVERTFILE</key> + <value>false</value> + </entry> + <entry> + <key>CONVERTELEMIN</key> + <value>false</value> + </entry> + <entry> + <key>CREATEDUMMY</key> + <value>true</value> + </entry> + <entry> + <key>ELEMLOG</key> + <value>true</value> + </entry> + <entry> + <key>TESTMODE</key> + <value>FALSE</value> + </entry> + <entry> + <key>TESTCOUNT</key> + <value>2</value> + </entry> + </job-data-map> + </job-detail> + + <trigger> + <simple> + <name>convertTrigger</name> + <group>DEFAULT</group> + <job-name>ConvertDgn2ShpIntoDirectory</job-name> + <job-group>DEFAULT</job-group> + <start-time>2008-03-01T18:10:00</start-time> + <!-- repeat indefinitely every 10 seconds --> + <repeat-count>0</repeat-count> + <repeat-interval>500</repeat-interval> + <!-- <repeat-interval>72000000</repeat-interval> --> + </simple> + </trigger> + + </job> +</quartz> diff --git a/xdgnjobs/ximple-jobcarrier/src/test/java/com/ximple/eofms/XQuartzJobCarrierTest.java b/xdgnjobs/ximple-jobcarrier/src/test/java/com/ximple/eofms/XQuartzJobCarrierTest.java new file mode 100644 index 0000000..d907cc1 --- /dev/null +++ b/xdgnjobs/ximple-jobcarrier/src/test/java/com/ximple/eofms/XQuartzJobCarrierTest.java @@ -0,0 +1,19 @@ +package com.ximple.eofms; + +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * Unit test for simple App. + */ +public class XQuartzJobCarrierTest +{ + /** + * Rigourous Test :-) + */ + @Test + public void testApp() + { + Assert.assertTrue(true); + } +} diff --git a/xdgnjobs/ximple-spatialjob/pom.xml b/xdgnjobs/ximple-spatialjob/pom.xml new file mode 100644 index 0000000..996a354 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/pom.xml @@ -0,0 +1,158 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-dgnjobs</artifactId> + <version>0.6.0</version> + </parent> + + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-spatialjob</artifactId> + <version>0.6.0</version> + <packaging>jar</packaging> + <name>ximple-spatialjob</name> + <url>http://www.ximple.com.tw</url> + + <properties> + <xdgnio.version>0.6.0</xdgnio.version> + </properties> + + <description> + Ximple Spatial Data Job for Quartz + </description> + + <organization> + <name>Ximple</name> + <url>http://www.ximple.com.tw</url> + </organization> + + <inceptionYear>2008</inceptionYear> + + <developers> + <developer> + <name>Kuo-Feng Kao</name> + <id>ulysseskao</id> + <email>ulysseskao@ximple.com.tw</email> + <organization>Ximple</organization> + <roles> + <role>Java Developer</role> + </roles> + </developer> + </developers> + + <contributors> + </contributors> + + <!-- =========================================================== --> + <!-- Dependencies to be inherited by all modules. --> + <!-- =========================================================== --> + <dependencies> + <dependency> + <artifactId>quartz</artifactId> + <groupId>opensymphony</groupId> + </dependency> + + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-shapefile</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-sample-data</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-data</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-jdbc</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-postgis</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-oracle-spatial</artifactId> + </dependency> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-mysql</artifactId> + </dependency> + + <!-- because main and sample-data depend on referencing we need a tie breaker --> + <dependency> + <groupId>org.geotools</groupId> + <artifactId>gt2-referencing</artifactId> + </dependency> + + <!-- We need this to make the referencing module useful --> + <dependency> + <artifactId>gt2-epsg-hsql</artifactId> + <groupId>org.geotools</groupId> + <scope>test</scope> + </dependency> + + <dependency> + <artifactId>jdom</artifactId> + <groupId>jdom</groupId> + </dependency> + + <dependency> + <artifactId>velocity</artifactId> + <groupId>velocity</groupId> + </dependency> + + <!-- ORACLE --> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc5</artifactId> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdoapi</artifactId> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdotype</artifactId> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>sdoutl</artifactId> + </dependency> + + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + <dependency> + <groupId>org.postgis</groupId> + <artifactId>postgis-driver</artifactId> + </dependency> + + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + + <!-- Ximple Library --> + <dependency> + <groupId>com.ximple.eofms</groupId> + <artifactId>ximple-dgnio</artifactId> + <version>${xdgnio.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + </plugins> + <resources> + </resources> + </build> +</project> diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureClassification.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureClassification.java new file mode 100644 index 0000000..e4024ec --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureClassification.java @@ -0,0 +1,28 @@ +package com.ximple.eofms.collector; + +import java.util.TreeMap; + +public class FeatureClassification +{ + private TreeMap<String, FeatureTypeCollector> clasificationRules; + + public FeatureClassification() + { + clasificationRules = new TreeMap<String, FeatureTypeCollector>(); + } + + public void addCollector(FeatureTypeCollector collector) + { + collector.getName(); + } + + public boolean containsKey(String typeName) + { + return clasificationRules.containsKey(typeName); + } + + public TreeMap<String, FeatureTypeCollector> getClasificationRules() + { + return clasificationRules; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureTypeCollector.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureTypeCollector.java new file mode 100644 index 0000000..7309b3f --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/collector/FeatureTypeCollector.java @@ -0,0 +1,48 @@ +package com.ximple.eofms.collector; + +import java.util.ArrayList; + +import com.ximple.eofms.util.StringUtils; + +public class FeatureTypeCollector +{ + private String name; + private String description; + private String featuretypeList; + private ArrayList<String> featureTypeNameList; + + public FeatureTypeCollector() + { + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public String getFeaturetypeList() + { + return featuretypeList; + } + + public void setFeaturetypeList(String featuretypeList) + { + featureTypeNameList = StringUtils.split(featuretypeList, ","); + this.featuretypeList = featuretypeList; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractDispatchableFilter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractDispatchableFilter.java new file mode 100644 index 0000000..d6e91b1 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractDispatchableFilter.java @@ -0,0 +1,101 @@ +package com.ximple.eofms.filter; + +import java.util.LinkedList; + +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.ximple.io.dgn7.Element; + +public abstract class AbstractDispatchableFilter implements ElementDispatchableFilter +{ + private String name; + private String description; + private LinkedList<ElementTypeCriterion> typeIdCriterions; + private LinkedList<ElementLevelCriterion> levelCriterions; + + protected Log logger = LogFactory.getLog(AbstractFLinkageDispatchableFilter.class); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public AbstractDispatchableFilter() + { + typeIdCriterions = new LinkedList<ElementTypeCriterion>(); + levelCriterions = new LinkedList<ElementLevelCriterion>(); + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public void addCriterion(ElementTypeCriterion criterion) + { + typeIdCriterions.add(criterion); + } + + public void addLevelCriterion(ElementLevelCriterion criterion) + { + levelCriterions.add(criterion); + } + + protected int compareType(Element element) + { + for (ElementTypeCriterion criterion : typeIdCriterions) + { + if (criterion.compareTo(element) == 0) + return 0; + } + return -1; + } + + protected int compareLevel(Element element) + { + for (ElementLevelCriterion criterion : levelCriterions) + { + if (criterion.compareTo(element) == 0) + return 0; + } + return -1; + } + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractFLinkageDispatchableFilter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractFLinkageDispatchableFilter.java new file mode 100644 index 0000000..48be949 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/AbstractFLinkageDispatchableFilter.java @@ -0,0 +1,26 @@ +package com.ximple.eofms.filter; + +import java.util.List; + +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public abstract class AbstractFLinkageDispatchableFilter extends AbstractDispatchableFilter +{ + public static FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateArcLineStringStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateArcLineStringStrategy.java new file mode 100644 index 0000000..54bc021 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateArcLineStringStrategy.java @@ -0,0 +1,116 @@ +package com.ximple.eofms.filter; + +import java.util.List; +import java.util.TreeMap; + +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Geometry; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateArcLineStringStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateLineStringStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateArcLineStringStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createArcFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof ArcElement) + { + ArcElement lineStringElement = (ArcElement) element; + convertDecorator.setConverter(lineStringElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineStringElement.getLevelIndex(), + colorTable.getColorCode(lineStringElement.getColorIndex()), + (short) lineStringElement.getWeight(), + (short) lineStringElement.getLineStyle() + }); + } + return feature; + } + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateComplexChainStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateComplexChainStrategy.java new file mode 100644 index 0000000..a372f9b --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateComplexChainStrategy.java @@ -0,0 +1,188 @@ +package com.ximple.eofms.filter; + +import java.util.List; +import java.util.TreeMap; +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateComplexChainStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateLineStringStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateComplexChainStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createMultiLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof LineStringElement) + { + LineStringElement lineStringElement = (LineStringElement) element; + convertDecorator.setConverter(lineStringElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj instanceof LineString) + { + gobj = geometryFactory.createMultiLineString(new LineString[] {(LineString) gobj}); + } + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineStringElement.getLevelIndex(), + colorTable.getColorCode(lineStringElement.getColorIndex()), + (short) lineStringElement.getWeight(), + (short) lineStringElement.getLineStyle() + }); + } else if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChain = (ComplexChainElement) element; + convertDecorator.setConverter(complexChain); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj instanceof LineString) + { + gobj = geometryFactory.createMultiLineString(new LineString[] {(LineString) gobj}); + } + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) complexChain.getLevelIndex(), + colorTable.getColorCode(complexChain.getColorIndex()), + (short) complexChain.getWeight(), + (short) complexChain.getLineStyle() + }); + } else if (element instanceof LineElement) + { + LineElement lineElement = (LineElement) element; + convertDecorator.setConverter(lineElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj instanceof LineString) + { + gobj = geometryFactory.createMultiLineString(new LineString[] {(LineString) gobj}); + } + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineElement.getLevelIndex(), + colorTable.getColorCode(lineElement.getColorIndex()), + (short) lineElement.getWeight(), + (short) lineElement.getLineStyle() + }); + return feature; + } else if (element instanceof ArcElement) + { + ArcElement lineStringElement = (ArcElement) element; + convertDecorator.setConverter(lineStringElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj instanceof LineString) + { + gobj = geometryFactory.createMultiLineString(new LineString[] {(LineString) gobj}); + } + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineStringElement.getLevelIndex(), + colorTable.getColorCode(lineStringElement.getColorIndex()), + (short) lineStringElement.getWeight(), + (short) lineStringElement.getLineStyle() + }); + } + + return feature; + } + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateEllipseShapeStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateEllipseShapeStrategy.java new file mode 100644 index 0000000..9d0c215 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateEllipseShapeStrategy.java @@ -0,0 +1,117 @@ +package com.ximple.eofms.filter; + +import java.util.List; +import java.util.TreeMap; + +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Geometry; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.EllipseElement; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateEllipseShapeStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateShapeStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateEllipseShapeStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createEllipseFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof EllipseElement) + { + EllipseElement shapeElement = (EllipseElement) element; + convertDecorator.setConverter(shapeElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) shapeElement.getLevelIndex(), + colorTable.getColorCode(shapeElement.getColorIndex()), + (short) shapeElement.getWeight(), + (short) shapeElement.getLineStyle() + }); + } + return feature; + } + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} + + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeEventListener.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeEventListener.java new file mode 100644 index 0000000..4a81200 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeEventListener.java @@ -0,0 +1,8 @@ +package com.ximple.eofms.filter; + +import java.util.EventListener; + +public interface CreateFeatureTypeEventListener extends EventListener +{ + public void createFeatureTypeOccurred(FeatureTypeEvent evt); +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeStrategy.java new file mode 100644 index 0000000..83d0074 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateFeatureTypeStrategy.java @@ -0,0 +1,17 @@ +package com.ximple.eofms.filter; + +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.ximple.io.dgn7.Element; + +public interface CreateFeatureTypeStrategy +{ + public FeatureType createFeatureElement(String featureName) throws SchemaException; + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException; + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener); + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener); +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java new file mode 100644 index 0000000..41ab334 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java @@ -0,0 +1,189 @@ +package com.ximple.eofms.filter; + +import java.util.List; +import java.util.TreeMap; + +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.CoordinateArrays; +import com.vividsolutions.jts.geom.CoordinateList; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateLineStringStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateLineStringStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateLineStringStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof LineStringElement) + { + LineStringElement lineStringElement = (LineStringElement) element; + convertDecorator.setConverter(lineStringElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + convertDecorator.toGeometry(geometryFactory), + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineStringElement.getLevelIndex(), + colorTable.getColorCode(lineStringElement.getColorIndex()), + (short) lineStringElement.getWeight(), + (short) lineStringElement.getLineStyle() + }); + } else if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChain = (ComplexChainElement) element; + convertDecorator.setConverter(complexChain); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if ((gobj != null) && (gobj instanceof MultiLineString)) + { + MultiLineString mline = (MultiLineString) gobj; + CoordinateList coordinateList = new CoordinateList(); + if (mline.getNumGeometries() == 1) + { + for (int i = 0; i < mline.getNumGeometries(); i++) + { + coordinateList.add(mline.getGeometryN(i).getCoordinates(), true); + } + } + + gobj = geometryFactory.createLineString(coordinateList.toCoordinateArray()); + } + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) complexChain.getLevelIndex(), + colorTable.getColorCode(complexChain.getColorIndex()), + (short) complexChain.getWeight(), + (short) complexChain.getLineStyle() + }); + } else if (element instanceof LineElement) + { + LineElement lineElement = (LineElement) element; + convertDecorator.setConverter(lineElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineElement.getLevelIndex(), + colorTable.getColorCode(lineElement.getColorIndex()), + (short) lineElement.getWeight(), + (short) lineElement.getLineStyle() + }); + return feature; + } else if (element instanceof ArcElement) + { + ArcElement lineStringElement = (ArcElement) element; + convertDecorator.setConverter(lineStringElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineStringElement.getLevelIndex(), + colorTable.getColorCode(lineStringElement.getColorIndex()), + (short) lineStringElement.getWeight(), + (short) lineStringElement.getLineStyle() + }); + } + + return feature; + } + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java new file mode 100644 index 0000000..e6a2761 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java @@ -0,0 +1,201 @@ +package com.ximple.eofms.filter; + +import java.util.List; +import java.util.TreeMap; + +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.CoordinateList; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.eofms.util.TWDDatumConverter; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateLineTextStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateLineTextStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateLineTextStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof LineStringElement) + { + LineStringElement lineStringElement = (LineStringElement) element; + convertDecorator.setConverter(lineStringElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineStringElement.getLevelIndex(), + colorTable.getColorCode(lineStringElement.getColorIndex()), + (short) lineStringElement.getWeight(), + (short) lineStringElement.getLineStyle() + }); + } else if (element instanceof TextElement) + { + TextElement txtElement = (TextElement) element; + Coordinate ptOrigin = txtElement.getUserOrigin(); + Coordinate ptEnd = new Coordinate(); + ptEnd.x = ptOrigin.x; + ptEnd.y = ptOrigin.y + txtElement.getTextHeight(); + Coordinate[] vect = new Coordinate[2]; + vect[0] = TWDDatumConverter.fromTM2ToTWD97(ptOrigin); + vect[1] = TWDDatumConverter.fromTM2ToTWD97(ptEnd); + + LineString line = geometryFactory.createLineString(vect); + // convertDecorator.setConverter(txtElement); + // Geometry geom = convertDecorator.toGeometry(geometryFactory); + + txtElement.getRotationAngle(); + + feature = featureType.create(new Object[]{ + line, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) txtElement.getLevelIndex(), + colorTable.getColorCode(txtElement.getColorIndex()), + (short) txtElement.getWeight(), + (short) txtElement.getLineStyle() + }); + } else if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChain = (ComplexChainElement) element; + convertDecorator.setConverter(complexChain); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if ((gobj != null) && (gobj instanceof MultiLineString)) + { + MultiLineString mline = (MultiLineString) gobj; + CoordinateList coordinateList = new CoordinateList(); + if (mline.getNumGeometries() == 1) + { + for (int i = 0; i < mline.getNumGeometries(); i++) + { + coordinateList.add(mline.getGeometryN(i).getCoordinates(), true); + } + } + + gobj = geometryFactory.createLineString(coordinateList.toCoordinateArray()); + } + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) complexChain.getLevelIndex(), + colorTable.getColorCode(complexChain.getColorIndex()), + (short) complexChain.getWeight(), + (short) complexChain.getLineStyle() + }); + } else if (element instanceof LineElement) + { + LineElement lineElement = (LineElement) element; + convertDecorator.setConverter(lineElement); + feature = featureType.create(new Object[]{ + convertDecorator.toGeometry(geometryFactory), + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) lineElement.getLevelIndex(), + colorTable.getColorCode(lineElement.getColorIndex()), + (short) lineElement.getWeight(), + (short) lineElement.getLineStyle() + }); + } + + return feature; + } + + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateShapeStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateShapeStrategy.java new file mode 100644 index 0000000..d42c1c8 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateShapeStrategy.java @@ -0,0 +1,135 @@ +package com.ximple.eofms.filter; + +import java.util.List; +import java.util.TreeMap; + +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Geometry; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.ComplexShapeElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.ShapeElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateShapeStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateShapeStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateShapeStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createPolygonFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof ShapeElement) + { + ShapeElement shapeElement = (ShapeElement) element; + convertDecorator.setConverter(shapeElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) shapeElement.getLevelIndex(), + colorTable.getColorCode(shapeElement.getColorIndex()), + (short) shapeElement.getWeight(), + (short) shapeElement.getLineStyle() + }); + } else if (element instanceof ComplexShapeElement) + { + ComplexShapeElement complexShape = (ComplexShapeElement) element; + convertDecorator.setConverter(complexShape); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) complexShape.getLevelIndex(), + colorTable.getColorCode(complexShape.getColorIndex()), + (short) complexShape.getWeight(), + (short) complexShape.getLineStyle() + }); + } + return feature; + } + + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateSymbolStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateSymbolStrategy.java new file mode 100644 index 0000000..2b3fd93 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateSymbolStrategy.java @@ -0,0 +1,143 @@ +package com.ximple.eofms.filter; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.TreeMap; + +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Geometry; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateSymbolStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateSymbolStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateSymbolStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createSymbolFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof TextElement) + { + TextElement txtElement = (TextElement) element; + double angle = txtElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + if (txtElement.getText().length() == 0) + { + logger.info("CreateSymbolStrategy cannot conver " + element.toString() + + "to Feature - getText() is empty."); + return null; + } + StringBuilder sb = new StringBuilder(); + sb.append("OCT"); + char id = txtElement.getText().toCharArray()[0]; + sb.append(Integer.toOctalString((int) id)); + sb.append("-"); + sb.append(txtElement.getFontIndex()); + + convertDecorator.setConverter(txtElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) txtElement.getLevelIndex(), + colorTable.getColorCode(txtElement.getColorIndex()), + (short) txtElement.getWeight(), + (short) txtElement.getLineStyle(), + (short) txtElement.getJustification(), + (float) txtElement.getTextHeight(), + (float) txtElement.getTextWidth(), + (float) angle, + sb.toString() + }); + } else + { + logger.info("CreateSymbolStrategy cannot conver " + element.toString() + "to Feature"); + } + return feature; + } + + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateTextStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateTextStrategy.java new file mode 100644 index 0000000..cca31c2 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateTextStrategy.java @@ -0,0 +1,161 @@ +package com.ximple.eofms.filter; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.TreeMap; +import javax.swing.event.EventListenerList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Geometry; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.TextNodeElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class CreateTextStrategy implements CreateFeatureTypeStrategy +{ + static final Log logger = LogFactory.getLog(CreateTextStrategy.class); + GeometryFactory geometryFactory = new GeometryFactory(); + TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public CreateTextStrategy() + { + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createPointFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + FrammeAttributeData fLinkage = getFeatureLinkage(element); + Feature feature = null; + if (fLinkage == null) return null; + if (element instanceof TextElement) + { + TextElement txtElement = (TextElement) element; + double angle = txtElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + String content = txtElement.getText(); + content = content.replace('\u0000', ' '); + convertDecorator.setConverter(txtElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) txtElement.getLevelIndex(), + colorTable.getColorCode(txtElement.getColorIndex()), + (short) txtElement.getWeight(), + (short) txtElement.getLineStyle(), + (short) txtElement.getJustification(), + (float) txtElement.getTextHeight(), + (float) txtElement.getTextWidth(), + (float) angle, + content + }); + } else if (element instanceof TextNodeElement) + { + TextNodeElement nodeElement = (TextNodeElement) element; + String[] texts = nodeElement.getTextArray(); + StringBuffer sb = new StringBuffer(); + for (String text : texts) + { + if (sb.length() != 0) + sb.append("\n"); + String content = text.replace('\u0000', ' '); + sb.append(content); + } + + double angle = nodeElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + convertDecorator.setConverter(nodeElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + fLinkage.getFsc(), + (long) fLinkage.getUfid(), + (short) fLinkage.getComponentID(), + (short) 0, + (short) nodeElement.getLevelIndex(), + colorTable.getColorCode(nodeElement.getColorIndex()), + (short) nodeElement.getWeight(), + (short) nodeElement.getLineStyle(), + (short) nodeElement.getJustification(), + (float) nodeElement.getTextNodeHeight(), + (float) nodeElement.getTextNodeLength(), + (float) angle, + sb.toString() + }); + } + return feature; + } + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatchableFilter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatchableFilter.java new file mode 100644 index 0000000..2eb54be --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatchableFilter.java @@ -0,0 +1,18 @@ +package com.ximple.eofms.filter; + +import org.geotools.feature.Feature; + +import com.ximple.io.dgn7.Element; + +public interface ElementDispatchableFilter +{ + public boolean isDispatchable(Element element); + + public Feature execute(Element element); + + void setUseLongName(boolean useLongName); + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener); + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener); +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatcher.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatcher.java new file mode 100644 index 0000000..a64d23e --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementDispatcher.java @@ -0,0 +1,91 @@ +package com.ximple.eofms.filter; + +import java.util.LinkedList; + +import javax.swing.event.EventListenerList; + +import org.geotools.feature.Feature; + +import com.ximple.io.dgn7.Element; + +public class ElementDispatcher implements CreateFeatureTypeEventListener +{ + private LinkedList<ElementDispatchableFilter> rules; + private boolean useLongName = false; + + // Create the listener list + protected EventListenerList listenerList = new EventListenerList(); + + public ElementDispatcher() + { + rules = new LinkedList<ElementDispatchableFilter>(); + } + + public LinkedList<ElementDispatchableFilter> getRules() + { + return rules; + } + + public void addRule(ElementDispatchableFilter rule) + { + rule.setUseLongName(useLongName); + rule.addCreateFeatureTypeEventListener(this); + rules.add(rule); + } + + public boolean isUseLongName() + { + return useLongName; + } + + public void setUseLongName(boolean useLongName) + { + if (this.useLongName != useLongName) + { + this.useLongName = useLongName; + for (ElementDispatchableFilter filter : rules) + { + filter.setUseLongName(useLongName); + } + } + } + + public Feature execute(Element element) + { + for (ElementDispatchableFilter rule : rules) + { + if (rule.isDispatchable(element)) + { + return rule.execute(element); + } + } + return null; + } + + public void addCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.add(CreateFeatureTypeEventListener.class, listener); + } + + public void removeCreateFeatureTypeEventListener(CreateFeatureTypeEventListener listener) + { + listenerList.remove(CreateFeatureTypeEventListener.class, listener); + } + + protected void fireFeatureTypeEvent(FeatureTypeEvent evt) + { + Object[] listeners = listenerList.getListenerList(); + for (int i = 0; i < listeners.length; i += 2) + { + if (listeners[i] == CreateFeatureTypeEventListener.class) + { + ((CreateFeatureTypeEventListener) listeners[i + 1]).createFeatureTypeOccurred(evt); + } + } + } + + public void createFeatureTypeOccurred(FeatureTypeEvent evt) + { + fireFeatureTypeEvent(evt); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementLevelCriterion.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementLevelCriterion.java new file mode 100644 index 0000000..679c157 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementLevelCriterion.java @@ -0,0 +1,48 @@ +package com.ximple.eofms.filter; + +import java.util.ArrayList; + +import com.ximple.io.dgn7.Element; + +public class ElementLevelCriterion implements Comparable +{ + private int elementLevel; + private ArrayList<Integer> elementLevelArray; + + public ElementLevelCriterion() + { + elementLevelArray = new ArrayList<Integer>(); + } + + public int compareTo(Object o) + { + if (o instanceof Element) + { + Element elm = (Element) o; + + for (Integer elevel : getElementLevelArray()) + { + if (elm.getElementType().id == elevel.intValue()) + return 0; + } + + } + return -1; + } + + public int getElementLevel() + { + return elementLevel; + } + + public ArrayList<Integer> getElementLevelArray() + { + return elementLevelArray; + } + + public void setElementLevel(int iLevel) + { + this.elementLevel = iLevel; + this.elementLevelArray.add(iLevel); + } +} \ No newline at end of file diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementTypeCriterion.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementTypeCriterion.java new file mode 100644 index 0000000..7d79918 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/ElementTypeCriterion.java @@ -0,0 +1,48 @@ +package com.ximple.eofms.filter; + +import java.util.ArrayList; + +import com.ximple.io.dgn7.Element; + +public class ElementTypeCriterion implements Comparable +{ + private int elementType; + private ArrayList<Integer> elementTypeArray; + + public ElementTypeCriterion() + { + elementTypeArray = new ArrayList<Integer>(); + } + + public int compareTo(Object o) + { + if (o instanceof Element) + { + Element elm = (Element) o; + + for (Integer etype : getElementTypeArray()) + { + if (elm.getElementType().id == etype.intValue()) + return 0; + } + + } + return -1; + } + + public int getElementType() + { + return elementType; + } + + public ArrayList<Integer> getElementTypeArray() + { + return elementTypeArray; + } + + public void setElementType(int itype) + { + this.elementType = itype; + this.elementTypeArray.add(itype); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/FeatureTypeEvent.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/FeatureTypeEvent.java new file mode 100644 index 0000000..c821382 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/FeatureTypeEvent.java @@ -0,0 +1,28 @@ +package com.ximple.eofms.filter; + +import java.util.EventObject; + +import org.geotools.feature.FeatureType; + +public class FeatureTypeEvent extends EventObject +{ + private FeatureType featureType; + + /** + * Constructs a prototypical Event. + * + * @param source The object on which the Event initially occurred. + * @param featureType featureType + * @throws IllegalArgumentException if source is null. + */ + public FeatureTypeEvent(Object source, FeatureType featureType) + { + super(source); + this.featureType = featureType; + } + + public FeatureType getFeatureType() + { + return featureType; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompIdDispatchableFilter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompIdDispatchableFilter.java new file mode 100644 index 0000000..4810b12 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompIdDispatchableFilter.java @@ -0,0 +1,139 @@ +package com.ximple.eofms.filter; + +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.eofms.util.StringUtils; + +public class TypeCompIdDispatchableFilter extends AbstractFLinkageDispatchableFilter + implements CreateFeatureTypeEventListener +{ + private int tid; + private int cid; + private CreateFeatureTypeStrategy createStrategy; + private boolean useLongName = false; + + public TypeCompIdDispatchableFilter() + { + } + + public TypeCompIdDispatchableFilter(String fname, + CreateFeatureTypeStrategy createStrategy, + int tid, int compid) + { + this.setName(fname); + this.tid = tid; + this.cid = compid; + this.createStrategy = createStrategy; + this.createStrategy.addCreateFeatureTypeEventListener(this); + } + + public int getTid() + { + return tid; + } + + public void setTid(int tid) + { + this.tid = tid; + } + + public int getCid() + { + return cid; + } + + public void setCid(int cid) + { + this.cid = cid; + } + + public CreateFeatureTypeStrategy getCreateStrategy() + { + return createStrategy; + } + + public void setCreateStrategy(CreateFeatureTypeStrategy createStrategy) + { + if (this.createStrategy != null) + { + this.createStrategy.removeCreateFeatureTypeEventListener(this); + } + this.createStrategy = createStrategy; + + if (this.createStrategy != null) + { + this.createStrategy.addCreateFeatureTypeEventListener(this); + } + } + + public boolean isUseLongName() + { + return useLongName; + } + + public void setUseLongName(boolean useLongName) + { + this.useLongName = useLongName; + } + + //�P�_�O�_�ũM���� + public boolean isDispatchable(Element element) + { + FrammeAttributeData featureLinkage = getFeatureLinkage(element); + return featureLinkage != null && tid == featureLinkage.getFsc() && + (cid == featureLinkage.getComponentID()) && + (compareType(element) == 0); + } + + public Feature execute(Element element) + { + try + { + String ftName = getFeatureTypeName(element); + FeatureType ftype = createStrategy.createFeatureElement(ftName); + return createStrategy.createFeature(ftype, element); + } catch (SchemaException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (NullPointerException e) + { + logger.error(e.getMessage(), e); + } + return null; + } + + public String getFeatureTypeName(Element element) + { + StringBuilder sb = new StringBuilder(); + String name = getName().toLowerCase(); + String[] pices = StringUtils.splitToArray(name, "."); + boolean bfirst = true; + for (String temp : pices) + { + if (bfirst) bfirst = false; + else sb.append('-'); + sb.append(temp); + } + if (useLongName) + { + sb.append("_"); + sb.append(element.getLevelIndex()); + sb.append("_"); + sb.append(element.getWeight()); + } + return sb.toString(); + } + + public void createFeatureTypeOccurred(FeatureTypeEvent evt) + { + fireFeatureTypeEvent(evt); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompLevelIdDispatchableFilter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompLevelIdDispatchableFilter.java new file mode 100644 index 0000000..ab302e4 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompLevelIdDispatchableFilter.java @@ -0,0 +1,148 @@ +package com.ximple.eofms.filter; + +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.eofms.util.StringUtils; + +public class TypeCompLevelIdDispatchableFilter extends AbstractFLinkageDispatchableFilter + implements CreateFeatureTypeEventListener +{ + private int tid; + private int cid; + private int lid; + private CreateFeatureTypeStrategy createStrategy; + private boolean useLongName = false; + + public TypeCompLevelIdDispatchableFilter() + { + } + + public TypeCompLevelIdDispatchableFilter(String fname, + CreateFeatureTypeStrategy createStrategy, + int tid, int compid, int level) + { + this.setName(fname); + this.tid = tid; + this.cid = compid; + this.lid = level; + this.createStrategy = createStrategy; + this.createStrategy.addCreateFeatureTypeEventListener(this); + } + + public int getTid() + { + return tid; + } + + public void setTid(int tid) + { + this.tid = tid; + } + + public int getCid() + { + return cid; + } + + public void setCid(int cid) + { + this.cid = cid; + } + + public int getLid() + { + return lid; + } + + public void setLid(int lid) + { + this.lid = lid; + } + + public CreateFeatureTypeStrategy getCreateStrategy() + { + return createStrategy; + } + + public void setCreateStrategy(CreateFeatureTypeStrategy createStrategy) + { + if (this.createStrategy != null) + { + this.createStrategy.removeCreateFeatureTypeEventListener(this); + } + this.createStrategy = createStrategy; + + if (this.createStrategy != null) + { + this.createStrategy.addCreateFeatureTypeEventListener(this); + } + } + + + public boolean isUseLongName() + { + return useLongName; + } + + public void setUseLongName(boolean useLongName) + { + this.useLongName = useLongName; + } + + public boolean isDispatchable(Element element) + { + FrammeAttributeData featureLinkage = getFeatureLinkage(element); + return featureLinkage != null && tid == featureLinkage.getFsc() && + (cid == featureLinkage.getComponentID()) && + (lid == element.getLevelIndex()) && (compareLevel(element) == 0); + } + + public Feature execute(Element element) + { + try + { + String ftName = getFeatureTypeName(element); + FeatureType ftype = createStrategy.createFeatureElement(ftName); + return createStrategy.createFeature(ftype, element); + } catch (SchemaException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } + return null; + } + + public String getFeatureTypeName(Element element) + { + StringBuilder sb = new StringBuilder(); + String name = getName().toLowerCase(); + String[] pices = StringUtils.splitToArray(name, "."); + boolean bfirst = true; + for (String temp : pices) + { + if (bfirst) bfirst = false; + else sb.append('-'); + sb.append(temp); + } + if (useLongName) + { + sb.append("_"); + sb.append(element.getLevelIndex()); + sb.append("_"); + sb.append(element.getWeight()); + } + return sb.toString(); + } + + public void createFeatureTypeOccurred(FeatureTypeEvent evt) + { + fireFeatureTypeEvent(evt); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeIdDispatchableFilter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeIdDispatchableFilter.java new file mode 100644 index 0000000..b683361 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeIdDispatchableFilter.java @@ -0,0 +1,120 @@ +package com.ximple.eofms.filter; + +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; + +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.eofms.util.StringUtils; + +public class TypeIdDispatchableFilter extends AbstractFLinkageDispatchableFilter implements CreateFeatureTypeEventListener +{ + private int tid; + private CreateFeatureTypeStrategy createStrategy; + private boolean useLongName = false; + + public TypeIdDispatchableFilter() + { + } + + public TypeIdDispatchableFilter(String fname, CreateFeatureTypeStrategy createStrategy, + int tid) + { + this.setName(fname); + this.tid = tid; + this.createStrategy = createStrategy; + this.createStrategy.addCreateFeatureTypeEventListener(this); + } + + public int getTid() + { + return tid; + } + + public void setTid(int tid) + { + this.tid = tid; + } + + public CreateFeatureTypeStrategy getCreateStrategy() + { + return createStrategy; + } + + public void setCreateStrategy(CreateFeatureTypeStrategy createStrategy) + { + if (this.createStrategy != null) + { + this.createStrategy.removeCreateFeatureTypeEventListener(this); + } + this.createStrategy = createStrategy; + + if (this.createStrategy != null) + { + this.createStrategy.addCreateFeatureTypeEventListener(this); + } + } + + public boolean isDispatchable(Element element) + { + FrammeAttributeData featureLinkage = getFeatureLinkage(element); + return featureLinkage != null && tid == featureLinkage.getFsc() && + (compareType(element) == 0); + } + + public Feature execute(Element element) + { + try + { + String ftName = getFeatureTypeName(element); + FeatureType ftype = createStrategy.createFeatureElement(ftName); + return createStrategy.createFeature(ftype, element); + } catch (SchemaException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } + return null; + } + + public boolean isUseLongName() + { + return useLongName; + } + + public void setUseLongName(boolean useLongName) + { + this.useLongName = useLongName; + } + + public String getFeatureTypeName(Element element) + { + StringBuilder sb = new StringBuilder(); + String name = getName().toLowerCase(); + String[] pices = StringUtils.splitToArray(name, "."); + boolean bfirst = true; + for (String temp : pices) + { + if (bfirst) bfirst = false; + else sb.append('-'); + sb.append(temp); + } + if (useLongName) + { + sb.append("_"); + sb.append(element.getLevelIndex()); + sb.append("_"); + sb.append(element.getWeight()); + } + return sb.toString(); + } + + public void createFeatureTypeOccurred(FeatureTypeEvent evt) + { + fireFeatureTypeEvent(evt); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java new file mode 100644 index 0000000..3ff0034 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java @@ -0,0 +1,414 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.geotools.data.DataStore; +import org.geotools.data.jdbc.ConnectionPoolManager; +import org.geotools.data.oracle.OracleDataStore; +import org.geotools.data.oracle.OracleDataStoreFactory; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import com.vividsolutions.jts.util.Assert; + +import oracle.sql.BLOB; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; + +public abstract class AbstractOracleDatabaseJob implements Job +{ + /** + * The Oracle driver class name + */ + private static final String JDBC_DRIVER = "oracle.jdbc.driver.OracleDriver"; + + private static final String ORACLE_URL = "jdbc:oracle:thin:@"; + private static final String PROPUsrKey = "user"; + private static final String PROPPassKey = "password"; + + private static final String JOBDATA_DIR = "JOBDATA_DIR"; + private static final String CONFELMSFILTER = "ELMSFILTER_CONF"; + private static final String SPATAILSCHEMA = "ORGSCHEMA"; + private static final String CONVERTDB = "CONVERTDB"; + private static final String CONVERTFILE = "CONVERTFILE"; + private static final String CONVERTELEMIN = "CONVERTELEMIN"; + private static final String CREATEDUMMY = "CREATEDUMMY"; + private static final String ELEMLOG = "ELEMLOG"; + private static final String ORAHOST = "ORAHOST"; + private static final String ORAINST = "ORAINST"; + private static final String ORAPORT = "ORAPORT"; + private static final String ORAUSER = "ORAUSER"; + private static final String ORAPASS = "ORAPASS"; + private static final String TESTMODE = "TESTMODE"; + private static final String TESTCOUNT = "TESTCOUNT"; + private static final String COPYCONNECTIVITYMODE = "COPYCONNECTIVITYMODE"; + + protected static OracleDataStoreFactory dataStoreFactory = new OracleDataStoreFactory(); + + protected String _dataPath; + protected String _filterPath; + protected String _oracleHost; + protected String _oracleInstance; + protected String _oraclePort; + protected String _username; + protected String _password; + protected String _convertDB; + protected String _convertFile; + protected String _convertElementIn; + protected String _elementLogging; + protected String _createDummy; + protected ArrayList<String> _orgSchema = new ArrayList<String>(); + protected boolean _testMode = false; + protected boolean _copyConnectivityMode = false; + protected int _testCount = -1; + protected OracleDataStore sourceDataStore; + private boolean driverFound = true; + + protected AbstractOracleDatabaseJob() + { + try + { + Class.forName(JDBC_DRIVER); + } catch (Throwable t) + { + // must be running off dummy jar! + driverFound = false; + } + } + + public abstract void execute(JobExecutionContext context) throws JobExecutionException; + + public abstract Log getLogger(); + + protected void extractJobConfiguration(JobDetail jobDetail) throws JobExecutionException + { + // The directory to scan is stored in the job map + JobDataMap dataMap = jobDetail.getJobDataMap(); + _dataPath = dataMap.getString(JOBDATA_DIR); + _filterPath = dataMap.getString(CONFELMSFILTER); + _oracleHost = dataMap.getString(ORAHOST); + _oracleInstance = dataMap.getString(ORAINST); + _oraclePort = dataMap.getString(ORAPORT); + _username = dataMap.getString(ORAUSER); + _password = dataMap.getString(ORAPASS); + _convertDB = dataMap.getString(CONVERTDB); + _convertFile = dataMap.getString(CONVERTFILE); + _convertElementIn = dataMap.getString(CONVERTELEMIN); + _elementLogging = dataMap.getString(ELEMLOG); + _createDummy = dataMap.getString(CREATEDUMMY); + + Log logger = getLogger(); + /* + logger.info("JOBDATA_DIR=" + _dataPath); + logger.info("CONFELMSFILTER=" + _filterPath); + logger.info("ORAHOST=" + _oracleHost); + logger.info("ORAINST=" + _oracleInstance); + logger.info("ORAPORT=" + _oraclePort); + logger.info("ORAUSER=" + _username); + logger.info("ORAPASS=" + _password); + logger.info("CONVERTDB=" + _convertDB); + logger.info("CONVERTFILE=" + _convertFile); + logger.info("CONVERTELEMIN=" + _convertElementIn); + logger.info("ELEMLOG=" + _elementLogging); + */ + + String strSchema = dataMap.getString(SPATAILSCHEMA); + StringTokenizer st = new StringTokenizer(strSchema, ","); + while (st.hasMoreTokens()) + { + String aSchema = st.nextToken().trim(); + _orgSchema.add(aSchema); + } + _testMode = dataMap.getBooleanFromString(TESTMODE); + _testCount = dataMap.getIntFromString(TESTCOUNT); + _copyConnectivityMode = dataMap.getBooleanFromString(COPYCONNECTIVITYMODE); + + // Validate the required input + if (_dataPath == null) + { + if (logger != null) + { + logger.warn("Cannot found data directory in configarion."); + } + throw new JobExecutionException("Directory not configured"); + } + + // Make sure the directory exists + File dir = new File(_dataPath); + if (!dir.exists()) + { + logger = getLogger(); + if (logger != null) + { + logger.warn("Cannot found data directory in file system.[" + _dataPath + "]"); + } + throw new JobExecutionException("Invalid Dir " + _dataPath); + } + + if (_oracleHost == null) + { + logger.warn("OracleHOST is null"); + throw new JobExecutionException("Unknown Oracle Host."); + } + if (_oracleInstance == null) + { + logger.warn("OracleINSTANCE is null"); + throw new JobExecutionException("Unknown Oracle Instance."); + } + if (_username == null) + { + logger.warn("OracleUSER is null"); + throw new JobExecutionException("Unknown Oracle Username."); + } + if (_password == null) + { + logger.warn("OraclePASS is null"); + throw new JobExecutionException("Unknown Oracle Password."); + } + if (_orgSchema == null) + { + logger.warn("OracleSchema is null"); + throw new JobExecutionException("Unknown Spatial Database Schema."); + } + } + + protected abstract AbstractOracleJobContext prepareJobContext(String filterPath); + + protected static byte[] getBytesFromBLOB(BLOB blob) throws SQLException + { + byte[] raw = null; + + // BLOB blob = (BLOB) rs.getBlob(1); + int optimalSize = blob.getChunkSize(); + byte[] chunk = new byte[optimalSize]; + InputStream is = blob.getBinaryStream(0); + ByteBuffer buffer = null; // ByteBuffer.allocate(optimalSize); + int len; + + try + { + while ((len = (is.read(chunk))) != -1) + { + if (buffer != null) + { + buffer.limit(buffer.limit() + len); + } else + { + buffer = ByteBuffer.allocate(len); + } + + buffer.put(chunk); + } + + is.close(); + + assert buffer != null; + buffer.position(0); + raw = buffer.array(); + } catch (IOException e) + { + e.printStackTrace(); // To change body of catch statement use File | Settings | File Templates. + Assert.shouldNeverReachHere(); + } + + return raw; + } + + public boolean isDriverFound() + { + return driverFound; + } + + public String getDataPath() + { + return _dataPath; + } + + public String getFilterPath() + { + return _filterPath; + } + + public String getOracleHost() + { + return _oracleHost; + } + + public String getOracleInstance() + { + return _oracleInstance; + } + + public String getOraclePort() + { + return _oraclePort; + } + + public String getUsername() + { + return _username; + } + + public String getPassword() + { + return _password; + } + + public ArrayList<String> getOriginSchema() + { + return _orgSchema; + } + + public boolean isTestMode() + { + return _testMode; + } + + public int getTestCount() + { + return _testCount; + } + + public String getConvertDB() + { + return _convertDB; + } + + public void setConvertDB(String convertDB) + { + _convertDB = convertDB; + } + + public String getConvertFile() + { + return _convertFile; + } + + public void setConvertFile(String convertFile) + { + _convertFile = convertFile; + } + + public String getConvertElementIn() + { + return _convertElementIn; + } + + public void setConvertElementIn(String convertElementIn) + { + _convertElementIn = convertElementIn; + } + + public boolean checkConvertDB() + { + return _convertDB != null && !_convertDB.equalsIgnoreCase("false") && + !_convertDB.equalsIgnoreCase("no") && !_convertDB.equalsIgnoreCase("0"); + } + + public boolean checkConvertFile() + { + return _convertFile != null && !_convertFile.equalsIgnoreCase("false") && + !_convertFile.equalsIgnoreCase("no") && !_convertFile.equalsIgnoreCase("0"); + } + + public boolean checkConvertElementIn() + { + return _convertElementIn != null && !_convertElementIn.equalsIgnoreCase("false") && + !_convertElementIn.equalsIgnoreCase("no") && !_convertElementIn.equalsIgnoreCase("0"); + } + + public String getElementLogging() + { + return _elementLogging; + } + + public void setElementLogging(String elementLogging) + { + this._elementLogging = elementLogging; + } + + public boolean checkElementLogging() + { + return _elementLogging != null && !_elementLogging.equalsIgnoreCase("false") && + !_elementLogging.equalsIgnoreCase("no") && !_elementLogging.equalsIgnoreCase("0"); + } + + public boolean checkCreateDummy() + { + return _createDummy != null && !_createDummy.equalsIgnoreCase("false") && + !_createDummy.equalsIgnoreCase("no") && !_createDummy.equalsIgnoreCase("0"); + } + + public boolean isCopyConnectivityMode() + { + return _copyConnectivityMode; + } + + public DataStore getSourceDataStore() + { + return sourceDataStore; + } + + protected void createSourceDataStore() throws JobExecutionException + { + if (sourceDataStore != null) + { + sourceDataStore.dispose(); + sourceDataStore = null; + } + + if (!isDriverFound()) + { + throw new JobExecutionException("Oracle JDBC Driver not found.-" + JDBC_DRIVER); + } + Map<String, String> map = new TreeMap<String, String>(); + map.put("host", _oracleHost); + map.put("port", _oraclePort); + map.put("instance", _oracleInstance); + map.put("user", _username); + map.put("passwd", _password); + map.put("dbtype", "oracle"); + map.put("alias", _oracleInstance); + map.put("namespace", null); + if (!map.containsKey(OracleDataStoreFactory.MAXCONN.key)) + { + map.put(OracleDataStoreFactory.MAXCONN.key, "10"); + } + if (!map.containsKey(OracleDataStoreFactory.MINCONN.key)) + { + map.put(OracleDataStoreFactory.MINCONN.key, "1"); + } + + if (!dataStoreFactory.canProcess(map)) + { + getLogger().warn("cannot process properties-"); + throw new JobExecutionException("cannot process properties-"); + } + try + { + sourceDataStore = (OracleDataStore) dataStoreFactory.createDataStore(map); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + + protected void disconnect() + { + ConnectionPoolManager manager = ConnectionPoolManager.getInstance(); + manager.closeAll(); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/DummyFeatureConvertJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/DummyFeatureConvertJobContext.java new file mode 100644 index 0000000..ba6584d --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/DummyFeatureConvertJobContext.java @@ -0,0 +1,305 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.filter.TypeCompIdDispatchableFilter; +import com.ximple.eofms.filter.TypeCompLevelIdDispatchableFilter; +import com.ximple.eofms.filter.TypeIdDispatchableFilter; +import com.ximple.eofms.jobs.context.AbstractDgnFileJobContext; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class DummyFeatureConvertJobContext extends AbstractDgnFileJobContext +{ + static final Log logger = LogFactory.getLog(DummyFeatureConvertJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + static final String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + + public DummyFeatureConvertJobContext(String dataPath, String filterConfig) + { + super(dataPath); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + assert elementDispatcher != null; + for (ElementDispatchableFilter filter : elementDispatcher.getRules()) + { + if (filter instanceof TypeCompIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeCompLevelIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } + } + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + File sfile = new File(getDataOutPath() + File.separator + featureType.getTypeName()); + logger.debug("Begin Save shapefile:" + sfile.toURI()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + // ShapefileDataStore shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL()); + /* + ShapefileDataStore shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL(), + true, Charset.forName("UTF-8")); + */ + if (!sfile.exists()) + { + ShapefileDataStore shapefileDataStore = new IndexedShapefileDataStore(sfile.toURI().toURL(), + null, true, true, IndexedShapefileDataStore.TREE_QIX, Charset.forName("UTF-8")); + shapefileDataStore.createSchema(featureType); + writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + ShapefileDataStore shapefileDataStore = new IndexedShapefileDataStore(sfile.toURI().toURL(), + null, true, true, IndexedShapefileDataStore.TREE_QIX, Charset.forName("UTF-8")); + writer = shapefileDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save shapefile:" + sfile.toURI()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2MySQLJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2MySQLJob.java new file mode 100644 index 0000000..ccea789 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2MySQLJob.java @@ -0,0 +1,1107 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.sql.Connection; +import java.util.Date; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.collections.OrderedMap; +import org.apache.commons.collections.OrderedMapIterator; +import org.apache.commons.collections.map.LinkedMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.data.DataStore; +import org.geotools.data.mysql.MySQLDataStore; +import org.geotools.data.mysql.MySQLDataStoreFactory; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleResultSet; +import oracle.sql.ARRAY; +import oracle.sql.BLOB; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.jobs.context.mysql.OracleConvertMySQLJobContext; +import com.ximple.eofms.jobs.context.mysql.IndexDgnConvertMySQLJobContext; +import com.ximple.eofms.jobs.context.mysql.GeneralDgnConvertMySQLJobContext; +import com.ximple.eofms.jobs.context.mysql.FeatureDgnConvertMySQLJobContext; +import com.ximple.eofms.util.BinConverter; +import com.ximple.eofms.util.ByteArrayCompressor; +import com.ximple.eofms.util.StringUtils; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Dgn7fileException; +import com.ximple.io.dgn7.Dgn7fileReader; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.ElementType; +import com.ximple.io.dgn7.IElementHandler; +import com.ximple.io.dgn7.Lock; +import com.ximple.io.dgn7.TextElement; +import com.ximple.util.PrintfFormat; + +public class OracleConvertDgn2MySQLJob extends AbstractOracleDatabaseJob +{ + final static Log logger = LogFactory.getLog(OracleConvertDgn2PostGISJob.class); + + private static final String MYHOST = "MYHOST"; + private static final String MYDATBASE = "MYDATBASE"; + private static final String MYPORT = "MYPORT"; + private static final String MYSCHEMA = "MYSCHEMA"; + private static final String MYUSER = "MYUSER"; + private static final String MYPASS = "MYPASS"; + private static final String USEWKB = "USEWKB"; + + private static final int FETCHSIZE = 30; + private static final int COMMITSIZE = 20; + + class Pair + { + Object first; + Object second; + + public Pair(Object first, Object second) + { + this.first = first; + this.second = second; + } + } + + protected static MySQLDataStoreFactory dataStoreFactory = new MySQLDataStoreFactory(); + + GeometryFactory _geomFactory = new GeometryFactory(); + protected String _myHost; + protected String _myDatabase; + protected String _myPort; + protected String _mySchema; + protected String _myUsername; + protected String _myPassword; + protected String _myUseWKB; + + protected Map<String, String> myProperties; + protected MySQLDataStore targetDataStore; + + public Log getLogger() + { + return logger; + } + + protected AbstractOracleJobContext prepareJobContext(String filterPath) + { + return new OracleConvertMySQLJobContext(getDataPath(), getTargetDataStore(), filterPath); + } + + protected void extractJobConfiguration(JobDetail jobDetail) throws JobExecutionException + { + super.extractJobConfiguration(jobDetail); + JobDataMap dataMap = jobDetail.getJobDataMap(); + _myHost = dataMap.getString(MYHOST); + _myDatabase = dataMap.getString(MYDATBASE); + _myPort = dataMap.getString(MYPORT); + _mySchema = dataMap.getString(MYSCHEMA); + _myUsername = dataMap.getString(MYUSER); + _myPassword = dataMap.getString(MYPASS); + _myUseWKB = dataMap.getString(USEWKB); + + Log logger = getLogger(); + /* + logger.info("MYHOST=" + _myHost); + logger.info("MYDATBASE=" + _myDatabase); + logger.info("MYPORT=" + _myPort); + logger.info("MYSCHEMA=" + _mySchema); + logger.info("MYUSER=" + _myUsername); + logger.info("MYPASS=" + _myPassword); + logger.info("USEWKB=" + _myUseWKB); + */ + + if (_myHost == null) + { + logger.warn("MYHOST is null"); + throw new JobExecutionException("Unknown PostGIS host."); + } + if (_myDatabase == null) + { + logger.warn("PGDATABASE is null"); + throw new JobExecutionException("Unknown PostGIS database."); + } + if (_myPort == null) + { + logger.warn("MYPORT is null"); + throw new JobExecutionException("Unknown PostGIS port."); + } + if (_mySchema == null) + { + logger.warn("MYSCHEMA is null"); + throw new JobExecutionException("Unknown PostGIS schema."); + } + if (_myUsername == null) + { + logger.warn("PGUSERNAME is null"); + throw new JobExecutionException("Unknown PostGIS username."); + } + if (_myPassword == null) + { + logger.warn("PGPASSWORD is null"); + throw new JobExecutionException("Unknown PostGIS password."); + } + + Map<String, String> remote = new TreeMap<String, String>(); + remote.put("dbtype", "postgis"); + remote.put("charset", "UTF-8"); + remote.put("host", _myHost); + remote.put("port", _myPort); + remote.put("database", _myDatabase); + remote.put("user", _myUsername); + remote.put("passwd", _myPassword); + remote.put("namespace", null); + myProperties = remote; + } + + public void execute(JobExecutionContext context) throws JobExecutionException + { + // Every job has its own job detail + JobDetail jobDetail = context.getJobDetail(); + + // The name is defined in the job definition + String jobName = jobDetail.getName(); + + // Log the time the job started + logger.info(jobName + " fired at " + new Date()); + extractJobConfiguration(jobDetail); + createSourceDataStore(); + createTargetDataStore(); + if (getSourceDataStore() == null) + { + logger.warn("Cannot connect source oracle database."); + throw new JobExecutionException("Cannot connect source oracle database."); + } + + if (getTargetDataStore() == null) + { + logger.warn("Cannot connect source postgreSQL database."); + throw new JobExecutionException("Cannot connect source postgreSQL database."); + } + + long t1 = System.currentTimeMillis(); + try + { + logger.info("-- step:clearOutputDatabase --"); + clearOutputDatabase(); + boolean bFirst = isCopyConnectivityMode(); + if (checkConvertDB()) + { + logger.info("-- step:convertOracleDB --"); + + for (String orgSchema : _orgSchema) + { + OracleConvertMySQLJobContext jobContext = + (OracleConvertMySQLJobContext) prepareJobContext(_filterPath); + jobContext.setSourceDataStore(getSourceDataStore()); + // jobContext.setConvertElementIn(_convertElementIn); + jobContext.setElementLogging(checkElementLogging()); + jobContext.setExecutionContext(context); + + if (bFirst) + copyConnectivity(jobContext); + else + bFirst = false; + + logger.info("----- start schema:" + orgSchema + " -----"); + exetcuteConvert(jobContext, orgSchema, _dataPath); + + //close all open filewriter instance + jobContext.closeFeatureWriter(); + } + } + + if (checkConvertFile()) + { + logger.info("-- step:convertIndexDesignFile --"); + convertIndexDesignFile(context); + logger.info("-- step:convertOtherDesignFile --"); + convertOtherDesignFile(context); + } + + if (checkConvertElementIn()) + { + logger.info("-- step:convertFeatureDesignFile --"); + convertFeatureDesignFile(context); + } + + if (checkCreateDummy()) + { + logger.info("-- step:createDummyFeatureFile --"); + createDummyFeatureFile(context); + } + + disconnect(); + long t2 = System.currentTimeMillis(); + // public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss"; + // SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW); + logger.warn("use time = " + ((t2 - t1) / 60000.0) + " min"); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException("Database error. " + e.getMessage(), e); + } catch (IOException ex) + { + logger.warn(ex.getMessage(), ex); + throw new JobExecutionException("IO error. " + ex.getMessage(), ex); + } + logger.info(jobName + " end at " + new Date()); + } + + /** + * Connectivity�ƻs�@�Ӫ����A�b�d�߹q�y��V�ɥΨӤ��OMS��Ʈw���q���s����(Connectivity) + * + * @param jobContext job context + * @throws SQLException sql exception + */ + private void copyConnectivity(OracleConvertMySQLJobContext jobContext) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + Statement stmt = connection.createStatement(); + stmt.execute(AbstractOracleJobContext.TRUNCATE_CONNECTIVITY_WEBCHECK); + stmt.execute(AbstractOracleJobContext.COPY_CONNECTIVITY_TO_WEBCHECK); + } + + private void exetcuteConvert(OracleConvertMySQLJobContext jobContext, + String querySchema, String dataPath) throws SQLException + { + int order = 0; + OrderedMap map = getBlobStorageList(jobContext.getOracleConnection(), querySchema, "SD$SPACENODES" + , null); + + logger.info("begin convert job:[" + map.size() + "]:testmode=" + _testMode); + + int total = map.size(); //spacenodes count + int step = total / 100; + int current = 0; + + //jobContext.startTransaction(); + jobContext.setCurrentSchema(querySchema); + jobContext.getExecutionContext().put("ConvertDgn2PostGISJobProgress", 0); + for (OrderedMapIterator it = map.orderedMapIterator(); it.hasNext();) + { + it.next(); + + Pair pair = (Pair) it.getValue(); + String tableSrc = (String) pair.first; + + logger.info("begin convert:[" + order + "]-" + tableSrc); + queryIgsetElement(jobContext, querySchema, tableSrc); + + order++; + + if (_testMode) + { + if ((_testCount < 0) || (order >= _testCount)) + break; + } + + if ((order % COMMITSIZE) == 0) + { + // OracleConnection connection = jobContext.getOracleConnection(); + // connection.commitTransaction(); + jobContext.commitTransaction(); + //jobContext.startTransaction(); + System.gc(); + System.runFinalization(); + } + + int now = order % step; + if (now != current) + { + current = now; + jobContext.getExecutionContext().put("ConvertDgn2PostGISJobProgress", current); + + } + } + jobContext.getExecutionContext().put("ConvertDgn2PostGISJobProgress", 100); + + jobContext.commitTransaction(); + + logger.info("end convert job:[" + order + "]"); + System.gc(); + System.runFinalization(); + } + + protected OrderedMap getBlobStorageList(Connection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT SNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + ResultSet rs = null; + + stmt.setFetchSize(FETCHSIZE); + + try + { + rs = stmt.executeQuery(fetchStmt); + int size = rs.getMetaData().getColumnCount(); + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(name, null)); + else + pair.first = name; + } + } catch (SQLException e) + { + logger.error(e.toString(), e); + logger.error("stmt=" + fetchStmt); + throw e; + } finally + { + if (rs != null) rs.close(); + stmt.close(); + } + + return orderedMap; + } + + protected OrderedMap getRawFormatStorageList(OracleConnection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT RNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmt.setFetchSize(FETCHSIZE); + + ResultSet rs = stmt.executeQuery(fetchStmt); + int size = rs.getMetaData().getColumnCount(); + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(null, name)); + else + pair.second = name; + } + + rs.close(); + stmt.close(); + + return orderedMap; + } + + protected void queryIgsetElement(OracleConvertMySQLJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchSrcStmtFmt); + String fetchSrcStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtSrc = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtSrc.setFetchSize(FETCHSIZE); + + ResultSet rsSrc = stmtSrc.executeQuery(fetchSrcStmt); + int igdsMetaType = rsSrc.getMetaData().getColumnType(1); + while (rsSrc.next()) + { + byte[] raw; + + if (igdsMetaType == Types.BLOB) + { + BLOB blob = (BLOB) rsSrc.getBlob(1); + + raw = getBytesFromBLOB(blob); + blob.close(); + } else + { + raw = rsSrc.getBytes(1); + } + + try + { + Element element = fetchBinaryElement(raw); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception", e); + } + } + + rsSrc.close(); + stmtSrc.close(); + } + + protected void queryRawElement(OracleConvertMySQLJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchDestStmtFmt = "SELECT ELEMENT FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchDestStmtFmt); + String fetchDestStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtDest = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtDest.setFetchSize(FETCHSIZE); + + ResultSet rsDest = stmtDest.executeQuery(fetchDestStmt); + + while (rsDest.next()) + { + ARRAY rawsValue = ((OracleResultSet) rsDest).getARRAY(1); + long[] rawData = rawsValue.getLongArray(); + byte[] comparessedValue; + + /* + if (dataMode == TransferTask.DataMode.Normal) + { + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + } else + { + comparessedValue = BinConverter.unmarshalCompactByteArray(rawData); + } + */ + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + + byte[] rawDest = ByteArrayCompressor.decompressByteArray(comparessedValue); + + + try + { + Element element = fetchBinaryElement(rawDest); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception:" + e.getMessage(), e); + } + } + + rsDest.close(); + stmtDest.close(); + } + + // Binary to Element + private Element fetchBinaryElement(byte[] raws) throws Dgn7fileException + { + ByteBuffer buffer = ByteBuffer.wrap(raws); + buffer.order(ByteOrder.LITTLE_ENDIAN); + short signature = buffer.getShort(); + + // byte type = (byte) (buffer.get() & 0x7f); + byte type = (byte) ((signature >>> 8) & 0x007f); + + // silly Bentley say contentLength is in 2-byte words + // and ByteByffer uses raws. + // track the record location + int elementLength = (buffer.getShort() * 2) + 4; + ElementType recordType = ElementType.forID(type); + IElementHandler handler; + + handler = recordType.getElementHandler(); + + Element dgnElement = (Element) handler.read(buffer, signature, elementLength); + if (recordType.isComplexElement() && (elementLength < raws.length)) + { + int offset = elementLength; + while (offset < (raws.length - 4)) + { + buffer.position(offset); + signature = buffer.getShort(); + type = (byte) ((signature >>> 8) & 0x007f); + elementLength = (buffer.getShort() * 2) + 4; + if (raws.length < (offset + elementLength)) + { + System.out.println("Length not match:" + offset + ":" + buffer.position() + ":" + buffer.limit()); + break; + } + recordType = ElementType.forID(type); + handler = recordType.getElementHandler(); + if (handler != null) + { + Element subElement = (Element) handler.read(buffer, signature, elementLength); + ((ComplexElement) dgnElement).add(subElement); + offset += elementLength; + } else + { + byte[] remain = new byte[buffer.remaining()]; + System.arraycopy(raws, offset, remain, 0, buffer.remaining()); + for (int i = 0; i < remain.length; i++) + { + if (remain[i] != 0) + { + logger.info("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + System.out.println("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + } + } + break; + } + } + } + + return dgnElement; + } + + /** + * �����ഫ�����ɪ��u�@ + * + * @param context �u�@�������� + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertIndexDesignFile(JobExecutionContext context) throws JobExecutionException + { + File indexDir = new File(getDataPath(), "index"); + if (!indexDir.exists()) + { + logger.info("index dir=" + indexDir + " not exist."); + return; + } + + if (!indexDir.isDirectory()) + { + logger.info("index dir=" + indexDir + " is not a directory."); + } + + File[] dgnFiles = indexDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + IndexDgnConvertMySQLJobContext convertContext = + new IndexDgnConvertMySQLJobContext(getDataPath(), getTargetDataStore()); + logger.debug("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanIndexDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + protected void scanIndexDgnElement(IndexDgnConvertMySQLJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + lastComplex = null; + } + + processIndexElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processIndexElement(Element element, IndexDgnConvertMySQLJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + if (element instanceof TextElement) + { + convertContext.putFeatureCollection(element); + } + } + + + /** + * �����ഫ��L�]�p���ɪ��u�@ + * + * @param context jobContext + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertOtherDesignFile(JobExecutionContext context) throws JobExecutionException + { + File otherDir = new File(getDataPath(), "other"); + if (!otherDir.exists()) + { + logger.info("other dir=" + otherDir + " not exist."); + return; + } + + if (!otherDir.isDirectory()) + { + logger.info("other dir=" + otherDir + " is not a directory."); + } + + File[] dgnFiles = otherDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + GeneralDgnConvertMySQLJobContext convertContext = + new GeneralDgnConvertMySQLJobContext(getDataPath(), getTargetDataStore()); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanOtherDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanOtherDgnElement(GeneralDgnConvertMySQLJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + lastComplex = null; + } + + processOtherElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processOtherElement(Element element, GeneralDgnConvertMySQLJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void clearOutputDatabase() + { + /* + File outDataPath = new File(getDataPath(), OracleConvertPostGISJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), IndexDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), GeneralDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + */ + } + + private void deleteFilesInPath(File outDataPath) + { + deleteFilesInPath(outDataPath, true); + } + + private void deleteFilesInPath(File outDataPath, boolean removeSubDir) + { + if (!outDataPath.isDirectory()) + { + return; + } + File[] files = outDataPath.listFiles(); + for (File file : files) + { + if (file.isFile()) + { + if (!file.delete()) + { + logger.info("Cannot delete file-" + file.toString()); + } + } else if (file.isDirectory()) + { + deleteFilesInPath(file, removeSubDir); + if (removeSubDir) + { + if (file.delete()) + { + logger.info("Cannot delete dir-" + file.toString()); + } + } + } + } + } + + private void convertFeatureDesignFile(JobExecutionContext context) throws JobExecutionException + { + File elminDir = new File(getDataPath(), "elmin"); + if (!elminDir.exists()) + { + logger.info("elmin dir=" + elminDir + " not exist."); + return; + } + + if (!elminDir.isDirectory()) + { + logger.info("elmin dir=" + elminDir + " is not a directory."); + } + + File[] dgnFiles = elminDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + FeatureDgnConvertMySQLJobContext convertContext = + new FeatureDgnConvertMySQLJobContext(getDataPath(), getTargetDataStore(), _filterPath); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanFeatureDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanFeatureDgnElement(FeatureDgnConvertMySQLJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + lastComplex = null; + } + + processFeatureElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processFeatureElement(Element element, FeatureDgnConvertMySQLJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void createDummyFeatureFile(JobExecutionContext context) throws JobExecutionException + { + /* + DummyFeatureConvertShpJobContext convertContext = new DummyFeatureConvertShpJobContext(getDataPath(), _filterPath); + try { + convertContext.startTransaction(); + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + */ + } + + public DataStore getTargetDataStore() + { + return targetDataStore; + } + + protected void createTargetDataStore() throws JobExecutionException + { + if (targetDataStore != null) + { + targetDataStore.dispose(); + targetDataStore = null; + } + + /* + if (!isDriverFound()) + { + throw new JobExecutionException("Oracle JDBC Driver not found.-" + JDBC_DRIVER); + } + */ + + if (!myProperties.containsKey("max connections" /*MySQLDataStoreFactory.MAXCONN.key */)) + { + myProperties.put("max connections", "2"); + } + + if (!myProperties.containsKey("min connections" /* MySQLDataStoreFactory.MINCONN.key */)) + { + myProperties.put("min connections", "1"); + } + + if (!myProperties.containsKey(MySQLDataStoreFactory.WKBENABLED.key)) + { + myProperties.put(MySQLDataStoreFactory.WKBENABLED.key, "true"); + } + + if (!dataStoreFactory.canProcess(myProperties)) + { + getLogger().warn("cannot process properties-"); + throw new JobExecutionException("cannot process properties-"); + } + try + { + targetDataStore = (MySQLDataStore) dataStoreFactory.createDataStore(myProperties); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2OraSDOJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2OraSDOJob.java new file mode 100644 index 0000000..e444094 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2OraSDOJob.java @@ -0,0 +1,1108 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.sql.Connection; +import java.util.Date; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.collections.OrderedMap; +import org.apache.commons.collections.OrderedMapIterator; +import org.apache.commons.collections.map.LinkedMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.data.DataStore; +import org.geotools.data.oracle.OracleDataStore; +import org.geotools.data.oracle.OracleDataStoreFactory; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleResultSet; +import oracle.sql.ARRAY; +import oracle.sql.BLOB; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.jobs.context.orasdo.FeatureDgnConvertOraSDOJobContext; +import com.ximple.eofms.jobs.context.orasdo.GeneralDgnConvertOraSDOJobContext; +import com.ximple.eofms.jobs.context.orasdo.IndexDgnConvertOraSDOJobContext; +import com.ximple.eofms.jobs.context.orasdo.OracleConvertOraSDOJobContext; +import com.ximple.eofms.util.BinConverter; +import com.ximple.eofms.util.ByteArrayCompressor; +import com.ximple.eofms.util.StringUtils; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Dgn7fileException; +import com.ximple.io.dgn7.Dgn7fileReader; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.ElementType; +import com.ximple.io.dgn7.IElementHandler; +import com.ximple.io.dgn7.Lock; +import com.ximple.io.dgn7.TextElement; +import com.ximple.util.PrintfFormat; + +public class OracleConvertDgn2OraSDOJob extends AbstractOracleDatabaseJob +{ + final static Log logger = LogFactory.getLog(OracleConvertDgn2OraSDOJob.class); + + private static final String SDOHOST = "SDOHOST"; + private static final String SDODDATBASE = "SDODDATBASE"; + private static final String SDOPORT = "SDOPORT"; + private static final String SDOSCHEMA = "SDOSCHEMA"; + private static final String SDOUSER = "SDOUSER"; + private static final String SDOPASS = "SDOPASS"; + private static final String USEWKB = "USEWKB"; + + private static final int FETCHSIZE = 30; + private static final int COMMITSIZE = 20; + + class Pair + { + Object first; + Object second; + + public Pair(Object first, Object second) + { + this.first = first; + this.second = second; + } + } + + protected static OracleDataStoreFactory dataStoreFactory = new OracleDataStoreFactory(); + + GeometryFactory _geomFactory = new GeometryFactory(); + protected String _sdoHost; + protected String _sdoDatabase; + protected String _sdoPort; + protected String _sdoSchema; + protected String _sdoUsername; + protected String _sdoPassword; + protected String _sdoUseWKB; + + protected Map<String, String> sdoProperties; + protected OracleDataStore targetDataStore; + + public Log getLogger() + { + return logger; + } + + protected AbstractOracleJobContext prepareJobContext(String filterPath) + { + return new OracleConvertOraSDOJobContext(getDataPath(), getTargetDataStore(), filterPath); + } + + protected void extractJobConfiguration(JobDetail jobDetail) throws JobExecutionException + { + super.extractJobConfiguration(jobDetail); + JobDataMap dataMap = jobDetail.getJobDataMap(); + _sdoHost = dataMap.getString(SDOHOST); + _sdoDatabase = dataMap.getString(SDODDATBASE); + _sdoPort = dataMap.getString(SDOPORT); + _sdoSchema = dataMap.getString(SDOSCHEMA); + _sdoUsername = dataMap.getString(SDOUSER); + _sdoPassword = dataMap.getString(SDOPASS); + _sdoUseWKB = dataMap.getString(USEWKB); + + Log logger = getLogger(); + /* + logger.info("SDOHOST=" + _myHost); + logger.info("SDODDATBASE=" + _myDatabase); + logger.info("SDOPORT=" + _myPort); + logger.info("SDOSCHEMA=" + _mySchema); + logger.info("SDOUSER=" + _myUsername); + logger.info("SDOPASS=" + _myPassword); + logger.info("USEWKB=" + _myUseWKB); + */ + + if (_sdoHost == null) + { + logger.warn("SDOHOST is null"); + throw new JobExecutionException("Unknown OraSDO host."); + } + if (_sdoDatabase == null) + { + logger.warn("PGDATABASE is null"); + throw new JobExecutionException("Unknown OraSDO database."); + } + if (_sdoPort == null) + { + logger.warn("SDOPORT is null"); + throw new JobExecutionException("Unknown OraSDO port."); + } + if (_sdoSchema == null) + { + logger.warn("SDOSCHEMA is null"); + throw new JobExecutionException("Unknown OraSDO schema."); + } + if (_sdoUsername == null) + { + logger.warn("PGUSERNAME is null"); + throw new JobExecutionException("Unknown OraSDO username."); + } + if (_sdoPassword == null) + { + logger.warn("PGPASSWORD is null"); + throw new JobExecutionException("Unknown OraSDO password."); + } + + Map<String, String> remote = new TreeMap<String, String>(); + remote.put("dbtype", "OraSDO"); + remote.put("charset", "UTF-8"); + remote.put("host", _sdoHost); + remote.put("port", _sdoPort); + remote.put("database", _sdoDatabase); + remote.put("user", _sdoUsername); + remote.put("passwd", _sdoPassword); + remote.put("namespace", null); + sdoProperties = remote; + } + + public void execute(JobExecutionContext context) throws JobExecutionException + { + // Every job has its own job detail + JobDetail jobDetail = context.getJobDetail(); + + // The name is defined in the job definition + String jobName = jobDetail.getName(); + + // Log the time the job started + logger.info(jobName + " fired at " + new Date()); + extractJobConfiguration(jobDetail); + createSourceDataStore(); + createTargetDataStore(); + if (getSourceDataStore() == null) + { + logger.warn("Cannot connect source oracle database."); + throw new JobExecutionException("Cannot connect source oracle database."); + } + + if (getTargetDataStore() == null) + { + logger.warn("Cannot connect source postgreSQL database."); + throw new JobExecutionException("Cannot connect source postgreSQL database."); + } + + long t1 = System.currentTimeMillis(); + try + { + logger.info("-- step:clearOutputDatabase --"); + clearOutputDatabase(); + boolean bFirst = isCopyConnectivityMode(); + if (checkConvertDB()) + { + logger.info("-- step:convertOracleDB --"); + + for (String orgSchema : _orgSchema) + { + OracleConvertOraSDOJobContext jobContext = + (OracleConvertOraSDOJobContext) prepareJobContext(_filterPath); + jobContext.setSourceDataStore(getSourceDataStore()); + // jobContext.setConvertElementIn(_convertElementIn); + jobContext.setElementLogging(checkElementLogging()); + jobContext.setExecutionContext(context); + + if (bFirst) + copyConnectivity(jobContext); + else + bFirst = false; + + logger.info("----- start schema:" + orgSchema + " -----"); + exetcuteConvert(jobContext, orgSchema, _dataPath); + + //close all open filewriter instance + jobContext.closeFeatureWriter(); + } + } + + if (checkConvertFile()) + { + logger.info("-- step:convertIndexDesignFile --"); + convertIndexDesignFile(context); + logger.info("-- step:convertOtherDesignFile --"); + convertOtherDesignFile(context); + } + + if (checkConvertElementIn()) + { + logger.info("-- step:convertFeatureDesignFile --"); + convertFeatureDesignFile(context); + } + + if (checkCreateDummy()) + { + logger.info("-- step:createDummyFeatureFile --"); + createDummyFeatureFile(context); + } + + disconnect(); + long t2 = System.currentTimeMillis(); + // public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss"; + // SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW); + logger.warn("use time = " + ((t2 - t1) / 60000.0) + " min"); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException("Database error. " + e.getMessage(), e); + } catch (IOException ex) + { + logger.warn(ex.getMessage(), ex); + throw new JobExecutionException("IO error. " + ex.getMessage(), ex); + } + logger.info(jobName + " end at " + new Date()); + } + + /** + * Connectivity�ƻs�@�Ӫ����A�b�d�߹q�y��V�ɥΨӤ��OMS��Ʈw���q���s����(Connectivity) + * + * @param jobContext job context + * @throws SQLException sql exception + */ + private void copyConnectivity(OracleConvertOraSDOJobContext jobContext) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + Statement stmt = connection.createStatement(); + stmt.execute(AbstractOracleJobContext.TRUNCATE_CONNECTIVITY_WEBCHECK); + stmt.execute(AbstractOracleJobContext.COPY_CONNECTIVITY_TO_WEBCHECK); + } + + private void exetcuteConvert(OracleConvertOraSDOJobContext jobContext, + String querySchema, String dataPath) throws SQLException + { + int order = 0; + OrderedMap map = getBlobStorageList(jobContext.getOracleConnection(), querySchema, "SD$SPACENODES" + , null); + + logger.info("begin convert job:[" + map.size() + "]:testmode=" + _testMode); + + int total = map.size(); //spacenodes count + int step = total / 100; + int current = 0; + + //jobContext.startTransaction(); + jobContext.setCurrentSchema(querySchema); + jobContext.getExecutionContext().put("ConvertDgn2OraSDOJobProgress", 0); + for (OrderedMapIterator it = map.orderedMapIterator(); it.hasNext();) + { + it.next(); + + Pair pair = (Pair) it.getValue(); + String tableSrc = (String) pair.first; + + logger.info("begin convert:[" + order + "]-" + tableSrc); + queryIgsetElement(jobContext, querySchema, tableSrc); + + order++; + + if (_testMode) + { + if ((_testCount < 0) || (order >= _testCount)) + break; + } + + if ((order % COMMITSIZE) == 0) + { + // OracleConnection connection = jobContext.getOracleConnection(); + // connection.commitTransaction(); + jobContext.commitTransaction(); + //jobContext.startTransaction(); + System.gc(); + System.runFinalization(); + } + + int now = order % step; + if (now != current) + { + current = now; + jobContext.getExecutionContext().put("ConvertDgn2OraSDOJobProgress", current); + + } + } + jobContext.getExecutionContext().put("ConvertDgn2OraSDOJobProgress", 100); + + jobContext.commitTransaction(); + + logger.info("end convert job:[" + order + "]"); + System.gc(); + System.runFinalization(); + } + + protected OrderedMap getBlobStorageList(Connection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT SNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + ResultSet rs = null; + + stmt.setFetchSize(FETCHSIZE); + + try + { + rs = stmt.executeQuery(fetchStmt); + int size = rs.getMetaData().getColumnCount(); + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(name, null)); + else + pair.first = name; + } + } catch (SQLException e) + { + logger.error(e.toString(), e); + logger.error("stmt=" + fetchStmt); + throw e; + } finally + { + if (rs != null) rs.close(); + stmt.close(); + } + + return orderedMap; + } + + protected OrderedMap getRawFormatStorageList(OracleConnection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT RNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmt.setFetchSize(FETCHSIZE); + + ResultSet rs = stmt.executeQuery(fetchStmt); + int size = rs.getMetaData().getColumnCount(); + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(null, name)); + else + pair.second = name; + } + + rs.close(); + stmt.close(); + + return orderedMap; + } + + protected void queryIgsetElement(OracleConvertOraSDOJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchSrcStmtFmt); + String fetchSrcStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtSrc = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtSrc.setFetchSize(FETCHSIZE); + + ResultSet rsSrc = stmtSrc.executeQuery(fetchSrcStmt); + int igdsMetaType = rsSrc.getMetaData().getColumnType(1); + while (rsSrc.next()) + { + byte[] raw; + if (igdsMetaType == Types.BLOB) + { + BLOB blob = (BLOB) rsSrc.getBlob(1); + + raw = getBytesFromBLOB(blob); + blob.close(); + } else + { + raw = rsSrc.getBytes(1); + } + + try + { + Element element = fetchBinaryElement(raw); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception", e); + } + } + + rsSrc.close(); + stmtSrc.close(); + } + + protected void queryRawElement(OracleConvertOraSDOJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchDestStmtFmt = "SELECT ELEMENT FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchDestStmtFmt); + String fetchDestStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtDest = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtDest.setFetchSize(FETCHSIZE); + + ResultSet rsDest = stmtDest.executeQuery(fetchDestStmt); + + while (rsDest.next()) + { + ARRAY rawsValue = ((OracleResultSet) rsDest).getARRAY(1); + long[] rawData = rawsValue.getLongArray(); + byte[] comparessedValue; + + /* + if (dataMode == TransferTask.DataMode.Normal) + { + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + } else + { + comparessedValue = BinConverter.unmarshalCompactByteArray(rawData); + } + */ + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + + byte[] rawDest = ByteArrayCompressor.decompressByteArray(comparessedValue); + + + try + { + Element element = fetchBinaryElement(rawDest); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception:" + e.getMessage(), e); + } + } + + rsDest.close(); + stmtDest.close(); + } + + // Binary to Element + private Element fetchBinaryElement(byte[] raws) throws Dgn7fileException + { + ByteBuffer buffer = ByteBuffer.wrap(raws); + buffer.order(ByteOrder.LITTLE_ENDIAN); + short signature = buffer.getShort(); + + // byte type = (byte) (buffer.get() & 0x7f); + byte type = (byte) ((signature >>> 8) & 0x007f); + + // silly Bentley say contentLength is in 2-byte words + // and ByteByffer uses raws. + // track the record location + int elementLength = (buffer.getShort() * 2) + 4; + ElementType recordType = ElementType.forID(type); + IElementHandler handler; + + handler = recordType.getElementHandler(); + + Element dgnElement = (Element) handler.read(buffer, signature, elementLength); + if (recordType.isComplexElement() && (elementLength < raws.length)) + { + int offset = elementLength; + while (offset < (raws.length - 4)) + { + buffer.position(offset); + signature = buffer.getShort(); + type = (byte) ((signature >>> 8) & 0x007f); + elementLength = (buffer.getShort() * 2) + 4; + if (raws.length < (offset + elementLength)) + { + System.out.println("Length not match:" + offset + ":" + buffer.position() + ":" + buffer.limit()); + break; + } + recordType = ElementType.forID(type); + handler = recordType.getElementHandler(); + if (handler != null) + { + Element subElement = (Element) handler.read(buffer, signature, elementLength); + ((ComplexElement) dgnElement).add(subElement); + offset += elementLength; + } else + { + byte[] remain = new byte[buffer.remaining()]; + System.arraycopy(raws, offset, remain, 0, buffer.remaining()); + for (int i = 0; i < remain.length; i++) + { + if (remain[i] != 0) + { + logger.info("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + System.out.println("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + } + } + break; + } + } + } + + return dgnElement; + } + + /** + * �����ഫ�����ɪ��u�@ + * + * @param context �u�@�������� + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertIndexDesignFile(JobExecutionContext context) throws JobExecutionException + { + File indexDir = new File(getDataPath(), "index"); + if (!indexDir.exists()) + { + logger.info("index dir=" + indexDir + " not exist."); + return; + } + + if (!indexDir.isDirectory()) + { + logger.info("index dir=" + indexDir + " is not a directory."); + } + + File[] dgnFiles = indexDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + IndexDgnConvertOraSDOJobContext convertContext = + new IndexDgnConvertOraSDOJobContext(getDataPath(), getTargetDataStore()); + logger.debug("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanIndexDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + protected void scanIndexDgnElement(IndexDgnConvertOraSDOJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + lastComplex = null; + } + + processIndexElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processIndexElement(Element element, IndexDgnConvertOraSDOJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + if (element instanceof TextElement) + { + convertContext.putFeatureCollection(element); + } + } + + + /** + * �����ഫ��L�]�p���ɪ��u�@ + * + * @param context jobContext + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertOtherDesignFile(JobExecutionContext context) throws JobExecutionException + { + File otherDir = new File(getDataPath(), "other"); + if (!otherDir.exists()) + { + logger.info("other dir=" + otherDir + " not exist."); + return; + } + + if (!otherDir.isDirectory()) + { + logger.info("other dir=" + otherDir + " is not a directory."); + } + + File[] dgnFiles = otherDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + GeneralDgnConvertOraSDOJobContext convertContext = + new GeneralDgnConvertOraSDOJobContext(getDataPath(), getTargetDataStore()); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanOtherDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanOtherDgnElement(GeneralDgnConvertOraSDOJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + lastComplex = null; + } + + processOtherElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processOtherElement(Element element, GeneralDgnConvertOraSDOJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void clearOutputDatabase() + { + /* + File outDataPath = new File(getDataPath(), OracleConvertOraSDOJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), IndexDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), GeneralDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + */ + } + + private void deleteFilesInPath(File outDataPath) + { + deleteFilesInPath(outDataPath, true); + } + + private void deleteFilesInPath(File outDataPath, boolean removeSubDir) + { + if (!outDataPath.isDirectory()) + { + return; + } + File[] files = outDataPath.listFiles(); + for (File file : files) + { + if (file.isFile()) + { + if (!file.delete()) + { + logger.info("Cannot delete file-" + file.toString()); + } + } else if (file.isDirectory()) + { + deleteFilesInPath(file, removeSubDir); + if (removeSubDir) + { + if (file.delete()) + { + logger.info("Cannot delete dir-" + file.toString()); + } + } + } + } + } + + private void convertFeatureDesignFile(JobExecutionContext context) throws JobExecutionException + { + File elminDir = new File(getDataPath(), "elmin"); + if (!elminDir.exists()) + { + logger.info("elmin dir=" + elminDir + " not exist."); + return; + } + + if (!elminDir.isDirectory()) + { + logger.info("elmin dir=" + elminDir + " is not a directory."); + } + + File[] dgnFiles = elminDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + FeatureDgnConvertOraSDOJobContext convertContext = + new FeatureDgnConvertOraSDOJobContext(getDataPath(), getTargetDataStore(), _filterPath); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanFeatureDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanFeatureDgnElement(FeatureDgnConvertOraSDOJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + lastComplex = null; + } + + processFeatureElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processFeatureElement(Element element, FeatureDgnConvertOraSDOJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void createDummyFeatureFile(JobExecutionContext context) throws JobExecutionException + { + /* + DummyFeatureConvertShpJobContext convertContext = new DummyFeatureConvertShpJobContext(getDataPath(), _filterPath); + try { + convertContext.startTransaction(); + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + */ + } + + public DataStore getTargetDataStore() + { + return targetDataStore; + } + + protected void createTargetDataStore() throws JobExecutionException + { + if (targetDataStore != null) + { + targetDataStore.dispose(); + targetDataStore = null; + } + + /* + if (!isDriverFound()) + { + throw new JobExecutionException("Oracle JDBC Driver not found.-" + JDBC_DRIVER); + } + */ + + if (!sdoProperties.containsKey(OracleDataStoreFactory.MAXCONN.key)) + { + sdoProperties.put(OracleDataStoreFactory.MAXCONN.key, "2"); + } + + if (!sdoProperties.containsKey(OracleDataStoreFactory.MINCONN.key)) + { + sdoProperties.put(OracleDataStoreFactory.MINCONN.key, "1"); + } + + /* + if (!sdoProperties.containsKey(OracleDataStoreFactory.WKBENABLED.key)) + { + sdoProperties.put(OracleDataStoreFactory.WKBENABLED.key, "true"); + } + */ + + if (!dataStoreFactory.canProcess(sdoProperties)) + { + getLogger().warn("cannot process properties-"); + throw new JobExecutionException("cannot process properties-"); + } + try + { + targetDataStore = (OracleDataStore) dataStoreFactory.createDataStore(sdoProperties); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2PostGISJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2PostGISJob.java new file mode 100644 index 0000000..47e8f13 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2PostGISJob.java @@ -0,0 +1,1118 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.Date; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.collections.OrderedMap; +import org.apache.commons.collections.OrderedMapIterator; +import org.apache.commons.collections.map.LinkedMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.data.DataStore; +import org.geotools.data.postgis.PostgisDataStore; +import org.geotools.data.postgis.PostgisDataStoreFactory; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleResultSet; +import oracle.sql.ARRAY; +import oracle.sql.BLOB; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.jobs.context.postgis.FeatureDgnConvertPostGISJobContext; +import com.ximple.eofms.jobs.context.postgis.GeneralDgnConvertPostGISJobContext; +import com.ximple.eofms.jobs.context.postgis.IndexDgnConvertPostGISJobContext; +import com.ximple.eofms.jobs.context.postgis.OracleConvertPostGISJobContext; +import com.ximple.eofms.util.BinConverter; +import com.ximple.eofms.util.ByteArrayCompressor; +import com.ximple.eofms.util.StringUtils; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Dgn7fileException; +import com.ximple.io.dgn7.Dgn7fileReader; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.ElementType; +import com.ximple.io.dgn7.IElementHandler; +import com.ximple.io.dgn7.Lock; +import com.ximple.io.dgn7.TextElement; +import com.ximple.util.PrintfFormat; + +public class OracleConvertDgn2PostGISJob extends AbstractOracleDatabaseJob +{ + final static Log logger = LogFactory.getLog(OracleConvertDgn2PostGISJob.class); + + private static final String PGHOST = "PGHOST"; + private static final String PGDDATBASE = "PGDDATBASE"; + private static final String PGPORT = "PGPORT"; + private static final String PGSCHEMA = "PGSCHEMA"; + private static final String PGUSER = "PGUSER"; + private static final String PGPASS = "PGPASS"; + private static final String USEWKB = "USEWKB"; + + private static final int FETCHSIZE = 30; + private static final int COMMITSIZE = 100; + + class Pair + { + Object first; + Object second; + + public Pair(Object first, Object second) + { + this.first = first; + this.second = second; + } + } + + protected static PostgisDataStoreFactory dataStoreFactory = new PostgisDataStoreFactory(); + + GeometryFactory _geomFactory = new GeometryFactory(); + protected String _pgHost; + protected String _pgDatabase; + protected String _pgPort; + protected String _pgSchema; + protected String _pgUsername; + protected String _pgPassword; + protected String _pgUseWKB; + + protected Map<String, String> pgProperties; + protected PostgisDataStore targetDataStore; + // protected OracleConvertPostGISJobContext oracleJobContext; + + public Log getLogger() + { + return logger; + } + + protected AbstractOracleJobContext prepareJobContext(String filterPath) + { + /* + if (oracleJobContext == null) + { + oracleJobContext = new OracleConvertPostGISJobContext(getDataPath(), getTargetDataStore(), filterPath); + } + return oracleJobContext; + */ + return new OracleConvertPostGISJobContext(getDataPath(), getTargetDataStore(), filterPath); + } + + protected void extractJobConfiguration(JobDetail jobDetail) throws JobExecutionException + { + super.extractJobConfiguration(jobDetail); + JobDataMap dataMap = jobDetail.getJobDataMap(); + _pgHost = dataMap.getString(PGHOST); + _pgDatabase = dataMap.getString(PGDDATBASE); + _pgPort = dataMap.getString(PGPORT); + _pgSchema = dataMap.getString(PGSCHEMA); + _pgUsername = dataMap.getString(PGUSER); + _pgPassword = dataMap.getString(PGPASS); + _pgUseWKB = dataMap.getString(USEWKB); + + Log logger = getLogger(); + /* + logger.info("PGHOST=" + _myHost); + logger.info("PGDDATBASE=" + _myDatabase); + logger.info("PGPORT=" + _myPort); + logger.info("PGSCHEMA=" + _mySchema); + logger.info("PGUSER=" + _myUsername); + logger.info("PGPASS=" + _myPassword); + logger.info("USEWKB=" + _myUseWKB); + */ + + if (_pgHost == null) + { + logger.warn("PGHOST is null"); + throw new JobExecutionException("Unknown PostGIS host."); + } + if (_pgDatabase == null) + { + logger.warn("PGDATABASE is null"); + throw new JobExecutionException("Unknown PostGIS database."); + } + if (_pgPort == null) + { + logger.warn("PGPORT is null"); + throw new JobExecutionException("Unknown PostGIS port."); + } + if (_pgSchema == null) + { + logger.warn("PGSCHEMA is null"); + throw new JobExecutionException("Unknown PostGIS schema."); + } + if (_pgUsername == null) + { + logger.warn("PGUSERNAME is null"); + throw new JobExecutionException("Unknown PostGIS username."); + } + if (_pgPassword == null) + { + logger.warn("PGPASSWORD is null"); + throw new JobExecutionException("Unknown PostGIS password."); + } + + Map<String, String> remote = new TreeMap<String, String>(); + remote.put("dbtype", "postgis"); + remote.put("charset", "UTF-8"); + remote.put("host", _pgHost); + remote.put("port", _pgPort); + remote.put("database", _pgDatabase); + remote.put("user", _pgUsername); + remote.put("passwd", _pgPassword); + remote.put("namespace", null); + pgProperties = remote; + } + + public void execute(JobExecutionContext context) throws JobExecutionException + { + // Every job has its own job detail + JobDetail jobDetail = context.getJobDetail(); + + // The name is defined in the job definition + String jobName = jobDetail.getName(); + + // Log the time the job started + logger.info(jobName + " fired at " + new Date()); + extractJobConfiguration(jobDetail); + createSourceDataStore(); + createTargetDataStore(); + if (getSourceDataStore() == null) + { + logger.warn("Cannot connect source oracle database."); + throw new JobExecutionException("Cannot connect source oracle database."); + } + + if (getTargetDataStore() == null) + { + logger.warn("Cannot connect source postgreSQL database."); + throw new JobExecutionException("Cannot connect source postgreSQL database."); + } + + long t1 = System.currentTimeMillis(); + try + { + logger.info("-- step:clearOutputDatabase --"); + clearOutputDatabase(); + if (checkConvertDB()) + { + logger.info("-- step:convertOracleDB --"); + + OracleConvertPostGISJobContext jobContext = + (OracleConvertPostGISJobContext) prepareJobContext(_filterPath); + jobContext.setSourceDataStore(getSourceDataStore()); + // jobContext.setConvertElementIn(_convertElementIn); + jobContext.setElementLogging(checkElementLogging()); + jobContext.setExecutionContext(context); + if (isCopyConnectivityMode()) + copyConnectivity(jobContext); + + for (String orgSchema : _orgSchema) + { + logger.info("----- start schema:" + orgSchema + " -----"); + exetcuteConvert(jobContext, orgSchema, _dataPath); + + //close all open filewriter instance + jobContext.closeFeatureWriter(); + } + } + + if (checkConvertFile()) + { + logger.info("-- step:convertIndexDesignFile --"); + convertIndexDesignFile(context); + logger.info("-- step:convertOtherDesignFile --"); + convertOtherDesignFile(context); + } + + if (checkConvertElementIn()) + { + logger.info("-- step:convertFeatureDesignFile --"); + convertFeatureDesignFile(context); + } + + if (checkCreateDummy()) + { + logger.info("-- step:createDummyFeatureFile --"); + createDummyFeatureFile(context); + } + + disconnect(); + long t2 = System.currentTimeMillis(); + // public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss"; + // SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW); + logger.warn("use time = " + ((int) ((t2 - t1) / 60000.0)) + " min - " + + (((int) ((t2 - t1) % 60000.0)) / 1000) + " sec"); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException("Database error. " + e.getMessage(), e); + } catch (IOException ex) + { + logger.warn(ex.getMessage(), ex); + throw new JobExecutionException("IO error. " + ex.getMessage(), ex); + } + logger.info(jobName + " end at " + new Date()); + } + + /** + * Connectivity�ƻs�@�Ӫ����A�b�d�߹q�y��V�ɥΨӤ��OMS��Ʈw���q���s����(Connectivity) + * + * @param jobContext job context + * @throws SQLException sql exception + */ + private void copyConnectivity(OracleConvertPostGISJobContext jobContext) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + Statement stmt = connection.createStatement(); + stmt.execute(AbstractOracleJobContext.TRUNCATE_CONNECTIVITY_WEBCHECK); + stmt.execute(AbstractOracleJobContext.COPY_CONNECTIVITY_TO_WEBCHECK); + stmt.close(); + } + + private void exetcuteConvert(OracleConvertPostGISJobContext jobContext, + String querySchema, String dataPath) throws SQLException + { + int order = 0; + OrderedMap map = getBlobStorageList(jobContext.getOracleConnection(), + querySchema, "SD$SPACENODES", null); + + logger.info("begin convert job:[" + map.size() + "]:testmode=" + _testMode); + + int total = map.size(); //spacenodes count + int step = total / 100; + int current = 0; + + //jobContext.startTransaction(); + jobContext.setCurrentSchema(querySchema); + jobContext.getExecutionContext().put("ConvertDgn2PostGISJobProgress", 0); + for (OrderedMapIterator it = map.orderedMapIterator(); it.hasNext();) + { + it.next(); + + Pair pair = (Pair) it.getValue(); + String tableSrc = (String) pair.first; + + logger.info("begin convert:[" + order + "]-" + tableSrc); + queryIgsetElement(jobContext, querySchema, tableSrc); + + order++; + + if (_testMode) + { + if ((_testCount < 0) || (order >= _testCount)) + break; + } + + if ((order % COMMITSIZE) == 0) + { + // OracleConnection connection = jobContext.getOracleConnection(); + // connection.commitTransaction(); + jobContext.commitTransaction(); + //jobContext.startTransaction(); + System.gc(); + System.runFinalization(); + } + + int now = order % step; + if (now != current) + { + current = now; + jobContext.getExecutionContext().put("ConvertDgn2PostGISJobProgress", current); + + } + } + jobContext.getExecutionContext().put("ConvertDgn2PostGISJobProgress", 100); + + jobContext.commitTransaction(); + jobContext.resetFeatureContext(); + logger.info("end convert job:[" + order + "]"); + System.gc(); + System.runFinalization(); + } + + protected OrderedMap getBlobStorageList(Connection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT SNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + ResultSet rs = null; + + stmt.setFetchSize(FETCHSIZE); + try + { + rs = stmt.executeQuery(fetchStmt); + int size = rs.getMetaData().getColumnCount(); + + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(name, null)); + else + pair.first = name; + } + } catch (SQLException e) + { + logger.error(e.toString(), e); + logger.error("stmt=" + fetchStmt); + throw e; + } finally + { + if (rs != null) rs.close(); + stmt.close(); + } + + return orderedMap; + } + + protected OrderedMap getRawFormatStorageList(OracleConnection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT RNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmt.setFetchSize(FETCHSIZE); + ResultSet rs = stmt.executeQuery(fetchStmt); + try + { + int size = rs.getMetaData().getColumnCount(); + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(null, name)); + else + pair.second = name; + } + } finally + { + rs.close(); + stmt.close(); + } + return orderedMap; + } + + protected void queryIgsetElement(OracleConvertPostGISJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchSrcStmtFmt); + String fetchSrcStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtSrc = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtSrc.setFetchSize(FETCHSIZE); + ResultSet rsSrc = stmtSrc.executeQuery(fetchSrcStmt); + int igdsMetaType = rsSrc.getMetaData().getColumnType(1); + while (rsSrc.next()) + { + byte[] raw; + if (igdsMetaType == Types.BLOB) + { + BLOB blob = (BLOB) rsSrc.getBlob(1); + + raw = getBytesFromBLOB(blob); + blob.close(); + } else + { + raw = rsSrc.getBytes(1); + } + + try + { + Element element = fetchBinaryElement(raw); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception", e); + } + } + + rsSrc.close(); + stmtSrc.close(); + } + + protected void queryRawElement(OracleConvertPostGISJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchDestStmtFmt = "SELECT ELEMENT FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchDestStmtFmt); + String fetchDestStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtDest = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtDest.setFetchSize(FETCHSIZE); + ResultSet rsDest = stmtDest.executeQuery(fetchDestStmt); + + try + { + while (rsDest.next()) + { + ARRAY rawsValue = ((OracleResultSet) rsDest).getARRAY(1); + long[] rawData = rawsValue.getLongArray(); + byte[] comparessedValue; + + /* + if (dataMode == TransferTask.DataMode.Normal) + { + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + } else + { + comparessedValue = BinConverter.unmarshalCompactByteArray(rawData); + } + */ + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + + byte[] rawDest = ByteArrayCompressor.decompressByteArray(comparessedValue); + + + try + { + Element element = fetchBinaryElement(rawDest); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception:" + e.getMessage(), e); + } + } + } finally + { + rsDest.close(); + stmtDest.close(); + } + } + + // Binary to Element + private Element fetchBinaryElement(byte[] raws) throws Dgn7fileException + { + ByteBuffer buffer = ByteBuffer.wrap(raws); + buffer.order(ByteOrder.LITTLE_ENDIAN); + short signature = buffer.getShort(); + + // byte type = (byte) (buffer.get() & 0x7f); + byte type = (byte) ((signature >>> 8) & 0x007f); + + // silly Bentley say contentLength is in 2-byte words + // and ByteByffer uses raws. + // track the record location + int elementLength = (buffer.getShort() * 2) + 4; + ElementType recordType = ElementType.forID(type); + IElementHandler handler; + + handler = recordType.getElementHandler(); + + Element dgnElement = (Element) handler.read(buffer, signature, elementLength); + if (recordType.isComplexElement() && (elementLength < raws.length)) + { + int offset = elementLength; + while (offset < (raws.length - 4)) + { + buffer.position(offset); + signature = buffer.getShort(); + type = (byte) ((signature >>> 8) & 0x007f); + elementLength = (buffer.getShort() * 2) + 4; + if (raws.length < (offset + elementLength)) + { + System.out.println("Length not match:" + offset + ":" + buffer.position() + ":" + buffer.limit()); + break; + } + recordType = ElementType.forID(type); + handler = recordType.getElementHandler(); + if (handler != null) + { + Element subElement = (Element) handler.read(buffer, signature, elementLength); + ((ComplexElement) dgnElement).add(subElement); + offset += elementLength; + } else + { + byte[] remain = new byte[buffer.remaining()]; + System.arraycopy(raws, offset, remain, 0, buffer.remaining()); + for (int i = 0; i < remain.length; i++) + { + if (remain[i] != 0) + { + logger.info("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + System.out.println("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + } + } + break; + } + } + } + + return dgnElement; + } + + /** + * �����ഫ�����ɪ��u�@ + * + * @param context �u�@�������� + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertIndexDesignFile(JobExecutionContext context) throws JobExecutionException + { + File indexDir = new File(getDataPath(), "index"); + if (!indexDir.exists()) + { + logger.info("index dir=" + indexDir + " not exist."); + return; + } + + if (!indexDir.isDirectory()) + { + logger.info("index dir=" + indexDir + " is not a directory."); + } + + File[] dgnFiles = indexDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + IndexDgnConvertPostGISJobContext convertContext = + new IndexDgnConvertPostGISJobContext(getDataPath(), getTargetDataStore()); + logger.debug("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.clearOutputDatabase(); + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanIndexDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + protected void scanIndexDgnElement(IndexDgnConvertPostGISJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + lastComplex = null; + } + + processIndexElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processIndexElement(Element element, IndexDgnConvertPostGISJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + if (element instanceof TextElement) + { + convertContext.putFeatureCollection(element); + } + } + + + /** + * �����ഫ��L�]�p���ɪ��u�@ + * + * @param context jobContext + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertOtherDesignFile(JobExecutionContext context) throws JobExecutionException + { + File otherDir = new File(getDataPath(), "other"); + if (!otherDir.exists()) + { + logger.info("other dir=" + otherDir + " not exist."); + return; + } + + if (!otherDir.isDirectory()) + { + logger.info("other dir=" + otherDir + " is not a directory."); + } + + File[] dgnFiles = otherDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + GeneralDgnConvertPostGISJobContext convertContext = + new GeneralDgnConvertPostGISJobContext(getDataPath(), getTargetDataStore()); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanOtherDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanOtherDgnElement(GeneralDgnConvertPostGISJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + lastComplex = null; + } + + processOtherElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processOtherElement(Element element, GeneralDgnConvertPostGISJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void clearOutputDatabase() + { + /* + File outDataPath = new File(getDataPath(), OracleConvertPostGISJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), IndexDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), GeneralDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + */ + } + + private void deleteFilesInPath(File outDataPath) + { + deleteFilesInPath(outDataPath, true); + } + + private void deleteFilesInPath(File outDataPath, boolean removeSubDir) + { + if (!outDataPath.isDirectory()) + { + return; + } + File[] files = outDataPath.listFiles(); + for (File file : files) + { + if (file.isFile()) + { + if (!file.delete()) + { + logger.info("Cannot delete file-" + file.toString()); + } + } else if (file.isDirectory()) + { + deleteFilesInPath(file, removeSubDir); + if (removeSubDir) + { + if (file.delete()) + { + logger.info("Cannot delete dir-" + file.toString()); + } + } + } + } + } + + private void convertFeatureDesignFile(JobExecutionContext context) throws JobExecutionException + { + File elminDir = new File(getDataPath(), "elmin"); + if (!elminDir.exists()) + { + logger.info("elmin dir=" + elminDir + " not exist."); + return; + } + + if (!elminDir.isDirectory()) + { + logger.info("elmin dir=" + elminDir + " is not a directory."); + } + + File[] dgnFiles = elminDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + FeatureDgnConvertPostGISJobContext convertContext = + new FeatureDgnConvertPostGISJobContext(getDataPath(), getTargetDataStore(), _filterPath); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanFeatureDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanFeatureDgnElement(FeatureDgnConvertPostGISJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + lastComplex = null; + } + + processFeatureElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processFeatureElement(Element element, FeatureDgnConvertPostGISJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void createDummyFeatureFile(JobExecutionContext context) throws JobExecutionException + { + /* + DummyFeatureConvertShpJobContext convertContext = new DummyFeatureConvertShpJobContext(getDataPath(), _filterPath); + try { + convertContext.startTransaction(); + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + */ + } + + public DataStore getTargetDataStore() + { + return targetDataStore; + } + + protected void createTargetDataStore() throws JobExecutionException + { + if (targetDataStore != null) + { + targetDataStore.dispose(); + targetDataStore = null; + } + + /* + if (!isDriverFound()) + { + throw new JobExecutionException("Oracle JDBC Driver not found.-" + JDBC_DRIVER); + } + */ + + if (!pgProperties.containsKey(PostgisDataStoreFactory.MAXCONN.key)) + { + pgProperties.put(PostgisDataStoreFactory.MAXCONN.key, "10"); + } + + if (!pgProperties.containsKey(PostgisDataStoreFactory.MINCONN.key)) + { + pgProperties.put(PostgisDataStoreFactory.MINCONN.key, "1"); + } + + if (!pgProperties.containsKey(PostgisDataStoreFactory.WKBENABLED.key)) + { + pgProperties.put(PostgisDataStoreFactory.WKBENABLED.key, "true"); + } + + if (!dataStoreFactory.canProcess(pgProperties)) + { + getLogger().warn("cannot process properties-"); + throw new JobExecutionException("cannot process properties-"); + } + try + { + targetDataStore = (PostgisDataStore) dataStoreFactory.createDataStore(pgProperties); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java new file mode 100644 index 0000000..4777d94 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java @@ -0,0 +1,958 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.sql.Connection; +import java.util.Date; + +import org.apache.commons.collections.OrderedMap; +import org.apache.commons.collections.OrderedMapIterator; +import org.apache.commons.collections.map.LinkedMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleResultSet; +import oracle.sql.ARRAY; +import oracle.sql.BLOB; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.jobs.context.shapefile.FeatureDgnConvertShpJobContext; +import com.ximple.eofms.jobs.context.shapefile.GeneralDgnConvertShpJobContext; +import com.ximple.eofms.jobs.context.shapefile.IndexDgnConvertShpJobContext; +import com.ximple.eofms.jobs.context.shapefile.OracleConvertShapefilesJobContext; +import com.ximple.eofms.util.BinConverter; +import com.ximple.eofms.util.ByteArrayCompressor; +import com.ximple.eofms.util.StringUtils; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Dgn7fileException; +import com.ximple.io.dgn7.Dgn7fileReader; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.ElementType; +import com.ximple.io.dgn7.IElementHandler; +import com.ximple.io.dgn7.Lock; +import com.ximple.io.dgn7.TextElement; +import com.ximple.util.PrintfFormat; + +/** + * + */ +public class OracleConvertDgn2ShpJob extends AbstractOracleDatabaseJob +{ + final static Log logger = LogFactory.getLog(OracleConvertDgn2ShpJob.class); + + private static final int FETCHSIZE = 30; + private static final int COMMITSIZE = 20; + + class Pair + { + Object first; + Object second; + + public Pair(Object first, Object second) + { + this.first = first; + this.second = second; + } + } + + GeometryFactory _geomFactory = new GeometryFactory(); + + public Log getLogger() + { + return logger; + } + + protected AbstractOracleJobContext prepareJobContext(String filterPath) + { + return new OracleConvertShapefilesJobContext(filterPath); + } + + protected void extractJobConfiguration(JobDetail jobDetail) throws JobExecutionException + { + super.extractJobConfiguration(jobDetail); + } + + public void execute(JobExecutionContext context) throws JobExecutionException + { + // Every job has its own job detail + JobDetail jobDetail = context.getJobDetail(); + + // The name is defined in the job definition + String jobName = jobDetail.getName(); + + // Log the time the job started + logger.info(jobName + " fired at " + new Date()); + extractJobConfiguration(jobDetail); + createSourceDataStore(); + if (getSourceDataStore() == null) + { + throw new JobExecutionException("Cannot connect source oracle database."); + } + + try + { + logger.info("-- step:clearOutputDirectory --"); + clearOutputDirectory(); + boolean bFirst = isCopyConnectivityMode(); + if (checkConvertDB()) + { + logger.info("-- step:convertOracleDB --"); + + for (String orgSchema : _orgSchema) + { + OracleConvertShapefilesJobContext jobContext = (OracleConvertShapefilesJobContext) prepareJobContext(_filterPath); + jobContext.setSourceDataStore(getSourceDataStore()); + jobContext.setDataPath(_dataPath); + jobContext.setConvertElementIn(_convertElementIn); + jobContext.setElementLogging(checkElementLogging()); + jobContext.setExecutionContext(context); + + if (bFirst) + { + copyConnectivity(jobContext); + bFirst = false; + } + + logger.info("----- start schema:" + orgSchema + " -----"); + exetcuteConvert(jobContext, orgSchema, _dataPath); + + //close all open filewriter instance + jobContext.closeFeatureWriter(); + } + } + + if (checkConvertFile()) + { + logger.info("-- step:convertIndexDesignFile --"); + convertIndexDesignFile(context); + logger.info("-- step:convertOtherDesignFile --"); + convertOtherDesignFile(context); + } + + if (checkConvertElementIn()) + { + logger.info("-- step:convertFeatureDesignFile --"); + convertFeatureDesignFile(context); + } + + if (checkCreateDummy()) + { + logger.info("-- step:createDummyFeatureFile --"); + createDummyFeatureFile(context); + } + + disconnect(); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException("Database error. " + e.getMessage(), e); + } catch (IOException ex) + { + logger.warn(ex.getMessage(), ex); + throw new JobExecutionException("IO error. " + ex.getMessage(), ex); + } + logger.info(jobName + " end at " + new Date()); + } + + /** + * Connectivity�ƻs�@�Ӫ����A�b�d�߹q�y��V�ɥΨӤ��OMS��Ʈw���q���s����(Connectivity) + * + * @param jobContext job context + * @throws SQLException sql exception + */ + private void copyConnectivity(OracleConvertShapefilesJobContext jobContext) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + Statement stmt = connection.createStatement(); + stmt.execute(OracleConvertShapefilesJobContext.TRUNCATE_CONNECTIVITY_WEBCHECK); + stmt.execute(OracleConvertShapefilesJobContext.COPY_CONNECTIVITY_TO_WEBCHECK); + } + + private void exetcuteConvert(OracleConvertShapefilesJobContext jobContext, + String querySchema, String dataPath) throws SQLException + { + int order = 0; + OrderedMap map = getBlobStorageList(jobContext.getOracleConnection(), querySchema, "SD$SPACENODES" + , null); + + logger.info("begin convert job:[" + map.size() + "]:testmode=" + _testMode); + + int total = map.size(); //spacenodes count + int step = total / 100; + int current = 0; + + //jobContext.startTransaction(); + jobContext.setCurrentSchema(querySchema); + jobContext.getExecutionContext().put("ConvertDgn2ShpJobProgress", 0); + for (OrderedMapIterator it = map.orderedMapIterator(); it.hasNext();) + { + it.next(); + + Pair pair = (Pair) it.getValue(); + String tableSrc = (String) pair.first; + + logger.info("begin convert:[" + order + "]-" + tableSrc); + queryIgsetElement(jobContext, querySchema, tableSrc); + + order++; + + if (_testMode) + { + if ((_testCount < 0) || (order >= _testCount)) + break; + } + + if ((order % COMMITSIZE) == 0) + { + // OracleConnection connection = jobContext.getOracleConnection(); + // connection.commitTransaction(); + jobContext.commitTransaction(); + //jobContext.startTransaction(); + System.gc(); + System.runFinalization(); + } + + int now = order % step; + if (now != current) + { + current = now; + jobContext.getExecutionContext().put("ConvertDgn2ShpJobProgress", current); + + } + } + jobContext.getExecutionContext().put("ConvertDgn2ShpJobProgress", 100); + + jobContext.commitTransaction(); + + logger.info("end convert job:[" + order + "]"); + System.gc(); + System.runFinalization(); + } + + protected OrderedMap getBlobStorageList(Connection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT SNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + ResultSet rs = null; + + stmt.setFetchSize(FETCHSIZE); + + try + { + rs = stmt.executeQuery(fetchStmt); + int size = rs.getMetaData().getColumnCount(); + + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(name, null)); + else + pair.first = name; + } + } catch (SQLException e) + { + logger.error(e.toString(), e); + logger.error("stmt=" + fetchStmt); + throw e; + } finally + { + if (rs != null) rs.close(); + stmt.close(); + } + + return orderedMap; + } + + protected OrderedMap getRawFormatStorageList(OracleConnection connection, String schemaSrc, String tableSrc, + OrderedMap orderedMap) throws SQLException + { + if (orderedMap == null) + orderedMap = new LinkedMap(99); + String fetchStmtFmt = "SELECT RNID, SPACETABLE FROM \"%s\".\"%s\""; + PrintfFormat spf = new PrintfFormat(fetchStmtFmt); + String fetchStmt = spf.sprintf(new Object[]{schemaSrc, tableSrc}); + Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmt.setFetchSize(FETCHSIZE); + ResultSet rs = stmt.executeQuery(fetchStmt); + int size = rs.getMetaData().getColumnCount(); + + while (rs.next()) + { + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) + { + values[i] = rs.getObject(i + 1); + } + + Integer key = ((BigDecimal) values[0]).intValue(); + String name = (String) values[1]; + + Pair pair = (Pair) orderedMap.get(key); + if (pair == null) + orderedMap.put(key, new Pair(null, name)); + else + pair.second = name; + } + + rs.close(); + stmt.close(); + + return orderedMap; + } + + protected void queryIgsetElement(OracleConvertShapefilesJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchSrcStmtFmt); + String fetchSrcStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtSrc = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtSrc.setFetchSize(FETCHSIZE); + + ResultSet rsSrc = stmtSrc.executeQuery(fetchSrcStmt); + int igdsMetaType = rsSrc.getMetaData().getColumnType(1); + while (rsSrc.next()) + { + byte[] raw; + + if (igdsMetaType == Types.BLOB) + { + BLOB blob = (BLOB) rsSrc.getBlob(1); + + raw = getBytesFromBLOB(blob); + blob.close(); + } else + { + raw = rsSrc.getBytes(1); + } + + try + { + Element element = fetchBinaryElement(raw); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception", e); + } + } + + rsSrc.close(); + stmtSrc.close(); + } + + protected void queryRawElement(OracleConvertShapefilesJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + String fetchDestStmtFmt = "SELECT ELEMENT FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchDestStmtFmt); + String fetchDestStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtDest = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtDest.setFetchSize(FETCHSIZE); + + ResultSet rsDest = stmtDest.executeQuery(fetchDestStmt); + + while (rsDest.next()) + { + ARRAY rawsValue = ((OracleResultSet) rsDest).getARRAY(1); + long[] rawData = rawsValue.getLongArray(); + byte[] comparessedValue; + + /* + if (dataMode == TransferTask.DataMode.Normal) + { + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + } else + { + comparessedValue = BinConverter.unmarshalCompactByteArray(rawData); + } + */ + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + + byte[] rawDest = ByteArrayCompressor.decompressByteArray(comparessedValue); + + + try + { + Element element = fetchBinaryElement(rawDest); + jobContext.putFeatureCollection(element); + } catch (Dgn7fileException e) + { + logger.warn("Dgn7Exception:" + e.getMessage(), e); + } + } + + rsDest.close(); + stmtDest.close(); + } + + // Binary to Element + private Element fetchBinaryElement(byte[] raws) throws Dgn7fileException + { + ByteBuffer buffer = ByteBuffer.wrap(raws); + buffer.order(ByteOrder.LITTLE_ENDIAN); + short signature = buffer.getShort(); + + // byte type = (byte) (buffer.get() & 0x7f); + byte type = (byte) ((signature >>> 8) & 0x007f); + + // silly Bentley say contentLength is in 2-byte words + // and ByteByffer uses raws. + // track the record location + int elementLength = (buffer.getShort() * 2) + 4; + ElementType recordType = ElementType.forID(type); + IElementHandler handler; + + handler = recordType.getElementHandler(); + + Element dgnElement = (Element) handler.read(buffer, signature, elementLength); + if (recordType.isComplexElement() && (elementLength < raws.length)) + { + int offset = elementLength; + while (offset < (raws.length - 4)) + { + buffer.position(offset); + signature = buffer.getShort(); + type = (byte) ((signature >>> 8) & 0x007f); + elementLength = (buffer.getShort() * 2) + 4; + if (raws.length < (offset + elementLength)) + { + System.out.println("Length not match:" + offset + ":" + buffer.position() + ":" + buffer.limit()); + break; + } + recordType = ElementType.forID(type); + handler = recordType.getElementHandler(); + if (handler != null) + { + Element subElement = (Element) handler.read(buffer, signature, elementLength); + ((ComplexElement) dgnElement).add(subElement); + offset += elementLength; + } else + { + byte[] remain = new byte[buffer.remaining()]; + System.arraycopy(raws, offset, remain, 0, buffer.remaining()); + for (int i = 0; i < remain.length; i++) + { + if (remain[i] != 0) + { + logger.info("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + System.out.println("fetch element has some error. index=" + (offset + i) + ":value=" + remain[i]); + } + } + break; + } + } + } + + return dgnElement; + } + + /** + * �����ഫ�����ɪ��u�@ + * + * @param context �u�@�������� + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertIndexDesignFile(JobExecutionContext context) throws JobExecutionException + { + File indexDir = new File(getDataPath(), "index"); + if (!indexDir.exists()) + { + logger.info("index dir=" + indexDir + " not exist."); + return; + } + + if (!indexDir.isDirectory()) + { + logger.info("index dir=" + indexDir + " is not a directory."); + } + + File[] dgnFiles = indexDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + IndexDgnConvertShpJobContext convertContext = new IndexDgnConvertShpJobContext(getDataPath()); + logger.debug("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanIndexDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + protected void scanIndexDgnElement(IndexDgnConvertShpJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + lastComplex = null; + } + + processIndexElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processIndexElement(lastComplex, convertContext); + } + + logger.debug("ElementRecord Count=" + count); + } + + private void processIndexElement(Element element, IndexDgnConvertShpJobContext convertContext) throws IllegalAttributeException, SchemaException + { + if (element instanceof TextElement) + { + convertContext.putFeatureCollection(element); + } + } + + + /** + * �����ഫ��L�]�p���ɪ��u�@ + * + * @param context jobContext + * @throws org.quartz.JobExecutionException + * exception + */ + private void convertOtherDesignFile(JobExecutionContext context) throws JobExecutionException + { + File otherDir = new File(getDataPath(), "other"); + if (!otherDir.exists()) + { + logger.info("other dir=" + otherDir + " not exist."); + return; + } + + if (!otherDir.isDirectory()) + { + logger.info("other dir=" + otherDir + " is not a directory."); + } + + File[] dgnFiles = otherDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + GeneralDgnConvertShpJobContext convertContext = new GeneralDgnConvertShpJobContext(getDataPath()); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanOtherDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanOtherDgnElement(GeneralDgnConvertShpJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + lastComplex = null; + } + + processOtherElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processOtherElement(lastComplex, convertContext); + } + + logger.debug("ElementRecord Count=" + count); + } + + private void processOtherElement(Element element, GeneralDgnConvertShpJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void clearOutputDirectory() + { + File outDataPath = new File(getDataPath(), OracleConvertShapefilesJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), IndexDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + outDataPath = new File(getDataPath(), GeneralDgnConvertShpJobContext.SHPOUTPATH); + if (outDataPath.exists() && outDataPath.isDirectory()) + { + deleteFilesInPath(outDataPath); + } + } + + private void deleteFilesInPath(File outDataPath) + { + deleteFilesInPath(outDataPath, true); + } + + private void deleteFilesInPath(File outDataPath, boolean removeSubDir) + { + if (!outDataPath.isDirectory()) + { + return; + } + File[] files = outDataPath.listFiles(); + for (File file : files) + { + if (file.isFile()) + { + if (!file.delete()) + { + logger.info("Cannot delete file-" + file.toString()); + } + } else if (file.isDirectory()) + { + deleteFilesInPath(file, removeSubDir); + if (removeSubDir) + { + if (file.delete()) + { + logger.info("Cannot delete dir-" + file.toString()); + } + } + } + } + } + + private void convertFeatureDesignFile(JobExecutionContext context) throws JobExecutionException + { + File elminDir = new File(getDataPath(), "elmin"); + if (!elminDir.exists()) + { + logger.info("elmin dir=" + elminDir + " not exist."); + return; + } + + if (!elminDir.isDirectory()) + { + logger.info("elmin dir=" + elminDir + " is not a directory."); + } + + File[] dgnFiles = elminDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + FeatureDgnConvertShpJobContext convertContext = new FeatureDgnConvertShpJobContext(getDataPath(), _filterPath); + logger.info("--- start dgnfile-" + dgnFile.toString() + " ---"); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.separator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + convertContext.startTransaction(); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanFeatureDgnElement(convertContext); + + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + System.gc(); + System.runFinalization(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + public void scanFeatureDgnElement(FeatureDgnConvertShpJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + lastComplex = null; + } + + processFeatureElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + lastComplex = element; + } + } + count++; + } + + if (lastComplex != null) + { + processFeatureElement(lastComplex, convertContext); + } + logger.debug("ElementRecord Count=" + count); + } + + private void processFeatureElement(Element element, FeatureDgnConvertShpJobContext convertContext) + throws IllegalAttributeException, SchemaException + { + convertContext.putFeatureCollection(element); + } + + private void createDummyFeatureFile(JobExecutionContext context) throws JobExecutionException + { + /* + DummyFeatureConvertShpJobContext convertContext = new DummyFeatureConvertShpJobContext(getDataPath(), _filterPath); + try { + convertContext.startTransaction(); + convertContext.commitTransaction(); + convertContext.closeFeatureWriter(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + */ + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleElementLogger.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleElementLogger.java new file mode 100644 index 0000000..2b146b3 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleElementLogger.java @@ -0,0 +1,420 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.ArrayList; +import java.util.ListIterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.vividsolutions.jts.util.Assert; + +import oracle.sql.BLOB; + +import com.ximple.eofms.util.PrintfFormat; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.ComplexShapeElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.EllipseElement; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.ShapeElement; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.TextNodeElement; +import com.ximple.io.dgn7.IElementHandler; +import com.ximple.io.dgn7.Dgn7fileException; + +public class OracleElementLogger +{ + static Log logger = LogFactory.getLog(OracleElementLogger.class); + private static final String DEFAULT_ELMOUTPATH = "elmout"; + private static final String TAB_IGDSSEED = "SD$IGDSSET_SEED"; + + private Connection connection; + private String dataOut = null; + private String dataPath; + private String currentSchema; + private boolean schemaChanged; + private FileOutputStream fos = null; + private FileChannel fch = null; + private int logCount = 0; + private ArrayList<byte[]> dgnFileHeader = null; + private String elmOutPath; + + public OracleElementLogger(Connection connection) + { + this.connection = connection; + elmOutPath = DEFAULT_ELMOUTPATH; + } + + public OracleElementLogger(Connection connection, String elmOutPath) + { + this.connection = connection; + this.elmOutPath = elmOutPath; + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), elmOutPath); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public String getDataPath() + { + return dataPath; + } + + public void setDataPath(String dataPath) + { + this.dataPath = dataPath; + } + + public void logElement(Element element, String currentSchema) + { + if ((this.currentSchema == null) || + (!this.currentSchema.equalsIgnoreCase(currentSchema))) + { + schemaChanged = true; + this.currentSchema = currentSchema; + try + { + createNewStream(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + return; + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + return; + } + } else + { + if (fch == null) + { + try + { + createNewStream(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + return; + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + return; + } + } + } + + ArrayList<ByteBuffer> subBuffers = new ArrayList<ByteBuffer>(); + if (fch != null) + { + ByteBuffer buf = null; + if (element instanceof LineElement) + { + int size = LineElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + LineElement.ElementHandler.getInstance().write(buf, element); + } else if (element instanceof ShapeElement) + { + int size = ShapeElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + ShapeElement.ElementHandler.getInstance().write(buf, element); + } else if (element instanceof LineStringElement) + { + int size = LineStringElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + LineStringElement.ElementHandler.getInstance().write(buf, element); + } else if (element instanceof ComplexChainElement) + { + int size = ComplexChainElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + ComplexChainElement.ElementHandler.getInstance().write(buf, element); + ComplexChainElement complexElement = (ComplexChainElement) element; + ListIterator it = complexElement.listIterator(); + while (it.hasNext()) + { + Element subElm = (Element) it.next(); + try + { + IElementHandler handler = subElm.getElementType().getElementHandler(); + size = handler.getLength(subElm); + ByteBuffer subBuf = ByteBuffer.allocate(size * 2); + handler.write(subBuf, subElm); + subBuffers.add(subBuf); + } catch (Dgn7fileException e) + { + logger.warn(e.getMessage(), e); + } + } + } else if (element instanceof ComplexShapeElement) + { + int size = ComplexShapeElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + ComplexShapeElement.ElementHandler.getInstance().write(buf, element); + ComplexShapeElement complexElement = (ComplexShapeElement) element; + ListIterator it = complexElement.listIterator(); + while (it.hasNext()) + { + Element subElm = (Element) it.next(); + try + { + IElementHandler handler = subElm.getElementType().getElementHandler(); + size = handler.getLength(subElm); + ByteBuffer subBuf = ByteBuffer.allocate(size * 2); + handler.write(subBuf, subElm); + subBuffers.add(subBuf); + } catch (Dgn7fileException e) + { + logger.warn(e.getMessage(), e); + } + } + } else if (element instanceof ArcElement) + { + int size = ArcElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + ArcElement.ElementHandler.getInstance().write(buf, element); + } else if (element instanceof EllipseElement) + { + int size = EllipseElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + EllipseElement.ElementHandler.getInstance().write(buf, element); + } else if (element instanceof TextElement) + { + int size = TextElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + TextElement.ElementHandler.getInstance().write(buf, element); + } else if (element instanceof TextNodeElement) + { + int size = TextNodeElement.ElementHandler.getInstance().getLength(element); + buf = ByteBuffer.allocate(size * 2); + TextNodeElement.ElementHandler.getInstance().write(buf, element); + TextNodeElement nodeElement = (TextNodeElement) element; + ListIterator it = nodeElement.listIterator(); + while (it.hasNext()) + { + Element subElm = (Element) it.next(); + try + { + IElementHandler handler = subElm.getElementType().getElementHandler(); + size = handler.getLength(subElm); + ByteBuffer subBuf = ByteBuffer.allocate(size * 2); + handler.write(subBuf, subElm); + subBuffers.add(subBuf); + } catch (Dgn7fileException e) + { + logger.warn(e.getMessage(), e); + } + } + } + + if ((buf != null) && (fch != null)) + { + try + { + buf.position(0); + int size = fch.write(buf); + if (size != buf.limit()) + { + long position = fch.position(); + logger.info("Pos:" + position); + } + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } + } + } + + if ((subBuffers.size() != 0) && (fch != null)) + { + for (ByteBuffer buf : subBuffers) + { + try + { + buf.position(0); + int size = fch.write(buf); + if (size != buf.limit()) + { + long position = fch.position(); + logger.info("Pos:" + position); + } + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } + } + } + } + + private void createNewStream() throws IOException, SQLException + { + if (fos != null) + { + putEndOfFileElement(); + fos.close(); + fos = null; + fch = null; + } + + File logFile = new File(getDataOutPath(), this.currentSchema + ".dgn"); + while (logFile.exists()) + { + logFile = new File(getDataOutPath(), this.currentSchema + "-" + + (++logCount) + ".dgn"); + } + + logger.warn("Create Dgn Logging File:" + logFile.toString()); + fos = new FileOutputStream(logFile); + fch = fos.getChannel(); + + prepareOutputElementStream(); + schemaChanged = false; + } + + private void putEndOfFileElement() throws IOException + { + if (fch == null) + return; + ByteBuffer bf = ByteBuffer.allocate(4); + bf.putInt(-1); + fch.write(bf); + } + + private void prepareOutputElementStream() throws SQLException, IOException + { + if (connection == null) + { + logger.warn("connection is null"); + return; + } + + if (dgnFileHeader != null) + { + for (byte[] raw : dgnFileHeader) + { + putElementIntoStream(raw); + } + return; + } + + dgnFileHeader = new ArrayList<byte[]>(); + String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchSrcStmtFmt); + String fetchSrcStmt = spf.sprintf(new Object[]{currentSchema, TAB_IGDSSEED}); + Statement stmtSrc = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + ResultSet rsSrc = stmtSrc.executeQuery(fetchSrcStmt); + int igdsMetaType = rsSrc.getMetaData().getColumnType(1); + + while (rsSrc.next()) + { + byte[] raw; + + if (igdsMetaType == Types.BLOB) + { + BLOB blob = (BLOB) rsSrc.getBlob(1); + + raw = getBytesFromBLOB(blob); + blob.close(); + } else + { + raw = rsSrc.getBytes(1); + } + + if (raw != null) + { + dgnFileHeader.add(raw); + putElementIntoStream(raw); + } + } + rsSrc.close(); + stmtSrc.close(); + } + + private void putElementIntoStream(byte[] raw) throws IOException + { + if (fch != null) + fch.write(ByteBuffer.wrap(raw)); + } + + protected static byte[] getBytesFromBLOB(BLOB blob) throws SQLException + { + byte[] raw = null; + + int optimalSize = blob.getChunkSize(); + byte[] chunk = new byte[optimalSize]; + InputStream is = blob.getBinaryStream(0); + ByteBuffer buffer = null; // ByteBuffer.allocate(optimalSize); + int len; + + try + { + while ((len = (is.read(chunk))) != -1) + { + if (buffer != null) + { + buffer.limit(buffer.limit() + len); + } else + { + buffer = ByteBuffer.allocate(len); + } + + buffer.put(chunk); + } + + is.close(); + assert buffer != null; + buffer.position(0); + raw = buffer.array(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + Assert.shouldNeverReachHere(); + } + return raw; + } + + public void flashLogging() + { + if (fos != null) + { + try + { + fos.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } + fos = null; + fch = null; + } + } + + public boolean isSchemaChanged() + { + return schemaChanged; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java new file mode 100644 index 0000000..76865af --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java @@ -0,0 +1,73 @@ +package com.ximple.eofms.jobs; + +import java.sql.SQLException; +import java.sql.Connection; +import java.util.Date; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleDatabaseMetaData; +import oracle.jdbc.OracleStatement; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.jobs.context.OracleUpgradeJobContext; + +public class OracleUpgradeBlob2UDTJob extends AbstractOracleDatabaseJob +{ + static Log logger = LogFactory.getLog(OracleUpgradeBlob2UDTJob.class); + + public void execute(JobExecutionContext context) throws JobExecutionException + { + // Every job has its own job detail + JobDetail jobDetail = context.getJobDetail(); + + // The name is defined in the job definition + String jobName = jobDetail.getName(); + + // Log the time the job started + logger.info(jobName + " fired at " + new Date()); + extractJobConfiguration(jobDetail); + createSourceDataStore(); + if (getSourceDataStore() == null) + { + throw new JobExecutionException("Cannot connect source oracle database."); + } + + AbstractOracleJobContext jobContext = prepareJobContext(_filterPath); + jobContext.setSourceDataStore(getSourceDataStore()); + + try + { + for (String orgSchema : _orgSchema) + { + exetcuteConvert(jobContext, orgSchema, _dataPath); + } + } catch (SQLException e) + { + throw new JobExecutionException("Database error.", e); + } + } + + public Log getLogger() + { + return logger; + } + + protected AbstractOracleJobContext prepareJobContext(String filterPath) + { + return new OracleUpgradeJobContext(); + } + + private void exetcuteConvert(AbstractOracleJobContext jobContext, + String orgSchema, String dataPath) throws SQLException + { + Connection connection = jobContext.getOracleConnection(); + OracleDatabaseMetaData metaData = (OracleDatabaseMetaData) connection.getMetaData(); + OracleStatement statement = (OracleStatement) connection.createStatement(); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractDgnFileJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractDgnFileJobContext.java new file mode 100644 index 0000000..8448eaf --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractDgnFileJobContext.java @@ -0,0 +1,83 @@ +package com.ximple.eofms.jobs.context; + +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.quartz.JobExecutionContext; + +import com.ximple.io.dgn7.Dgn7fileReader; + +public abstract class AbstractDgnFileJobContext +{ + /** + * Encoding of URL path. + */ + protected static final String ENCODING = "UTF-8"; + + private JobExecutionContext executionContext = null; + + protected String _dataPath = null; + protected Map properties = null; + + private Dgn7fileReader reader = null; + private String filename = null; + private boolean _elementLogging; + + public AbstractDgnFileJobContext(String dataPath) + { + _dataPath = dataPath; + } + + public String getDataPath() + { + return _dataPath; + } + + public JobExecutionContext getExecutionContext() + { + return executionContext; + } + + public void setExecutionContext(JobExecutionContext context) + { + executionContext = context; + } + + public abstract void startTransaction(); + + public abstract void commitTransaction(); + + public abstract void rollbackTransaction(); + + public Dgn7fileReader getReader() + { + return this.reader; + } + + public void setReader(Dgn7fileReader reader) + { + this.reader = reader; + } + + public String getFilename() + { + return filename; + } + + public void setFilename(String filename) + { + this.filename = filename; + } + + public boolean getElementLogging() + { + return _elementLogging; + } + + public void setElementLogging(boolean elementLogging) + { + this._elementLogging = elementLogging; + } + + public abstract Log getLogger(); +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractOracleJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractOracleJobContext.java new file mode 100644 index 0000000..19f757d --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/AbstractOracleJobContext.java @@ -0,0 +1,286 @@ +package com.ximple.eofms.jobs.context; + +import java.io.IOException; +import java.util.Properties; +import java.sql.Connection; + +import org.apache.commons.logging.Log; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.data.oracle.OracleDataStore; + +import oracle.jdbc.OracleConnection; + +public abstract class AbstractOracleJobContext +{ + /** + * Table Prefiex + */ + protected static final String TABLE_PREFIX = "GEO$"; + protected static final String UDT_SCHEMA = "SPATIALDB"; + /** + * User Types + */ + protected static final String UDT_RAWS = "CREATE OR REPLACE TYPE \"" + UDT_SCHEMA + "\".\"RAWS\" AS VARRAY (1048576) OF NUMBER(38)"; + protected static final String UDT_OFMID = "CREATE OR REPLACE TYPE \"" + UDT_SCHEMA + "\".\"OFMID\" AS OBJECT (" + + "\"CLSID\" NUMBER(5), \"OID\" NUMBER(10), \"STATUS\" NUMBER(5), \"COMPID\" NUMBER(3), " + + "\"RULEID\" NUMBER(3), \"OCCID\" NUMBER(3))"; + protected static final String UDT_RAWSNAME = "RAWS"; + protected static final String UDT_OFMIDNAME = "OFMID"; + /** + * Utility SQL + */ + protected static final String TAB_DROP = "DROP TABLE %s.%s CASCADE CONSTRAINTS"; + protected static final String TAB_DELETE = "DELETE FROM %s.%s"; + /** + * Table Schema + */ + protected static final String TAB_RANGENODEINDEX_1 = "CREATE TABLE \"%s\".\"%s\"\n" + + " ( \"RNID\" INTEGER NOT NULL ENABLE,\n" + + " \"RPID\" INTEGER NOT NULL ENABLE,\n" + + " \"RNG_LOWX\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"RNG_LOWY\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"RNG_HIGHX\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"RNG_HIGHY\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"EXTENTS\" MDSYS.SDO_GEOMETRY,\n" + + " \"RNDESCR\" VARCHAR2(255), \n" + + " PRIMARY KEY ( \"RNID\" ) ENABLE )"; + protected static final String TAB_RANGENODEINDEX = "CREATE TABLE \"%s\".\"%s\"\n" + + " ( \"RNID\" INTEGER NOT NULL ENABLE,\n" + + " \"RPID\" INTEGER NOT NULL ENABLE,\n" + + " \"RNG_LOWX\" FLOAT NOT NULL ENABLE,\n" + + " \"RNG_LOWY\" FLOAT NOT NULL ENABLE,\n" + + " \"RNG_HIGHX\" FLOAT NOT NULL ENABLE,\n" + + " \"RNG_HIGHY\" FLOAT NOT NULL ENABLE,\n" + + " \"RNDESCR\" VARCHAR2(255), \n" + + " PRIMARY KEY ( \"RNID\" ) ENABLE )"; + protected static final String TAB_RANGENODESTORAGE = "CREATE TABLE \"%s\".\"%s\"\n" + + " ( \"RNID\" INTEGER NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5,0) NOT NULL ENABLE,\n" + + " \"LASTUPDATE\" DATE NOT NULL ENABLE,\n" + + " \"SPACETABLE\" VARCHAR2(255)\n" + " )"; + protected static final String TAB_ELEMENTINDEX_1 = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"TYPE\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"XLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"ZLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"XHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"ZHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"SPACENAME\" VARCHAR2(255) NOT NULL ENABLE,\n" + + " PRIMARY KEY (\"ELMNO\") ENABLE\n" + + " )"; + protected static final String TAB_ELEMENTINDEX = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"TYPE\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"XLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"YLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"ZLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"XHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"YHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"ZHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"SPACENAME\" VARCHAR2(255) NOT NULL ENABLE,\n" + + " PRIMARY KEY (\"ELMNO\") ENABLE\n" + + " )"; + protected static final String TAB_IGDSSEED = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"SEEDELM\" \"" + UDT_SCHEMA + + "\".\"RAWS\" NOT NULL ENABLE\n" + " )"; + protected static final String TAB_STORAGE_1 = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"XLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"XHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"EXTENTS\" MDSYS.SDO_GEOMETRY, \n" + + " \"PROPS\" INTEGER NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"ELEMENT\" \"" + UDT_SCHEMA + "\".\"RAWS\" NOT NULL ENABLE, \n" + + " \"GEOM\" MDSYS.SDO_GEOMETRY \n" + + " )"; + protected static final String TAB_STORAGE = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"XLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"YLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"XHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"YHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"PROPS\" INTEGER NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"ELEMENT\" \"" + UDT_SCHEMA + "\".\"RAWS\" NOT NULL ENABLE \n" + + " )"; + protected static final String TAB_STORAGE2 = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"XLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"XHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"EXTENTS\" MDSYS.SDO_GEOMETRY, \n" + + " \"PROPS\" INTEGER NOT NULL ENABLE,\n" + + " \"ID\" " + UDT_SCHEMA + ".OFMID NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"ELEMENT\" \"" + UDT_SCHEMA + "\".\"RAWS\" NOT NULL ENABLE \n" + + " )"; + /** + * Trigger + */ + protected static final String TRG_SPACENODE = "CREATE OR REPLACE TRIGGER \"%s\".\"%s\"\n" + + " AFTER DELETE OR INSERT OR UPDATE ON \"%s\".\"%s\"\n" + " BEGIN\n" + + " UPDATE SPACENODES SET LASTUPDATE = SYSDATE\n" + " WHERE SNID = \"%d\";\n" + + " END;"; + protected static final String TRG_ELMINDEX = + "CREATE OR REPLACE TRIGGER \"%s\".\"%s\"\n" + + " AFTER INSERT OR UPDATE OR DELETE ON \"%s\".\"%s\"\n" + + " REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW\n" + + " BEGIN\n" + + " IF INSERTING THEN\n" + + " INSERT INTO \"%s\".\"%s\" (ELMNO, TYPE, XLOW, YLOW, XHIGH, YHIGH,\n" + + " UFID, FSC, COMPID, OCCID, SPACENAME)\n" + + " VALUES (SD$ELEMENTNUMBER_SEQ.NEXTVAL, :new.ELMTYPE, :new.XLOW, :new.YLOW, :new.XHIGH, :new.YHIGH,\n" + + " :new.UFID, :new.FSC, :new.COMPID, :new.OCCID, '%s');\n" + + " ELSIF DELETING THEN\n" + + " DELETE FROM \"%s\".\"%s\"\n" + + " WHERE \"%s\".UFID = :old.UFID AND\n" + + " \"%s\".FSC = :old.FSC AND\n" + + " \"%s\".COMPID = :old.COMPID AND\n" + + " \"%s\".OCCID = :old.OCCID;\n" + + " ELSE\n" + " UPDATE \"%s\"\n" + + " SET XLOW = :new.XLOW, YLOW = :new.YLOW, XHIGH = :new.XHIGH, YHIGH = :new.YHIGH\n" + + " WHERE FSC = :new.FSC AND UFID = :new.UFID AND COMPID = :new.COMPID AND OCCID = :new.OCCID;\n" + + " END IF;\n" + " END;"; + + /** + * copy connectivity to connectivity_webcheck sql + */ + public static final String TRUNCATE_CONNECTIVITY_WEBCHECK = "TRUNCATE TABLE BASEDB.CONNECTIVITY_WEBCHECK"; + protected static final String CREATE_CONNECTIVITY_WEBCHECK = "CREATE TABLE BASEDB.CONNECTIVITY_WEBCHECK\n" + + "( FSC NUMBER(5) NOT NULL," + + " UFID NUMBER(10) NOT NULL," + + " N1 NUMBER(10)," + + " N2 NUMBER(10)," + + " FDR1 NUMBER(5)," + + " FDR2 NUMBER(5)," + + " DIR NUMBER(3)," + + " OHUG NUMBER(3)," + + " OSTATUS NUMBER(3)," + + " PHASE NUMBER(3)," + + " X NUMBER(10,3) NOT NULL," + + " Y NUMBER(10,3) NOT NULL" + + ")\n" + + "TABLESPACE BASE_DATA PCTUSED 40 PCTFREE 10 INITRANS 1 MAXTRANS 255\n" + + "STORAGE (INITIAL 19120K MINEXTENTS 1 MAXEXTENTS 2147483645 \n" + + "PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT )\n" + + "LOGGING NOCOMPRESS NOCACHE NOPARALLEL MONITORING;"; + + public static final String COPY_CONNECTIVITY_TO_WEBCHECK = "INSERT /*+ APPEND */ INTO BASEDB.CONNECTIVITY_WEBCHECK\n" + + "(FSC, UFID, N1, N2, FDR1, FDR2, DIR, OHUG,OSTATUS, PHASE, X, Y)\n" + + "SELECT FSC, UFID, N1, N2, FDR1, FDR2, DIR, OHUG, OSTATUS, PHASE, X, Y FROM BASEDB.CONNECTIVITY "; + + + /** + * + */ + protected static final String TAB_ELEMENTSET_PREFIX = "ELMSET_"; + protected static final String STMT_CLEARCYCLEBIN = "PURGE RECYCLEBIN"; + protected static final String SMTM_GRANTOBJECTTYPE = "GRANT EXECUTE ANY TYPE TO \"" + UDT_SCHEMA + "\""; + protected static final long TIMEOUT = Long.MAX_VALUE; + + /** + * Encoding of URL path. + */ + protected static final String ENCODING = "UTF-8"; + protected OracleDataStore sourceDataStore; + + protected String _dataPath; + protected Properties properties; + protected boolean _elementLogging; + private Connection connection = null; + + public OracleDataStore getSourceDataStore() + { + return sourceDataStore; + } + + public void setSourceDataStore(DataStore sourceDataStore) + { + if ((sourceDataStore != null) && (sourceDataStore instanceof OracleDataStore)) + { + this.sourceDataStore = (OracleDataStore) sourceDataStore; + } else + { + assert sourceDataStore != null; + getLogger().warn("setSourceDataStore(datastore) need OracleDataStore but got " + + sourceDataStore.getClass().getName()); + } + } + + public Connection getOracleConnection() + { + if (connection != null) return connection; + try + { + if (sourceDataStore != null) + { + connection = sourceDataStore.getConnection(Transaction.AUTO_COMMIT); + } + + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + } + + return connection; + } + + public void setDataPath(String dataPath) + { + _dataPath = dataPath; + } + + public String getDataPath() + { + return _dataPath; + } + + public boolean getElementLogging() + { + return _elementLogging; + } + + public void setElementLogging(boolean elementLogging) + { + _elementLogging = elementLogging; + } + + public abstract void startTransaction(); + + public abstract void commitTransaction(); + + public abstract void rollbackTransaction(); + + protected abstract Log getLogger(); +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/OracleUpgradeJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/OracleUpgradeJobContext.java new file mode 100644 index 0000000..29e1acf --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/OracleUpgradeJobContext.java @@ -0,0 +1,23 @@ +package com.ximple.eofms.jobs.context; + +import org.apache.commons.logging.Log; + +public class OracleUpgradeJobContext extends AbstractOracleJobContext +{ + public void startTransaction() + { + } + + public void commitTransaction() + { + } + + public void rollbackTransaction() + { + } + + protected Log getLogger() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractDgnToMySQLJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractDgnToMySQLJobContext.java new file mode 100644 index 0000000..34b94ea --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractDgnToMySQLJobContext.java @@ -0,0 +1,66 @@ +package com.ximple.eofms.jobs.context.mysql; + +import java.io.IOException; +import java.sql.Connection; + +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.data.SchemaNotFoundException; +import org.geotools.data.mysql.MySQLDataStore; +import org.geotools.feature.FeatureType; + +import com.ximple.eofms.jobs.context.AbstractDgnFileJobContext; + +public abstract class AbstractDgnToMySQLJobContext extends AbstractDgnFileJobContext +{ + protected MySQLDataStore targetDataStore; + + public AbstractDgnToMySQLJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath); + this.targetDataStore = (MySQLDataStore) targetDataStore; + } + + public MySQLDataStore getTargetDataStore() + { + return targetDataStore; + } + + public void setTargetDataStore(MySQLDataStore targetDataStore) + { + this.targetDataStore = targetDataStore; + } + + public Connection getConnection() + { + if (targetDataStore != null) + { + try + { + return targetDataStore.getConnection(Transaction.AUTO_COMMIT); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + } + } + return null; + } + + + protected boolean isExistFeature(FeatureType featureType) + { + try + { + FeatureType existFeatureType = targetDataStore.getSchema(featureType.getTypeName()); + return existFeatureType != null && existFeatureType.equals(featureType); + } catch (SchemaNotFoundException e) + { + return false; + } catch (IOException e) + { + getLogger().info(e.getMessage(), e); + return false; + } + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractOracleToMySQLJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractOracleToMySQLJobContext.java new file mode 100644 index 0000000..8fb18fc --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/AbstractOracleToMySQLJobContext.java @@ -0,0 +1,70 @@ +package com.ximple.eofms.jobs.context.mysql; + +import java.io.IOException; +import java.sql.Connection; + +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.data.SchemaNotFoundException; +import org.geotools.data.mysql.MySQLDataStore; +import org.geotools.feature.FeatureType; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; + +public abstract class AbstractOracleToMySQLJobContext extends AbstractOracleJobContext +{ + protected MySQLDataStore targetDataStore; + + public AbstractOracleToMySQLJobContext(String dataPath, DataStore targetDataStore) + { + if ((targetDataStore != null) && (targetDataStore instanceof MySQLDataStore)) + { + this.targetDataStore = (MySQLDataStore) targetDataStore; + } else + { + getLogger().info("targetDataStore has wrong."); + } + setDataPath(dataPath); + } + + public MySQLDataStore getTargetDataStore() + { + return targetDataStore; + } + + public void setTargetDataStore(MySQLDataStore targetDataStore) + { + this.targetDataStore = targetDataStore; + } + + public Connection getConnection() + { + if (targetDataStore != null) + { + try + { + return targetDataStore.getConnection(Transaction.AUTO_COMMIT); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + } + } + return null; + } + + protected boolean isExistFeature(FeatureType featureType) + { + try + { + FeatureType existFeatureType = targetDataStore.getSchema(featureType.getTypeName()); + return existFeatureType != null && existFeatureType.equals(featureType); + } catch (SchemaNotFoundException e) + { + return false; + } catch (IOException e) + { + getLogger().info(e.getMessage(), e); + return false; + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/DummyFeatureConvertMySQlJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/DummyFeatureConvertMySQlJobContext.java new file mode 100644 index 0000000..d67239c --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/DummyFeatureConvertMySQlJobContext.java @@ -0,0 +1,304 @@ +package com.ximple.eofms.jobs.context.mysql; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.net.URL; +import java.net.MalformedURLException; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.LoggerFacade; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.geotools.feature.Feature; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.FeatureType; +import org.geotools.feature.SimpleFeature; +import org.geotools.data.FeatureWriter; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.jobs.context.orasdo.AbstractDgnToOraSDOJobContext; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatchableFilter; +import com.ximple.eofms.filter.TypeCompIdDispatchableFilter; +import com.ximple.eofms.filter.TypeCompLevelIdDispatchableFilter; +import com.ximple.eofms.filter.TypeIdDispatchableFilter; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class DummyFeatureConvertMySQlJobContext extends AbstractDgnToMySQLJobContext +{ + static final Log logger = LogFactory.getLog(DummyFeatureConvertMySQlJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + static final String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public DummyFeatureConvertMySQlJobContext(String dataPath, DataStore targetDataStore, String filterConfig) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + assert elementDispatcher != null; + for (ElementDispatchableFilter filter : elementDispatcher.getRules()) + { + if (filter instanceof TypeCompIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeCompLevelIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } + } + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/FeatureDgnConvertMySQLJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/FeatureDgnConvertMySQLJobContext.java new file mode 100644 index 0000000..3f5a0f6 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/FeatureDgnConvertMySQLJobContext.java @@ -0,0 +1,268 @@ +package com.ximple.eofms.jobs.context.mysql; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.net.URL; +import java.net.MalformedURLException; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.LoggerFacade; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.geotools.feature.Feature; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.FeatureType; +import org.geotools.feature.SimpleFeature; +import org.geotools.data.FeatureWriter; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class FeatureDgnConvertMySQLJobContext extends AbstractDgnToMySQLJobContext +{ + static final Log logger = LogFactory.getLog(FeatureDgnConvertMySQLJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public FeatureDgnConvertMySQLJobContext(String dataPath, DataStore targetDataStore, String filterConfig) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} + + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java new file mode 100644 index 0000000..de90663 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java @@ -0,0 +1,521 @@ +package com.ximple.eofms.jobs.context.mysql; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.TreeMap; +import java.util.Iterator; +import java.util.List; +import java.net.MalformedURLException; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.LoggerFacade; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.geotools.data.FeatureWriter; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Geometry; + +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.ShapeElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.TextNodeElement; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.EllipseElement; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class GeneralDgnConvertMySQLJobContext extends AbstractDgnToMySQLJobContext +{ + static final Log logger = LogFactory.getLog(GeneralDgnConvertMySQLJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + private TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + private TreeMap<String, FeatureType> featureTypes = new TreeMap<String, FeatureType>(); + + private TWD97GeometryConverterDecorator convertDecorator = null; + private String featureBaseName = null; + private boolean withIndex = false; + + public GeneralDgnConvertMySQLJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + convertDecorator = new TWD97GeometryConverterDecorator(); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + FeatureType ft = lookupFeatureType(element); + if (ft != null) + { + Feature feature = createFeature(ft, element); + if (feature == null) + { + if (element instanceof TextElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + else if (element instanceof ShapeElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ShapeElement) element).getVerticeSize() + "'" + + ((ShapeElement) element).getStartPoint()); + else if (element instanceof LineStringElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((LineStringElement) element).getVerticeSize() + "'" + + ((LineStringElement) element).getStartPoint()); + else if (element instanceof ArcElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ArcElement) element).getOrigin().toString() + "'" + + ((ArcElement) element).getRotationAngle()); + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); + } + ArrayList<Feature> arrayList = (ArrayList<Feature>) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } else + { + logger.info("Unknown Element :" + element.getType() + ", lv=" + element.getLevelIndex()); + } + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save into OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save into OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + public FeatureType createPointFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalPointFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createLineFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createArcFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalArcFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createEllipseFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalEllipseFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + convertDecorator.setConverter(textElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textElement.getRotationAngle(); + String content = textElement.getText(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getFontIndex(), + textElement.getJustification(), + textElement.getTextHeight(), + textElement.getTextWidth(), + angle, + content + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof TextNodeElement) + { + TextNodeElement textNodeElement = (TextNodeElement) element; + convertDecorator.setConverter(textNodeElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textNodeElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + String[] texts = textNodeElement.getTextArray(); + StringBuffer sb = new StringBuffer(); + for (String text : texts) + { + if (sb.length() != 0) + sb.append("\n"); + sb.append(text); + } + + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textNodeElement.getColorIndex()), + textNodeElement.getFontIndex(), + textNodeElement.getJustification(), + textNodeElement.getTextNodeHeight(), + textNodeElement.getTextNodeLength(), + angle, + sb.toString() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof ShapeElement) + { + ShapeElement shapeElement = (ShapeElement) element; + convertDecorator.setConverter(shapeElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(shapeElement.getColorIndex()), + shapeElement.getWeight(), + shapeElement.getLineStyle() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof LineStringElement) + { + LineStringElement linestring = (LineStringElement) element; + convertDecorator.setConverter(linestring); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(linestring.getColorIndex()), + linestring.getWeight(), + linestring.getLineStyle() + }); + return null; + } else if (element instanceof LineElement) + { + LineElement line = (LineElement) element; + convertDecorator.setConverter(line); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(line.getColorIndex()), + line.getWeight(), + line.getLineStyle() + }); + return null; + } else if (element instanceof ArcElement) + { + ArcElement arcElement = (ArcElement) element; + /* + logger.fatal("" + arcElement.getPrimary() + ":" + arcElement.getSecondary() + + "-" + arcElement.getStartAngle() + ":" + arcElement.getSweepAngle() + ":" + + arcElement.getRotationAngle() + ":" + arcElement.getOrigin()); + */ + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof EllipseElement) + { + EllipseElement arcElement = (EllipseElement) element; + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChainElement = (ComplexChainElement) element; + convertDecorator.setConverter(complexChainElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(complexChainElement.getColorIndex()), + complexChainElement.getWeight(), + complexChainElement.getLineStyle() + }); + return null; + } + return null; + } + + private String getFeatureBaseName() + { + if (featureBaseName == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureBaseName = dgnname; + } + return featureBaseName; + } + + private FeatureType lookupFeatureType(Element element) throws SchemaException, IllegalAttributeException + { + String typeName; + if (element instanceof TextElement) + { + typeName = getFeatureBaseName() + "_P"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof TextNodeElement) + { + typeName = getFeatureBaseName() + "_P"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof LineStringElement) + { + if (element instanceof ShapeElement) + { + typeName = getFeatureBaseName() + "_R"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else + { + typeName = getFeatureBaseName() + "_L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + } else if (element instanceof LineElement) + { + typeName = getFeatureBaseName() + "_L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ComplexChainElement) + { + typeName = getFeatureBaseName() + "_ML"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ArcElement) + { + typeName = getFeatureBaseName() + "_A"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createArcFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof EllipseElement) + { + typeName = getFeatureBaseName() + "_R"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createEllipseFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + + return null; + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/IndexDgnConvertMySQLJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/IndexDgnConvertMySQLJobContext.java new file mode 100644 index 0000000..c825407 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/IndexDgnConvertMySQLJobContext.java @@ -0,0 +1,320 @@ +package com.ximple.eofms.jobs.context.mysql; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.net.MalformedURLException; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.LoggerFacade; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.geotools.data.FeatureWriter; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Coordinate; + +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.TPCLIDConverter; +import com.ximple.eofms.util.TWDDatumConverter; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class IndexDgnConvertMySQLJobContext extends AbstractDgnToMySQLJobContext +{ + static final Log logger = LogFactory.getLog(IndexDgnConvertMySQLJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + private FeatureTypeBuilder typeBuilderPnt = null; + private FeatureTypeBuilder typeBuilderRect = null; + private FeatureType featureType = null; + private FeatureType featureType2 = null; + + public IndexDgnConvertMySQLJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + if (!(element instanceof TextElement)) + { + return; + } + + Feature feature = createFeature((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + + feature = createFeature2((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature2." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + for (Feature feature1 : features) + { + ((SimpleFeature) writer.next()).setAttributes(feature1.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (typeBuilderRect == null) + { + typeBuilderRect = FeatureTypeBuilderUtil.createNormalIndexFeatureTypeBuilder(featureName); + } + return typeBuilderRect.getFeatureType(); + } + + public FeatureType createFeatureElement2(String featureName) throws SchemaException + { + if (typeBuilderPnt == null) + { + typeBuilderPnt = FeatureTypeBuilderUtil.createNormalIndexTextFeatureTypeBuilder(featureName); + } + return typeBuilderPnt.getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + String tpclid = textElement.getText(); + + Envelope extent = TPCLIDConverter.convertTpclIdToEnvelope(tpclid); + Geometry geom = geometryFactory.createLinearRing(new Coordinate[] + { + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + }); + + return featureType.create(new Object[]{ + geom, + extent.getMinX(), + extent.getMinY(), + extent.getMaxX(), + extent.getMaxY(), + tpclid, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getWeight(), + textElement.getLineStyle() + }); + } + return null; + } + + public Feature createFeature2(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement txtElement = (TextElement) element; + double angle = txtElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + convertDecorator.setConverter(txtElement); + Feature feature = featureType.create(new Object[]{ + convertDecorator.toGeometry(geometryFactory), + colorTable.getColorCode(txtElement.getColorIndex()), + txtElement.getWeight(), + txtElement.getLineStyle(), + txtElement.getJustification(), + txtElement.getTextHeight(), + txtElement.getTextWidth(), + angle, + txtElement.getText() + }); + return feature; + } + return null; + } + + private Feature createFeature(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureType = createFeatureElement(dgnname); + } + return createFeature(featureType, element); + } + + private Feature createFeature2(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType2 == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + dgnname = dgnname + "P"; + featureType2 = createFeatureElement2(dgnname); + } + return createFeature2(featureType2, element); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public Log getLogger() + { + return logger; + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/OracleConvertMySQLJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/OracleConvertMySQLJobContext.java new file mode 100644 index 0000000..890fced --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/OracleConvertMySQLJobContext.java @@ -0,0 +1,311 @@ +package com.ximple.eofms.jobs.context.mysql; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.mysql.MySQLDataStoreFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SimpleFeature; +import org.quartz.JobExecutionContext; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.util.Assert; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.jobs.OracleElementLogger; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; + +public class OracleConvertMySQLJobContext extends AbstractOracleToMySQLJobContext +{ + static Log logger = LogFactory.getLog(OracleConvertMySQLJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + + static MySQLDataStoreFactory dataStoreFactory = new MySQLDataStoreFactory(); + + private OracleElementLogger elmLogger = null; + + static + { + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + } catch (SQLException e) + { + Assert.shouldNeverReachHere(e.getMessage()); + } + } + + private String _filterConfig; + + private ElementDispatcher elementDispatcher; + + private HashMap featuresContext = new HashMap(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + private PessimisticMapWrapper txFeaturesContext; + + private JobExecutionContext executionContext; + + private String currentSchema = null; + private String mysqlCurrentSchema = null; + private boolean schemaChanged = false; + // private String _convertElementIn = null; + + public OracleConvertMySQLJobContext(String dataPath, DataStore oraDS, String filterConfig) + { + super(dataPath, oraDS); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) + { + assert elementDispatcher != null; + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + boolean isEmptySize = false; + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size() + ":" + + (linkage == null ? "NULL" : (linkage.getUfid()))); + isEmptySize = true; + } + + if (getElementLogging() && (!isEmptySize)) + { + getElementLogger().logElement(element, getCurrentSchema()); + } + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + //txFeaturesContext.startTransaction(); + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + + if (this.getElementLogger() != null) + this.getElementLogger().flashLogging(); + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + FeatureWriter writer = null; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + DataStore postGisDataStore = null; + postGisDataStore = dataStoreFactory.createDataStore(properties); + + boolean existTable = isExistFeature(featureType); + + if (!existTable) + { + postGisDataStore.createSchema(featureType); + writer = postGisDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = postGisDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList features = (ArrayList) featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + + } + + public JobExecutionContext getExecutionContext() + { + return executionContext; + } + + public void setExecutionContext(JobExecutionContext context) + { + executionContext = context; + } + + /** + * �����]�Ƽg�J�� + * + * @throws IOException IO�o�Ϳ��~ + */ + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected OracleElementLogger getElementLogger() + { + if (elmLogger == null) + { + elmLogger = new OracleElementLogger(getOracleConnection()); + elmLogger.setDataPath(this.getDataPath()); + } + return elmLogger; + } + + public boolean isSchemaChanged() + { + return schemaChanged; + } + + public String getCurrentSchema() + { + return currentSchema; + } + + public void setCurrentSchema(String querySchema) + { + this.currentSchema = querySchema; + this.schemaChanged = true; + } + + protected Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractDgnToOraSDOJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractDgnToOraSDOJobContext.java new file mode 100644 index 0000000..2596fc8 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractDgnToOraSDOJobContext.java @@ -0,0 +1,65 @@ +package com.ximple.eofms.jobs.context.orasdo; + +import java.io.IOException; +import java.sql.Connection; + +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.data.SchemaNotFoundException; +import org.geotools.data.oracle.OracleDataStore; +import org.geotools.feature.FeatureType; + +import com.ximple.eofms.jobs.context.AbstractDgnFileJobContext; + +public abstract class AbstractDgnToOraSDOJobContext extends AbstractDgnFileJobContext +{ + protected OracleDataStore targetDataStore; + + public AbstractDgnToOraSDOJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath); + this.targetDataStore = (OracleDataStore) targetDataStore; + } + + public OracleDataStore getTargetDataStore() + { + return targetDataStore; + } + + public void setTargetDataStore(OracleDataStore targetDataStore) + { + this.targetDataStore = targetDataStore; + } + + public Connection getConnection() + { + if (targetDataStore != null) + { + try + { + return targetDataStore.getConnection(Transaction.AUTO_COMMIT); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + } + } + return null; + } + + + protected boolean isExistFeature(FeatureType featureType) + { + try + { + FeatureType existFeatureType = targetDataStore.getSchema(featureType.getTypeName()); + return existFeatureType != null && existFeatureType.equals(featureType); + } catch (SchemaNotFoundException e) + { + return false; + } catch (IOException e) + { + getLogger().info(e.getMessage(), e); + return false; + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractOracleToOraSDOJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractOracleToOraSDOJobContext.java new file mode 100644 index 0000000..d535cb6 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/AbstractOracleToOraSDOJobContext.java @@ -0,0 +1,72 @@ +package com.ximple.eofms.jobs.context.orasdo; + +import java.io.IOException; +import java.sql.Connection; + +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.data.SchemaNotFoundException; +import org.geotools.data.oracle.OracleDataStore; +import org.geotools.feature.FeatureType; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.jobs.context.mysql.OracleConvertMySQLJobContext; + +public abstract class AbstractOracleToOraSDOJobContext extends AbstractOracleJobContext +{ + protected OracleDataStore targetDataStore; + + public AbstractOracleToOraSDOJobContext(String dataPath, DataStore targetDataStore) + { + if ((targetDataStore != null) && (targetDataStore instanceof OracleDataStore)) + { + this.targetDataStore = (OracleDataStore) targetDataStore; + } else + { + getLogger().info("targetDataStore has wrong."); + } + setDataPath(dataPath); + } + + public OracleDataStore getTargetDataStore() + { + return targetDataStore; + } + + public void setTargetDataStore(OracleDataStore targetDataStore) + { + this.targetDataStore = targetDataStore; + } + + public Connection getConnection() + { + if (targetDataStore != null) + { + try + { + return targetDataStore.getConnection(Transaction.AUTO_COMMIT); + } catch (IOException e) + { + getLogger().warn(e.getMessage(), e); + } + } + return null; + } + + + protected boolean isExistFeature(FeatureType featureType) + { + try + { + FeatureType existFeatureType = targetDataStore.getSchema(featureType.getTypeName()); + return existFeatureType != null && existFeatureType.equals(featureType); + } catch (SchemaNotFoundException e) + { + return false; + } catch (IOException e) + { + getLogger().info(e.getMessage(), e); + return false; + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/DummyFeatureConvertOraSDOJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/DummyFeatureConvertOraSDOJobContext.java new file mode 100644 index 0000000..b892399 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/DummyFeatureConvertOraSDOJobContext.java @@ -0,0 +1,303 @@ +package com.ximple.eofms.jobs.context.orasdo; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.filter.TypeCompIdDispatchableFilter; +import com.ximple.eofms.filter.TypeCompLevelIdDispatchableFilter; +import com.ximple.eofms.filter.TypeIdDispatchableFilter; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class DummyFeatureConvertOraSDOJobContext extends AbstractDgnToOraSDOJobContext +{ + static final Log logger = LogFactory.getLog(DummyFeatureConvertOraSDOJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + static final String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public DummyFeatureConvertOraSDOJobContext(String dataPath, DataStore targetDataStore, String filterConfig) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + assert elementDispatcher != null; + for (ElementDispatchableFilter filter : elementDispatcher.getRules()) + { + if (filter instanceof TypeCompIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeCompLevelIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } + } + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/FeatureDgnConvertOraSDOJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/FeatureDgnConvertOraSDOJobContext.java new file mode 100644 index 0000000..19c149a --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/FeatureDgnConvertOraSDOJobContext.java @@ -0,0 +1,267 @@ +package com.ximple.eofms.jobs.context.orasdo; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class FeatureDgnConvertOraSDOJobContext extends AbstractDgnToOraSDOJobContext +{ + static final Log logger = LogFactory.getLog(FeatureDgnConvertOraSDOJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public FeatureDgnConvertOraSDOJobContext(String dataPath, DataStore targetDataStore, String filterConfig) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/GeneralDgnConvertOraSDOJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/GeneralDgnConvertOraSDOJobContext.java new file mode 100644 index 0000000..fcdcece --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/GeneralDgnConvertOraSDOJobContext.java @@ -0,0 +1,522 @@ +package com.ximple.eofms.jobs.context.orasdo; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.EllipseElement; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.ShapeElement; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.TextNodeElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class GeneralDgnConvertOraSDOJobContext extends AbstractDgnToOraSDOJobContext +{ + static final Log logger = LogFactory.getLog(GeneralDgnConvertOraSDOJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + private TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + private TreeMap<String, FeatureType> featureTypes = new TreeMap<String, FeatureType>(); + + private TWD97GeometryConverterDecorator convertDecorator = null; + private String featureBaseName = null; + private boolean withIndex = false; + + public GeneralDgnConvertOraSDOJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + convertDecorator = new TWD97GeometryConverterDecorator(); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + FeatureType ft = lookupFeatureType(element); + if (ft != null) + { + Feature feature = createFeature(ft, element); + if (feature == null) + { + if (element instanceof TextElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + else if (element instanceof ShapeElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ShapeElement) element).getVerticeSize() + "'" + + ((ShapeElement) element).getStartPoint()); + else if (element instanceof LineStringElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((LineStringElement) element).getVerticeSize() + "'" + + ((LineStringElement) element).getStartPoint()); + else if (element instanceof ArcElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ArcElement) element).getOrigin().toString() + "'" + + ((ArcElement) element).getRotationAngle()); + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); + } + ArrayList<Feature> arrayList = (ArrayList<Feature>) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } else + { + logger.info("Unknown Element :" + element.getType() + ", lv=" + element.getLevelIndex()); + } + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save into OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save into OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + public FeatureType createPointFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalPointFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createLineFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createArcFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalArcFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createEllipseFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalEllipseFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + convertDecorator.setConverter(textElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textElement.getRotationAngle(); + String content = textElement.getText(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getFontIndex(), + textElement.getJustification(), + textElement.getTextHeight(), + textElement.getTextWidth(), + angle, + content + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof TextNodeElement) + { + TextNodeElement textNodeElement = (TextNodeElement) element; + convertDecorator.setConverter(textNodeElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textNodeElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + String[] texts = textNodeElement.getTextArray(); + StringBuffer sb = new StringBuffer(); + for (String text : texts) + { + if (sb.length() != 0) + sb.append("\n"); + sb.append(text); + } + + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textNodeElement.getColorIndex()), + textNodeElement.getFontIndex(), + textNodeElement.getJustification(), + textNodeElement.getTextNodeHeight(), + textNodeElement.getTextNodeLength(), + angle, + sb.toString() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof ShapeElement) + { + ShapeElement shapeElement = (ShapeElement) element; + convertDecorator.setConverter(shapeElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(shapeElement.getColorIndex()), + shapeElement.getWeight(), + shapeElement.getLineStyle() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof LineStringElement) + { + LineStringElement linestring = (LineStringElement) element; + convertDecorator.setConverter(linestring); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(linestring.getColorIndex()), + linestring.getWeight(), + linestring.getLineStyle() + }); + return null; + } else if (element instanceof LineElement) + { + LineElement line = (LineElement) element; + convertDecorator.setConverter(line); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(line.getColorIndex()), + line.getWeight(), + line.getLineStyle() + }); + return null; + } else if (element instanceof ArcElement) + { + ArcElement arcElement = (ArcElement) element; + /* + logger.fatal("" + arcElement.getPrimary() + ":" + arcElement.getSecondary() + + "-" + arcElement.getStartAngle() + ":" + arcElement.getSweepAngle() + ":" + + arcElement.getRotationAngle() + ":" + arcElement.getOrigin()); + */ + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof EllipseElement) + { + EllipseElement arcElement = (EllipseElement) element; + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChainElement = (ComplexChainElement) element; + convertDecorator.setConverter(complexChainElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(complexChainElement.getColorIndex()), + complexChainElement.getWeight(), + complexChainElement.getLineStyle() + }); + return null; + } + return null; + } + + private String getFeatureBaseName() + { + if (featureBaseName == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureBaseName = dgnname; + } + return featureBaseName; + } + + private FeatureType lookupFeatureType(Element element) throws SchemaException, IllegalAttributeException + { + String typeName; + if (element instanceof TextElement) + { + typeName = getFeatureBaseName() + "P"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof TextNodeElement) + { + typeName = getFeatureBaseName() + "P"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof LineStringElement) + { + if (element instanceof ShapeElement) + { + typeName = getFeatureBaseName() + "R"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else + { + typeName = getFeatureBaseName() + "L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + } else if (element instanceof LineElement) + { + typeName = getFeatureBaseName() + "L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ComplexChainElement) + { + typeName = getFeatureBaseName() + "L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ArcElement) + { + typeName = getFeatureBaseName() + "A"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createArcFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof EllipseElement) + { + typeName = getFeatureBaseName() + "R"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createEllipseFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + + return null; + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/IndexDgnConvertOraSDOJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/IndexDgnConvertOraSDOJobContext.java new file mode 100644 index 0000000..5db125b --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/IndexDgnConvertOraSDOJobContext.java @@ -0,0 +1,320 @@ +package com.ximple.eofms.jobs.context.orasdo; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TPCLIDConverter; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.eofms.util.TWDDatumConverter; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class IndexDgnConvertOraSDOJobContext extends AbstractDgnToOraSDOJobContext +{ + static final Log logger = LogFactory.getLog(IndexDgnConvertOraSDOJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + private FeatureTypeBuilder typeBuilderPnt = null; + private FeatureTypeBuilder typeBuilderRect = null; + private FeatureType featureType = null; + private FeatureType featureType2 = null; + + public IndexDgnConvertOraSDOJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + if (!(element instanceof TextElement)) + { + return; + } + + Feature feature = createFeature((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + + feature = createFeature2((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature2." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save OracleSDO:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + for (Feature feature1 : features) + { + ((SimpleFeature) writer.next()).setAttributes(feature1.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (typeBuilderRect == null) + { + typeBuilderRect = FeatureTypeBuilderUtil.createNormalIndexFeatureTypeBuilder(featureName); + } + return typeBuilderRect.getFeatureType(); + } + + public FeatureType createFeatureElement2(String featureName) throws SchemaException + { + if (typeBuilderPnt == null) + { + typeBuilderPnt = FeatureTypeBuilderUtil.createNormalIndexTextFeatureTypeBuilder(featureName); + } + return typeBuilderPnt.getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + String tpclid = textElement.getText(); + + Envelope extent = TPCLIDConverter.convertTpclIdToEnvelope(tpclid); + Geometry geom = geometryFactory.createLinearRing(new Coordinate[] + { + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + }); + + return featureType.create(new Object[]{ + geom, + extent.getMinX(), + extent.getMinY(), + extent.getMaxX(), + extent.getMaxY(), + tpclid, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getWeight(), + textElement.getLineStyle() + }); + } + return null; + } + + public Feature createFeature2(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement txtElement = (TextElement) element; + double angle = txtElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + convertDecorator.setConverter(txtElement); + Feature feature = featureType.create(new Object[]{ + convertDecorator.toGeometry(geometryFactory), + colorTable.getColorCode(txtElement.getColorIndex()), + txtElement.getWeight(), + txtElement.getLineStyle(), + txtElement.getJustification(), + txtElement.getTextHeight(), + txtElement.getTextWidth(), + angle, + txtElement.getText() + }); + return feature; + } + return null; + } + + private Feature createFeature(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureType = createFeatureElement(dgnname); + } + return createFeature(featureType, element); + } + + private Feature createFeature2(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType2 == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + dgnname = dgnname + "P"; + featureType2 = createFeatureElement2(dgnname); + } + return createFeature2(featureType2, element); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public Log getLogger() + { + return logger; + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/OracleConvertOraSDOJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/OracleConvertOraSDOJobContext.java new file mode 100644 index 0000000..f51ec60 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/orasdo/OracleConvertOraSDOJobContext.java @@ -0,0 +1,310 @@ +package com.ximple.eofms.jobs.context.orasdo; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.oracle.OracleDataStoreFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SimpleFeature; +import org.quartz.JobExecutionContext; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.util.Assert; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.jobs.OracleElementLogger; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; + +public class OracleConvertOraSDOJobContext extends AbstractOracleToOraSDOJobContext +{ + static Log logger = LogFactory.getLog(OracleConvertOraSDOJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + + static OracleDataStoreFactory dataStoreFactory = new OracleDataStoreFactory(); + + private OracleElementLogger elmLogger = null; + + static + { + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + } catch (SQLException e) + { + Assert.shouldNeverReachHere(e.getMessage()); + } + } + + private String _filterConfig; + + private ElementDispatcher elementDispatcher; + + private HashMap featuresContext = new HashMap(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + private PessimisticMapWrapper txFeaturesContext; + + private JobExecutionContext executionContext; + + private String currentSchema = null; + private String oraCurrentSchema = null; + private boolean schemaChanged = false; + // private String _convertElementIn = null; + + public OracleConvertOraSDOJobContext(String dataPath, DataStore oraDS, String filterConfig) + { + super(dataPath, oraDS); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) + { + assert elementDispatcher != null; + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + boolean isEmptySize = false; + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size() + ":" + + (linkage == null ? "NULL" : (linkage.getUfid()))); + isEmptySize = true; + } + + if (getElementLogging() && (!isEmptySize)) + { + getElementLogger().logElement(element, getCurrentSchema()); + } + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + //txFeaturesContext.startTransaction(); + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + + if (this.getElementLogger() != null) + this.getElementLogger().flashLogging(); + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + FeatureWriter writer = null; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + DataStore postGisDataStore = null; + postGisDataStore = dataStoreFactory.createDataStore(properties); + + boolean existTable = isExistFeature(featureType); + + if (!existTable) + { + postGisDataStore.createSchema(featureType); + writer = postGisDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = postGisDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList features = (ArrayList) featuresContext.get(featureType); + for (Object feature1 : features) + { + Feature feature = (Feature) feature1; + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save OracleSDO:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + + } + + public JobExecutionContext getExecutionContext() + { + return executionContext; + } + + public void setExecutionContext(JobExecutionContext context) + { + executionContext = context; + } + + /** + * �����]�Ƽg�J�� + * + * @throws IOException IO�o�Ϳ��~ + */ + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected OracleElementLogger getElementLogger() + { + if (elmLogger == null) + { + elmLogger = new OracleElementLogger(getOracleConnection()); + elmLogger.setDataPath(this.getDataPath()); + } + return elmLogger; + } + + public boolean isSchemaChanged() + { + return schemaChanged; + } + + public String getCurrentSchema() + { + return currentSchema; + } + + public void setCurrentSchema(String querySchema) + { + this.currentSchema = querySchema; + this.schemaChanged = true; + } + + protected Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java new file mode 100644 index 0000000..f919f16 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java @@ -0,0 +1,760 @@ +package com.ximple.eofms.jobs.context.postgis; + +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.geotools.data.DataSourceException; +import org.geotools.data.DataStore; +import org.geotools.data.SchemaNotFoundException; +import org.geotools.data.Transaction; +import org.geotools.data.jdbc.JDBCUtils; +import org.geotools.data.postgis.PostgisDataStore; +import org.geotools.feature.AttributeType; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.GeometryAttributeType; +import org.geotools.filter.LengthFunction; +import org.geotools.referencing.NamedIdentifier; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.opengis.filter.BinaryComparisonOperator; +import org.opengis.filter.Filter; +import org.opengis.filter.PropertyIsLessThan; +import org.opengis.filter.PropertyIsLessThanOrEqualTo; +import org.opengis.filter.expression.Literal; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.io.WKBWriter; +import com.vividsolutions.jts.io.WKTWriter; + +import com.ximple.eofms.jobs.context.AbstractDgnFileJobContext; +import com.ximple.eofms.util.postjts.JtsBinaryWriter; + +public abstract class AbstractDgnToPostGISJobContext extends AbstractDgnFileJobContext +{ + private static Map<String, Class> GEOM_TYPE_MAP = new HashMap<String, Class>(); + private static Map<String, Class> GEOM3D_TYPE_MAP = new HashMap<String, Class>(); + + static + { + GEOM_TYPE_MAP.put("GEOMETRY", Geometry.class); + GEOM_TYPE_MAP.put("POINT", Point.class); + GEOM_TYPE_MAP.put("LINESTRING", LineString.class); + GEOM_TYPE_MAP.put("POLYGON", Polygon.class); + GEOM_TYPE_MAP.put("MULTIPOINT", MultiPoint.class); + GEOM_TYPE_MAP.put("MULTILINESTRING", MultiLineString.class); + GEOM_TYPE_MAP.put("MULTIPOLYGON", MultiPolygon.class); + GEOM_TYPE_MAP.put("GEOMETRYCOLLECTION", GeometryCollection.class); + + GEOM3D_TYPE_MAP.put("POINTM", Point.class); + GEOM3D_TYPE_MAP.put("LINESTRINGM", LineString.class); + GEOM3D_TYPE_MAP.put("POLYGONM", Polygon.class); + GEOM3D_TYPE_MAP.put("MULTIPOINTM", MultiPoint.class); + GEOM3D_TYPE_MAP.put("MULTILINESTRINGM", MultiLineString.class); + GEOM3D_TYPE_MAP.put("MULTIPOLYGONM", MultiPolygon.class); + GEOM3D_TYPE_MAP.put("GEOMETRYCOLLECTIONM", GeometryCollection.class); + } + + private static Map<Class, String> CLASS_MAPPINGS = new HashMap<Class, String>(); + + static + { + CLASS_MAPPINGS.put(String.class, "VARCHAR"); + + CLASS_MAPPINGS.put(Boolean.class, "BOOLEAN"); + + CLASS_MAPPINGS.put(Short.class, "SMALLINT"); + CLASS_MAPPINGS.put(Integer.class, "INTEGER"); + CLASS_MAPPINGS.put(Long.class, "BIGINT"); + + CLASS_MAPPINGS.put(Float.class, "REAL"); + CLASS_MAPPINGS.put(Double.class, "DOUBLE PRECISION"); + + CLASS_MAPPINGS.put(BigDecimal.class, "DECIMAL"); + + CLASS_MAPPINGS.put(java.sql.Date.class, "DATE"); + CLASS_MAPPINGS.put(java.util.Date.class, "DATE"); + CLASS_MAPPINGS.put(java.sql.Time.class, "TIME"); + CLASS_MAPPINGS.put(java.sql.Timestamp.class, "TIMESTAMP"); + } + + private static Map<Class, String> GEOM_CLASS_MAPPINGS = new HashMap<Class, String>(); + + //why don't we just stick this in with the non-geom class mappings? + static + { + // init the inverse map + Set keys = GEOM_TYPE_MAP.keySet(); + + for (Object key : keys) + { + String name = (String) key; + Class geomClass = GEOM_TYPE_MAP.get(name); + GEOM_CLASS_MAPPINGS.put(geomClass, name); + } + } + + /** + * Maximum string size for postgres + */ + private static final int MAX_ALLOWED_VALUE = 10485760; + + // protected static final int BATCHSIZE = 2048; + protected static final int BATCHSIZE = 256; + + /** + * Well Known Text writer (from JTS). + */ + protected static WKTWriter geometryWriter = new WKTWriter(); + protected static JtsBinaryWriter binaryWriter = new JtsBinaryWriter(); + + protected PostgisDataStore targetDataStore; + private Connection connection; + protected boolean schemaEnabled = true; + + public AbstractDgnToPostGISJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath); + this.targetDataStore = (PostgisDataStore) targetDataStore; + this.connection = null; + } + + public PostgisDataStore getTargetDataStore() + { + return targetDataStore; + } + + public void setTargetDataStore(PostgisDataStore targetDataStore) + { + this.targetDataStore = targetDataStore; + } + + public Connection getConnection() + { + if (connection != null) return connection; + + if (targetDataStore != null) + { + try + { + connection = targetDataStore.getDataSource().getConnection(); + } catch (SQLException e) + { + getLogger().warn(e.getMessage(), e); + return null; + } + } + return connection; + } + + public void closeConnection() + { + if (connection == null) + { + JDBCUtils.close(connection, Transaction.AUTO_COMMIT, null); + connection = null; + } + } + + protected boolean isExistFeature(FeatureType featureType) + { + try + { + FeatureType existFeatureType = targetDataStore.getSchema(featureType.getTypeName()); + return existFeatureType != null; // && existFeatureType.equals(featureType); + } catch (SchemaNotFoundException e) + { + return false; + } catch (IOException e) + { + getLogger().info(e.getMessage(), e); + return false; + } + } + + protected void deleteTable(Connection conn, String tableName) throws SQLException + { + Statement stmt = conn.createStatement(); + StringBuilder sb = new StringBuilder(); + sb.append("DELETE FROM \""); + sb.append(targetDataStore.getDatabaseSchemaName()); + sb.append("\".\""); + sb.append(tableName); + sb.append('\"'); + getLogger().info("Execute-" + sb.toString()); + stmt.execute(sb.toString()); + stmt.close(); + conn.commit(); + } + + protected void dropTable(Connection conn, String tableName) throws SQLException + { + Statement stmt = conn.createStatement(); + StringBuilder sb = new StringBuilder(); + sb.append("DROP TABLE \""); + sb.append(targetDataStore.getDatabaseSchemaName()); + sb.append("\".\""); + sb.append(tableName); + sb.append("\" CASCADE"); + getLogger().info("Execute-" + sb.toString()); + stmt.execute(sb.toString()); + stmt.close(); + conn.commit(); + } + + protected void dropGeometryColumn(Connection conn, String tableName, String geomField) throws SQLException + { + Statement stmt = conn.createStatement(); + StringBuilder sb = new StringBuilder(); + sb.append("SELECT DropGeometryColumn('','"); + sb.append(tableName); + sb.append("','"); + sb.append(geomField); + sb.append("')"); + getLogger().info("Execute-" + sb.toString()); + stmt.execute(sb.toString()); + stmt.close(); + conn.commit(); + } + + protected String dropGeometryColumn(String dbSchema, String tableName, String geomField) + { + StringBuilder sb = new StringBuilder(); + sb.append("SELECT DropGeometryColumn('"); + sb.append(dbSchema); + sb.append("','"); + sb.append(tableName); + sb.append("','"); + sb.append(geomField); + sb.append("')"); + getLogger().info("Execute-" + sb.toString()); + return sb.toString(); + } + + private String addGeometryColumn(String dbSchema, String tableName, GeometryAttributeType geometryAttribute, int srid) + { + StringBuilder sql; + String typeName = getGeometrySQLTypeName(geometryAttribute.getBinding()); + if (typeName == null) + { + getLogger().warn("Error: " + geometryAttribute.getLocalName() + " unknown type!!!"); + throw new RuntimeException("Error: " + geometryAttribute.getLocalName() + " unknown type!!!"); + } + + sql = new StringBuilder("SELECT AddGeometryColumn('"); + sql.append(dbSchema); + sql.append("','"); + sql.append(tableName); + sql.append("','"); + sql.append(geometryAttribute.getLocalName()); + sql.append("','"); + sql.append(srid); + sql.append("','"); + sql.append(typeName); + sql.append("', 2);"); + + //prints statement for later reuse + return sql.toString(); + } + + public ArrayList<String> createNewSchemaTexts(FeatureType featureType) throws IOException + { + String origintableName = featureType.getTypeName(); + String tableName = origintableName.toLowerCase(); + + ArrayList<String> result = new ArrayList<String>(); + + AttributeType[] attributeType = featureType.getAttributeTypes(); + // String dbSchema = targetDataStore.getDatabaseSchemaName(); + + Connection con = getConnection(); + + boolean shouldDrop = tablePresent(tableName, con); + if (shouldDrop) + { + String sqlStr = "DROP TABLE " + encodeSchemaTableName(tableName) + ";"; + getLogger().info(sqlStr); + result.add(sqlStr); + } + + StringBuffer sql = new StringBuffer("CREATE TABLE "); + sql.append(encodeSchemaTableName(tableName)); + sql.append(" ( gid serial PRIMARY KEY, "); + sql.append(makeNonGeomSqlCreate(attributeType)); + sql.append(");"); + + String sqlStr = sql.toString(); + getLogger().info(sqlStr); + result.add(sqlStr); + + for (AttributeType anAttributeType : attributeType) + { + if (!(anAttributeType instanceof GeometryAttributeType)) + { + continue; + } + GeometryAttributeType geomAttribute = (GeometryAttributeType) anAttributeType; + + if (shouldDrop) + { + sqlStr = dropGeometryColumn("", tableName, geomAttribute.getLocalName()); + getLogger().info(sqlStr); + result.add(sqlStr); + } + + CoordinateReferenceSystem refSys = geomAttribute.getCoordinateSystem(); + int SRID; + + if (refSys != null) + { + try + { + Set ident = refSys.getIdentifiers(); + if ((ident == null || ident.isEmpty()) && refSys == DefaultGeographicCRS.WGS84) + { + SRID = 4326; + } else + { + String code = ((NamedIdentifier) ident.toArray()[0]).getCode(); + SRID = Integer.parseInt(code); + } + } catch (Exception e) + { + getLogger().warn("SRID could not be determined"); + SRID = -1; + } + } else + { + SRID = -1; + } + + sqlStr = addGeometryColumn("", tableName, geomAttribute, SRID); + getLogger().info(sqlStr); + result.add(sqlStr); + + + String indexName = tableName.replace('-', '_'); + //also build a spatial index on each geometry column. + sql = new StringBuffer("CREATE INDEX spatial_"); + sql.append(indexName); + sql.append("_"); + sql.append(anAttributeType.getLocalName().toLowerCase()); + sql.append(" ON "); + sql.append(encodeSchemaTableName(tableName)); + sql.append(" USING GIST ("); + sql.append(encodeSchemaColumnName(anAttributeType.getLocalName())); + sql.append(" gist_geometry_ops);"); + + sqlStr = sql.toString(); + getLogger().info(sqlStr); + + result.add(sqlStr); + } + + return result; + } + + private boolean tablePresent(String table, Connection conn) throws IOException + { + final int TABLE_NAME_COL = 3; + + try + { + conn = getConnection(); + + DatabaseMetaData meta = conn.getMetaData(); + String[] tableType = {"TABLE"}; + ResultSet tables = meta.getTables(null, + targetDataStore.getDatabaseSchemaName(), "%", tableType); + + while (tables.next()) + { + String tableName = tables.getString(TABLE_NAME_COL); + + if (allowTable(tableName) && (tableName != null) + && (tableName.equalsIgnoreCase(table))) + { + tables.close(); + return (true); + } + } + + tables.close(); + return false; + } catch (SQLException sqlException) + { + // JDBCUtils.close(conn, Transaction.AUTO_COMMIT, sqlException); + // conn = null; + + String message = "Error querying database for list of tables:" + + sqlException.getMessage(); + throw new DataSourceException(message, sqlException); + } finally + { + // JDBCUtils.close(conn, Transaction.AUTO_COMMIT, null); + } + } + + protected boolean allowTable(String tablename) + { + if (tablename.equals("geometry_columns")) + { + return false; + } else if (tablename.startsWith("spatial_ref_sys")) + { + return false; + } + + //others? + return true; + } + + + private StringBuffer makeNonGeomSqlCreate(AttributeType[] attributeType) + throws IOException + { + StringBuffer buf = new StringBuffer(""); + + for (AttributeType anAttributeType : attributeType) + { + String typeName; + typeName = CLASS_MAPPINGS.get(anAttributeType.getBinding()); + if (typeName == null) + { + typeName = GEOM_CLASS_MAPPINGS.get(anAttributeType.getBinding()); + if (typeName != null) continue; + } + + if (typeName != null) + { + if (typeName.equals("VARCHAR")) + { + int length = -1; + Filter f = anAttributeType.getRestriction(); + if (f != null && f != Filter.EXCLUDE && f != Filter.INCLUDE && + (f instanceof PropertyIsLessThan || f instanceof PropertyIsLessThanOrEqualTo)) + { + try + { + BinaryComparisonOperator cf = (BinaryComparisonOperator) f; + if (cf.getExpression1() instanceof LengthFunction) + { + length = Integer.parseInt(((Literal) cf.getExpression2()).getValue().toString()); + } else + { + if (cf.getExpression2() instanceof LengthFunction) + { + length = Integer.parseInt(((Literal) cf.getExpression1()).getValue().toString()); + } + } + } catch (NumberFormatException e) + { + length = 256; + } + } else + { + length = 256; + } + + if (length < 1) + { + getLogger().warn("FeatureType did not specify string length; defaulted to 256"); + length = 256; + } else if (length > MAX_ALLOWED_VALUE) + { + length = MAX_ALLOWED_VALUE; + } + typeName = typeName + "(" + length + ")"; + } + + if (!anAttributeType.isNillable()) + { + typeName = typeName + " NOT NULL"; + } + + //TODO review!!! Is toString() always OK??? + Object defaultValue = anAttributeType.createDefaultValue(); + + if (defaultValue != null) + { + typeName = typeName + " DEFAULT '" + + defaultValue.toString() + "'"; + } + + buf.append(" \"").append(anAttributeType.getLocalName()).append("\" ").append(typeName).append(","); + + } else + { + String msg; + if (anAttributeType == null) + { + msg = "AttributeType was null!"; + } else + { + msg = "Type '" + anAttributeType.getBinding() + "' not supported!"; + } + throw (new IOException(msg)); + } + } + + return buf.deleteCharAt(buf.length() - 1); + } + + private String getGeometrySQLTypeName(Class type) + { + String res = GEOM_CLASS_MAPPINGS.get(type); + + if (res == null) + { + throw new RuntimeException("Unknown type name for class " + type + + " please update GEOMETRY_MAPPINGS"); + } + + return res; + } + + protected String getGeometryInsertText(Geometry geom, int srid) // throws IOException + { + if (geom == null) + { + return "null"; + } + + if (targetDataStore.isWKBEnabled()) + { + //String wkb = WKBEncoder.encodeGeometryHex(geom); + String wkb = WKBWriter.bytesToHex(new WKBWriter().write(geom)); + + if (targetDataStore.isByteaWKB()) + { + return "setSRID('" + wkb + "'::geometry," + srid + ")"; + } else + { + return "GeomFromWKB('" + wkb + "', " + srid + ")"; + } + } + + String geoText = geometryWriter.write(geom); + + return "GeometryFromText('" + geoText + "', " + srid + ")"; + } + + protected String makeInsertSql(Feature feature, int srid) // throws IOException + { + FeatureType featureType = feature.getFeatureType(); + + String tableName = encodeSchemaTableName(featureType.getTypeName()); + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + + String attrValue; + + StringBuffer statementSQL = new StringBuffer("INSERT INTO " + tableName + " ("); + + // encode insertion for attributes, but remember to avoid auto-increment ones, + // they may be included in the feature type as well + for (AttributeType attributeType : attributeTypes) + { + String attName = attributeType.getLocalName(); + + if (feature.getAttribute(attName) != null) + { + String colName = encodeSchemaColumnName(attName); + statementSQL.append(colName).append(","); + } + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + statementSQL.append(" VALUES ("); + + Object[] attributes = feature.getAttributes(null); + + for (int i = 0; i < attributeTypes.length; i++) + { + attrValue = null; + + if (attributeTypes[i] instanceof GeometryAttributeType) + { + // String geomName = attributeTypes[i].getLocalName(); + // int srid = ftInfo.getSRID(geomName); + Geometry geometry = (Geometry) attributes[i]; + + if (geometry == null) + { + attrValue = "NULL"; + } else + { + attrValue = getGeometryInsertText(geometry, srid); + } + } else + { + if (attributes[i] != null) + { + attrValue = addQuotes(attributes[i]); + } + } + + if (attrValue != null) + { + statementSQL.append(attrValue).append(","); + } + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + + return (statementSQL.toString()); + } + + protected String makePrepareInsertSql(FeatureType featureType) + { + String tableName = encodeSchemaTableName(featureType.getTypeName()); + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + + String attrValue; + + StringBuffer statementSQL = new StringBuffer("INSERT INTO " + tableName + " ("); + + // encode insertion for attributes, but remember to avoid auto-increment ones, + // they may be included in the feature type as well + for (AttributeType attributeType : attributeTypes) + { + String attName = attributeType.getLocalName(); + + String colName = encodeSchemaColumnName(attName); + statementSQL.append(colName).append(","); + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + statementSQL.append(" VALUES ("); + + for (AttributeType attributeType : attributeTypes) + { + statementSQL.append(" ? ,"); + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + + return (statementSQL.toString()); + } + + protected String addQuotes(Object value) + { + String retString; + + if (value != null) + { + if (value instanceof Number) + { + retString = value.toString(); + } else + { + retString = "'" + doubleQuote(value) + "'"; + } + } else + { + retString = "null"; + } + + return retString; + } + + String doubleQuote(Object obj) + { + return obj.toString().replaceAll("'", "''"); + } + + protected String encodeName(String tableName) + { + return tableName; + } + + protected String encodeColumnName(String colName) + { + return encodeName(colName); + } + + public String encodeSchemaTableName(String tableName) + { + return schemaEnabled ? ("\"" + targetDataStore.getDatabaseSchemaName() + "\".\"" + tableName + "\"") + : ("\"" + tableName + "\""); + } + + public String encodeSchemaColumnName(String columnName) + { + return "\"" + columnName + "\""; + } + + protected void bindFeatureParameters(PreparedStatement pstmt, Feature feature) throws SQLException + { + FeatureType featureType = feature.getFeatureType(); + + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + Object[] attributes = feature.getAttributes(null); + + for (int i = 0; i < attributeTypes.length; i++) + { + if (attributeTypes[i] instanceof GeometryAttributeType) + { + pstmt.setBytes(i + 1, binaryWriter.writeBinary((Geometry) attributes[i])); + } else + { + if (attributeTypes[i].getBinding().equals(Short.class)) + { + pstmt.setShort(i + 1, (Short) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Integer.class)) + { + pstmt.setInt(i + 1, (Short) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Long.class)) + { + pstmt.setLong(i + 1, (Long) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(String.class)) + { + pstmt.setString(i + 1, (String) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Float.class)) + { + pstmt.setFloat(i + 1, (Float) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Double.class)) + { + pstmt.setDouble(i + 1, (Double) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Boolean.class)) + { + pstmt.setBoolean(i + 1, (Boolean) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(BigDecimal.class)) + { + pstmt.setBigDecimal(i + 1, (BigDecimal) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Date.class)) + { + pstmt.setDate(i + 1, (java.sql.Date) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Time.class)) + { + pstmt.setTime(i + 1, (java.sql.Time) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Timestamp.class)) + { + pstmt.setTimestamp(i + 1, (java.sql.Timestamp) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.util.Date.class)) + { + java.sql.Date sDate = new java.sql.Date(((java.util.Date) attributes[i]).getTime()); + pstmt.setDate(i + 1, sDate); + } + } + + } + } + +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java new file mode 100644 index 0000000..bd4d0c8 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java @@ -0,0 +1,762 @@ +package com.ximple.eofms.jobs.context.postgis; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.PreparedStatement; +import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.ArrayList; +import java.math.BigDecimal; + +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.data.SchemaNotFoundException; +import org.geotools.data.DataSourceException; +import org.geotools.data.jdbc.JDBCUtils; +import org.geotools.data.postgis.PostgisDataStore; +import org.geotools.feature.FeatureType; +import org.geotools.feature.AttributeType; +import org.geotools.feature.GeometryAttributeType; +import org.geotools.feature.Feature; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.referencing.NamedIdentifier; +import org.geotools.filter.LengthFunction; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.filter.Filter; +import org.opengis.filter.PropertyIsLessThan; +import org.opengis.filter.PropertyIsLessThanOrEqualTo; +import org.opengis.filter.BinaryComparisonOperator; +import org.opengis.filter.expression.Literal; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.io.WKTWriter; +import com.vividsolutions.jts.io.WKBWriter; + +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.util.postjts.JtsBinaryWriter; + +public abstract class AbstractOracleToPostGISJobContext extends AbstractOracleJobContext +{ + private static Map<String, Class> GEOM_TYPE_MAP = new HashMap<String, Class>(); + private static Map<String, Class> GEOM3D_TYPE_MAP = new HashMap<String, Class>(); + + static + { + GEOM_TYPE_MAP.put("GEOMETRY", Geometry.class); + GEOM_TYPE_MAP.put("POINT", Point.class); + GEOM_TYPE_MAP.put("LINESTRING", LineString.class); + GEOM_TYPE_MAP.put("POLYGON", Polygon.class); + GEOM_TYPE_MAP.put("MULTIPOINT", MultiPoint.class); + GEOM_TYPE_MAP.put("MULTILINESTRING", MultiLineString.class); + GEOM_TYPE_MAP.put("MULTIPOLYGON", MultiPolygon.class); + GEOM_TYPE_MAP.put("GEOMETRYCOLLECTION", GeometryCollection.class); + + GEOM3D_TYPE_MAP.put("POINTM", Point.class); + GEOM3D_TYPE_MAP.put("LINESTRINGM", LineString.class); + GEOM3D_TYPE_MAP.put("POLYGONM", Polygon.class); + GEOM3D_TYPE_MAP.put("MULTIPOINTM", MultiPoint.class); + GEOM3D_TYPE_MAP.put("MULTILINESTRINGM", MultiLineString.class); + GEOM3D_TYPE_MAP.put("MULTIPOLYGONM", MultiPolygon.class); + GEOM3D_TYPE_MAP.put("GEOMETRYCOLLECTIONM", GeometryCollection.class); + } + + private static Map<Class, String> CLASS_MAPPINGS = new HashMap<Class, String>(); + + static + { + CLASS_MAPPINGS.put(String.class, "VARCHAR"); + + CLASS_MAPPINGS.put(Boolean.class, "BOOLEAN"); + + CLASS_MAPPINGS.put(Short.class, "SMALLINT"); + CLASS_MAPPINGS.put(Integer.class, "INTEGER"); + CLASS_MAPPINGS.put(Long.class, "BIGINT"); + + CLASS_MAPPINGS.put(Float.class, "REAL"); + CLASS_MAPPINGS.put(Double.class, "DOUBLE PRECISION"); + + CLASS_MAPPINGS.put(BigDecimal.class, "DECIMAL"); + + CLASS_MAPPINGS.put(java.sql.Date.class, "DATE"); + CLASS_MAPPINGS.put(java.util.Date.class, "DATE"); + CLASS_MAPPINGS.put(java.sql.Time.class, "TIME"); + CLASS_MAPPINGS.put(java.sql.Timestamp.class, "TIMESTAMP"); + } + + private static Map<Class, String> GEOM_CLASS_MAPPINGS = new HashMap<Class, String>(); + + //why don't we just stick this in with the non-geom class mappings? + static + { + // init the inverse map + Set keys = GEOM_TYPE_MAP.keySet(); + + for (Object key : keys) + { + String name = (String) key; + Class geomClass = GEOM_TYPE_MAP.get(name); + GEOM_CLASS_MAPPINGS.put(geomClass, name); + } + } + + /** + * Maximum string size for postgres + */ + private static final int MAX_ALLOWED_VALUE = 10485760; + + protected static final int BATCHSIZE = 512; + + /** + * Well Known Text writer (from JTS). + */ + protected static WKTWriter geometryWriter = new WKTWriter(); + protected static JtsBinaryWriter binaryWriter = new JtsBinaryWriter(); + + protected PostgisDataStore targetDataStore; + private Connection connection; + protected boolean schemaEnabled = true; + + public AbstractOracleToPostGISJobContext(String dataPath, DataStore targetDataStore) + { + if ((targetDataStore != null) && (targetDataStore instanceof PostgisDataStore)) + { + this.targetDataStore = (PostgisDataStore) targetDataStore; + } else + { + getLogger().info("targetDataStore has wrong."); + } + setDataPath(dataPath); + } + + public PostgisDataStore getTargetDataStore() + { + return targetDataStore; + } + + public void setTargetDataStore(PostgisDataStore targetDataStore) + { + this.targetDataStore = targetDataStore; + } + + public Connection getConnection() + { + if (connection != null) return connection; + + if (targetDataStore != null) + { + try + { + connection = targetDataStore.getDataSource().getConnection(); + } catch (SQLException e) + { + getLogger().warn(e.getMessage(), e); + return null; + } + } + return connection; + } + + public void closeConnection() + { + if (connection == null) + { + JDBCUtils.close(connection, Transaction.AUTO_COMMIT, null); + connection = null; + } + } + + protected boolean isExistFeature(FeatureType featureType) + { + try + { + FeatureType existFeatureType = targetDataStore.getSchema(featureType.getTypeName()); + return existFeatureType != null; // && existFeatureType.equals(featureType); + } catch (SchemaNotFoundException e) + { + return false; + } catch (IOException e) + { + getLogger().info(e.getMessage(), e); + return false; + } + } + + protected void deleteTable(Connection conn, String tableName) throws SQLException + { + Statement stmt = conn.createStatement(); + StringBuilder sb = new StringBuilder(); + sb.append("DELETE FROM \""); + sb.append(targetDataStore.getDatabaseSchemaName()); + sb.append("\".\""); + sb.append(tableName); + sb.append('\"'); + getLogger().info("Execute-" + sb.toString()); + stmt.execute(sb.toString()); + stmt.close(); + conn.commit(); + } + + protected void dropTable(Connection conn, String tableName) throws SQLException + { + Statement stmt = conn.createStatement(); + StringBuilder sb = new StringBuilder(); + sb.append("DROP TABLE \""); + sb.append(targetDataStore.getDatabaseSchemaName()); + sb.append("\".\""); + sb.append(tableName); + sb.append("\" CASCADE"); + getLogger().info("Execute-" + sb.toString()); + stmt.execute(sb.toString()); + stmt.close(); + conn.commit(); + } + + protected void dropGeometryColumn(Connection conn, String tableName, String geomField) throws SQLException + { + Statement stmt = conn.createStatement(); + StringBuilder sb = new StringBuilder(); + sb.append("SELECT DropGeometryColumn('','"); + sb.append(tableName); + sb.append("','"); + sb.append(geomField); + sb.append("')"); + getLogger().info("Execute-" + sb.toString()); + stmt.execute(sb.toString()); + stmt.close(); + conn.commit(); + } + + protected String dropGeometryColumn(String dbSchema, String tableName, String geomField) + { + StringBuilder sb = new StringBuilder(); + sb.append("SELECT DropGeometryColumn('"); + sb.append(dbSchema); + sb.append("','"); + sb.append(tableName); + sb.append("','"); + sb.append(geomField); + sb.append("')"); + getLogger().info("Execute-" + sb.toString()); + return sb.toString(); + } + + private String addGeometryColumn(String dbSchema, String tableName, GeometryAttributeType geometryAttribute, int srid) + { + StringBuilder sql; + String typeName = getGeometrySQLTypeName(geometryAttribute.getBinding()); + if (typeName == null) + { + getLogger().warn("Error: " + geometryAttribute.getLocalName() + " unknown type!!!"); + throw new RuntimeException("Error: " + geometryAttribute.getLocalName() + " unknown type!!!"); + } + + sql = new StringBuilder("SELECT AddGeometryColumn('"); + sql.append(dbSchema); + sql.append("','"); + sql.append(tableName); + sql.append("','"); + sql.append(geometryAttribute.getLocalName()); + sql.append("','"); + sql.append(srid); + sql.append("','"); + sql.append(typeName); + sql.append("', 2);"); + + //prints statement for later reuse + return sql.toString(); + } + + public ArrayList<String> createNewSchemaTexts(FeatureType featureType) throws IOException + { + String origintableName = featureType.getTypeName(); + String tableName = origintableName.toLowerCase(); + + ArrayList<String> result = new ArrayList<String>(); + + AttributeType[] attributeType = featureType.getAttributeTypes(); + // String dbSchema = targetDataStore.getDatabaseSchemaName(); + + Connection con = getConnection(); + + boolean shouldDrop = tablePresent(tableName, con); + if (shouldDrop) + { + String sqlStr = "DROP TABLE " + encodeSchemaTableName(tableName) + ";"; + getLogger().info(sqlStr); + result.add(sqlStr); + } + + StringBuffer sql = new StringBuffer("CREATE TABLE "); + sql.append(encodeSchemaTableName(tableName)); + sql.append(" ( gid serial PRIMARY KEY, "); + sql.append(makeNonGeomSqlCreate(attributeType)); + sql.append(");"); + + String sqlStr = sql.toString(); + getLogger().info(sqlStr); + result.add(sqlStr); + + for (AttributeType anAttributeType : attributeType) + { + if (!(anAttributeType instanceof GeometryAttributeType)) + { + continue; + } + GeometryAttributeType geomAttribute = (GeometryAttributeType) anAttributeType; + + if (shouldDrop) + { + sqlStr = dropGeometryColumn("", tableName, geomAttribute.getLocalName()); + getLogger().info(sqlStr); + result.add(sqlStr); + } + + CoordinateReferenceSystem refSys = geomAttribute.getCoordinateSystem(); + int SRID; + + if (refSys != null) + { + try + { + Set ident = refSys.getIdentifiers(); + if ((ident == null || ident.isEmpty()) && refSys == DefaultGeographicCRS.WGS84) + { + SRID = 4326; + } else + { + String code = ((NamedIdentifier) ident.toArray()[0]).getCode(); + SRID = Integer.parseInt(code); + } + } catch (Exception e) + { + getLogger().warn("SRID could not be determined"); + SRID = -1; + } + } else + { + SRID = -1; + } + + sqlStr = addGeometryColumn("", tableName, geomAttribute, SRID); + getLogger().info(sqlStr); + result.add(sqlStr); + + + String indexName = tableName.replace('-', '_'); + //also build a spatial index on each geometry column. + sql = new StringBuffer("CREATE INDEX spatial_"); + sql.append(indexName); + sql.append("_"); + sql.append(anAttributeType.getLocalName().toLowerCase()); + sql.append(" ON "); + sql.append(encodeSchemaTableName(tableName)); + sql.append(" USING GIST ("); + sql.append(encodeSchemaColumnName(anAttributeType.getLocalName())); + sql.append(" gist_geometry_ops);"); + + sqlStr = sql.toString(); + getLogger().info(sqlStr); + + result.add(sqlStr); + } + + return result; + } + + private boolean tablePresent(String table, Connection conn) throws IOException + { + final int TABLE_NAME_COL = 3; + + try + { + conn = getConnection(); + + DatabaseMetaData meta = conn.getMetaData(); + String[] tableType = {"TABLE"}; + ResultSet tables = meta.getTables(null, + targetDataStore.getDatabaseSchemaName(), "%", tableType); + + while (tables.next()) + { + String tableName = tables.getString(TABLE_NAME_COL); + + if (allowTable(tableName) && (tableName != null) + && (tableName.equalsIgnoreCase(table))) + { + tables.close(); + return true; + } + } + + tables.close(); + return false; + } catch (SQLException sqlException) + { + // JDBCUtils.close(conn, Transaction.AUTO_COMMIT, sqlException); + // conn = null; + + String message = "Error querying database for list of tables:" + + sqlException.getMessage(); + throw new DataSourceException(message, sqlException); + } finally + { + // JDBCUtils.close(conn, Transaction.AUTO_COMMIT, null); + } + } + + protected boolean allowTable(String tablename) + { + if (tablename.equals("geometry_columns")) + { + return false; + } else if (tablename.startsWith("spatial_ref_sys")) + { + return false; + } + + //others? + return true; + } + + + private StringBuffer makeNonGeomSqlCreate(AttributeType[] attributeType) + throws IOException + { + StringBuffer buf = new StringBuffer(""); + + for (AttributeType anAttributeType : attributeType) + { + String typeName; + typeName = CLASS_MAPPINGS.get(anAttributeType.getBinding()); + if (typeName == null) + { + typeName = GEOM_CLASS_MAPPINGS.get(anAttributeType.getBinding()); + if (typeName != null) continue; + } + + if (typeName != null) + { + if (typeName.equals("VARCHAR")) + { + int length = -1; + Filter f = anAttributeType.getRestriction(); + if (f != null && f != Filter.EXCLUDE && f != Filter.INCLUDE && + (f instanceof PropertyIsLessThan || f instanceof PropertyIsLessThanOrEqualTo)) + { + try + { + BinaryComparisonOperator cf = (BinaryComparisonOperator) f; + if (cf.getExpression1() instanceof LengthFunction) + { + length = Integer.parseInt(((Literal) cf.getExpression2()).getValue().toString()); + } else + { + if (cf.getExpression2() instanceof LengthFunction) + { + length = Integer.parseInt(((Literal) cf.getExpression1()).getValue().toString()); + } + } + } catch (NumberFormatException e) + { + length = 256; + } + } else + { + length = 256; + } + + if (length < 1) + { + getLogger().warn("FeatureType did not specify string length; defaulted to 256"); + length = 256; + } else if (length > MAX_ALLOWED_VALUE) + { + length = MAX_ALLOWED_VALUE; + } + typeName = typeName + "(" + length + ")"; + } + + if (!anAttributeType.isNillable()) + { + typeName = typeName + " NOT NULL"; + } + + //TODO review!!! Is toString() always OK??? + Object defaultValue = anAttributeType.createDefaultValue(); + + if (defaultValue != null) + { + typeName = typeName + " DEFAULT '" + + defaultValue.toString() + "'"; + } + + buf.append(" \"").append(anAttributeType.getLocalName()).append("\" ").append(typeName).append(","); + + } else + { + String msg; + if (anAttributeType == null) + { + msg = "AttributeType was null!"; + } else + { + msg = "Type '" + anAttributeType.getBinding() + "' not supported!"; + } + throw (new IOException(msg)); + } + } + + return buf.deleteCharAt(buf.length() - 1); + } + + private String getGeometrySQLTypeName(Class type) + { + String res = GEOM_CLASS_MAPPINGS.get(type); + + if (res == null) + { + throw new RuntimeException("Unknown type name for class " + type + + " please update GEOMETRY_MAPPINGS"); + } + + return res; + } + + protected String getGeometryInsertText(Geometry geom, int srid) // throws IOException + { + if (geom == null) + { + return "null"; + } + + if (targetDataStore.isWKBEnabled()) + { + //String wkb = WKBEncoder.encodeGeometryHex(geom); + String wkb = WKBWriter.bytesToHex(new WKBWriter().write(geom)); + + if (targetDataStore.isByteaWKB()) + { + return "setSRID('" + wkb + "'::geometry," + srid + ")"; + } else + { + return "GeomFromWKB('" + wkb + "', " + srid + ")"; + } + } + + String geoText = geometryWriter.write(geom); + + return "GeometryFromText('" + geoText + "', " + srid + ")"; + } + + protected String makeInsertSql(Feature feature, int srid) // throws IOException + { + FeatureType featureType = feature.getFeatureType(); + + String tableName = encodeSchemaTableName(featureType.getTypeName()); + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + + String attrValue; + + StringBuilder statementSQL = new StringBuilder(512); + statementSQL.append("INSERT INTO ").append(tableName).append(" ("); + + // encode insertion for attributes, but remember to avoid auto-increment ones, + // they may be included in the feature type as well + for (AttributeType attributeType : attributeTypes) + { + String attName = attributeType.getLocalName(); + + if (feature.getAttribute(attName) != null) + { + String colName = encodeSchemaColumnName(attName); + statementSQL.append(colName).append(","); + } + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + statementSQL.append(" VALUES ("); + + Object[] attributes = feature.getAttributes(null); + + for (int i = 0; i < attributeTypes.length; i++) + { + attrValue = null; + + if (attributeTypes[i] instanceof GeometryAttributeType) + { + // String geomName = attributeTypes[i].getLocalName(); + // int srid = ftInfo.getSRID(geomName); + Geometry geometry = (Geometry) attributes[i]; + + if (geometry == null) + { + attrValue = "NULL"; + } else + { + attrValue = getGeometryInsertText(geometry, srid); + } + } else + { + if (attributes[i] != null) + { + attrValue = addQuotes(attributes[i]); + } + } + + if (attrValue != null) + { + statementSQL.append(attrValue).append(","); + } + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + + return (statementSQL.toString()); + } + + protected String makePrepareInsertSql(FeatureType featureType) + { + String tableName = encodeSchemaTableName(featureType.getTypeName()); + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + + String attrValue; + + StringBuffer statementSQL = new StringBuffer("INSERT INTO " + tableName + " ("); + + // encode insertion for attributes, but remember to avoid auto-increment ones, + // they may be included in the feature type as well + for (AttributeType attributeType : attributeTypes) + { + String attName = attributeType.getLocalName(); + + String colName = encodeSchemaColumnName(attName); + statementSQL.append(colName).append(","); + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + statementSQL.append(" VALUES ("); + + for (AttributeType attributeType : attributeTypes) + { + statementSQL.append(" ? ,"); + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + + return (statementSQL.toString()); + } + + protected String addQuotes(Object value) + { + String retString; + + if (value != null) + { + if (value instanceof Number) + { + retString = value.toString(); + } else + { + retString = "'" + doubleQuote(value) + "'"; + } + } else + { + retString = "null"; + } + + return retString; + } + + String doubleQuote(Object obj) + { + return obj.toString().replaceAll("'", "''"); + } + + protected String encodeName(String tableName) + { + return tableName; + } + + protected String encodeColumnName(String colName) + { + return encodeName(colName); + } + + public String encodeSchemaTableName(String tableName) { + return schemaEnabled ? ("\"" + targetDataStore.getDatabaseSchemaName() + "\".\"" + tableName + "\"") + : ("\"" + tableName + "\""); + } + + public String encodeSchemaColumnName(String columnName) { + return "\"" + columnName + "\""; + } + + protected void bindFeatureParameters(PreparedStatement pstmt, Feature feature) throws SQLException + { + FeatureType featureType = feature.getFeatureType(); + + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + Object[] attributes = feature.getAttributes(null); + + for (int i = 0; i < attributeTypes.length; i++) + { + if (attributeTypes[i] instanceof GeometryAttributeType) + { + pstmt.setBytes(i + 1, binaryWriter.writeBinary((Geometry) attributes[i])); + } else + { + if (attributeTypes[i].getBinding().equals(Short.class)) + { + pstmt.setShort(i + 1, (Short) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Integer.class)) + { + pstmt.setInt(i + 1, (Short) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Long.class)) + { + pstmt.setLong(i + 1, (Long) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(String.class)) + { + pstmt.setString(i + 1, (String) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Float.class)) + { + pstmt.setFloat(i + 1, (Float) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Double.class)) + { + pstmt.setDouble(i + 1, (Double) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Boolean.class)) + { + pstmt.setBoolean(i + 1, (Boolean) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(BigDecimal.class)) + { + pstmt.setBigDecimal(i + 1, (BigDecimal) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Date.class)) + { + pstmt.setDate(i + 1, (java.sql.Date) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Time.class)) + { + pstmt.setTime(i + 1, (java.sql.Time) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Timestamp.class)) + { + pstmt.setTimestamp(i + 1, (java.sql.Timestamp) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.util.Date.class)) + { + java.sql.Date sDate = new java.sql.Date(((java.util.Date) attributes[i]).getTime()); + pstmt.setDate(i + 1, sDate); + } + } + + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/DummyFeatureConvertPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/DummyFeatureConvertPostGISJobContext.java new file mode 100644 index 0000000..7c48de5 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/DummyFeatureConvertPostGISJobContext.java @@ -0,0 +1,284 @@ +package com.ximple.eofms.jobs.context.postgis; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.filter.TypeCompIdDispatchableFilter; +import com.ximple.eofms.filter.TypeCompLevelIdDispatchableFilter; +import com.ximple.eofms.filter.TypeIdDispatchableFilter; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class DummyFeatureConvertPostGISJobContext extends AbstractDgnToPostGISJobContext +{ + static final Log logger = LogFactory.getLog(DummyFeatureConvertPostGISJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public DummyFeatureConvertPostGISJobContext(String dataPath, DataStore targetDataStore, String filterConfig) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + assert elementDispatcher != null; + for (ElementDispatchableFilter filter : elementDispatcher.getRules()) + { + if (filter instanceof TypeCompIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeCompLevelIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } + } + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save PostGIS:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save PostGIS:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/FeatureDgnConvertPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/FeatureDgnConvertPostGISJobContext.java new file mode 100644 index 0000000..2ac1836 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/FeatureDgnConvertPostGISJobContext.java @@ -0,0 +1,266 @@ +package com.ximple.eofms.jobs.context.postgis; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class FeatureDgnConvertPostGISJobContext extends AbstractDgnToPostGISJobContext +{ + static final Log logger = LogFactory.getLog(FeatureDgnConvertPostGISJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public FeatureDgnConvertPostGISJobContext(String dataPath, DataStore targetDataStore, String filterConfig) + { + super(dataPath, targetDataStore); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList<Feature> arrayList = (ArrayList<Feature>) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + logger.debug("Begin Save PostGIS:" + featureType.getTypeName()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + if (!isExistFeature(featureType)) + { + targetDataStore.createSchema(featureType); + writer = targetDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = targetDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save PostGIS:" + featureType.getTypeName()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java new file mode 100644 index 0000000..9e0e019 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java @@ -0,0 +1,613 @@ +package com.ximple.eofms.jobs.context.postgis; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.TreeMap; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.postgresql.util.PSQLException; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.EllipseElement; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.ShapeElement; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.TextNodeElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class GeneralDgnConvertPostGISJobContext extends AbstractDgnToPostGISJobContext +{ + static final Log logger = LogFactory.getLog(GeneralDgnConvertPostGISJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + + private HashMap<FeatureType, ArrayList<Feature>> txFeaturesContext = new HashMap<FeatureType, ArrayList<Feature>>(); + + private TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + private TreeMap<String, FeatureType> featureTypes = new TreeMap<String, FeatureType>(); + + private TWD97GeometryConverterDecorator convertDecorator = null; + private String featureBaseName = null; + private boolean dropTableMode = true; + + private int accumulate = 0; + + public GeneralDgnConvertPostGISJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath, targetDataStore); + convertDecorator = new TWD97GeometryConverterDecorator(); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + FeatureType ft = lookupFeatureType(element); + if (ft != null) + { + Feature feature = createFeature(ft, element); + if (feature == null) + { + if (element instanceof TextElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + else if (element instanceof ShapeElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ShapeElement) element).getVerticeSize() + "'" + + ((ShapeElement) element).getStartPoint()); + else if (element instanceof LineStringElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((LineStringElement) element).getVerticeSize() + "'" + + ((LineStringElement) element).getStartPoint()); + else if (element instanceof ArcElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ArcElement) element).getOrigin().toString() + "'" + + ((ArcElement) element).getRotationAngle()); + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); + } + ArrayList<Feature> arrayList = txFeaturesContext.get(feature.getFeatureType()); + if (feature.getDefaultGeometry() != null && !feature.getDefaultGeometry().isEmpty()) + { + arrayList.add(feature); + accumulate++; + } + } else + { + logger.info("Unknown Element :" + element.getType() + ", lv=" + element.getLevelIndex()); + } + + if (accumulate > BATCHSIZE) + { + commitTransaction(); + } + } + + // private Transaction transaction; + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!txFeaturesContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + } + + private void updateDataStore() + { + Iterator<FeatureType> it = txFeaturesContext.keySet().iterator(); + try + { + while (it.hasNext()) + { + FeatureType featureType = it.next(); + logger.debug("Begin Save into PostGIS:" + featureType.getTypeName()); + + String bindingStmt = makePrepareInsertSql(featureType); + ArrayList<Feature> features = txFeaturesContext.get(featureType); + Connection conn = getConnection(); + boolean autoCommit = conn.getAutoCommit(); + conn.setAutoCommit(true); + PreparedStatement pstmt = conn.prepareStatement(bindingStmt); + + for (Feature feature : features) + { + // currentStmt = feature; + // Statement stmt = conn.createStatement(); + try + { + // stmt.execute(feature); + bindFeatureParameters(pstmt, feature); + pstmt.execute(); + } catch (PSQLException e) + { + if (bindingStmt != null) + { + logger.error("Execute:" + bindingStmt); + } + logger.error(e.getServerErrorMessage()); + logger.error(e.getMessage(), e); + } + } + + pstmt.close(); + features.clear(); + conn.setAutoCommit(autoCommit); + logger.debug("End Save into PostGIS:" + featureType.getTypeName()); + } + accumulate = 0; + } catch (SQLException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + txFeaturesContext.clear(); + /* + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + */ + } + + public FeatureType createPointFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalPointFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createPolygonFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalPolygonFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createLineFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createMultiLineFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalMultiLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createArcFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalArcFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createEllipseFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalEllipseFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + convertDecorator.setConverter(textElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textElement.getRotationAngle(); + String content = textElement.getText(); + content = content.replace('\u0000', ' '); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getFontIndex(), + textElement.getJustification(), + textElement.getTextHeight(), + textElement.getTextWidth(), + angle, + content + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof TextNodeElement) + { + TextNodeElement textNodeElement = (TextNodeElement) element; + convertDecorator.setConverter(textNodeElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textNodeElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + String[] texts = textNodeElement.getTextArray(); + StringBuffer sb = new StringBuffer(); + for (String text : texts) + { + if (sb.length() != 0) + sb.append("\n"); + String content = text.replace('\u0000', ' '); + sb.append(content); + } + + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textNodeElement.getColorIndex()), + textNodeElement.getFontIndex(), + textNodeElement.getJustification(), + textNodeElement.getTextNodeHeight(), + textNodeElement.getTextNodeLength(), + angle, + sb.toString() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof ShapeElement) + { + ShapeElement shapeElement = (ShapeElement) element; + convertDecorator.setConverter(shapeElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(shapeElement.getColorIndex()), + shapeElement.getWeight(), + shapeElement.getLineStyle() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof LineStringElement) + { + LineStringElement linestring = (LineStringElement) element; + convertDecorator.setConverter(linestring); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(linestring.getColorIndex()), + linestring.getWeight(), + linestring.getLineStyle() + }); + return null; + } else if (element instanceof LineElement) + { + LineElement line = (LineElement) element; + convertDecorator.setConverter(line); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(line.getColorIndex()), + line.getWeight(), + line.getLineStyle() + }); + return null; + } else if (element instanceof ArcElement) + { + ArcElement arcElement = (ArcElement) element; + /* + logger.fatal("" + arcElement.getPrimary() + ":" + arcElement.getSecondary() + + "-" + arcElement.getStartAngle() + ":" + arcElement.getSweepAngle() + ":" + + arcElement.getRotationAngle() + ":" + arcElement.getOrigin()); + */ + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof EllipseElement) + { + EllipseElement arcElement = (EllipseElement) element; + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChainElement = (ComplexChainElement) element; + convertDecorator.setConverter(complexChainElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(complexChainElement.getColorIndex()), + complexChainElement.getWeight(), + complexChainElement.getLineStyle() + }); + return null; + } + return null; + } + + private String getFeatureBaseName() + { + if (featureBaseName == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureBaseName = dgnname; + } + return featureBaseName; + } + + private FeatureType lookupFeatureType(Element element) throws SchemaException, IllegalAttributeException + { + String typeName; + if (element instanceof TextElement) + { + typeName = getFeatureBaseName() + "_P"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof TextNodeElement) + { + typeName = getFeatureBaseName() + "_P"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof LineStringElement) + { + if (element instanceof ShapeElement) + { + typeName = getFeatureBaseName() + "_R"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPolygonFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else + { + typeName = getFeatureBaseName() + "_L"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + } else if (element instanceof LineElement) + { + typeName = getFeatureBaseName() + "_L"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ComplexChainElement) + { + typeName = getFeatureBaseName() + "_ML"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createMultiLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ArcElement) + { + typeName = getFeatureBaseName() + "_A"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createArcFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof EllipseElement) + { + typeName = getFeatureBaseName() + "_R"; + typeName = typeName.toLowerCase(); + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createEllipseFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + + return null; + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public Log getLogger() + { + return logger; + } + + public boolean isDropTableMode() + { + return dropTableMode; + } + + public void setDropTableMode(boolean dropTableMode) + { + this.dropTableMode = dropTableMode; + } + + protected void clearFeatureData(FeatureTypeBuilder typeBuilder) throws SchemaException + { + String featureName = typeBuilder.getName(); + if (isExistFeature(typeBuilder.getFeatureType())) + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + if (dropTableMode) + { + dropGeometryColumn(conn, featureName, + typeBuilder.getFeatureType().getDefaultGeometry().getLocalName()); + dropTable(conn, featureName); + + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilder.getFeatureType()); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + } else { + deleteTable(conn, featureName); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } else + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilder.getFeatureType()); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java new file mode 100644 index 0000000..523d151 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java @@ -0,0 +1,468 @@ +package com.ximple.eofms.jobs.context.postgis; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.postgresql.util.PSQLException; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TPCLIDConverter; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.eofms.util.TWDDatumConverter; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class IndexDgnConvertPostGISJobContext extends AbstractDgnToPostGISJobContext +{ + static final Log logger = LogFactory.getLog(IndexDgnConvertPostGISJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + + private HashMap<FeatureType, ArrayList<Feature>> txFeaturesContext = new HashMap<FeatureType, ArrayList<Feature>>(); + + private FeatureTypeBuilder typeBuilderPnt = null; + private FeatureTypeBuilder typeBuilderRect = null; + private FeatureType featureType = null; + private FeatureType featureType2 = null; + + private boolean dropTableMode = true; + private int accumulate = 0; + + public IndexDgnConvertPostGISJobContext(String dataPath, DataStore targetDataStore) + { + super(dataPath, targetDataStore); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + if (!(element instanceof TextElement)) + { + return; + } + + Feature feature = createFeature((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); + } + ArrayList<Feature> arrayList = txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + + feature = createFeature2((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature2." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); + } + arrayList = txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + accumulate++; + + if (accumulate > BATCHSIZE) + { + commitTransaction(); + } + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + } else + { + logger.debug("Transaction is empty."); + } + + if (!txFeaturesContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + } + + private void updateDataStore() + { + Iterator<FeatureType> it = txFeaturesContext.keySet().iterator(); + try + { + while (it.hasNext()) + { + FeatureType featureType = it.next(); + logger.debug("Begin Save PostGIS:" + featureType.getTypeName()); + + String bindingStmt = makePrepareInsertSql(featureType); + ArrayList<Feature> features = txFeaturesContext.get(featureType); + Connection conn = getConnection(); + boolean autoCommit = conn.getAutoCommit(); + conn.setAutoCommit(true); + PreparedStatement pstmt = conn.prepareStatement(bindingStmt); + + for (Feature feature : features) + { + // currentStmt = feature; + // Statement stmt = conn.createStatement(); + try + { + // stmt.execute(feature); + bindFeatureParameters(pstmt, feature); + pstmt.execute(); + } catch (PSQLException e) + { + if (bindingStmt != null) + { + logger.error("Execute:" + bindingStmt); + } + logger.error(e.getServerErrorMessage()); + logger.error(e.getMessage(), e); + /* + } finally { + stmt.close(); + */ + } + } + /* + if ((i % BATCHSIZE) != 0) + { + stmt.executeBatch(); + } + stmt.close(); + */ + + pstmt.close(); + features.clear(); + + conn.setAutoCommit(autoCommit); + logger.debug("End Save PostGIS:" + featureType.getTypeName()); + } + accumulate = 0; + } catch (PSQLException e) + { + logger.error(e.getServerErrorMessage()); + logger.error(e.getMessage(), e); + } catch (SQLException e) + { + logger.error(e.getMessage(), e); + } + } + + public void closeFeatureWriter() throws IOException + { + txFeaturesContext.clear(); + /* + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + */ + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (typeBuilderRect == null) + { + typeBuilderRect = FeatureTypeBuilderUtil.createNormalIndexFeatureTypeBuilder(featureName); + if (isExistFeature(typeBuilderRect.getFeatureType())) + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + if (dropTableMode) + { + try + { + dropGeometryColumn(conn, featureName, + typeBuilderRect.getFeatureType().getDefaultGeometry().getLocalName()); + } catch (PSQLException e) + { + logger.debug(e.getMessage(), e); + } + try + { + dropTable(conn, featureName); + } catch (PSQLException e) + { + logger.debug(e.getMessage(), e); + } + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderRect.getFeatureType()); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + } else + { + deleteTable(conn, featureName); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } else + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderRect.getFeatureType()); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } + } + return typeBuilderRect.getFeatureType(); + } + + public FeatureType createFeatureElement2(String featureName) throws SchemaException + { + if (typeBuilderPnt == null) + { + typeBuilderPnt = FeatureTypeBuilderUtil.createNormalIndexTextFeatureTypeBuilder(featureName); + if (isExistFeature(typeBuilderPnt.getFeatureType())) + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + if (dropTableMode) + { + dropGeometryColumn(conn, featureName, + typeBuilderPnt.getFeatureType().getDefaultGeometry().getLocalName()); + dropTable(conn, featureName); + + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderPnt.getFeatureType()); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + } else + { + deleteTable(conn, featureName); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } else + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderPnt.getFeatureType()); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } + } + return typeBuilderPnt.getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + String tpclid = textElement.getText(); + + Envelope extent = TPCLIDConverter.convertTpclIdToEnvelope(tpclid); + Geometry geom = geometryFactory.createPolygon(geometryFactory.createLinearRing(new Coordinate[] + { + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + }), null); + + return featureType.create(new Object[]{ + geom, + extent.getMinX(), + extent.getMinY(), + extent.getMaxX(), + extent.getMaxY(), + tpclid, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getWeight(), + textElement.getLineStyle() + }); + } + return null; + } + + public Feature createFeature2(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + Feature feature = null; + TextElement txtElement = (TextElement) element; + double angle = txtElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + convertDecorator.setConverter(txtElement); + Geometry gobj = convertDecorator.toGeometry(geometryFactory); + if (gobj != null) + feature = featureType.create(new Object[]{ + gobj, + colorTable.getColorCode(txtElement.getColorIndex()), + txtElement.getWeight(), + txtElement.getLineStyle(), + txtElement.getJustification(), + txtElement.getTextHeight(), + txtElement.getTextWidth(), + angle, + txtElement.getText() + }); + return feature; + } + return null; + } + + private Feature createFeature(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureType = createFeatureElement(dgnname.toLowerCase()); + } + return createFeature(featureType, element); + } + + private Feature createFeature2(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType2 == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + dgnname = dgnname + "_p"; + featureType2 = createFeatureElement2(dgnname.toLowerCase()); + } + return createFeature2(featureType2, element); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public Log getLogger() + { + return logger; + } + + public boolean isDropTableMode() + { + return dropTableMode; + } + + public void setDropTableMode(boolean dropTableMode) + { + this.dropTableMode = dropTableMode; + } + + public void clearOutputDatabase() + { + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/OracleConvertPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/OracleConvertPostGISJobContext.java new file mode 100644 index 0000000..348d2b3 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/OracleConvertPostGISJobContext.java @@ -0,0 +1,390 @@ +package com.ximple.eofms.jobs.context.postgis; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.DataStore; +import org.geotools.data.Transaction; +import org.geotools.data.postgis.PostgisDataStoreFactory; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.SchemaException; +import org.postgresql.util.PSQLException; +import org.quartz.JobExecutionContext; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.util.Assert; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.CreateFeatureTypeEventListener; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.filter.FeatureTypeEvent; +import com.ximple.eofms.jobs.OracleElementLogger; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; + +public class OracleConvertPostGISJobContext extends AbstractOracleToPostGISJobContext + implements CreateFeatureTypeEventListener +{ + static Log logger = LogFactory.getLog(OracleConvertPostGISJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + + static PostgisDataStoreFactory dataStoreFactory = new PostgisDataStoreFactory(); + + private OracleElementLogger elmLogger = null; + + static + { + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + } catch (SQLException e) + { + Assert.shouldNeverReachHere(e.getMessage()); + } + } + + private String _filterConfig; + + private ElementDispatcher elementDispatcher; + + private HashMap<FeatureType, ArrayList<Feature>> txFeaturesContext = new HashMap<FeatureType, ArrayList<Feature>>(); + + private JobExecutionContext executionContext; + + private String currentSchema = null; + private boolean schemaChanged = false; + private boolean dropTableMode = true; + private int accumulate = 0; + + public OracleConvertPostGISJobContext(String dataPath, DataStore pgDS, String filterConfig) + { + super(dataPath, pgDS); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + elementDispatcher.addCreateFeatureTypeEventListener(this); + // txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) + { + assert elementDispatcher != null; + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + boolean isEmptySize = false; + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size() + ":" + + (linkage == null ? "NULL" : (linkage.getUfid()))); + isEmptySize = true; + } + + if (getElementLogging() && (!isEmptySize)) + { + getElementLogger().logElement(element, getCurrentSchema()); + } + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); + } + ArrayList<Feature> arrayList = txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + accumulate++; + if (accumulate > BATCHSIZE) + { + commitTransaction(); + } + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!txFeaturesContext.isEmpty()) + { + updateDataStore(); + } + + if (this.getElementLogger() != null) + this.getElementLogger().flashLogging(); + } + + public void rollbackTransaction() + { + } + + public void resetFeatureContext() + { + txFeaturesContext.clear(); + } + + private void updateDataStore() + { + Iterator<FeatureType> it = txFeaturesContext.keySet().iterator(); + try + { + Connection conn = getConnection(); + boolean autoCommit = conn.getAutoCommit(); + conn.setAutoCommit(true); + while (it.hasNext()) + { + FeatureType featureType = it.next(); + logger.debug("Begin Save into PostGIS:" + featureType.getTypeName()); + + String bindingStmt = makePrepareInsertSql(featureType); + ArrayList<Feature> features = txFeaturesContext.get(featureType); + PreparedStatement pstmt = conn.prepareStatement(bindingStmt); + + for (Feature feature : features) + { + try + { + // stmt.execute(feature); + bindFeatureParameters(pstmt, feature); + pstmt.execute(); + } catch (PSQLException e) + { + if (bindingStmt != null) + { + logger.error("Execute:" + bindingStmt); + } + logger.error(e.getServerErrorMessage()); + logger.error(e.getMessage(), e); + } catch (ClassCastException e) + { + if (bindingStmt != null) + { + logger.error("Execute:" + bindingStmt); + } + for (int i = 0; i < feature.getNumberOfAttributes(); i++) + { + logger.info("attr[" + i + "]-" + ((feature.getAttribute(i) == null) ? " NULL" : + feature.getAttribute(i).toString())); + } + logger.error(e.getMessage(), e); + } + } + + pstmt.close(); + features.clear(); + logger.debug("End Save into PostGIS:" + featureType.getTypeName()); + } + conn.setAutoCommit(autoCommit); + accumulate = 0; + } catch (SQLException e) + { + logger.error(e.getMessage(), e); + } + } + + public JobExecutionContext getExecutionContext() + { + return executionContext; + } + + public void setExecutionContext(JobExecutionContext context) + { + executionContext = context; + } + + /** + * �����]�Ƽg�J�� + * + * @throws IOException IO�o�Ϳ��~ + */ + public void closeFeatureWriter() throws IOException + { + } + + protected OracleElementLogger getElementLogger() + { + if (elmLogger == null) + { + elmLogger = new OracleElementLogger(getOracleConnection()); + elmLogger.setDataPath(this.getDataPath()); + } + return elmLogger; + } + + public String getCurrentSchema() + { + return currentSchema; + } + + public void setCurrentSchema(String querySchema) + { + this.currentSchema = querySchema; + this.schemaChanged = true; + } + + protected Log getLogger() + { + return logger; + } + + public boolean isDropTableMode() + { + return dropTableMode; + } + + public void setDropTableMode(boolean dropTableMode) + { + this.dropTableMode = dropTableMode; + } + + public void createFeatureTypeOccurred(FeatureTypeEvent evt) + { + try + { + clearFeatureData(evt.getFeatureType()); + } catch (SchemaException e) + { + logger.warn(e.getMessage(), e); + } + } + + protected void clearFeatureData(FeatureType featureType) throws SchemaException + { + String featureName = featureType.getTypeName(); + if (isExistFeature(featureType)) + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + if (dropTableMode) + { + dropGeometryColumn(conn, featureName, + featureType.getDefaultGeometry().getLocalName()); + dropTable(conn, featureName); + + ArrayList<String> schemaTexts = createNewSchemaTexts(featureType); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + } else + { + deleteTable(conn, featureName); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } else + { + try + { + Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); + ArrayList<String> schemaTexts = createNewSchemaTexts(featureType); + for (String stmtText : schemaTexts) + { + Statement stmt = conn.createStatement(); + stmt.execute(stmtText); + stmt.close(); + } + conn.close(); + } catch (IOException e) + { + logger.warn(e.getMessage(), e); + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } + } + + public boolean isSchemaChanged() + { + return schemaChanged; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/AbstractDgnToShapefileJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/AbstractDgnToShapefileJobContext.java new file mode 100644 index 0000000..395adc2 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/AbstractDgnToShapefileJobContext.java @@ -0,0 +1,13 @@ +package com.ximple.eofms.jobs.context.shapefile; + +import com.ximple.eofms.jobs.context.AbstractDgnFileJobContext; + +public abstract class AbstractDgnToShapefileJobContext extends AbstractDgnFileJobContext +{ + public AbstractDgnToShapefileJobContext(String dataPath) + { + super(dataPath); + } + + public abstract String getDataOutPath(); +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/DummyFeatureConvertShpJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/DummyFeatureConvertShpJobContext.java new file mode 100644 index 0000000..fda158f --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/DummyFeatureConvertShpJobContext.java @@ -0,0 +1,320 @@ +package com.ximple.eofms.jobs.context.shapefile; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.filter.TypeCompIdDispatchableFilter; +import com.ximple.eofms.filter.TypeCompLevelIdDispatchableFilter; +import com.ximple.eofms.filter.TypeIdDispatchableFilter; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class DummyFeatureConvertShpJobContext extends AbstractDgnToShapefileJobContext +{ + static final Log logger = LogFactory.getLog(DummyFeatureConvertShpJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + static final String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public DummyFeatureConvertShpJobContext(String dataPath, String filterConfig) + { + super(dataPath); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + assert elementDispatcher != null; + for (ElementDispatchableFilter filter : elementDispatcher.getRules()) + { + if (filter instanceof TypeCompIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeCompLevelIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } else if (filter instanceof TypeIdDispatchableFilter) + { + ((TypeCompIdDispatchableFilter) filter).getCreateStrategy(); + } + } + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + File sfile = new File(getDataOutPath() + File.separator + featureType.getTypeName()); + logger.debug("Begin Save shapefile:" + sfile.toURI()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + ShapefileDataStore shapefileDataStore = null; + boolean existFile = sfile.exists(); + + if (!withIndex) + { + shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL(), + true, Charset.forName("UTF-8")); + } else + { + shapefileDataStore = new IndexedShapefileDataStore(sfile.toURI().toURL(), + null, true, true, IndexedShapefileDataStore.TREE_QIX, Charset.forName("UTF-8")); + } + + if (!existFile) + { + shapefileDataStore.createSchema(featureType); + writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = shapefileDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save shapefile:" + sfile.toURI()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/FeatureDgnConvertShpJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/FeatureDgnConvertShpJobContext.java new file mode 100644 index 0000000..638c328 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/FeatureDgnConvertShpJobContext.java @@ -0,0 +1,303 @@ +package com.ximple.eofms.jobs.context.shapefile; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.UserAttributeData; + +public class FeatureDgnConvertShpJobContext extends AbstractDgnToShapefileJobContext +{ + static final Log logger = LogFactory.getLog(FeatureDgnConvertShpJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + static final String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + + private ElementDispatcher elementDispatcher; + private String _filterConfig; + private boolean withIndex = false; + + public FeatureDgnConvertShpJobContext(String dataPath, String filterConfig) + { + super(dataPath); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + assert elementDispatcher != null; + + if (element == null) + { + logger.warn("Unknown Element:" + null); + return; + } + + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size()); + } + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + File sfile = new File(getDataOutPath() + File.separator + featureType.getTypeName()); + logger.debug("Begin Save shapefile:" + sfile.toURI()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + ShapefileDataStore shapefileDataStore = null; + boolean existFile = sfile.exists(); + + if (!withIndex) + { + shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL(), + true, Charset.forName("UTF-8")); + } else + { + shapefileDataStore = new IndexedShapefileDataStore(sfile.toURI().toURL(), + null, true, true, IndexedShapefileDataStore.TREE_QIX, Charset.forName("UTF-8")); + } + + if (!existFile) + { + shapefileDataStore.createSchema(featureType); + writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = shapefileDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save shapefile:" + sfile.toURI()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} + diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/GeneralDgnConvertShpJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/GeneralDgnConvertShpJobContext.java new file mode 100644 index 0000000..0da1bc0 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/GeneralDgnConvertShpJobContext.java @@ -0,0 +1,556 @@ +package com.ximple.eofms.jobs.context.shapefile; + +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.MalformedURLException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.io.dgn7.ArcElement; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.EllipseElement; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.LineElement; +import com.ximple.io.dgn7.LineStringElement; +import com.ximple.io.dgn7.ShapeElement; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.TextNodeElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class GeneralDgnConvertShpJobContext extends AbstractDgnToShapefileJobContext +{ + static final Log logger = LogFactory.getLog(GeneralDgnConvertShpJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + public static final String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + private TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); + private TreeMap<String, FeatureType> featureTypes = new TreeMap<String, FeatureType>(); + + private TWD97GeometryConverterDecorator convertDecorator = null; + private String featureBaseName = null; + private boolean withIndex = false; + + public GeneralDgnConvertShpJobContext(String dataPath) + { + super(dataPath); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + convertDecorator = new TWD97GeometryConverterDecorator(); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + FeatureType ft = lookupFeatureType(element); + if (ft != null) + { + Feature feature = createFeature(ft, element); + if (feature == null) + { + if (element instanceof TextElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + else if (element instanceof ShapeElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ShapeElement) element).getVerticeSize() + "'" + + ((ShapeElement) element).getStartPoint()); + else if (element instanceof LineStringElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((LineStringElement) element).getVerticeSize() + "'" + + ((LineStringElement) element).getStartPoint()); + else if (element instanceof ArcElement) + logger.info("cannot craete feature." + element.toString() + "'" + + ((ArcElement) element).getOrigin().toString() + "'" + + ((ArcElement) element).getRotationAngle()); + + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); + } + ArrayList<Feature> arrayList = (ArrayList<Feature>) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } else + { + logger.info("Unknown Element :" + element.getType() + ", lv=" + element.getLevelIndex()); + } + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + File sfile = new File(getDataOutPath() + File.separator + featureType.getTypeName()); + logger.debug("Begin Save shapefile:" + sfile.toURI()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + ShapefileDataStore shapefileDataStore = null; + boolean existFile = sfile.exists(); + + if (!withIndex) + { + shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL(), + true, Charset.forName("UTF-8")); + } else + { + shapefileDataStore = new IndexedShapefileDataStore(sfile.toURI().toURL(), + null, true, true, IndexedShapefileDataStore.TREE_QIX, Charset.forName("UTF-8")); + } + + if (!existFile) + { + shapefileDataStore.createSchema(featureType); + writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = shapefileDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save shapefile:" + sfile.toURI()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + public FeatureType createPointFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalPointFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createLineFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createArcFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalArcFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createEllipseFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalEllipseFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + convertDecorator.setConverter(textElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textElement.getRotationAngle(); + String content = textElement.getText(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getFontIndex(), + textElement.getJustification(), + textElement.getTextHeight(), + textElement.getTextWidth(), + angle, + content + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof TextNodeElement) + { + TextNodeElement textNodeElement = (TextNodeElement) element; + convertDecorator.setConverter(textNodeElement); + + Geometry geom = convertDecorator.toGeometry(geometryFactory); + double angle = textNodeElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + String[] texts = textNodeElement.getTextArray(); + StringBuffer sb = new StringBuffer(); + for (String text : texts) + { + if (sb.length() != 0) + sb.append("\n"); + sb.append(text); + } + + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(textNodeElement.getColorIndex()), + textNodeElement.getFontIndex(), + textNodeElement.getJustification(), + textNodeElement.getTextNodeHeight(), + textNodeElement.getTextNodeLength(), + angle, + sb.toString() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof ShapeElement) + { + ShapeElement shapeElement = (ShapeElement) element; + convertDecorator.setConverter(shapeElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + { + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(shapeElement.getColorIndex()), + shapeElement.getWeight(), + shapeElement.getLineStyle() + }); + } else + { + logger.info("geometry is null." + element.toString()); + } + return null; + } else if (element instanceof LineStringElement) + { + LineStringElement linestring = (LineStringElement) element; + convertDecorator.setConverter(linestring); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(linestring.getColorIndex()), + linestring.getWeight(), + linestring.getLineStyle() + }); + return null; + } else if (element instanceof LineElement) + { + LineElement line = (LineElement) element; + convertDecorator.setConverter(line); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(line.getColorIndex()), + line.getWeight(), + line.getLineStyle() + }); + return null; + } else if (element instanceof ArcElement) + { + ArcElement arcElement = (ArcElement) element; + /* + logger.fatal("" + arcElement.getPrimary() + ":" + arcElement.getSecondary() + + "-" + arcElement.getStartAngle() + ":" + arcElement.getSweepAngle() + ":" + + arcElement.getRotationAngle() + ":" + arcElement.getOrigin()); + */ + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof EllipseElement) + { + EllipseElement arcElement = (EllipseElement) element; + convertDecorator.setConverter(arcElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(arcElement.getColorIndex()), + arcElement.getWeight(), + arcElement.getLineStyle() + }); + return null; + } else if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChainElement = (ComplexChainElement) element; + convertDecorator.setConverter(complexChainElement); + Geometry geom = convertDecorator.toGeometry(geometryFactory); + if (geom != null) + return featureType.create(new Object[]{ + geom, + colorTable.getColorCode(complexChainElement.getColorIndex()), + complexChainElement.getWeight(), + complexChainElement.getLineStyle() + }); + return null; + } + return null; + } + + private String getFeatureBaseName() + { + if (featureBaseName == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureBaseName = dgnname; + } + return featureBaseName; + } + + private FeatureType lookupFeatureType(Element element) throws SchemaException, IllegalAttributeException + { + String typeName; + if (element instanceof TextElement) + { + typeName = getFeatureBaseName() + "P"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof TextNodeElement) + { + typeName = getFeatureBaseName() + "P"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createPointFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof LineStringElement) + { + if (element instanceof ShapeElement) + { + typeName = getFeatureBaseName() + "R"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else + { + typeName = getFeatureBaseName() + "L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + } else if (element instanceof LineElement) + { + typeName = getFeatureBaseName() + "L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ComplexChainElement) + { + typeName = getFeatureBaseName() + "L"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createLineFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof ArcElement) + { + typeName = getFeatureBaseName() + "A"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createArcFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } else if (element instanceof EllipseElement) + { + typeName = getFeatureBaseName() + "R"; + if (!featureTypes.containsKey(typeName)) + { + featureTypes.put(typeName, createEllipseFeatureElement(typeName)); + } + return featureTypes.get(typeName); + } + + return null; + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + public Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/IndexDgnConvertShpJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/IndexDgnConvertShpJobContext.java new file mode 100644 index 0000000..c1806cf --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/IndexDgnConvertShpJobContext.java @@ -0,0 +1,343 @@ +package com.ximple.eofms.jobs.context.shapefile; + +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.MalformedURLException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; +import org.geotools.feature.SimpleFeature; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.FeatureTypeBuilderUtil; +import com.ximple.eofms.util.TPCLIDConverter; +import com.ximple.eofms.util.TWD97GeometryConverterDecorator; +import com.ximple.eofms.util.TWDDatumConverter; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.UserAttributeData; + +public class IndexDgnConvertShpJobContext extends AbstractDgnToShapefileJobContext +{ + static final Log logger = LogFactory.getLog(IndexDgnConvertShpJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + static final GeometryFactory geometryFactory = new GeometryFactory(); + TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); + public static final String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap<String, ArrayList<Feature>> featuresContext = new HashMap<String, ArrayList<Feature>>(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + + private PessimisticMapWrapper txFeaturesContext; + private FeatureTypeBuilder typeBuilderPnt = null; + private FeatureTypeBuilder typeBuilderRect = null; + private FeatureType featureType = null; + private FeatureType featureType2 = null; + + public IndexDgnConvertShpJobContext(String dataPath) + { + super(dataPath); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + if (!(element instanceof TextElement)) + { + return; + } + + Feature feature = createFeature((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + + feature = createFeature2((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature2." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + File sfile = new File(getDataOutPath() + File.separator + featureType.getTypeName()); + logger.debug("Begin Save shapefile:" + sfile.toURI()); + + FeatureWriter writer; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + /* + ShapefileDataStore shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL(), + true, Charset.forName("UTF-8")); + */ + ShapefileDataStore shapefileDataStore = new IndexedShapefileDataStore(sfile.toURI().toURL(), + null, true, true, IndexedShapefileDataStore.TREE_QIX, Charset.forName("UTF-8")); + shapefileDataStore.createSchema(featureType); + writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT); + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList<Feature> features = featuresContext.get(featureType); + for (Feature feature1 : features) + { + ((SimpleFeature) writer.next()).setAttributes(feature1.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save shapefile:" + sfile.toURI()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (typeBuilderRect == null) + { + typeBuilderRect = FeatureTypeBuilderUtil.createNormalIndexFeatureTypeBuilder(featureName); + } + return typeBuilderRect.getFeatureType(); + } + + public FeatureType createFeatureElement2(String featureName) throws SchemaException + { + if (typeBuilderPnt == null) + { + typeBuilderPnt = FeatureTypeBuilderUtil.createNormalIndexTextFeatureTypeBuilder(featureName); + } + return typeBuilderPnt.getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElement = (TextElement) element; + String tpclid = textElement.getText(); + + Envelope extent = TPCLIDConverter.convertTpclIdToEnvelope(tpclid); + Geometry geom = geometryFactory.createLinearRing(new Coordinate[] + { + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMinY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMaxY())), + TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), + }); + + return featureType.create(new Object[]{ + geom, + extent.getMinX(), + extent.getMinY(), + extent.getMaxX(), + extent.getMaxY(), + tpclid, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getWeight(), + textElement.getLineStyle() + }); + } + return null; + } + + public Feature createFeature2(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement txtElement = (TextElement) element; + double angle = txtElement.getRotationAngle(); + angle = BigDecimal.valueOf(angle).setScale(3, RoundingMode.HALF_UP).doubleValue(); + convertDecorator.setConverter(txtElement); + Feature feature = featureType.create(new Object[]{ + convertDecorator.toGeometry(geometryFactory), + colorTable.getColorCode(txtElement.getColorIndex()), + txtElement.getWeight(), + txtElement.getLineStyle(), + txtElement.getJustification(), + txtElement.getTextHeight(), + txtElement.getTextWidth(), + angle, + txtElement.getText() + }); + return feature; + } + return null; + } + + private Feature createFeature(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureType = createFeatureElement(dgnname); + } + return createFeature(featureType, element); + } + + private Feature createFeature2(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType2 == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + dgnname = dgnname + "P"; + featureType2 = createFeatureElement2(dgnname); + } + return createFeature2(featureType2, element); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } + + public Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/OracleConvertShapefilesJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/OracleConvertShapefilesJobContext.java new file mode 100644 index 0000000..697ed62 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/shapefile/OracleConvertShapefilesJobContext.java @@ -0,0 +1,371 @@ +package com.ximple.eofms.jobs.context.shapefile; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Properties; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.transaction.util.CommonsLoggingLogger; +import org.apache.commons.transaction.util.LoggerFacade; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore; +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SimpleFeature; +import org.quartz.JobExecutionContext; +import org.xml.sax.SAXException; + +import com.vividsolutions.jts.util.Assert; + +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.filter.ElementDispatcher; +import com.ximple.eofms.jobs.OracleElementLogger; +import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.io.dgn7.ComplexElement; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; + + +public class OracleConvertShapefilesJobContext extends AbstractOracleJobContext +{ + static Log logger = LogFactory.getLog(OracleConvertShapefilesJobContext.class); + static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + + public static final String SHPOUTPATH = "shpout"; + + private OracleElementLogger elmLogger = null; + + static + { + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + } catch (SQLException e) + { + Assert.shouldNeverReachHere(e.getMessage()); + } + } + + private String _filterConfig; + + private ElementDispatcher elementDispatcher; + + private HashMap featuresContext = new HashMap(); + private HashMap<String, FeatureWriter> featuresWriterContext = new HashMap<String, FeatureWriter>(); + private PessimisticMapWrapper txFeaturesContext; + + private JobExecutionContext executionContext; + + private String dataOut = null; + private String _convertDB = null; + private String _convertFile = null; + private String _convertElementIn = null; + private String currentSchema = null; + private boolean schemaChanged = false; + private boolean withIndex = false; + + public OracleConvertShapefilesJobContext(String filterConfig) + { + properties = new Properties(); + _filterConfig = filterConfig; + elementDispatcher = createElementDispatcher(); + txFeaturesContext = new PessimisticMapWrapper(featuresContext, sLogger); + } + + private ElementDispatcher createElementDispatcher() + { + try + { + URL rulesURL = ElementDispatcher.class.getResource("ElementDispatcherRules.xml"); + assert rulesURL != null; + Digester digester = DigesterLoader.createDigester(rulesURL); + URL filterURL = null; + if (_filterConfig != null) + { + File config = new File(_filterConfig); + if (config.exists()) + { + filterURL = config.toURI().toURL(); + } + } + if (filterURL == null) + { + // config = new File("conf/DefaultConvertShpFilter.xml"); + filterURL = this.getClass().getResource("/conf/DefaultConvertShpFilter.xml"); + // filterURL = this.getClass().getResource("/conf/ConvertShpFilterForLevel.xml"); + } + assert filterURL != null; + return (ElementDispatcher) digester.parse(filterURL); + } catch (UnsupportedEncodingException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (MalformedURLException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) + { + logger.info(e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public void putFeatureCollection(Element element) + { + assert elementDispatcher != null; + // �P�_�O�_�ũM���� + Feature feature = elementDispatcher.execute(element); + if (feature == null) + { + boolean isEmptySize = false; + FrammeAttributeData linkage = + AbstractFLinkageDispatchableFilter.getFeatureLinkage(element); + logger.warn("Unknown Element:" + element.getElementType().toString() + + ":type=" + element.getType() + ":lv=" + element.getLevelIndex() + ":id=" + + (linkage == null ? "NULL" : (linkage.getFsc() + "|" + linkage.getComponentID()))); + + if (element instanceof ComplexElement) + { + ComplexElement complex = (ComplexElement) element; + logger.warn("----Complex Element size=" + complex.size() + ":" + + (linkage == null ? "NULL" : (linkage.getUfid()))); + isEmptySize = true; + } + + if (getElementLogging() && (!isEmptySize)) + { + getElementLogger().logElement(element, getCurrentSchema()); + } + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + //txFeaturesContext.startTransaction(); + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + + if (this.getElementLogger() != null) + this.getElementLogger().flashLogging(); + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + File sfile = new File(getDataOutPath() + File.separator + featureType.getTypeName()); + logger.debug("Begin Save shapefile:" + sfile.toURI()); + + FeatureWriter writer = null; + if (featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = featuresWriterContext.get(featureType.getTypeName()); + } else + { + ShapefileDataStore shapefileDataStore = null; + boolean existFile = sfile.exists(); + + if (!withIndex) + { + shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL(), + true, Charset.forName("UTF-8")); + } else + { + shapefileDataStore = new IndexedShapefileDataStore(sfile.toURI().toURL(), + null, true, true, IndexedShapefileDataStore.TREE_QIX, Charset.forName("UTF-8")); + } + + if (!existFile) + { + shapefileDataStore.createSchema(featureType); + writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } else + { + writer = shapefileDataStore.getFeatureWriterAppend(featureType.getTypeName(), + Transaction.AUTO_COMMIT); + } + featuresWriterContext.put(featureType.getTypeName(), writer); + } + + ArrayList features = (ArrayList) featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save shapefile:" + sfile.toURI()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + + } + + public JobExecutionContext getExecutionContext() + { + return executionContext; + } + + public void setExecutionContext(JobExecutionContext context) + { + executionContext = context; + } + + /** + * �����]�Ƽg�J�� + * + * @throws IOException IO�o�Ϳ��~ + */ + public void closeFeatureWriter() throws IOException + { + + for (FeatureWriter featureWriter : this.featuresWriterContext.values()) + { + featureWriter.close(); + } + + this.featuresWriterContext.clear(); + } + + /** + * ���o��ƿ�X���| + * + * @return ���|���r�� + */ + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = outPath.toString(); + } + return dataOut; + } + + public void setConvertDB(String convertDB) + { + _convertDB = convertDB; + } + + public void setConvertFile(String convertFile) + { + _convertFile = convertFile; + } + + protected OracleElementLogger getElementLogger() + { + if (elmLogger == null) + { + elmLogger = new OracleElementLogger(getOracleConnection()); + elmLogger.setDataPath(this.getDataPath()); + } + return elmLogger; + } + + public String getCurrentSchema() + { + return currentSchema; + } + + public void setCurrentSchema(String querySchema) + { + this.currentSchema = querySchema; + this.schemaChanged = true; + } + + public void setConvertElementIn(String convertElementIn) + { + _convertElementIn = convertElementIn; + } + + public boolean isWithIndex() + { + return withIndex; + } + + public void setWithIndex(boolean withIndex) + { + this.withIndex = withIndex; + } + + protected Log getLogger() + { + return logger; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java new file mode 100644 index 0000000..13d7c92 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java @@ -0,0 +1,551 @@ +package com.ximple.eofms.util; + +import java.util.Arrays; + +public class Base64 +{ + private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + private static final int[] IA = new int[256]; + + static + { + Arrays.fill(IA, -1); + for (int i = 0, iS = CA.length; i < iS; i++) + IA[CA[i]] = i; + IA['='] = 0; + } + + // **************************************************************************************** + // * char[] version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045. + * + * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned. + * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br> + * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a + * little faster. + * @return A BASE64 encoded array. Never <code>null</code>. + */ + public static char[] encodeToChar(byte[] sArr, boolean lineSep) + { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new char[0]; + + int eLen = (sLen / 3) * 3; // Length of even 24-bits. + int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count + int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array + char[] dArr = new char[dLen]; + + // Encode even 24-bits + for (int s = 0, d = 0, cc = 0; s < eLen;) + { + // Copy next three bytes into lower 24 bits of int, paying attension to sign. + int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff); + + // Encode the int into four chars + dArr[d++] = CA[(i >>> 18) & 0x3f]; + dArr[d++] = CA[(i >>> 12) & 0x3f]; + dArr[d++] = CA[(i >>> 6) & 0x3f]; + dArr[d++] = CA[i & 0x3f]; + + // Add optional line separator + if (lineSep && ++cc == 19 && d < dLen - 2) + { + dArr[d++] = '\r'; + dArr[d++] = '\n'; + cc = 0; + } + } + + // Pad and encode last bits if source isn't even 24 bits. + int left = sLen - eLen; // 0 - 2. + if (left > 0) + { + // Prepare the int + int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0); + + // Set last four chars + dArr[dLen - 4] = CA[i >> 12]; + dArr[dLen - 3] = CA[(i >>> 6) & 0x3f]; + dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '='; + dArr[dLen - 1] = '='; + } + return dArr; + } + + /** + * Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with + * and without line separators. + * + * @param sArr The source array. <code>null</code> or length 0 will return an empty array. + * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters + * (including '=') isn't divideable by 4. (I.e. definitely corrupted). + */ + public static byte[] decode(char[] sArr) + { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new byte[0]; + + // Count illegal characters (including '\r', '\n') to know what size the returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out. + if (IA[sArr[i]] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + int pad = 0; + for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;) + if (sArr[i] == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) + { // j only increased if a valid char was found. + int c = IA[sArr[s++]]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) + { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + return dArr; + } + + /** + * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as + * fast as {@link #decode(char[])}. The preconditions are:<br> + * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> + * + Line separator must be "\r\n", as specified in RFC 2045 + * + The array must not contain illegal characters within the encoded string<br> + * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> + * + * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public byte[] decodeFast(char[] sArr) + { + // Check special case + int sLen = sArr.length; + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[sArr[sIx]] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[sArr[eIx]] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) + { + sIx += 2; + cc = 0; + } + } + + if (d < len) + { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[sArr[sIx++]] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } + + // **************************************************************************************** + // * byte[] version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045. + * + * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned. + * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br> + * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a + * little faster. + * @return A BASE64 encoded array. Never <code>null</code>. + */ + public static byte[] encodeToByte(byte[] sArr, boolean lineSep) + { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new byte[0]; + + int eLen = (sLen / 3) * 3; // Length of even 24-bits. + int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count + int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array + byte[] dArr = new byte[dLen]; + + // Encode even 24-bits + for (int s = 0, d = 0, cc = 0; s < eLen;) + { + // Copy next three bytes into lower 24 bits of int, paying attension to sign. + int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff); + + // Encode the int into four chars + dArr[d++] = (byte) CA[(i >>> 18) & 0x3f]; + dArr[d++] = (byte) CA[(i >>> 12) & 0x3f]; + dArr[d++] = (byte) CA[(i >>> 6) & 0x3f]; + dArr[d++] = (byte) CA[i & 0x3f]; + + // Add optional line separator + if (lineSep && ++cc == 19 && d < dLen - 2) + { + dArr[d++] = '\r'; + dArr[d++] = '\n'; + cc = 0; + } + } + + // Pad and encode last bits if source isn't an even 24 bits. + int left = sLen - eLen; // 0 - 2. + if (left > 0) + { + // Prepare the int + int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0); + + // Set last four chars + dArr[dLen - 4] = (byte) CA[i >> 12]; + dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f]; + dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '='; + dArr[dLen - 1] = '='; + } + return dArr; + } + + /** + * Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with + * and without line separators. + * + * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters + * (including '=') isn't divideable by 4. (I.e. definitely corrupted). + */ + public static byte[] decode(byte[] sArr) + { + // Check special case + int sLen = sArr.length; + + // Count illegal characters (including '\r', '\n') to know what size the returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out. + if (IA[sArr[i] & 0xff] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + int pad = 0; + for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;) + if (sArr[i] == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) + { // j only increased if a valid char was found. + int c = IA[sArr[s++] & 0xff]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) + { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + + return dArr; + } + + + /** + * Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as + * fast as {@link #decode(byte[])}. The preconditions are:<br> + * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> + * + Line separator must be "\r\n", as specified in RFC 2045 + * + The array must not contain illegal characters within the encoded string<br> + * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> + * + * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public static byte[] decodeFast(byte[] sArr) + { + // Check special case + int sLen = sArr.length; + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) + { + sIx += 2; + cc = 0; + } + } + + if (d < len) + { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[sArr[sIx++]] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } + + // **************************************************************************************** + // * String version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045. + * + * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned. + * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br> + * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a + * little faster. + * @return A BASE64 encoded array. Never <code>null</code>. + */ + public static String encodeToString(byte[] sArr, boolean lineSep) + { + // Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower. + return new String(encodeToChar(sArr, lineSep)); + } + + /** + * Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with + * and without line separators.<br> + * <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That + * will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string. + * + * @param str The source string. <code>null</code> or length 0 will return an empty array. + * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters + * (including '=') isn't divideable by 4. (I.e. definitely corrupted). + */ + public static byte[] decode(String str) + { + // Check special case + int sLen = str != null ? str.length() : 0; + if (sLen == 0) + return new byte[0]; + + // Count illegal characters (including '\r', '\n') to know what size the returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out. + if (IA[str.charAt(i)] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + // Count '=' at end + int pad = 0; + for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;) + if (str.charAt(i) == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) + { // j only increased if a valid char was found. + int c = IA[str.charAt(s++)]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) + { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + return dArr; + } + + /** + * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as + * fast as {@link #decode(String)}. The preconditions are:<br> + * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> + * + Line separator must be "\r\n", as specified in RFC 2045 + * + The array must not contain illegal characters within the encoded string<br> + * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> + * + * @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public static byte[] decodeFast(String s) + { + // Check special case + int sLen = s.length(); + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) + { + sIx += 2; + cc = 0; + } + } + + if (d < len) + { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[s.charAt(sIx++)] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java new file mode 100644 index 0000000..2dd4c53 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java @@ -0,0 +1,363 @@ +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.LongBuffer; + +/** + * BinConverter + * User: Ulysses + * Date: 2007/9/17 + * Time: �W�� 01:13:13 + */ +public class BinConverter +{ + // our table for binhex conversion + final static char[] HEXTAB = + { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + /** + * gets bytes from an array into a long + * + * @param buffer where to get the bytes + * @param nStartIndex index from where to read the data + * @return the 64bit integer + */ + public static long byteArrayToLong(byte[] buffer, int nStartIndex) + { + return (((long) buffer[nStartIndex]) << 56) | (((long) buffer[nStartIndex + 1] & 0x0ffL) << 48) + | (((long) buffer[nStartIndex + 2] & 0x0ffL) << 40) | (((long) buffer[nStartIndex + 3] & 0x0ffL) << 32) + | (((long) buffer[nStartIndex + 4] & 0x0ffL) << 24) | (((long) buffer[nStartIndex + 5] & 0x0ffL) << 16) + | (((long) buffer[nStartIndex + 6] & 0x0ffL) << 8) | ((long) buffer[nStartIndex + 7] & 0x0ff); + } + + /** + * converts a long o bytes which are put into a given array + * + * @param lValue the 64bit integer to convert + * @param buffer the target buffer + * @param nStartIndex where to place the bytes in the buffer + */ + public static void longToByteArray(long lValue, byte[] buffer, int nStartIndex) + { + buffer[nStartIndex] = (byte) (lValue >>> 56); + buffer[nStartIndex + 1] = (byte) ((lValue >>> 48) & 0x0ff); + buffer[nStartIndex + 2] = (byte) ((lValue >>> 40) & 0x0ff); + buffer[nStartIndex + 3] = (byte) ((lValue >>> 32) & 0x0ff); + buffer[nStartIndex + 4] = (byte) ((lValue >>> 24) & 0x0ff); + buffer[nStartIndex + 5] = (byte) ((lValue >>> 16) & 0x0ff); + buffer[nStartIndex + 6] = (byte) ((lValue >>> 8) & 0x0ff); + buffer[nStartIndex + 7] = (byte) lValue; + } + + /** + * converts values from an integer array to a long + * + * @param buffer where to get the bytes + * @param nStartIndex index from where to read the data + * @return the 64bit integer + */ + public static long intArrayToLong(int[] buffer, int nStartIndex) + { + return (((long) buffer[nStartIndex]) << 32) | (((long) buffer[nStartIndex + 1]) & 0x0ffffffffL); + } + + /** + * converts a long to integers which are put into a given array + * + * @param lValue the 64bit integer to convert + * @param buffer the target buffer + * @param nStartIndex where to place the bytes in the buffer + */ + public static void longToIntArray(long lValue, int[] buffer, int nStartIndex) + { + buffer[nStartIndex] = (int) (lValue >>> 32); + buffer[nStartIndex + 1] = (int) lValue; + } + + /** + * makes a long from two integers (treated unsigned) + * + * @param nLo lower 32bits + * @param nHi higher 32bits + * @return the built long + */ + public static long makeLong(int nLo, int nHi) + { + return (((long) nHi << 32) | ((long) nLo & 0x00000000ffffffffL)); + } + + /** + * gets the lower 32 bits of a long + * + * @param lVal the long integer + * @return lower 32 bits + */ + public static int longLo32(long lVal) + { + return (int) lVal; + } + + /** + * gets the higher 32 bits of a long + * + * @param lVal the long integer + * @return higher 32 bits + */ + public static int longHi32(long lVal) + { + return (int) ((long) (lVal >>> 32)); + } + + /** + * converts a byte array to a binhex string + * + * @param data the byte array + * @return the binhex string + */ + public static String bytesToBinHex(byte[] data) + { + // just map the call + return bytesToBinHex(data, 0, data.length); + } + + /** + * converts a byte array to a binhex string + * + * @param data the byte array + * @param nStartPos start index where to get the bytes + * @param nNumOfBytes number of bytes to convert + * @return the binhex string + */ + public static String bytesToBinHex(byte[] data, int nStartPos, int nNumOfBytes) + { + StringBuffer sbuf = new StringBuffer(); + + sbuf.setLength(nNumOfBytes << 1); + + int nPos = 0; + + for (int nI = 0; nI < nNumOfBytes; nI++) + { + sbuf.setCharAt(nPos++, HEXTAB[(data[nI + nStartPos] >> 4) & 0x0f]); + sbuf.setCharAt(nPos++, HEXTAB[data[nI + nStartPos] & 0x0f]); + } + + return sbuf.toString(); + } + + /** + * converts a binhex string back into a byte array (invalid codes will be skipped) + * + * @param sBinHex binhex string + * @param data the target array + * @param nSrcPos from which character in the string the conversion should begin, + * remember that (nSrcPos modulo 2) should equals 0 normally + * @param nDstPos to store the bytes from which position in the array + * @param nNumOfBytes number of bytes to extract + * @return number of extracted bytes + */ + public static int binHexToBytes(String sBinHex, byte[] data, int nSrcPos, int nDstPos, int nNumOfBytes) + { + // check for correct ranges + int nStrLen = sBinHex.length(); + int nAvailBytes = (nStrLen - nSrcPos) >> 1; + + if (nAvailBytes < nNumOfBytes) + { + nNumOfBytes = nAvailBytes; + } + + int nOutputCapacity = data.length - nDstPos; + + if (nNumOfBytes > nOutputCapacity) + { + nNumOfBytes = nOutputCapacity; + } + + // convert now + int nResult = 0; + + for (int nI = 0; nI < nNumOfBytes; nI++) + { + byte bActByte = 0; + boolean blConvertOK = true; + + for (int nJ = 0; nJ < 2; nJ++) + { + bActByte <<= 4; + + char cActChar = sBinHex.charAt(nSrcPos++); + + if ((cActChar >= 'a') && (cActChar <= 'f')) + { + bActByte |= (byte) (cActChar - 'a') + 10; + } else if ((cActChar >= '0') && (cActChar <= '9')) + { + bActByte |= (byte) (cActChar - '0'); + } else + { + blConvertOK = false; + } + } + + if (blConvertOK) + { + data[nDstPos++] = bActByte; + nResult++; + } + } + + return nResult; + } + + /** + * converts a byte array into an UNICODE string + * + * @param data the byte array + * @param nStartPos where to begin the conversion + * @param nNumOfBytes number of bytes to handle + * @return the string + */ + public static String byteArrayToUNCString(byte[] data, int nStartPos, int nNumOfBytes) + { + // we need two bytes for every character + nNumOfBytes &= ~1; + + // enough bytes in the buffer? + int nAvailCapacity = data.length - nStartPos; + + if (nAvailCapacity < nNumOfBytes) + { + nNumOfBytes = nAvailCapacity; + } + + StringBuffer sbuf = new StringBuffer(); + + sbuf.setLength(nNumOfBytes >> 1); + + int nSBufPos = 0; + + while (nNumOfBytes > 0) + { + sbuf.setCharAt(nSBufPos++, (char) (((int) data[nStartPos] << 8) | ((int) data[nStartPos + 1] & 0x0ff))); + nStartPos += 2; + nNumOfBytes -= 2; + } + + return sbuf.toString(); + } + + public static long[] marshalByteArray(byte[] raws, boolean hasSignature) + { + int remainder = raws.length % 8; + ByteBuffer rawData = ByteBuffer.wrap(raws); + + rawData.rewind(); + rawData.order(ByteOrder.LITTLE_ENDIAN); + + LongBuffer longBuffer = ((ByteBuffer) rawData.rewind()).asLongBuffer(); + int resultSize = longBuffer.limit() + ((remainder != 0) + ? 1 + : 0) + (hasSignature + ? 1 + : 0); + long[] result = new long[resultSize]; + int i = 0; + + if (hasSignature) + { + result[i] = raws.length; + i++; + } + + while (longBuffer.hasRemaining()) + { + result[i] = longBuffer.get(); + i++; + } + + if (remainder != 0) + { + int pos = (i - (hasSignature + ? 1 + : 0)) * 8; + + // int pos = rawData.position(); + byte[] temp = new byte[8]; + + for (int j = 0; j < remainder; j++) + { + temp[7 - j] = raws[pos + j]; + } + + // System.arraycopy(raws, pos, temp, 0, remainder); + result[i] = BinConverter.byteArrayToLong(temp, 0); + } + + return result; + } + + public static byte[] unmarshalByteArray(long[] raws, boolean hasSignature) + { + LongBuffer longBuffer = LongBuffer.wrap(raws); + int resultBufferSize = (raws.length - (hasSignature + ? 1 + : 0)) * 8; + int resultSize = resultBufferSize; + + if (hasSignature) + { + resultSize = (int) longBuffer.get(); + } + + ByteBuffer result = ByteBuffer.allocate(resultBufferSize); + + result.order(ByteOrder.LITTLE_ENDIAN); + + while (longBuffer.hasRemaining()) + { + result.putLong(longBuffer.get()); + } + + if (resultSize == resultBufferSize) + { + return result.array(); + } + + byte[] resultData = new byte[resultSize]; + + result.position(0); + result.get(resultData, 0, resultSize); + + return resultData; + } + + public static long[] marshalCompactByteArray(byte[] raws) + { + byte[] compactRaws = new byte[raws.length + 2]; + ByteBuffer bbCompact = ByteBuffer.wrap(compactRaws); + bbCompact.order(ByteOrder.LITTLE_ENDIAN); + bbCompact.putShort((short) raws.length); + bbCompact.put(raws); + long[] longData = BinConverter.marshalByteArray(compactRaws, false); + return longData; + } + + public static byte[] unmarshalCompactByteArray(long[] raws) + { + byte[] rawData = BinConverter.unmarshalByteArray(raws, false); + + ByteBuffer bbCompact = ByteBuffer.wrap(rawData); + bbCompact.order(ByteOrder.LITTLE_ENDIAN); + short originSize = bbCompact.getShort(); + + byte[] rawOriginData = new byte[originSize]; + bbCompact.get(rawOriginData, 0, originSize); + return rawOriginData; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java new file mode 100644 index 0000000..5e529ac --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java @@ -0,0 +1,323 @@ +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.nio.ByteOrder; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import sun.misc.VM; + +/** + * Bits + * User: Ulysses + * Date: 2007/6/17 + * Time: �W�� 01:16:39 + */ +public class Bits +{ + // -- Unsafe access -- + // private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // -- Processor and memory-system properties -- + private static ByteOrder byteOrder = null; + private static int pageSize = -1; + private static boolean unaligned; + private static boolean unalignedKnown = false; + + // -- Direct memory management -- + // A user-settable upper limit on the maximum amount of allocatable + // direct buffer memory. This value may be changed during VM + // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>". + private static volatile long maxMemory = VM.maxDirectMemory(); + private static volatile long reservedMemory = 0; + private static boolean memoryLimitSet = false; + + private Bits() + { + } + + // -- Swapping -- + public static short swap(short x) + { + return (short) ((x << 8) | ((x >> 8) & 0xff)); + } + + public static char swap(char x) + { + return (char) ((x << 8) | ((x >> 8) & 0xff)); + } + + public static int swap(int x) + { + return (int) ((swap((short) x) << 16) | (swap((short) (x >> 16)) & 0xffff)); + } + + public static long swap(long x) + { + return (long) (((long) swap((int) (x)) << 32) | ((long) swap((int) (x >> 32)) & 0xffffffffL)); + } + + // -- get/put char -- + static private char makeChar(byte b1, byte b0) + { + return (char) ((b1 << 8) | (b0 & 0xff)); + } + + private static byte char1(char x) + { + return (byte) (x >> 8); + } + + private static byte char0(char x) + { + return (byte) (x >> 0); + } + + // --get/put short-- + public static short makeShort(byte b1, byte b0) + { + return (short) ((b1 << 8) | (b0 & 0xff)); + } + + private static byte short1(short x) + { + return (byte) (x >> 8); + } + + public static byte short0(short x) + { + return (byte) (x >> 0); + } + + // -- get/put int -- + public static int makeInt(byte b3, byte b2, byte b1, byte b0) + { + return (int) ((((b3 & 0xff) << 24) | ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | ((b0 & 0xff) << 0))); + } + + public static int makeInt(short hiword, short loword) + { + return ((hiword & 0xffff) << 16) + (loword & 0xffff); + } + + public static short getHiShort(int qwValue) + { + return ((short) (qwValue >>> 16)); + } + + public static short getLoShort(int qwValue) + { + return ((short) (qwValue & 0xFFFF)); + } + + public static byte int3(int x) + { + return (byte) (x >> 24); + } + + public static byte int2(int x) + { + return (byte) (x >> 16); + } + + private static byte int1(int x) + { + return (byte) (x >> 8); + } + + private static byte int0(int x) + { + return (byte) (x >> 0); + } + + // -- get/put long -- + public static long makeLong(byte b7, byte b6, byte b5, byte b4, byte b3, byte b2, byte b1, byte b0) + { + return ((((long) b7 & 0xff) << 56) | (((long) b6 & 0xff) << 48) | (((long) b5 & 0xff) << 40) | (((long) b4 & 0xff) << 32) + | (((long) b3 & 0xff) << 24) | (((long) b2 & 0xff) << 16) | (((long) b1 & 0xff) << 8) + | (((long) b0 & 0xff) << 0)); + } + + public static long makeLong(int LoValue, int HiValue) + { + return (((long) HiValue & 0xFFFFFFFF) << 32) + (((long) LoValue) & 0xFFFFFFFF); + } + + public static int getHiInt(long qwValue) + { + return ((int) (qwValue >>> 32)); + } + + public static int getLoInt(long qwValue) + { + return ((int) (qwValue & 0xFFFFFFFF)); + } + + private static byte long7(long x) + { + return (byte) (x >> 56); + } + + private static byte long6(long x) + { + return (byte) (x >> 48); + } + + private static byte long5(long x) + { + return (byte) (x >> 40); + } + + private static byte long4(long x) + { + return (byte) (x >> 32); + } + + private static byte long3(long x) + { + return (byte) (x >> 24); + } + + private static byte long2(long x) + { + return (byte) (x >> 16); + } + + private static byte long1(long x) + { + return (byte) (x >> 8); + } + + private static byte long0(long x) + { + return (byte) (x >> 0); + } + + // -- get/put float -- + + // -- get/put double -- + + /* + private static byte _get(long a) + { + return unsafe.getByte(a); + } + + private static void _put(long a, byte b) + { + unsafe.putByte(a, b); + } + + static Unsafe unsafe() + { + return unsafe; + } + + static ByteOrder byteOrder() + { + if (byteOrder != null) + { + return byteOrder; + } + + long a = unsafe.allocateMemory(8); + + try + { + unsafe.putLong(a, 0x0102030405060708L); + + byte b = unsafe.getByte(a); + + switch (b) + { + case 0x01 : + byteOrder = ByteOrder.BIG_ENDIAN; + + break; + + case 0x08 : + byteOrder = ByteOrder.LITTLE_ENDIAN; + + break; + + default : + throw new Error("Unknown byte order"); + } + } finally + { + unsafe.freeMemory(a); + } + + return byteOrder; + } + */ + + static boolean unaligned() + { + if (unalignedKnown) + { + return unaligned; + } + + PrivilegedAction pa = new sun.security.action.GetPropertyAction("os.arch"); + String arch = (String) AccessController.doPrivileged(pa); + + unaligned = arch.equals("i386") || arch.equals("x86"); + unalignedKnown = true; + + return unaligned; + } + + // These methods should be called whenever direct memory is allocated or + // freed. They allow the user to control the amount of direct memory + // which a process may access. All sizes are specified in bytes. + static void reserveMemory(long size) + { + synchronized (Bits.class) + { + if (!memoryLimitSet && VM.isBooted()) + { + maxMemory = VM.maxDirectMemory(); + memoryLimitSet = true; + } + + if (size <= maxMemory - reservedMemory) + { + reservedMemory += size; + + return; + } + } + + System.gc(); + + try + { + Thread.sleep(100); + } catch (InterruptedException x) + { + // Restore interrupt status + Thread.currentThread().interrupt(); + } + + synchronized (Bits.class) + { + if (reservedMemory + size > maxMemory) + { + throw new OutOfMemoryError("Direct buffer memory"); + } + + reservedMemory += size; + } + } + + static synchronized void unreserveMemory(long size) + { + if (reservedMemory > 0) + { + reservedMemory -= size; + assert (reservedMemory > -1); + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java new file mode 100644 index 0000000..f22eaec --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java @@ -0,0 +1,97 @@ +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + * ByteArrayCompressor + * User: Ulysses + * Date: 2007/6/15 + * Time: �U�� 02:21:00 + * To change this template use File | Settings | File Templates. + */ +public final class ByteArrayCompressor +{ + public static byte[] decompressByteArray(byte[] raw) + { + // Create the decompressor and give it the data to compress + Inflater decompressor = new Inflater(); + + decompressor.setInput(raw); + + // Create an expandable byte array to hold the decompressed data + ByteArrayOutputStream bos = new ByteArrayOutputStream(raw.length); + + // Decompress the data + byte[] buf = new byte[1024]; + + while (!decompressor.finished()) + { + try + { + int count = decompressor.inflate(buf); + + bos.write(buf, 0, count); + } catch (DataFormatException e) + { + } + } + + try + { + bos.close(); + } catch (IOException e) + { + } + + // Get the decompressed data + byte[] decompressedData = bos.toByteArray(); + + return decompressedData; + } + + public static byte[] compressByteArray(byte[] raw) + { + // Create the compressor with highest level of compression + Deflater compressor = new Deflater(); + + compressor.setLevel(Deflater.BEST_SPEED); + + // Give the compressor the data to compress + compressor.setInput(raw); + compressor.finish(); + + // Create an expandable byte array to hold the compressed data. + // You cannot use an array that's the same size as the orginal because + // there is no guarantee that the compressed data will be smaller than + // the uncompressed data. + ByteArrayOutputStream bos = new ByteArrayOutputStream(raw.length); + + // Compress the data + byte[] buf = new byte[1024]; + + while (!compressor.finished()) + { + int count = compressor.deflate(buf); + + bos.write(buf, 0, count); + } + + try + { + bos.close(); + } catch (IOException e) + { + } + + // Get the compressed data + byte[] compressedData = bos.toByteArray(); + + return compressedData; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ColorTableMapping.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ColorTableMapping.java new file mode 100644 index 0000000..a93c23e --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ColorTableMapping.java @@ -0,0 +1,15 @@ +package com.ximple.eofms.util; + +import java.awt.Color; +import java.util.List; + +public interface ColorTableMapping +{ + boolean contain(Color color); + + List findId(Color color); + + Color getColor(int value); + + String getColorCode(int i); +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/DefaultColorTable.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/DefaultColorTable.java new file mode 100644 index 0000000..36c1a5f --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/DefaultColorTable.java @@ -0,0 +1,368 @@ +package com.ximple.eofms.util; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; + +public class DefaultColorTable implements ColorTableMapping +{ + private static DefaultColorTable _instance = null; + + public static ColorTableMapping getInstance() + { + if (_instance == null) + { + _instance = new DefaultColorTable(); + } + + return _instance; + } + + private ArrayList<Color> colortable = null; + + private DefaultColorTable() + { + initializeColorTable(); + } + + private void initializeColorTable() + { + if (colortable != null) + { + return; + } + + colortable = new ArrayList<Color>(255); + colortable.add(0, new Color(255, 255, 255)); + colortable.add(1, new Color(0, 0, 255)); + colortable.add(2, new Color(0, 255, 0)); + colortable.add(3, new Color(255, 0, 0)); + colortable.add(4, new Color(255, 255, 0)); + colortable.add(5, new Color(255, 0, 255)); + colortable.add(6, new Color(255, 127, 0)); + colortable.add(7, new Color(0, 255, 255)); + colortable.add(8, new Color(64, 64, 64)); + colortable.add(9, new Color(192, 192, 192)); + colortable.add(10, new Color(254, 0, 96)); + colortable.add(11, new Color(160, 224, 0)); + colortable.add(12, new Color(0, 254, 160)); + colortable.add(13, new Color(128, 0, 160)); + colortable.add(14, new Color(176, 176, 176)); + colortable.add(15, new Color(0, 240, 240)); + colortable.add(16, new Color(240, 240, 240)); + colortable.add(17, new Color(0, 0, 240)); + colortable.add(18, new Color(0, 240, 0)); + colortable.add(19, new Color(240, 0, 0)); + colortable.add(20, new Color(240, 240, 0)); + colortable.add(21, new Color(240, 0, 240)); + colortable.add(22, new Color(240, 122, 0)); + colortable.add(23, new Color(0, 240, 240)); + colortable.add(24, new Color(240, 240, 240)); + colortable.add(25, new Color(0, 0, 240)); + colortable.add(26, new Color(0, 240, 0)); + colortable.add(27, new Color(240, 0, 0)); + colortable.add(28, new Color(240, 240, 0)); + colortable.add(29, new Color(240, 0, 240)); + colortable.add(30, new Color(240, 122, 0)); + colortable.add(31, new Color(0, 225, 225)); + colortable.add(32, new Color(225, 225, 225)); + colortable.add(33, new Color(0, 0, 225)); + colortable.add(34, new Color(0, 225, 0)); + colortable.add(35, new Color(225, 0, 0)); + colortable.add(36, new Color(225, 225, 0)); + colortable.add(37, new Color(225, 0, 225)); + colortable.add(38, new Color(225, 117, 0)); + colortable.add(39, new Color(0, 225, 225)); + colortable.add(40, new Color(225, 225, 225)); + colortable.add(41, new Color(0, 0, 225)); + colortable.add(42, new Color(0, 225, 0)); + colortable.add(43, new Color(225, 0, 0)); + colortable.add(44, new Color(225, 225, 0)); + colortable.add(45, new Color(225, 0, 225)); + colortable.add(46, new Color(225, 117, 0)); + colortable.add(47, new Color(0, 210, 210)); + colortable.add(48, new Color(210, 210, 210)); + colortable.add(49, new Color(0, 0, 210)); + colortable.add(50, new Color(0, 210, 0)); + colortable.add(51, new Color(210, 0, 0)); + colortable.add(52, new Color(210, 210, 0)); + colortable.add(53, new Color(210, 0, 210)); + colortable.add(54, new Color(210, 112, 0)); + colortable.add(55, new Color(0, 210, 210)); + colortable.add(56, new Color(210, 210, 210)); + colortable.add(57, new Color(0, 0, 210)); + colortable.add(58, new Color(0, 210, 0)); + colortable.add(59, new Color(210, 0, 0)); + colortable.add(60, new Color(210, 210, 0)); + colortable.add(61, new Color(210, 0, 210)); + colortable.add(62, new Color(210, 112, 0)); + colortable.add(63, new Color(0, 195, 195)); + colortable.add(64, new Color(195, 195, 195)); + colortable.add(65, new Color(0, 0, 195)); + colortable.add(66, new Color(0, 195, 0)); + colortable.add(67, new Color(195, 0, 0)); + colortable.add(68, new Color(195, 195, 0)); + colortable.add(69, new Color(195, 0, 195)); + colortable.add(70, new Color(195, 107, 0)); + colortable.add(71, new Color(0, 195, 195)); + colortable.add(72, new Color(195, 195, 195)); + colortable.add(73, new Color(0, 0, 195)); + colortable.add(74, new Color(0, 195, 0)); + colortable.add(75, new Color(195, 0, 0)); + colortable.add(76, new Color(195, 195, 0)); + colortable.add(77, new Color(195, 0, 195)); + colortable.add(78, new Color(195, 107, 0)); + colortable.add(79, new Color(0, 180, 180)); + colortable.add(80, new Color(180, 180, 180)); + colortable.add(81, new Color(0, 0, 180)); + colortable.add(82, new Color(0, 180, 0)); + colortable.add(83, new Color(180, 0, 0)); + colortable.add(84, new Color(180, 180, 0)); + colortable.add(85, new Color(180, 0, 180)); + colortable.add(86, new Color(180, 102, 0)); + colortable.add(87, new Color(0, 180, 180)); + colortable.add(88, new Color(180, 180, 180)); + colortable.add(89, new Color(0, 0, 180)); + colortable.add(90, new Color(0, 180, 0)); + colortable.add(91, new Color(180, 0, 0)); + colortable.add(92, new Color(180, 180, 0)); + colortable.add(93, new Color(180, 0, 180)); + colortable.add(94, new Color(180, 102, 0)); + colortable.add(95, new Color(0, 165, 165)); + colortable.add(96, new Color(165, 165, 165)); + colortable.add(97, new Color(0, 0, 165)); + colortable.add(98, new Color(0, 165, 0)); + colortable.add(99, new Color(165, 0, 0)); + colortable.add(100, new Color(165, 165, 0)); + colortable.add(101, new Color(165, 0, 165)); + colortable.add(102, new Color(165, 97, 0)); + colortable.add(103, new Color(0, 165, 165)); + colortable.add(104, new Color(165, 165, 165)); + colortable.add(105, new Color(0, 0, 165)); + colortable.add(106, new Color(0, 165, 0)); + colortable.add(107, new Color(165, 0, 0)); + colortable.add(108, new Color(165, 165, 0)); + colortable.add(109, new Color(165, 0, 165)); + colortable.add(110, new Color(165, 97, 0)); + colortable.add(111, new Color(0, 150, 150)); + colortable.add(112, new Color(150, 150, 150)); + colortable.add(113, new Color(0, 0, 150)); + colortable.add(114, new Color(0, 150, 0)); + colortable.add(115, new Color(150, 0, 0)); + colortable.add(116, new Color(150, 150, 0)); + colortable.add(117, new Color(150, 0, 150)); + colortable.add(118, new Color(150, 92, 0)); + colortable.add(119, new Color(0, 150, 150)); + colortable.add(120, new Color(150, 150, 150)); + colortable.add(121, new Color(0, 0, 150)); + colortable.add(122, new Color(0, 150, 0)); + colortable.add(123, new Color(150, 0, 0)); + colortable.add(124, new Color(150, 150, 0)); + colortable.add(125, new Color(150, 0, 150)); + colortable.add(126, new Color(150, 92, 0)); + colortable.add(127, new Color(0, 135, 135)); + colortable.add(128, new Color(135, 135, 135)); + colortable.add(129, new Color(0, 0, 135)); + colortable.add(130, new Color(0, 135, 0)); + colortable.add(131, new Color(135, 0, 0)); + colortable.add(132, new Color(135, 135, 0)); + colortable.add(133, new Color(135, 0, 135)); + colortable.add(134, new Color(135, 87, 0)); + colortable.add(135, new Color(0, 135, 135)); + colortable.add(136, new Color(135, 135, 135)); + colortable.add(137, new Color(0, 0, 135)); + colortable.add(138, new Color(0, 135, 0)); + colortable.add(139, new Color(135, 0, 0)); + colortable.add(140, new Color(135, 135, 0)); + colortable.add(141, new Color(135, 0, 135)); + colortable.add(142, new Color(135, 87, 0)); + colortable.add(143, new Color(0, 120, 120)); + colortable.add(144, new Color(120, 120, 120)); + colortable.add(145, new Color(0, 0, 120)); + colortable.add(146, new Color(0, 120, 0)); + colortable.add(147, new Color(120, 0, 0)); + colortable.add(148, new Color(120, 120, 0)); + colortable.add(149, new Color(120, 0, 120)); + colortable.add(150, new Color(120, 82, 0)); + colortable.add(151, new Color(0, 120, 120)); + colortable.add(152, new Color(120, 120, 120)); + colortable.add(153, new Color(0, 0, 120)); + colortable.add(154, new Color(0, 120, 0)); + colortable.add(155, new Color(120, 0, 0)); + colortable.add(156, new Color(120, 120, 0)); + colortable.add(157, new Color(120, 0, 120)); + colortable.add(158, new Color(120, 82, 0)); + colortable.add(159, new Color(0, 105, 105)); + colortable.add(160, new Color(105, 105, 105)); + colortable.add(161, new Color(0, 0, 105)); + colortable.add(162, new Color(0, 105, 0)); + colortable.add(163, new Color(105, 0, 0)); + colortable.add(164, new Color(105, 105, 0)); + colortable.add(165, new Color(105, 0, 105)); + colortable.add(166, new Color(105, 77, 0)); + colortable.add(167, new Color(0, 105, 105)); + colortable.add(168, new Color(105, 105, 105)); + colortable.add(169, new Color(0, 0, 105)); + colortable.add(170, new Color(0, 105, 0)); + colortable.add(171, new Color(105, 0, 0)); + colortable.add(172, new Color(105, 105, 0)); + colortable.add(173, new Color(105, 0, 105)); + colortable.add(174, new Color(105, 77, 0)); + colortable.add(175, new Color(0, 90, 90)); + colortable.add(176, new Color(90, 90, 90)); + colortable.add(177, new Color(0, 0, 90)); + colortable.add(178, new Color(0, 90, 0)); + colortable.add(179, new Color(90, 0, 0)); + colortable.add(180, new Color(90, 90, 0)); + colortable.add(181, new Color(90, 0, 90)); + colortable.add(182, new Color(90, 72, 0)); + colortable.add(183, new Color(0, 90, 90)); + colortable.add(184, new Color(90, 90, 90)); + colortable.add(185, new Color(0, 0, 90)); + colortable.add(186, new Color(0, 90, 0)); + colortable.add(187, new Color(90, 0, 0)); + colortable.add(188, new Color(90, 90, 0)); + colortable.add(189, new Color(90, 0, 90)); + colortable.add(190, new Color(90, 72, 0)); + colortable.add(191, new Color(0, 75, 75)); + colortable.add(192, new Color(75, 75, 75)); + colortable.add(193, new Color(0, 0, 75)); + colortable.add(194, new Color(0, 75, 0)); + colortable.add(195, new Color(75, 0, 0)); + colortable.add(196, new Color(75, 75, 0)); + colortable.add(197, new Color(75, 0, 75)); + colortable.add(198, new Color(75, 67, 0)); + colortable.add(199, new Color(0, 75, 75)); + colortable.add(200, new Color(75, 75, 75)); + colortable.add(201, new Color(0, 0, 75)); + colortable.add(202, new Color(0, 75, 0)); + colortable.add(203, new Color(75, 0, 0)); + colortable.add(204, new Color(75, 75, 0)); + colortable.add(205, new Color(75, 0, 75)); + colortable.add(206, new Color(75, 67, 0)); + colortable.add(207, new Color(0, 60, 60)); + colortable.add(208, new Color(60, 60, 60)); + colortable.add(209, new Color(0, 0, 60)); + colortable.add(210, new Color(0, 60, 0)); + colortable.add(211, new Color(60, 0, 0)); + colortable.add(212, new Color(60, 60, 0)); + colortable.add(213, new Color(60, 0, 60)); + colortable.add(214, new Color(60, 62, 0)); + colortable.add(215, new Color(0, 60, 60)); + colortable.add(216, new Color(60, 60, 60)); + colortable.add(217, new Color(0, 0, 60)); + colortable.add(218, new Color(0, 60, 0)); + colortable.add(219, new Color(60, 0, 0)); + colortable.add(220, new Color(60, 60, 0)); + colortable.add(221, new Color(60, 0, 60)); + colortable.add(222, new Color(60, 62, 0)); + colortable.add(223, new Color(0, 45, 45)); + colortable.add(224, new Color(45, 45, 45)); + colortable.add(225, new Color(0, 0, 45)); + colortable.add(226, new Color(0, 45, 0)); + colortable.add(227, new Color(45, 0, 0)); + colortable.add(228, new Color(45, 45, 0)); + colortable.add(229, new Color(45, 0, 45)); + colortable.add(230, new Color(45, 57, 0)); + colortable.add(231, new Color(0, 45, 45)); + colortable.add(232, new Color(45, 45, 45)); + colortable.add(233, new Color(0, 0, 45)); + colortable.add(234, new Color(0, 45, 0)); + colortable.add(235, new Color(45, 0, 0)); + colortable.add(236, new Color(45, 45, 0)); + colortable.add(237, new Color(45, 0, 45)); + colortable.add(238, new Color(45, 57, 0)); + colortable.add(239, new Color(0, 30, 30)); + colortable.add(240, new Color(30, 30, 30)); + colortable.add(241, new Color(0, 0, 30)); + colortable.add(242, new Color(0, 30, 0)); + colortable.add(243, new Color(30, 0, 0)); + colortable.add(244, new Color(30, 30, 0)); + colortable.add(245, new Color(30, 0, 30)); + colortable.add(246, new Color(30, 52, 0)); + colortable.add(247, new Color(0, 30, 30)); + colortable.add(248, new Color(30, 30, 30)); + colortable.add(249, new Color(0, 0, 30)); + colortable.add(250, new Color(0, 30, 0)); + colortable.add(251, new Color(30, 0, 0)); + colortable.add(252, new Color(30, 30, 0)); + colortable.add(253, new Color(30, 0, 30)); + colortable.add(254, new Color(30, 52, 0)); + } + + public List findId(Color color) + { + ArrayList<Integer> codelist = new ArrayList<Integer>(); + for (int i = 0; i < colortable.size(); i++) + { + Color colorDef = colortable.get(i); + if (colorDef.equals(color)) + { + codelist.add(i); + } + } + return codelist; + } + + public Color getColor(int i) + { + return colortable.get(i); + } + + public String getColorCode(int i) + { + Color color = colortable.get(i); + if (!color.equals(Color.WHITE)) + return colorToString(colortable.get(i)); + return colorToString(Color.GRAY); + } + + public boolean contain(Color color) + { + for (Color colorDef : colortable) + { + if (colorDef.equals(color)) + { + return true; + } + } + return false; + } + + private static String colorToString(Color c) + { + char[] buf = new char[7]; + buf[0] = '#'; + String s = Integer.toHexString(c.getRed()); + if (s.length() == 1) + { + buf[1] = '0'; + buf[2] = s.charAt(0); + } else + { + buf[1] = s.charAt(0); + buf[2] = s.charAt(1); + } + s = Integer.toHexString(c.getGreen()); + if (s.length() == 1) + { + buf[3] = '0'; + buf[4] = s.charAt(0); + } else + { + buf[3] = s.charAt(0); + buf[4] = s.charAt(1); + } + s = Integer.toHexString(c.getBlue()); + if (s.length() == 1) + { + buf[5] = '0'; + buf[6] = s.charAt(0); + } else + { + buf[5] = s.charAt(0); + buf[6] = s.charAt(1); + } + return String.valueOf(buf); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java new file mode 100644 index 0000000..4fb6712 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java @@ -0,0 +1,237 @@ +package com.ximple.eofms.util; + +import org.geotools.feature.AttributeTypeFactory; +import org.geotools.feature.FeatureTypeBuilder; + +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.MultiLineString; + +public final class FeatureTypeBuilderUtil +{ + protected static GeometryFactory _geomFactory = new GeometryFactory(); + + public static FeatureTypeBuilder createNormalPointFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("font", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("just", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("height", Float.class, false, 1, (float) 1.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("width", Float.class, false, 1, (float) 1.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("angle", Float.class, false, 1, (float) 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("context", String.class, false, 254, "")); + return typeBuilder; + } + + public static FeatureTypeBuilder createNormalLineFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", LineString.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); + return typeBuilder; + } + + public static FeatureTypeBuilder createNormalMultiLineFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", MultiLineString.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); + return typeBuilder; + } + + public static FeatureTypeBuilder createNormalPolygonFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Polygon.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); + return typeBuilder; + } + + public static FeatureTypeBuilder createNormalArcFeatureTypeBuilder(String featureName) + { + return createNormalLineFeatureTypeBuilder(featureName); + /* + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + */ + } + + public static FeatureTypeBuilder createNormalEllipseFeatureTypeBuilder(String featureName) + { + return createNormalPolygonFeatureTypeBuilder(featureName); + /* + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + */ + } + + public static FeatureTypeBuilder createNormalIndexFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Polygon.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("x1", Double.class, false, 1, 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("y1", Double.class, false, 1, 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("x2", Double.class, false, 1, 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("y2", Double.class, false, 1, 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tpclid", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); + return typeBuilder; + } + + public static FeatureTypeBuilder createNormalIndexTextFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("just", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("height", Float.class, false, 1, (float) 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("width", Float.class, false, 1, (float) 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("angle", Float.class, false, 1, (float) 0.0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tpclid", String.class, false, 12, "")); + return typeBuilder; + } + + public static FeatureTypeBuilder createPointFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("just", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("height", Float.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("width", Float.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("angle", Float.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("context", String.class, true, 254)); + return typeBuilder; + } + + public static FeatureTypeBuilder createSymbolFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("just", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("height", Float.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("width", Float.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("angle", Float.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symbol", String.class, false, 20)); + return typeBuilder; + } + + public static FeatureTypeBuilder createPolygonFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Polygon.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + } + + public static FeatureTypeBuilder createLineFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", LineString.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + } + + public static FeatureTypeBuilder createMultiLineFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", MultiLineString.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + } + + public static FeatureTypeBuilder createEllipseFeatureTypeBuilder(String featureName) + { + return createPolygonFeatureTypeBuilder(featureName); + /* + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + */ + } + + public static FeatureTypeBuilder createArcFeatureTypeBuilder(String featureName) + { + return createLineFeatureTypeBuilder(featureName); + /* + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + */ + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java new file mode 100644 index 0000000..8cd89e4 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java @@ -0,0 +1,30 @@ +package com.ximple.eofms.util; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +/** + * Created by IntelliJ IDEA. + * User: Ulysses + * Date: 2007/6/15 + * Time: �W�� 01:20:20 + * To change this template use File | Settings | File Templates. + */ +public final class GeomUtil +{ + public static double convertLogicalValue(double value) + { + return value / 1000.0 + 2147483.648; + } + + public static Coordinate convertLogicalCooridate(Coordinate value) + { + return new Coordinate(convertLogicalValue(value.x), convertLogicalValue(value.y), convertLogicalValue(value.z)); + } + + public static Envelope convertLogicalEnvelope(Envelope value) + { + return new Envelope(convertLogicalValue(value.getMinX()), convertLogicalValue(value.getMaxX()), + convertLogicalValue(value.getMinY()), convertLogicalValue(value.getMaxY())); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java new file mode 100644 index 0000000..c8c933d --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java @@ -0,0 +1,104 @@ +package com.ximple.eofms.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import com.vividsolutions.jts.util.Assert; + +/** + * Created by IntelliJ IDEA. + * User: Ulysses + * Date: 2007/6/15 + * Time: �W�� 01:21:25 + * To change this template use File | Settings | File Templates. + */ +public class LangUtil +{ + private static Map primitiveToWrapperMap = new HashMap() + { + + { + put(byte.class, Byte.class); + put(char.class, Character.class); + put(short.class, Short.class); + put(int.class, Integer.class); + put(long.class, Long.class); + put(float.class, Float.class); + put(double.class, Double.class); + put(boolean.class, Boolean.class); + } + }; + + public static String emptyStringIfNull(String s) + { + return (s == null) ? "" : s; + } + + /** + * Useful because an expression used to generate o need only be + * evaluated once. + */ + public static Object ifNull(Object o, Object alternative) + { + return (o == null) ? alternative : o; + } + + public static Object ifNotNull(Object o, Object alternative) + { + return (o != null) ? alternative : o; + } + + public static Class toPrimitiveWrapperClass(Class primitiveClass) + { + return (Class) primitiveToWrapperMap.get(primitiveClass); + } + + public static boolean isPrimitive(Class c) + { + return primitiveToWrapperMap.containsKey(c); + } + + public static boolean bothNullOrEqual(Object a, Object b) + { + return (a == null && b == null) || (a != null && b != null && a.equals(b)); + } + + public static Object newInstance(Class c) + { + try + { + return c.newInstance(); + } catch (Exception e) + { + Assert.shouldNeverReachHere(e.toString()); + return null; + } + } + + public static Collection classesAndInterfaces(Class c) + { + ArrayList classesAndInterfaces = new ArrayList(); + classesAndInterfaces.add(c); + superclasses(c, classesAndInterfaces); + for (Iterator i = new ArrayList(classesAndInterfaces).iterator(); i.hasNext();) + { + Class x = (Class) i.next(); + classesAndInterfaces.addAll(Arrays.asList(x.getInterfaces())); + } + return classesAndInterfaces; + } + + private static void superclasses(Class c, Collection results) + { + if (c.getSuperclass() == null) + { + return; + } + results.add(c.getSuperclass()); + superclasses(c.getSuperclass(), results); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java new file mode 100644 index 0000000..8aeac8e --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java @@ -0,0 +1,4830 @@ +// +//(c) 2000 Sun Microsystems, Inc. +//ALL RIGHTS RESERVED +// +//License Grant- +// +// +//Permission to use, copy, modify, and distribute this Software and its +//documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is +//hereby granted. +// +//This Software is provided "AS IS". All express warranties, including any +//implied warranty of merchantability, satisfactory quality, fitness for a +//particular purpose, or non-infringement, are disclaimed, except to the extent +//that such disclaimers are held to be legally invalid. +// +//You acknowledge that Software is not designed, licensed or intended for use in +//the design, construction, operation or maintenance of any nuclear facility +//("High Risk Activities"). Sun disclaims any express or implied warranty of +//fitness for such uses. +// +//Please refer to the file http://www.sun.com/policies/trademarks/ for further +//important trademark information and to +//http://java.sun.com/nav/business/index.html for further important licensing +//information for the Java Technology. +// + +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.text.DecimalFormatSymbols; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +/** + * PrintfFormat allows the formatting of an array of + * objects embedded within a string. Primitive types + * must be passed using wrapper types. The formatting + * is controlled by a control string. + * <p> + * A control string is a Java string that contains a + * control specification. The control specification + * starts at the first percent sign (%) in the string, + * provided that this percent sign + * <ol> + * <li>is not escaped protected by a matching % or is + * not an escape % character, + * <li>is not at the end of the format string, and + * <li>precedes a sequence of characters that parses as + * a valid control specification. + * </ol> + * </p><p> + * A control specification usually takes the form: + * <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ + * { [hlL] }+ [idfgGoxXeEcs] + * </pre> + * There are variants of this basic form that are + * discussed below.</p> + * <p> + * The format is composed of zero or more directives + * defined as follows: + * <ul> + * <li>ordinary characters, which are simply copied to + * the output stream; + * <li>escape sequences, which represent non-graphic + * characters; and + * <li>conversion specifications, each of which + * results in the fetching of zero or more arguments. + * </ul></p> + * <p> + * The results are undefined if there are insufficient + * arguments for the format. Usually an unchecked + * exception will be thrown. If the format is + * exhausted while arguments remain, the excess + * arguments are evaluated but are otherwise ignored. + * In format strings containing the % form of + * conversion specifications, each argument in the + * argument list is used exactly once.</p> + * <p> + * Conversions can be applied to the <code>n</code>th + * argument after the format in the argument list, + * rather than to the next unused argument. In this + * case, the conversion characer % is replaced by the + * sequence %<code>n</code>$, where <code>n</code> is + * a decimal integer giving the position of the + * argument in the argument list.</p> + * <p> + * In format strings containing the %<code>n</code>$ + * form of conversion specifications, each argument + * in the argument list is used exactly once.</p> + * <p/> + * <h4>Escape Sequences</h4> + * <p> + * The following table lists escape sequences and + * associated actions on display devices capable of + * the action. + * <table> + * <tr><th align=left>Sequence</th> + * <th align=left>Name</th> + * <th align=left>Description</th></tr> + * <tr><td>\\</td><td>backlash</td><td>None. + * </td></tr> + * <tr><td>\a</td><td>alert</td><td>Attempts to alert + * the user through audible or visible + * notification. + * </td></tr> + * <tr><td>\b</td><td>backspace</td><td>Moves the + * printing position to one column before + * the current position, unless the + * current position is the start of a line. + * </td></tr> + * <tr><td>\f</td><td>form-feed</td><td>Moves the + * printing position to the initial + * printing position of the next logical + * page. + * </td></tr> + * <tr><td>\n</td><td>newline</td><td>Moves the + * printing position to the start of the + * next line. + * </td></tr> + * <tr><td>\r</td><td>carriage-return</td><td>Moves + * the printing position to the start of + * the current line. + * </td></tr> + * <tr><td>\t</td><td>tab</td><td>Moves the printing + * position to the next implementation- + * defined horizontal tab position. + * </td></tr> + * <tr><td>\v</td><td>vertical-tab</td><td>Moves the + * printing position to the start of the + * next implementation-defined vertical + * tab position. + * </td></tr> + * </table></p> + * <h4>Conversion Specifications</h4> + * <p> + * Each conversion specification is introduced by + * the percent sign character (%). After the character + * %, the following appear in sequence:</p> + * <p> + * Zero or more flags (in any order), which modify the + * meaning of the conversion specification.</p> + * <p> + * An optional minimum field width. If the converted + * value has fewer characters than the field width, it + * will be padded with spaces by default on the left; + * t will be padded on the right, if the left- + * adjustment flag (-), described below, is given to + * the field width. The field width takes the form + * of a decimal integer. If the conversion character + * is s, the field width is the the minimum number of + * characters to be printed.</p> + * <p> + * An optional precision that gives the minumum number + * of digits to appear for the d, i, o, x or X + * conversions (the field is padded with leading + * zeros); the number of digits to appear after the + * radix character for the e, E, and f conversions, + * the maximum number of significant digits for the g + * and G conversions; or the maximum number of + * characters to be written from a string is s and S + * conversions. The precision takes the form of an + * optional decimal digit string, where a null digit + * string is treated as 0. If a precision appears + * with a c conversion character the precision is + * ignored. + * </p> + * <p> + * An optional h specifies that a following d, i, o, + * x, or X conversion character applies to a type + * short argument (the argument will be promoted + * according to the integral promotions and its value + * converted to type short before printing).</p> + * <p> + * An optional l (ell) specifies that a following + * d, i, o, x, or X conversion character applies to a + * type long argument.</p> + * <p> + * A field width or precision may be indicated by an + * asterisk (*) instead of a digit string. In this + * case, an integer argument supplised the field width + * precision. The argument that is actually converted + * is not fetched until the conversion letter is seen, + * so the the arguments specifying field width or + * precision must appear before the argument (if any) + * to be converted. If the precision argument is + * negative, it will be changed to zero. A negative + * field width argument is taken as a - flag, followed + * by a positive field width.</p> + * <p> + * In format strings containing the %<code>n</code>$ + * form of a conversion specification, a field width + * or precision may be indicated by the sequence + * *<code>m</code>$, where m is a decimal integer + * giving the position in the argument list (after the + * format argument) of an integer argument containing + * the field width or precision.</p> + * <p> + * The format can contain either numbered argument + * specifications (that is, %<code>n</code>$ and + * *<code>m</code>$), or unnumbered argument + * specifications (that is % and *), but normally not + * both. The only exception to this is that %% can + * be mixed with the %<code>n</code>$ form. The + * results of mixing numbered and unnumbered argument + * specifications in a format string are undefined.</p> + * <p/> + * <h4>Flag Characters</h4> + * <p> + * The flags and their meanings are:</p> + * <dl> + * <dt>'<dd> integer portion of the result of a + * decimal conversion (%i, %d, %f, %g, or %G) will + * be formatted with thousands' grouping + * characters. For other conversions the flag + * is ignored. The non-monetary grouping + * character is used. + * <dt>-<dd> result of the conversion is left-justified + * within the field. (It will be right-justified + * if this flag is not specified).</td></tr> + * <dt>+<dd> result of a signed conversion always + * begins with a sign (+ or -). (It will begin + * with a sign only when a negative value is + * converted if this flag is not specified.) + * <dt><space><dd> If the first character of a + * signed conversion is not a sign, a space + * character will be placed before the result. + * This means that if the space character and + + * flags both appear, the space flag will be + * ignored. + * <dt>#<dd> value is to be converted to an alternative + * form. For c, d, i, and s conversions, the flag + * has no effect. For o conversion, it increases + * the precision to force the first digit of the + * result to be a zero. For x or X conversion, a + * non-zero result has 0x or 0X prefixed to it, + * respectively. For e, E, f, g, and G + * conversions, the result always contains a radix + * character, even if no digits follow the radix + * character (normally, a decimal point appears in + * the result of these conversions only if a digit + * follows it). For g and G conversions, trailing + * zeros will not be removed from the result as + * they normally are. + * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G + * conversions, leading zeros (following any + * indication of sign or base) are used to pad to + * the field width; no space padding is + * performed. If the 0 and - flags both appear, + * the 0 flag is ignored. For d, i, o, x, and X + * conversions, if a precision is specified, the + * 0 flag will be ignored. For c conversions, + * the flag is ignored. + * </dl> + * <p/> + * <h4>Conversion Characters</h4> + * <p> + * Each conversion character results in fetching zero + * or more arguments. The results are undefined if + * there are insufficient arguments for the format. + * Usually, an unchecked exception will be thrown. + * If the format is exhausted while arguments remain, + * the excess arguments are ignored.</p> + * <p/> + * <p> + * The conversion characters and their meanings are: + * </p> + * <dl> + * <dt>d,i<dd>The int argument is converted to a + * signed decimal in the style [-]dddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + * <dt>o<dd> The int argument is converted to unsigned + * octal format in the style ddddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + * <dt>x<dd> The int argument is converted to unsigned + * hexadecimal format in the style dddd; the + * letters abcdef are used. The precision + * specifies the minimum numberof digits to + * appear; if the value being converted can be + * represented in fewer digits, it will be + * expanded with leading zeros. The default + * precision is 1. The result of converting 0 + * with an explicit precision of 0 is no + * characters. + * <dt>X<dd> Behaves the same as the x conversion + * character except that letters ABCDEF are + * used instead of abcdef. + * <dt>f<dd> The floating point number argument is + * written in decimal notation in the style + * [-]ddd.ddd, where the number of digits after + * the radix character (shown here as a decimal + * point) is equal to the precision + * specification. A Locale is used to determine + * the radix character to use in this format. + * If the precision is omitted from the + * argument, six digits are written after the + * radix character; if the precision is + * explicitly 0 and the # flag is not specified, + * no radix character appears. If a radix + * character appears, at least 1 digit appears + * before it. The value is rounded to the + * appropriate number of digits. + * <dt>e,E<dd>The floating point number argument is + * written in the style [-]d.ddde{+-}dd + * (the symbols {+-} indicate either a plus or + * minus sign), where there is one digit before + * the radix character (shown here as a decimal + * point) and the number of digits after it is + * equal to the precision. A Locale is used to + * determine the radix character to use in this + * format. When the precision is missing, six + * digits are written after the radix character; + * if the precision is 0 and the # flag is not + * specified, no radix character appears. The + * E conversion will produce a number with E + * instead of e introducing the exponent. The + * exponent always contains at least two digits. + * However, if the value to be written requires + * an exponent greater than two digits, + * additional exponent digits are written as + * necessary. The value is rounded to the + * appropriate number of digits. + * <dt>g,G<dd>The floating point number argument is + * written in style f or e (or in sytle E in the + * case of a G conversion character), with the + * precision specifying the number of + * significant digits. If the precision is + * zero, it is taken as one. The style used + * depends on the value converted: style e + * (or E) will be used only if the exponent + * resulting from the conversion is less than + * -4 or greater than or equal to the precision. + * Trailing zeros are removed from the result. + * A radix character appears only if it is + * followed by a digit. + * <dt>c,C<dd>The integer argument is converted to a + * char and the result is written. + * <p/> + * <dt>s,S<dd>The argument is taken to be a string and + * bytes from the string are written until the + * end of the string or the number of bytes + * indicated by the precision specification of + * the argument is reached. If the precision + * is omitted from the argument, it is taken to + * be infinite, so all characters up to the end + * of the string are written. + * <dt>%<dd>Write a % character; no argument is + * converted. + * </dl> + * <p> + * If a conversion specification does not match one of + * the above forms, an IllegalArgumentException is + * thrown and the instance of PrintfFormat is not + * created.</p> + * <p> + * If a floating point value is the internal + * representation for infinity, the output is + * [+]Infinity, where Infinity is either Infinity or + * Inf, depending on the desired output string length. + * Printing of the sign follows the rules described + * above.</p> + * <p> + * If a floating point value is the internal + * representation for "not-a-number," the output is + * [+]NaN. Printing of the sign follows the rules + * described above.</p> + * <p> + * In no case does a non-existent or small field width + * cause truncation of a field; if the result of a + * conversion is wider than the field width, the field + * is simply expanded to contain the conversion result. + * </p> + * <p> + * The behavior is like printf. One exception is that + * the minimum number of exponent digits is 3 instead + * of 2 for e and E formats when the optional L is used + * before the e, E, g, or G conversion character. The + * optional L does not imply conversion to a long long + * double. </p> + * <p> + * The biggest divergence from the C printf + * specification is in the use of 16 bit characters. + * This allows the handling of characters beyond the + * small ASCII character set and allows the utility to + * interoperate correctly with the rest of the Java + * runtime environment.</p> + * <p> + * Omissions from the C printf specification are + * numerous. All the known omissions are present + * because Java never uses bytes to represent + * characters and does not have pointers:</p> + * <ul> + * <li>%c is the same as %C. + * <li>%s is the same as %S. + * <li>u, p, and n conversion characters. + * <li>%ws format. + * <li>h modifier applied to an n conversion character. + * <li>l (ell) modifier applied to the c, n, or s + * conversion characters. + * <li>ll (ell ell) modifier to d, i, o, u, x, or X + * conversion characters. + * <li>ll (ell ell) modifier to an n conversion + * character. + * <li>c, C, d,i,o,u,x, and X conversion characters + * apply to Byte, Character, Short, Integer, Long + * types. + * <li>f, e, E, g, and G conversion characters apply + * to Float and Double types. + * <li>s and S conversion characters apply to String + * types. + * <li>All other reference types can be formatted + * using the s or S conversion characters only. + * </ul> + * <p> + * Most of this specification is quoted from the Unix + * man page for the sprintf utility.</p> + * + * @author Allan Jacobs + * @version 1 + * Release 1: Initial release. + * Release 2: Asterisk field widths and precisions + * %n$ and *m$ + * Bug fixes + * g format fix (2 digits in e form corrupt) + * rounding in f format implemented + * round up when digit not printed is 5 + * formatting of -0.0f + * round up/down when last digits are 50000... + */ +public final class PrintfFormat +{ + /** + * Vector of control strings and format literals. + */ + private Vector vFmt = new Vector(); + + /** + * Character position. Used by the constructor. + */ + private int cPos = 0; + + /** + * Character position. Used by the constructor. + */ + private DecimalFormatSymbols dfs = null; + + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * + * @param fmtArg Control string. + * @throws IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(String fmtArg) throws IllegalArgumentException + { + this(Locale.getDefault(), fmtArg); + } + + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * + * @param fmtArg Control string. + * @throws IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(Locale locale, String fmtArg) throws IllegalArgumentException + { + dfs = new DecimalFormatSymbols(locale); + + int ePos = 0; + ConversionSpecification sFmt = null; + String unCS = this.nonControl(fmtArg, 0); + + if (unCS != null) + { + sFmt = new ConversionSpecification(); + sFmt.setLiteral(unCS); + vFmt.addElement(sFmt); + } + + while ((cPos != -1) && (cPos < fmtArg.length())) + { + for (ePos = cPos + 1; ePos < fmtArg.length(); ePos++) + { + char c = 0; + + c = fmtArg.charAt(ePos); + + if (c == 'i') + { + break; + } + + if (c == 'd') + { + break; + } + + if (c == 'f') + { + break; + } + + if (c == 'g') + { + break; + } + + if (c == 'G') + { + break; + } + + if (c == 'o') + { + break; + } + + if (c == 'x') + { + break; + } + + if (c == 'X') + { + break; + } + + if (c == 'e') + { + break; + } + + if (c == 'E') + { + break; + } + + if (c == 'c') + { + break; + } + + if (c == 's') + { + break; + } + + if (c == '%') + { + break; + } + } + + ePos = Math.min(ePos + 1, fmtArg.length()); + sFmt = new ConversionSpecification(fmtArg.substring(cPos, ePos)); + vFmt.addElement(sFmt); + unCS = this.nonControl(fmtArg, ePos); + + if (unCS != null) + { + sFmt = new ConversionSpecification(); + sFmt.setLiteral(unCS); + vFmt.addElement(sFmt); + } + } + } + + /** + * Return a substring starting at + * <code>start</code> and ending at either the end + * of the String <code>s</code>, the next unpaired + * percent sign, or at the end of the String if the + * last character is a percent sign. + * + * @param s Control string. + * @param start Position in the string + * <code>s</code> to begin looking for the start + * of a control string. + * @return the substring from the start position + * to the beginning of the control string. + */ + private String nonControl(String s, int start) + { + String ret = ""; + + cPos = s.indexOf("%", start); + + if (cPos == -1) + { + cPos = s.length(); + } + + return s.substring(start, cPos); + } + + /** + * Format an array of objects. Byte, Short, + * Integer, Long, Float, Double, and Character + * arguments are treated as wrappers for primitive + * types. + * + * @param o The array of objects to format. + * @return The formatted String. + */ + public String sprintf(Object[] o) + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + int i = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + if (cs.isPositionalSpecification()) + { + i = cs.getArgumentPosition() - 1; + + if (cs.isPositionalFieldWidth()) + { + int ifw = cs.getArgumentPositionForFieldWidth() - 1; + + cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue()); + } + + if (cs.isPositionalPrecision()) + { + int ipr = cs.getArgumentPositionForPrecision() - 1; + + cs.setPrecisionWithArg(((Integer) o[ipr]).intValue()); + } + } else + { + if (cs.isVariableFieldWidth()) + { + cs.setFieldWidthWithArg(((Integer) o[i]).intValue()); + i++; + } + + if (cs.isVariablePrecision()) + { + cs.setPrecisionWithArg(((Integer) o[i]).intValue()); + i++; + } + } + + if (o[i] instanceof Byte) + { + sb.append(cs.internalsprintf(((Byte) o[i]).byteValue())); + } else if (o[i] instanceof Short) + { + sb.append(cs.internalsprintf(((Short) o[i]).shortValue())); + } else if (o[i] instanceof Integer) + { + sb.append(cs.internalsprintf(((Integer) o[i]).intValue())); + } else if (o[i] instanceof Long) + { + sb.append(cs.internalsprintf(((Long) o[i]).longValue())); + } else if (o[i] instanceof Float) + { + sb.append(cs.internalsprintf(((Float) o[i]).floatValue())); + } else if (o[i] instanceof Double) + { + sb.append(cs.internalsprintf(((Double) o[i]).doubleValue())); + } else if (o[i] instanceof Character) + { + sb.append(cs.internalsprintf(((Character) o[i]).charValue())); + } else if (o[i] instanceof String) + { + sb.append(cs.internalsprintf((String) o[i])); + } else + { + sb.append(cs.internalsprintf(o[i])); + } + + if (!cs.isPositionalSpecification()) + { + i++; + } + } + } + + return sb.toString(); + } + + /** + * Format nothing. Just use the control string. + * + * @return the formatted String. + */ + public String sprintf() + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } + } + + return sb.toString(); + } + + /** + * Format an int. + * + * @param x The int to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(int x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format an long. + * + * @param x The long to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(long x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format a double. + * + * @param x The double to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is c, C, s, S, + * d, d, x, X, or o. + */ + public String sprintf(double x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format a String. + * + * @param x The String to format. + * @return The formatted String. + * @throws IllegalArgumentException if the + * conversion character is neither s nor S. + */ + public String sprintf(String x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format an Object. Convert wrapper types to + * their primitive equivalents and call the + * appropriate internal formatting method. Convert + * Strings using an internal formatting method for + * Strings. Otherwise use the default formatter + * (use toString). + * + * @param x the Object to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is inappropriate for + * formatting an unwrapped value. + */ + public String sprintf(Object x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + if (x instanceof Byte) + { + sb.append(cs.internalsprintf(((Byte) x).byteValue())); + } else if (x instanceof Short) + { + sb.append(cs.internalsprintf(((Short) x).shortValue())); + } else if (x instanceof Integer) + { + sb.append(cs.internalsprintf(((Integer) x).intValue())); + } else if (x instanceof Long) + { + sb.append(cs.internalsprintf(((Long) x).longValue())); + } else if (x instanceof Float) + { + sb.append(cs.internalsprintf(((Float) x).floatValue())); + } else if (x instanceof Double) + { + sb.append(cs.internalsprintf(((Double) x).doubleValue())); + } else if (x instanceof Character) + { + sb.append(cs.internalsprintf(((Character) x).charValue())); + } else if (x instanceof String) + { + sb.append(cs.internalsprintf((String) x)); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + } + + return sb.toString(); + } + + /** + * <p/> + * ConversionSpecification allows the formatting of + * a single primitive or object embedded within a + * string. The formatting is controlled by a + * format string. Only one Java primitive or + * object can be formatted at a time. + * <p/> + * A format string is a Java string that contains + * a control string. The control string starts at + * the first percent sign (%) in the string, + * provided that this percent sign + * <ol> + * <li>is not escaped protected by a matching % or + * is not an escape % character, + * <li>is not at the end of the format string, and + * <li>precedes a sequence of characters that parses + * as a valid control string. + * </ol> + * <p/> + * A control string takes the form: + * <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ + * { [hlL] }+ [idfgGoxXeEcs] + * </pre> + * <p/> + * The behavior is like printf. One (hopefully the + * only) exception is that the minimum number of + * exponent digits is 3 instead of 2 for e and E + * formats when the optional L is used before the + * e, E, g, or G conversion character. The + * optional L does not imply conversion to a long + * long double. + */ + private class ConversionSpecification + { + /** + * Default precision. + */ + private final static int defaultDigits = 6; + + /** + * The integer portion of the result of a decimal + * conversion (i, d, u, f, g, or G) will be + * formatted with thousands' grouping characters. + * For other conversions the flag is ignored. + */ + private boolean thousands = false; + + /** + * The result of the conversion will be + * left-justified within the field. + */ + private boolean leftJustify = false; + + /** + * The result of a signed conversion will always + * begin with a sign (+ or -). + */ + private boolean leadingSign = false; + + /** + * Flag indicating that left padding with spaces is + * specified. + */ + private boolean leadingSpace = false; + + /** + * For an o conversion, increase the precision to + * force the first digit of the result to be a + * zero. For x (or X) conversions, a non-zero + * result will have 0x (or 0X) prepended to it. + * For e, E, f, g, or G conversions, the result + * will always contain a radix character, even if + * no digits follow the point. For g and G + * conversions, trailing zeros will not be removed + * from the result. + */ + private boolean alternateForm = false; + + /** + * Flag indicating that left padding with zeroes is + * specified. + */ + private boolean leadingZeros = false; + + /** + * Flag indicating that the field width is *. + */ + private boolean variableFieldWidth = false; + + /** + * If the converted value has fewer bytes than the + * field width, it will be padded with spaces or + * zeroes. + */ + private int fieldWidth = 0; + + /** + * Flag indicating whether or not the field width + * has been set. + */ + private boolean fieldWidthSet = false; + + /** + * The minimum number of digits to appear for the + * d, i, o, u, x, or X conversions. The number of + * digits to appear after the radix character for + * the e, E, and f conversions. The maximum number + * of significant digits for the g and G + * conversions. The maximum number of bytes to be + * printed from a string in s and S conversions. + */ + private int precision = 0; + + /** + * Flag indicating that the precision is *. + */ + private boolean variablePrecision = false; + + /** + * Flag indicating whether or not the precision has + * been set. + */ + private boolean precisionSet = false; + + /* + */ + private boolean positionalSpecification = false; + private int argumentPosition = 0; + private boolean positionalFieldWidth = false; + private int argumentPositionForFieldWidth = 0; + private boolean positionalPrecision = false; + private int argumentPositionForPrecision = 0; + + /** + * Flag specifying that a following d, i, o, u, x, + * or X conversion character applies to a type + * short int. + */ + private boolean optionalh = false; + + /** + * Flag specifying that a following d, i, o, u, x, + * or X conversion character applies to a type lont + * int argument. + */ + private boolean optionall = false; + + /** + * Flag specifying that a following e, E, f, g, or + * G conversion character applies to a type double + * argument. This is a noop in Java. + */ + private boolean optionalL = false; + + /** + * Control string type. + */ + private char conversionCharacter = '\0'; + + /** + * Position within the control string. Used by + * the constructor. + */ + private int pos = 0; + + /** + * Literal or control format string. + */ + private String fmt; + + /** + * Constructor. Used to prepare an instance + * to hold a literal, not a control string. + */ + ConversionSpecification() + { + } + + /** + * Constructor for a conversion specification. + * The argument must begin with a % and end + * with the conversion character for the + * conversion specification. + * + * @param fmtArg String specifying the + * conversion specification. + * @throws IllegalArgumentException if the + * input string is null, zero length, or + * otherwise malformed. + */ + ConversionSpecification(String fmtArg) throws IllegalArgumentException + { + if (fmtArg == null) + { + throw new NullPointerException(); + } + + if (fmtArg.length() == 0) + { + throw new IllegalArgumentException("Control strings must have positive" + " lengths."); + } + + if (fmtArg.charAt(0) == '%') + { + fmt = fmtArg; + pos = 1; + setArgPosition(); + setFlagCharacters(); + setFieldWidth(); + setPrecision(); + setOptionalHL(); + + if (setConversionCharacter()) + { + if (pos == fmtArg.length()) + { + if (leadingZeros && leftJustify) + { + leadingZeros = false; + } + + if (precisionSet && leadingZeros) + { + if ((conversionCharacter == 'd') || (conversionCharacter == 'i') || (conversionCharacter == 'o') + || (conversionCharacter == 'x')) + { + leadingZeros = false; + } + } + } else + { + throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg); + } + } else + { + throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg); + } + } else + { + throw new IllegalArgumentException("Control strings must begin with %."); + } + } + + /** + * Set the String for this instance. + * + * @param s the String to store. + */ + void setLiteral(String s) + { + fmt = s; + } + + /** + * Get the String for this instance. Translate + * any escape sequences. + * + * @return s the stored String. + */ + String getLiteral() + { + StringBuffer sb = new StringBuffer(); + int i = 0; + + while (i < fmt.length()) + { + if (fmt.charAt(i) == '\\') + { + i++; + + if (i < fmt.length()) + { + char c = fmt.charAt(i); + + switch (c) + { + case 'a': + sb.append((char) 0x07); + + break; + + case 'b': + sb.append('\b'); + + break; + + case 'f': + sb.append('\f'); + + break; + + case 'n': + sb.append(System.getProperty("line.separator")); + + break; + + case 'r': + sb.append('\r'); + + break; + + case 't': + sb.append('\t'); + + break; + + case 'v': + sb.append((char) 0x0b); + + break; + + case '\\': + sb.append('\\'); + + break; + } + + i++; + } else + { + sb.append('\\'); + } + } else + { + i++; + } + } + + return fmt; + } + + /** + * Get the conversion character that tells what + * type of control character this instance has. + * + * @return the conversion character. + */ + char getConversionCharacter() + { + return conversionCharacter; + } + + /** + * Check whether the specifier has a variable + * field width that is going to be set by an + * argument. + * + * @return <code>true</code> if the conversion + * uses an * field width; otherwise + * <code>false</code>. + */ + boolean isVariableFieldWidth() + { + return variableFieldWidth; + } + + /** + * Set the field width with an argument. A + * negative field width is taken as a - flag + * followed by a positive field width. + * + * @param fw the field width. + */ + void setFieldWidthWithArg(int fw) + { + if (fw < 0) + { + leftJustify = true; + } + + fieldWidthSet = true; + fieldWidth = Math.abs(fw); + } + + /** + * Check whether the specifier has a variable + * precision that is going to be set by an + * argument. + * + * @return <code>true</code> if the conversion + * uses an * precision; otherwise + * <code>false</code>. + */ + boolean isVariablePrecision() + { + return variablePrecision; + } + + /** + * Set the precision with an argument. A + * negative precision will be changed to zero. + * + * @param pr the precision. + */ + void setPrecisionWithArg(int pr) + { + precisionSet = true; + precision = Math.max(pr, 0); + } + + /** + * Format an int argument using this conversion + * specification. + * + * @param s the int to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(int s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'd': + case 'i': + if (optionalh) + { + s2 = printDFormat((short) s); + } else if (optionall) + { + s2 = printDFormat((long) s); + } else + { + s2 = printDFormat(s); + } + + break; + + case 'x': + case 'X': + if (optionalh) + { + s2 = printXFormat((short) s); + } else if (optionall) + { + s2 = printXFormat((long) s); + } else + { + s2 = printXFormat(s); + } + + break; + + case 'o': + if (optionalh) + { + s2 = printOFormat((short) s); + } else if (optionall) + { + s2 = printOFormat((long) s); + } else + { + s2 = printOFormat(s); + } + + break; + + case 'c': + case 'C': + s2 = printCFormat((char) s); + + break; + + default: + throw new IllegalArgumentException("Cannot format a int with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a long argument using this conversion + * specification. + * + * @param s the long to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(long s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'd': + case 'i': + if (optionalh) + { + s2 = printDFormat((short) s); + } else if (optionall) + { + s2 = printDFormat(s); + } else + { + s2 = printDFormat((int) s); + } + + break; + + case 'x': + case 'X': + if (optionalh) + { + s2 = printXFormat((short) s); + } else if (optionall) + { + s2 = printXFormat(s); + } else + { + s2 = printXFormat((int) s); + } + + break; + + case 'o': + if (optionalh) + { + s2 = printOFormat((short) s); + } else if (optionall) + { + s2 = printOFormat(s); + } else + { + s2 = printOFormat((int) s); + } + + break; + + case 'c': + case 'C': + s2 = printCFormat((char) s); + + break; + + default: + throw new IllegalArgumentException("Cannot format a long with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a double argument using this conversion + * specification. + * + * @param s the double to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is c, C, s, S, i, d, + * x, X, or o. + */ + String internalsprintf(double s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'f': + s2 = printFFormat(s); + + break; + + case 'E': + case 'e': + s2 = printEFormat(s); + + break; + + case 'G': + case 'g': + s2 = printGFormat(s); + + break; + + default: + throw new IllegalArgumentException("Cannot " + "format a double with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a String argument using this conversion + * specification. + * + * @param s the String to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(String s) throws IllegalArgumentException + { + String s2 = ""; + + if ((conversionCharacter == 's') || (conversionCharacter == 'S')) + { + s2 = printSFormat(s); + } else + { + throw new IllegalArgumentException("Cannot " + "format a String with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format an Object argument using this conversion + * specification. + * + * @param s the Object to format. + * @return the formatted String. + * @throws IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(Object s) + { + String s2 = ""; + + if ((conversionCharacter == 's') || (conversionCharacter == 'S')) + { + s2 = printSFormat(s.toString()); + } else + { + throw new IllegalArgumentException("Cannot format a String with a format using" + " a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * For f format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both + * a '+' and a ' ' are specified, the blank flag + * is ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the number of digits + * to appear after the radix character. Padding is + * with trailing 0s. + */ + private char[] fFormatDigits(double x) + { + // int defaultDigits=6; + String sx, sxOut; + int i, j, k; + int n1In, n2In; + int expon = 0; + boolean minusSign = false; + + if (x > 0.0) + { + sx = Double.toString(x); + } else if (x < 0.0) + { + sx = Double.toString(-x); + minusSign = true; + } else + { + sx = Double.toString(x); + + if (sx.charAt(0) == '-') + { + minusSign = true; + sx = sx.substring(1); + } + } + + int ePos = sx.indexOf('E'); + int rPos = sx.indexOf('.'); + + if (rPos != -1) + { + n1In = rPos; + } else if (ePos != -1) + { + n1In = ePos; + } else + { + n1In = sx.length(); + } + + if (rPos != -1) + { + if (ePos != -1) + { + n2In = ePos - rPos - 1; + } else + { + n2In = sx.length() - rPos - 1; + } + } else + { + n2In = 0; + } + + if (ePos != -1) + { + int ie = ePos + 1; + + expon = 0; + + if (sx.charAt(ie) == '-') + { + for (++ie; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = -Integer.parseInt(sx.substring(ie)); + } + } else + { + if (sx.charAt(ie) == '+') + { + ++ie; + } + + for (; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = Integer.parseInt(sx.substring(ie)); + } + } + } + + int p; + + if (precisionSet) + { + p = precision; + } else + { + p = defaultDigits - 1; + } + + char[] ca1 = sx.toCharArray(); + char[] ca2 = new char[n1In + n2In]; + char[] ca3, ca4, ca5; + + for (j = 0; j < n1In; j++) + { + ca2[j] = ca1[j]; + } + + i = j + 1; + + for (k = 0; k < n2In; j++, i++, k++) + { + ca2[j] = ca1[i]; + } + + if (n1In + expon <= 0) + { + ca3 = new char[-expon + n2In]; + + for (j = 0, k = 0; k < (-n1In - expon); k++, j++) + { + ca3[j] = '0'; + } + + for (i = 0; i < (n1In + n2In); i++, j++) + { + ca3[j] = ca2[i]; + } + } else + { + ca3 = ca2; + } + + boolean carry = false; + + if (p < -expon + n2In) + { + if (expon < 0) + { + i = p; + } else + { + i = p + n1In; + } + + carry = checkForCarry(ca3, i); + + if (carry) + { + carry = startSymbolicCarry(ca3, i - 1, 0); + } + } + + if (n1In + expon <= 0) + { + ca4 = new char[2 + p]; + + if (!carry) + { + ca4[0] = '0'; + } else + { + ca4[0] = '1'; + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4[1] = '.'; + + for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++) + { + ca4[j] = ca3[i]; + } + + for (; j < ca4.length; j++) + { + ca4[j] = '0'; + } + } + } else + { + if (!carry) + { + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4 = new char[n1In + expon + p + 1]; + } else + { + ca4 = new char[n1In + expon]; + } + + j = 0; + } else + { + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4 = new char[n1In + expon + p + 2]; + } else + { + ca4 = new char[n1In + expon + 1]; + } + + ca4[0] = '1'; + j = 1; + } + + for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++) + { + ca4[j] = ca3[i]; + } + + for (; i < n1In + expon; i++, j++) + { + ca4[j] = '0'; + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca4[j] = '.'; + j++; + + for (k = 0; (i < ca3.length) && (k < p); i++, j++, k++) + { + ca4[j] = ca3[i]; + } + + for (; j < ca4.length; j++) + { + ca4[j] = '0'; + } + } + } + + int nZeros = 0; + + if (!leftJustify && leadingZeros) + { + int xThousands = 0; + + if (thousands) + { + int xlead = 0; + + if ((ca4[0] == '+') || (ca4[0] == '-') || (ca4[0] == ' ')) + { + xlead = 1; + } + + int xdp = xlead; + + for (; xdp < ca4.length; xdp++) + { + if (ca4[xdp] == '.') + { + break; + } + } + + xThousands = (xdp - xlead) / 3; + } + + if (fieldWidthSet) + { + nZeros = fieldWidth - ca4.length; + } + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + nZeros--; + } + + nZeros -= xThousands; + + if (nZeros < 0) + { + nZeros = 0; + } + } + + j = 0; + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + ca5 = new char[ca4.length + nZeros + 1]; + j++; + } else + { + ca5 = new char[ca4.length + nZeros]; + } + + if (!minusSign) + { + if (leadingSign) + { + ca5[0] = '+'; + } + + if (leadingSpace) + { + ca5[0] = ' '; + } + } else + { + ca5[0] = '-'; + } + + for (i = 0; i < nZeros; i++, j++) + { + ca5[j] = '0'; + } + + for (i = 0; i < ca4.length; i++, j++) + { + ca5[j] = ca4[i]; + } + + int lead = 0; + + if ((ca5[0] == '+') || (ca5[0] == '-') || (ca5[0] == ' ')) + { + lead = 1; + } + + int dp = lead; + + for (; dp < ca5.length; dp++) + { + if (ca5[dp] == '.') + { + break; + } + } + + int nThousands = (dp - lead) / 3; + + // Localize the decimal point. + if (dp < ca5.length) + { + ca5[dp] = dfs.getDecimalSeparator(); + } + + char[] ca6 = ca5; + + if (thousands && (nThousands > 0)) + { + ca6 = new char[ca5.length + nThousands + lead]; + ca6[0] = ca5[0]; + + for (i = lead, k = lead; i < dp; i++) + { + if ((i > 0) && (dp - i) % 3 == 0) + { + // ca6[k]=','; + ca6[k] = dfs.getGroupingSeparator(); + ca6[k + 1] = ca5[i]; + k += 2; + } else + { + ca6[k] = ca5[i]; + k++; + } + } + + for (; i < ca5.length; i++, k++) + { + ca6[k] = ca5[i]; + } + } + + return ca6; + } + + /** + * An intermediate routine on the way to creating + * an f format String. The method decides whether + * the input double value is an infinity, + * not-a-number, or a finite double and formats + * each type of input appropriately. + * + * @param x the double value to be formatted. + * @return the converted double value. + */ + private String fFormatString(double x) + { + boolean noDigits = false; + char[] ca6, ca7; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca6 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca6 = " Inf".toCharArray(); + } else + { + ca6 = "Inf".toCharArray(); + } + } else + { + ca6 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca6 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca6 = " NaN".toCharArray(); + } else + { + ca6 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + ca6 = fFormatDigits(x); + } + + ca7 = applyFloatPadding(ca6, false); + + return new String(ca7); + } + + /** + * For e format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear after the radix character. + * Padding is with trailing 0s. + * <p/> + * The behavior is like printf. One (hopefully the + * only) exception is that the minimum number of + * exponent digits is 3 instead of 2 for e and E + * formats when the optional L is used before the + * e, E, g, or G conversion character. The optional + * L does not imply conversion to a long long + * double. + */ + private char[] eFormatDigits(double x, char eChar) + { + char[] ca1, ca2, ca3; + + // int defaultDigits=6; + String sx, sxOut; + int i, j, k, p; + int n1In, n2In; + int expon = 0; + int ePos, rPos, eSize; + boolean minusSign = false; + + if (x > 0.0) + { + sx = Double.toString(x); + } else if (x < 0.0) + { + sx = Double.toString(-x); + minusSign = true; + } else + { + sx = Double.toString(x); + + if (sx.charAt(0) == '-') + { + minusSign = true; + sx = sx.substring(1); + } + } + + ePos = sx.indexOf('E'); + + if (ePos == -1) + { + ePos = sx.indexOf('e'); + } + + rPos = sx.indexOf('.'); + + if (rPos != -1) + { + n1In = rPos; + } else if (ePos != -1) + { + n1In = ePos; + } else + { + n1In = sx.length(); + } + + if (rPos != -1) + { + if (ePos != -1) + { + n2In = ePos - rPos - 1; + } else + { + n2In = sx.length() - rPos - 1; + } + } else + { + n2In = 0; + } + + if (ePos != -1) + { + int ie = ePos + 1; + + expon = 0; + + if (sx.charAt(ie) == '-') + { + for (++ie; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = -Integer.parseInt(sx.substring(ie)); + } + } else + { + if (sx.charAt(ie) == '+') + { + ++ie; + } + + for (; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = Integer.parseInt(sx.substring(ie)); + } + } + } + + if (rPos != -1) + { + expon += rPos - 1; + } + + if (precisionSet) + { + p = precision; + } else + { + p = defaultDigits - 1; + } + + if ((rPos != -1) && (ePos != -1)) + { + ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray(); + } else if (rPos != -1) + { + ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray(); + } else if (ePos != -1) + { + ca1 = sx.substring(0, ePos).toCharArray(); + } else + { + ca1 = sx.toCharArray(); + } + + boolean carry = false; + int i0 = 0; + + if (ca1[0] != '0') + { + i0 = 0; + } else + { + for (i0 = 0; i0 < ca1.length; i0++) + { + if (ca1[i0] != '0') + { + break; + } + } + } + + if (i0 + p < ca1.length - 1) + { + carry = checkForCarry(ca1, i0 + p + 1); + + if (carry) + { + carry = startSymbolicCarry(ca1, i0 + p, i0); + } + + if (carry) + { + ca2 = new char[i0 + p + 1]; + ca2[i0] = '1'; + + for (j = 0; j < i0; j++) + { + ca2[j] = '0'; + } + + for (i = i0, j = i0 + 1; j < p + 1; i++, j++) + { + ca2[j] = ca1[i]; + } + + expon++; + ca1 = ca2; + } + } + + if ((Math.abs(expon) < 100) && !optionalL) + { + eSize = 4; + } else + { + eSize = 5; + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca2 = new char[2 + p + eSize]; + } else + { + ca2 = new char[1 + eSize]; + } + + if (ca1[0] != '0') + { + ca2[0] = ca1[0]; + j = 1; + } else + { + for (j = 1; j < ((ePos == -1) + ? ca1.length + : ePos); j++) + { + if (ca1[j] != '0') + { + break; + } + } + + if (((ePos != -1) && (j < ePos)) || ((ePos == -1) && (j < ca1.length))) + { + ca2[0] = ca1[j]; + expon -= j; + j++; + } else + { + ca2[0] = '0'; + j = 2; + } + } + + if (alternateForm || !precisionSet || (precision != 0)) + { + ca2[1] = '.'; + i = 2; + } else + { + i = 1; + } + + for (k = 0; (k < p) && (j < ca1.length); j++, i++, k++) + { + ca2[i] = ca1[j]; + } + + for (; i < ca2.length - eSize; i++) + { + ca2[i] = '0'; + } + + ca2[i++] = eChar; + + if (expon < 0) + { + ca2[i++] = '-'; + } else + { + ca2[i++] = '+'; + } + + expon = Math.abs(expon); + + if (expon >= 100) + { + switch (expon / 100) + { + case 1: + ca2[i] = '1'; + + break; + + case 2: + ca2[i] = '2'; + + break; + + case 3: + ca2[i] = '3'; + + break; + + case 4: + ca2[i] = '4'; + + break; + + case 5: + ca2[i] = '5'; + + break; + + case 6: + ca2[i] = '6'; + + break; + + case 7: + ca2[i] = '7'; + + break; + + case 8: + ca2[i] = '8'; + + break; + + case 9: + ca2[i] = '9'; + + break; + } + + i++; + } + + switch ((expon % 100) / 10) + { + case 0: + ca2[i] = '0'; + + break; + + case 1: + ca2[i] = '1'; + + break; + + case 2: + ca2[i] = '2'; + + break; + + case 3: + ca2[i] = '3'; + + break; + + case 4: + ca2[i] = '4'; + + break; + + case 5: + ca2[i] = '5'; + + break; + + case 6: + ca2[i] = '6'; + + break; + + case 7: + ca2[i] = '7'; + + break; + + case 8: + ca2[i] = '8'; + + break; + + case 9: + ca2[i] = '9'; + + break; + } + + i++; + + switch (expon % 10) + { + case 0: + ca2[i] = '0'; + + break; + + case 1: + ca2[i] = '1'; + + break; + + case 2: + ca2[i] = '2'; + + break; + + case 3: + ca2[i] = '3'; + + break; + + case 4: + ca2[i] = '4'; + + break; + + case 5: + ca2[i] = '5'; + + break; + + case 6: + ca2[i] = '6'; + + break; + + case 7: + ca2[i] = '7'; + + break; + + case 8: + ca2[i] = '8'; + + break; + + case 9: + ca2[i] = '9'; + + break; + } + + int nZeros = 0; + + if (!leftJustify && leadingZeros) + { + int xThousands = 0; + + if (thousands) + { + int xlead = 0; + + if ((ca2[0] == '+') || (ca2[0] == '-') || (ca2[0] == ' ')) + { + xlead = 1; + } + + int xdp = xlead; + + for (; xdp < ca2.length; xdp++) + { + if (ca2[xdp] == '.') + { + break; + } + } + + xThousands = (xdp - xlead) / 3; + } + + if (fieldWidthSet) + { + nZeros = fieldWidth - ca2.length; + } + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + nZeros--; + } + + nZeros -= xThousands; + + if (nZeros < 0) + { + nZeros = 0; + } + } + + j = 0; + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + ca3 = new char[ca2.length + nZeros + 1]; + j++; + } else + { + ca3 = new char[ca2.length + nZeros]; + } + + if (!minusSign) + { + if (leadingSign) + { + ca3[0] = '+'; + } + + if (leadingSpace) + { + ca3[0] = ' '; + } + } else + { + ca3[0] = '-'; + } + + for (k = 0; k < nZeros; j++, k++) + { + ca3[j] = '0'; + } + + for (i = 0; (i < ca2.length) && (j < ca3.length); i++, j++) + { + ca3[j] = ca2[i]; + } + + int lead = 0; + + if ((ca3[0] == '+') || (ca3[0] == '-') || (ca3[0] == ' ')) + { + lead = 1; + } + + int dp = lead; + + for (; dp < ca3.length; dp++) + { + if (ca3[dp] == '.') + { + break; + } + } + + int nThousands = dp / 3; + + // Localize the decimal point. + if (dp < ca3.length) + { + ca3[dp] = dfs.getDecimalSeparator(); + } + + char[] ca4 = ca3; + + if (thousands && (nThousands > 0)) + { + ca4 = new char[ca3.length + nThousands + lead]; + ca4[0] = ca3[0]; + + for (i = lead, k = lead; i < dp; i++) + { + if ((i > 0) && (dp - i) % 3 == 0) + { + // ca4[k]=','; + ca4[k] = dfs.getGroupingSeparator(); + ca4[k + 1] = ca3[i]; + k += 2; + } else + { + ca4[k] = ca3[i]; + k++; + } + } + + for (; i < ca3.length; i++, k++) + { + ca4[k] = ca3[i]; + } + } + + return ca4; + } + + /** + * Check to see if the digits that are going to + * be truncated because of the precision should + * force a round in the preceding digits. + * + * @param ca1 the array of digits + * @param icarry the index of the first digit that + * is to be truncated from the print + * @return <code>true</code> if the truncation forces + * a round that will change the print + */ + private boolean checkForCarry(char[] ca1, int icarry) + { + boolean carry = false; + + if (icarry < ca1.length) + { + if ((ca1[icarry] == '6') || (ca1[icarry] == '7') || (ca1[icarry] == '8') || (ca1[icarry] == '9')) + { + carry = true; + } else if (ca1[icarry] == '5') + { + int ii = icarry + 1; + + for (; ii < ca1.length; ii++) + { + if (ca1[ii] != '0') + { + break; + } + } + + carry = ii < ca1.length; + + if (!carry && (icarry > 0)) + { + carry = ((ca1[icarry - 1] == '1') || (ca1[icarry - 1] == '3') || (ca1[icarry - 1] == '5') + || (ca1[icarry - 1] == '7') || (ca1[icarry - 1] == '9')); + } + } + } + + return carry; + } + + /** + * Start the symbolic carry process. The process + * is not quite finished because the symbolic + * carry may change the length of the string and + * change the exponent (in e format). + * + * @param cLast index of the last digit changed + * by the round + * @param cFirst index of the first digit allowed + * to be changed by this phase of the round + * @return <code>true</code> if the carry forces + * a round that will change the print still + * more + */ + private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) + { + boolean carry = true; + + for (int i = cLast; carry && (i >= cFirst); i--) + { + carry = false; + + switch (ca[i]) + { + case '0': + ca[i] = '1'; + + break; + + case '1': + ca[i] = '2'; + + break; + + case '2': + ca[i] = '3'; + + break; + + case '3': + ca[i] = '4'; + + break; + + case '4': + ca[i] = '5'; + + break; + + case '5': + ca[i] = '6'; + + break; + + case '6': + ca[i] = '7'; + + break; + + case '7': + ca[i] = '8'; + + break; + + case '8': + ca[i] = '9'; + + break; + + case '9': + ca[i] = '0'; + carry = true; + + break; + } + } + + return carry; + } + + /** + * An intermediate routine on the way to creating + * an e format String. The method decides whether + * the input double value is an infinity, + * not-a-number, or a finite double and formats + * each type of input appropriately. + * + * @param x the double value to be formatted. + * @param eChar an 'e' or 'E' to use in the + * converted double value. + * @return the converted double value. + */ + private String eFormatString(double x, char eChar) + { + boolean noDigits = false; + char[] ca4, ca5; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca4 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca4 = " Inf".toCharArray(); + } else + { + ca4 = "Inf".toCharArray(); + } + } else + { + ca4 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca4 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca4 = " NaN".toCharArray(); + } else + { + ca4 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + ca4 = eFormatDigits(x, eChar); + } + + ca5 = applyFloatPadding(ca4, false); + + return new String(ca5); + } + + /** + * Apply zero or blank, left or right padding. + * + * @param ca4 array of characters before padding is + * finished + * @param noDigits NaN or signed Inf + * @return a padded array of characters + */ + private char[] applyFloatPadding(char[] ca4, boolean noDigits) + { + char[] ca5 = ca4; + + if (fieldWidthSet) + { + int i, j, nBlanks; + + if (leftJustify) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + + for (i = 0; i < ca4.length; i++) + { + ca5[i] = ca4[i]; + } + + for (j = 0; j < nBlanks; j++, i++) + { + ca5[i] = ' '; + } + } + } else if (!leadingZeros || noDigits) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + + for (i = 0; i < nBlanks; i++) + { + ca5[i] = ' '; + } + + for (j = 0; j < ca4.length; i++, j++) + { + ca5[i] = ca4[j]; + } + } + } else if (leadingZeros) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + i = 0; + j = 0; + + if (ca4[0] == '-') + { + ca5[0] = '-'; + i++; + j++; + } + + for (int k = 0; k < nBlanks; i++, k++) + { + ca5[i] = '0'; + } + + for (; j < ca4.length; i++, j++) + { + ca5[i] = ca4[j]; + } + } + } + } + + return ca5; + } + + /** + * Format method for the f conversion character. + * + * @param x the double to format. + * @return the formatted String. + */ + private String printFFormat(double x) + { + return fFormatString(x); + } + + /** + * Format method for the e or E conversion + * character. + * + * @param x the double to format. + * @return the formatted String. + */ + private String printEFormat(double x) + { + if (conversionCharacter == 'e') + { + return eFormatString(x, 'e'); + } else + { + return eFormatString(x, 'E'); + } + } + + /** + * Format method for the g conversion character. + * <p/> + * For g format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear after the radix character. + * Padding is with trailing 0s. + * + * @param x the double to format. + * @return the formatted String. + */ + private String printGFormat(double x) + { + String sx, sy, sz, ret; + int savePrecision = precision; + int i; + char[] ca4, ca5; + boolean noDigits = false; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca4 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca4 = " Inf".toCharArray(); + } else + { + ca4 = "Inf".toCharArray(); + } + } else + { + ca4 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca4 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca4 = " NaN".toCharArray(); + } else + { + ca4 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + if (!precisionSet) + { + precision = defaultDigits; + } + + if (precision == 0) + { + precision = 1; + } + + int ePos = -1; + + if (conversionCharacter == 'g') + { + sx = eFormatString(x, 'e').trim(); + ePos = sx.indexOf('e'); + } else + { + sx = eFormatString(x, 'E').trim(); + ePos = sx.indexOf('E'); + } + + i = ePos + 1; + + int expon = 0; + + if (sx.charAt(i) == '-') + { + for (++i; i < sx.length(); i++) + { + if (sx.charAt(i) != '0') + { + break; + } + } + + if (i < sx.length()) + { + expon = -Integer.parseInt(sx.substring(i)); + } + } else + { + if (sx.charAt(i) == '+') + { + ++i; + } + + for (; i < sx.length(); i++) + { + if (sx.charAt(i) != '0') + { + break; + } + } + + if (i < sx.length()) + { + expon = Integer.parseInt(sx.substring(i)); + } + } + + // Trim trailing zeros. + // If the radix character is not followed by + // a digit, trim it, too. + if (!alternateForm) + { + if ((expon >= -4) && (expon < precision)) + { + sy = fFormatString(x).trim(); + } else + { + sy = sx.substring(0, ePos); + } + + i = sy.length() - 1; + + for (; i >= 0; i--) + { + if (sy.charAt(i) != '0') + { + break; + } + } + + if ((i >= 0) && (sy.charAt(i) == '.')) + { + i--; + } + + if (i == -1) + { + sz = "0"; + } else if (!Character.isDigit(sy.charAt(i))) + { + sz = sy.substring(0, i + 1) + "0"; + } else + { + sz = sy.substring(0, i + 1); + } + + if ((expon >= -4) && (expon < precision)) + { + ret = sz; + } else + { + ret = sz + sx.substring(ePos); + } + } else + { + if ((expon >= -4) && (expon < precision)) + { + ret = fFormatString(x).trim(); + } else + { + ret = sx; + } + } + + // leading space was trimmed off during + // construction + if (leadingSpace) + { + if (x >= 0) + { + ret = " " + ret; + } + } + + ca4 = ret.toCharArray(); + } + + // Pad with blanks or zeros. + ca5 = applyFloatPadding(ca4, false); + precision = savePrecision; + + return new String(ca5); + } + + /** + * Format method for the d conversion specifer and + * short argument. + * <p/> + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the short to format. + * @return the formatted String. + */ + private String printDFormat(short x) + { + return printDFormat(Short.toString(x)); + } + + /** + * Format method for the d conversion character and + * long argument. + * <p/> + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the long to format. + * @return the formatted String. + */ + private String printDFormat(long x) + { + return printDFormat(Long.toString(x)); + } + + /** + * Format method for the d conversion character and + * int argument. + * <p/> + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the int to format. + * @return the formatted String. + */ + private String printDFormat(int x) + { + return printDFormat(Integer.toString(x)); + } + + /** + * Utility method for formatting using the d + * conversion character. + * + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printDFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0, + n = 0; + int i = 0, + jFirst = 0; + boolean neg = sx.charAt(0) == '-'; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (!neg) + { + if (precisionSet && (sx.length() < precision)) + { + nLeadingZeros = precision - sx.length(); + } + } else + { + if (precisionSet && (sx.length() - 1) < precision) + { + nLeadingZeros = precision - sx.length() + 1; + } + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + + if (!neg && (leadingSign || leadingSpace)) + { + nBlanks--; + } + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + if (leadingSign) + { + n++; + } else if (leadingSpace) + { + n++; + } + + n += nBlanks; + n += nLeadingZeros; + n += sx.length(); + + char[] ca = new char[n]; + + if (leftJustify) + { + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + + char[] csx = sx.toCharArray(); + + jFirst = neg + ? 1 + : 0; + + for (int j = 0; j < nLeadingZeros; i++, j++) + { + ca[i] = '0'; + } + + for (int j = jFirst; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; i++, j++) + { + ca[i] = ' '; + } + } else + { + if (!leadingZeros) + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = ' '; + } + + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + } else + { + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = '0'; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + jFirst = neg + ? 1 + : 0; + + for (int j = jFirst; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + return new String(ca); + } + + /** + * Format method for the x conversion character and + * short argument. + * <p/> + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the short to format. + * @return the formatted String. + */ + private String printXFormat(short x) + { + String sx = null; + + if (x == Short.MIN_VALUE) + { + sx = "8000"; + } else if (x < 0) + { + String t; + + if (x == Short.MIN_VALUE) + { + t = "0"; + } else + { + t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16); + + if ((t.charAt(0) == 'F') || (t.charAt(0) == 'f')) + { + t = t.substring(16, 32); + } + } + + switch (t.length()) + { + case 1: + sx = "800" + t; + + break; + + case 2: + sx = "80" + t; + + break; + + case 3: + sx = "8" + t; + + break; + + case 4: + switch (t.charAt(0)) + { + case '1': + sx = "9" + t.substring(1, 4); + + break; + + case '2': + sx = "a" + t.substring(1, 4); + + break; + + case '3': + sx = "b" + t.substring(1, 4); + + break; + + case '4': + sx = "c" + t.substring(1, 4); + + break; + + case '5': + sx = "d" + t.substring(1, 4); + + break; + + case '6': + sx = "e" + t.substring(1, 4); + + break; + + case '7': + sx = "f" + t.substring(1, 4); + + break; + } + + break; + } + } else + { + sx = Integer.toString((int) x, 16); + } + + return printXFormat(sx); + } + + /** + * Format method for the x conversion character and + * long argument. + * <p/> + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the long to format. + * @return the formatted String. + */ + private String printXFormat(long x) + { + String sx = null; + + if (x == Long.MIN_VALUE) + { + sx = "8000000000000000"; + } else if (x < 0) + { + String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16); + + switch (t.length()) + { + case 1: + sx = "800000000000000" + t; + + break; + + case 2: + sx = "80000000000000" + t; + + break; + + case 3: + sx = "8000000000000" + t; + + break; + + case 4: + sx = "800000000000" + t; + + break; + + case 5: + sx = "80000000000" + t; + + break; + + case 6: + sx = "8000000000" + t; + + break; + + case 7: + sx = "800000000" + t; + + break; + + case 8: + sx = "80000000" + t; + + break; + + case 9: + sx = "8000000" + t; + + break; + + case 10: + sx = "800000" + t; + + break; + + case 11: + sx = "80000" + t; + + break; + + case 12: + sx = "8000" + t; + + break; + + case 13: + sx = "800" + t; + + break; + + case 14: + sx = "80" + t; + + break; + + case 15: + sx = "8" + t; + + break; + + case 16: + switch (t.charAt(0)) + { + case '1': + sx = "9" + t.substring(1, 16); + + break; + + case '2': + sx = "a" + t.substring(1, 16); + + break; + + case '3': + sx = "b" + t.substring(1, 16); + + break; + + case '4': + sx = "c" + t.substring(1, 16); + + break; + + case '5': + sx = "d" + t.substring(1, 16); + + break; + + case '6': + sx = "e" + t.substring(1, 16); + + break; + + case '7': + sx = "f" + t.substring(1, 16); + + break; + } + + break; + } + } else + { + sx = Long.toString(x, 16); + } + + return printXFormat(sx); + } + + /** + * Format method for the x conversion character and + * int argument. + * <p/> + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the int to format. + * @return the formatted String. + */ + private String printXFormat(int x) + { + String sx = null; + + if (x == Integer.MIN_VALUE) + { + sx = "80000000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16); + + switch (t.length()) + { + case 1: + sx = "8000000" + t; + + break; + + case 2: + sx = "800000" + t; + + break; + + case 3: + sx = "80000" + t; + + break; + + case 4: + sx = "8000" + t; + + break; + + case 5: + sx = "800" + t; + + break; + + case 6: + sx = "80" + t; + + break; + + case 7: + sx = "8" + t; + + break; + + case 8: + switch (t.charAt(0)) + { + case '1': + sx = "9" + t.substring(1, 8); + + break; + + case '2': + sx = "a" + t.substring(1, 8); + + break; + + case '3': + sx = "b" + t.substring(1, 8); + + break; + + case '4': + sx = "c" + t.substring(1, 8); + + break; + + case '5': + sx = "d" + t.substring(1, 8); + + break; + + case '6': + sx = "e" + t.substring(1, 8); + + break; + + case '7': + sx = "f" + t.substring(1, 8); + + break; + } + + break; + } + } else + { + sx = Integer.toString(x, 16); + } + + return printXFormat(sx); + } + + /** + * Utility method for formatting using the x + * conversion character. + * + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printXFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (precisionSet) + { + nLeadingZeros = precision - sx.length(); + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + + if (alternateForm) + { + nBlanks = nBlanks - 2; + } + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + int n = 0; + + if (alternateForm) + { + n += 2; + } + + n += nLeadingZeros; + n += sx.length(); + n += nBlanks; + + char[] ca = new char[n]; + int i = 0; + + if (leftJustify) + { + if (alternateForm) + { + ca[i++] = '0'; + ca[i++] = 'x'; + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } else + { + if (!leadingZeros) + { + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } + + if (alternateForm) + { + ca[i++] = '0'; + ca[i++] = 'x'; + } + + if (leadingZeros) + { + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = '0'; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + String caReturn = new String(ca); + + if (conversionCharacter == 'X') + { + caReturn = caReturn.toUpperCase(); + } + + return caReturn; + } + + /** + * Format method for the o conversion character and + * short argument. + * <p/> + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the short to format. + * @return the formatted String. + */ + private String printOFormat(short x) + { + String sx = null; + + if (x == Short.MIN_VALUE) + { + sx = "100000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8); + + switch (t.length()) + { + case 1: + sx = "10000" + t; + + break; + + case 2: + sx = "1000" + t; + + break; + + case 3: + sx = "100" + t; + + break; + + case 4: + sx = "10" + t; + + break; + + case 5: + sx = "1" + t; + + break; + } + } else + { + sx = Integer.toString((int) x, 8); + } + + return printOFormat(sx); + } + + /** + * Format method for the o conversion character and + * long argument. + * <p/> + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the long to format. + * @return the formatted String. + */ + private String printOFormat(long x) + { + String sx = null; + + if (x == Long.MIN_VALUE) + { + sx = "1000000000000000000000"; + } else if (x < 0) + { + String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8); + + switch (t.length()) + { + case 1: + sx = "100000000000000000000" + t; + + break; + + case 2: + sx = "10000000000000000000" + t; + + break; + + case 3: + sx = "1000000000000000000" + t; + + break; + + case 4: + sx = "100000000000000000" + t; + + break; + + case 5: + sx = "10000000000000000" + t; + + break; + + case 6: + sx = "1000000000000000" + t; + + break; + + case 7: + sx = "100000000000000" + t; + + break; + + case 8: + sx = "10000000000000" + t; + + break; + + case 9: + sx = "1000000000000" + t; + + break; + + case 10: + sx = "100000000000" + t; + + break; + + case 11: + sx = "10000000000" + t; + + break; + + case 12: + sx = "1000000000" + t; + + break; + + case 13: + sx = "100000000" + t; + + break; + + case 14: + sx = "10000000" + t; + + break; + + case 15: + sx = "1000000" + t; + + break; + + case 16: + sx = "100000" + t; + + break; + + case 17: + sx = "10000" + t; + + break; + + case 18: + sx = "1000" + t; + + break; + + case 19: + sx = "100" + t; + + break; + + case 20: + sx = "10" + t; + + break; + + case 21: + sx = "1" + t; + + break; + } + } else + { + sx = Long.toString(x, 8); + } + + return printOFormat(sx); + } + + /** + * Format method for the o conversion character and + * int argument. + * <p/> + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * <p/> + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * + * @param x the int to format. + * @return the formatted String. + */ + private String printOFormat(int x) + { + String sx = null; + + if (x == Integer.MIN_VALUE) + { + sx = "20000000000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8); + + switch (t.length()) + { + case 1: + sx = "2000000000" + t; + + break; + + case 2: + sx = "200000000" + t; + + break; + + case 3: + sx = "20000000" + t; + + break; + + case 4: + sx = "2000000" + t; + + break; + + case 5: + sx = "200000" + t; + + break; + + case 6: + sx = "20000" + t; + + break; + + case 7: + sx = "2000" + t; + + break; + + case 8: + sx = "200" + t; + + break; + + case 9: + sx = "20" + t; + + break; + + case 10: + sx = "2" + t; + + break; + + case 11: + sx = "3" + t.substring(1); + + break; + } + } else + { + sx = Integer.toString(x, 8); + } + + return printOFormat(sx); + } + + /** + * Utility method for formatting using the o + * conversion character. + * + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printOFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (precisionSet) + { + nLeadingZeros = precision - sx.length(); + } + + if (alternateForm) + { + nLeadingZeros++; + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + int n = nLeadingZeros + sx.length() + nBlanks; + char[] ca = new char[n]; + int i; + + if (leftJustify) + { + for (i = 0; i < nLeadingZeros; i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } else + { + if (leadingZeros) + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = '0'; + } + } else + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = ' '; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + return new String(ca); + } + + /** + * Format method for the c conversion character and + * char argument. + * <p/> + * The only flag character that affects c format is + * the '-', meaning that the output should be left + * justified within the field. The default is to + * pad with blanks on the left. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. Padding is with + * blanks by default. The default width is 1. + * <p/> + * The precision, if set, is ignored. + * + * @param x the char to format. + * @return the formatted String. + */ + private String printCFormat(char x) + { + int nPrint = 1; + int width = fieldWidth; + + if (!fieldWidthSet) + { + width = nPrint; + } + + char[] ca = new char[width]; + int i = 0; + + if (leftJustify) + { + ca[0] = x; + + for (i = 1; i <= width - nPrint; i++) + { + ca[i] = ' '; + } + } else + { + for (i = 0; i < width - nPrint; i++) + { + ca[i] = ' '; + } + + ca[i] = x; + } + + return new String(ca); + } + + /** + * Format method for the s conversion character and + * String argument. + * <p/> + * The only flag character that affects s format is + * the '-', meaning that the output should be left + * justified within the field. The default is to + * pad with blanks on the left. + * <p/> + * The field width is treated as the minimum number + * of characters to be printed. The default is the + * smaller of the number of characters in the the + * input and the precision. Padding is with blanks + * by default. + * <p/> + * The precision, if set, specifies the maximum + * number of characters to be printed from the + * string. A null digit string is treated + * as a 0. The default is not to set a maximum + * number of characters to be printed. + * + * @param x the String to format. + * @return the formatted String. + */ + private String printSFormat(String x) + { + int nPrint = x.length(); + int width = fieldWidth; + + if (precisionSet && (nPrint > precision)) + { + nPrint = precision; + } + + if (!fieldWidthSet) + { + width = nPrint; + } + + int n = 0; + + if (width > nPrint) + { + n += width - nPrint; + } + + if (nPrint >= x.length()) + { + n += x.length(); + } else + { + n += nPrint; + } + + char[] ca = new char[n]; + int i = 0; + + if (leftJustify) + { + if (nPrint >= x.length()) + { + char[] csx = x.toCharArray(); + + for (i = 0; i < x.length(); i++) + { + ca[i] = csx[i]; + } + } else + { + char[] csx = x.substring(0, nPrint).toCharArray(); + + for (i = 0; i < nPrint; i++) + { + ca[i] = csx[i]; + } + } + + for (int j = 0; j < width - nPrint; j++, i++) + { + ca[i] = ' '; + } + } else + { + for (i = 0; i < width - nPrint; i++) + { + ca[i] = ' '; + } + + if (nPrint >= x.length()) + { + char[] csx = x.toCharArray(); + + for (int j = 0; j < x.length(); i++, j++) + { + ca[i] = csx[j]; + } + } else + { + char[] csx = x.substring(0, nPrint).toCharArray(); + + for (int j = 0; j < nPrint; i++, j++) + { + ca[i] = csx[j]; + } + } + } + + return new String(ca); + } + + /** + * Check for a conversion character. If it is + * there, store it. + * + * @return <code>true</code> if the conversion + * character is there, and + * <code>false</code> otherwise. + */ + private boolean setConversionCharacter() + { + /* idfgGoxXeEcs */ + boolean ret = false; + + conversionCharacter = '\0'; + + if (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if ((c == 'i') || (c == 'd') || (c == 'f') || (c == 'g') || (c == 'G') || (c == 'o') || (c == 'x') || (c == 'X') + || (c == 'e') || (c == 'E') || (c == 'c') || (c == 's') || (c == '%')) + { + conversionCharacter = c; + pos++; + ret = true; + } + } + + return ret; + } + + /** + * Check for an h, l, or L in a format. An L is + * used to control the minimum number of digits + * in an exponent when using floating point + * formats. An l or h is used to control + * conversion of the input to a long or short, + * respectively, before formatting. If any of + * these is present, store them. + */ + private void setOptionalHL() + { + optionalh = false; + optionall = false; + optionalL = false; + + if (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (c == 'h') + { + optionalh = true; + pos++; + } else if (c == 'l') + { + optionall = true; + pos++; + } else if (c == 'L') + { + optionalL = true; + pos++; + } + } + } + + /** + * Set the precision. + */ + private void setPrecision() + { + int firstPos = pos; + + precisionSet = false; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '.')) + { + pos++; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) + { + pos++; + + if (!setPrecisionArgPosition()) + { + variablePrecision = true; + precisionSet = true; + } + + return; + } else + { + while (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (Character.isDigit(c)) + { + pos++; + } else + { + break; + } + } + + if (pos > firstPos + 1) + { + String sz = fmt.substring(firstPos + 1, pos); + + precision = Integer.parseInt(sz); + precisionSet = true; + } + } + } + } + + /** + * Set the field width. + */ + private void setFieldWidth() + { + int firstPos = pos; + + fieldWidth = 0; + fieldWidthSet = false; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) + { + pos++; + + if (!setFieldWidthArgPosition()) + { + variableFieldWidth = true; + fieldWidthSet = true; + } + } else + { + while (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (Character.isDigit(c)) + { + pos++; + } else + { + break; + } + } + + if ((firstPos < pos) && (firstPos < fmt.length())) + { + String sz = fmt.substring(firstPos, pos); + + fieldWidth = Integer.parseInt(sz); + fieldWidthSet = true; + } + } + } + + /** + * Store the digits <code>n</code> in %n$ forms. + */ + private void setArgPosition() + { + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalSpecification = true; + argumentPosition = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + } + } + } + + /** + * Store the digits <code>n</code> in *n$ forms. + */ + private boolean setFieldWidthArgPosition() + { + boolean ret = false; + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalFieldWidth = true; + argumentPositionForFieldWidth = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + ret = true; + } + } + + return ret; + } + + /** + * Store the digits <code>n</code> in *n$ forms. + */ + private boolean setPrecisionArgPosition() + { + boolean ret = false; + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalPrecision = true; + argumentPositionForPrecision = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + ret = true; + } + } + + return ret; + } + + boolean isPositionalSpecification() + { + return positionalSpecification; + } + + int getArgumentPosition() + { + return argumentPosition; + } + + boolean isPositionalFieldWidth() + { + return positionalFieldWidth; + } + + int getArgumentPositionForFieldWidth() + { + return argumentPositionForFieldWidth; + } + + boolean isPositionalPrecision() + { + return positionalPrecision; + } + + int getArgumentPositionForPrecision() + { + return argumentPositionForPrecision; + } + + /** + * Set flag characters, one of '-+#0 or a space. + */ + private void setFlagCharacters() + { + /* '-+ #0 */ + thousands = false; + leftJustify = false; + leadingSign = false; + leadingSpace = false; + alternateForm = false; + leadingZeros = false; + + for (; pos < fmt.length(); pos++) + { + char c = fmt.charAt(pos); + + if (c == '\'') + { + thousands = true; + } else if (c == '-') + { + leftJustify = true; + leadingZeros = false; + } else if (c == '+') + { + leadingSign = true; + leadingSpace = false; + } else if (c == ' ') + { + if (!leadingSign) + { + leadingSpace = true; + } + } else if (c == '#') + { + alternateForm = true; + } else if (c == '0') + { + if (!leftJustify) + { + leadingZeros = true; + } + } else + { + break; + } + } + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java new file mode 100644 index 0000000..5821070 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java @@ -0,0 +1,2885 @@ +package com.ximple.eofms.util; + +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.net.URLEncoder; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.text.BreakIterator; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class StringUtils +{ + public static String ENCODING_US_ASCII = "US-ASCII"; + public static String ENCODING_ISO_8859_1 = "ISO-8859-1"; + public static String ENCODING_ISO_8859_2 = "ISO-8859-2"; + public static String ENCODING_ISO_8859_5 = "ISO-8859-5"; + public static String ENCODING_UTF_8 = "UTF-8"; + public static String ENCODING_UTF_16BE = "UTF-16BE"; + public static String ENCODING_UTF_16LE = "UTF-16LE"; + public static String ENCODING_UTF_16 = "UTF-16"; + + public static Charset CHARSET_US_ASCII = Charset.forName(StringUtils.ENCODING_US_ASCII); + + public static final Pattern BBCODE_COLOR = Pattern.compile("\\[color\\s*=\\s*([#\\w]*)\\s*\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_SIZE = Pattern.compile("\\[size\\s*=\\s*([+\\-]?[0-9]*)\\s*\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_URL_SHORT = Pattern.compile("\\[url\\]\\s*([^\\s]*)\\s*\\[\\/url\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_URL_LONG = Pattern.compile("\\[url=([^\\[]*)\\]([^\\[]*)\\[/url\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_IMG = Pattern.compile("\\[img\\]\\s*([^\\s]*)\\s*\\[\\/img\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_QUOTE_LONG = Pattern.compile("\\[quote=([^\\]]+\\]*)\\]", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + public static final Pattern BBCODE_BAREURL = Pattern.compile("(?:[^\"'=>\\]]|^)((?:http|ftp)s?://(?:%[\\p{Digit}A-Fa-f][\\p{Digit}A-Fa-f]|[\\-_\\.!~*';\\|/?:@#&=\\+$,\\p{Alnum}])+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + + private static final Map<Character, String> AGGRESSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> DEFENSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> XML_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> STRING_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> SQL_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> LATEX_ENCODE_MAP = new HashMap<Character, String>(); + + private static final Map<String, Character> HTML_DECODE_MAP = new HashMap<String, Character>(); + + private static final HtmlEncoderFallbackHandler HTML_ENCODER_FALLBACK = new HtmlEncoderFallbackHandler(); + + static + { + // Html encoding mapping according to the HTML 4.0 spec + // http://www.w3.org/TR/REC-html40/sgml/entities.html + + // Special characters for HTML + AGGRESSIVE_HTML_ENCODE_MAP.put('\u0026', "&"); + AGGRESSIVE_HTML_ENCODE_MAP.put('\u003C', "<"); + AGGRESSIVE_HTML_ENCODE_MAP.put('\u003E', ">"); + AGGRESSIVE_HTML_ENCODE_MAP.put('\u0022', """); + + DEFENSIVE_HTML_ENCODE_MAP.put('\u0152', "Œ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0153', "œ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0160', "Š"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0161', "š"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0178', "Ÿ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u02C6', "ˆ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u02DC', "˜"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2002', " "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2003', " "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2009', " "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200C', "‌"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200D', "‍"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200E', "‎"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200F', "‏"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2013', "–"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2014', "—"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2018', "‘"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2019', "’"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201A', "‚"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201C', "“"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201D', "”"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201E', "„"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2020', "†"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2021', "‡"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2030', "‰"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2039', "‹"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u203A', "›"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u20AC', "€"); + + // Character entity references for ISO 8859-1 characters + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A0', " "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A1', "¡"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A2', "¢"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A3', "£"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A4', "¤"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A5', "¥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A6', "¦"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A7', "§"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A8', "¨"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A9', "©"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AA', "ª"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AB', "«"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AC', "¬"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AD', "­"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AE', "®"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AF', "¯"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B0', "°"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B1', "±"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B2', "²"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B3', "³"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B4', "´"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B5', "µ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B6', "¶"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B7', "·"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B8', "¸"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B9', "¹"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BA', "º"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BB', "»"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BC', "¼"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BD', "½"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BE', "¾"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BF', "¿"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C0', "À"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C1', "Á"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C2', "Â"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C3', "Ã"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C4', "Ä"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C5', "Å"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C6', "Æ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C7', "Ç"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C8', "È"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C9', "É"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CA', "Ê"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CB', "Ë"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CC', "Ì"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CD', "Í"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CE', "Î"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CF', "Ï"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D0', "Ð"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D1', "Ñ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D2', "Ò"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D3', "Ó"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D4', "Ô"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D5', "Õ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D6', "Ö"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D7', "×"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D8', "Ø"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D9', "Ù"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DA', "Ú"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DB', "Û"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DC', "Ü"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DD', "Ý"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DE', "Þ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DF', "ß"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E0', "à"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E1', "á"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E2', "â"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E3', "ã"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E4', "ä"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E5', "å"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E6', "æ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E7', "ç"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E8', "è"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E9', "é"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EA', "ê"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EB', "ë"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EC', "ì"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00ED', "í"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EE', "î"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EF', "ï"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F0', "ð"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F1', "ñ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F2', "ò"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F3', "ó"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F4', "ô"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F5', "õ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F6', "ö"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F7', "÷"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F8', "ø"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F9', "ù"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FA', "ú"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FB', "û"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FC', "ü"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FD', "ý"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FE', "þ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FF', "ÿ"); + + // Mathematical, Greek and Symbolic characters for HTML + DEFENSIVE_HTML_ENCODE_MAP.put('\u0192', "ƒ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0391', "Α"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0392', "Β"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0393', "Γ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0394', "Δ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0395', "Ε"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0396', "Ζ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0397', "Η"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0398', "Θ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0399', "Ι"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039A', "Κ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039B', "Λ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039C', "Μ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039D', "Ν"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039E', "Ξ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039F', "Ο"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A0', "Π"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A1', "Ρ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A3', "Σ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A4', "Τ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A5', "Υ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A6', "Φ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A7', "Χ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A8', "Ψ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A9', "Ω"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B1', "α"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B2', "β"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B3', "γ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B4', "δ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B5', "ε"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B6', "ζ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B7', "η"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B8', "θ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B9', "ι"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BA', "κ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BB', "λ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BC', "μ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BD', "ν"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BE', "ξ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BF', "ο"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C0', "π"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C1', "ρ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C2', "ς"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C3', "σ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C4', "τ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C5', "υ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C6', "φ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C7', "χ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C8', "ψ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C9', "ω"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03D1', "ϑ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03D2', "ϒ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03D6', "ϖ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2022', "•"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2026', "…"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2032', "′"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2033', "″"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u203E', "‾"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2044', "⁄"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2118', "℘"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2111', "ℑ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u211C', "ℜ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2122', "™"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2135', "ℵ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2190', "←"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2191', "↑"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2192', "→"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2193', "↓"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2194', "↔"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21B5', "↵"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D0', "⇐"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D1', "⇑"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D2', "⇒"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D3', "⇓"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D4', "⇔"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2200', "∀"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2202', "∂"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2203', "∃"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2205', "∅"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2207', "∇"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2208', "∈"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2209', "∉"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u220B', "∋"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u220F', "∏"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2211', "∑"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2212', "−"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2217', "∗"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u221A', "√"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u221D', "∝"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u221E', "∞"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2220', "∠"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2227', "∧"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2228', "∨"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2229', "∩"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u222A', "∪"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u222B', "∫"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2234', "∴"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u223C', "∼"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2245', "≅"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2248', "≈"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2260', "≠"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2261', "≡"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2264', "≤"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2265', "≥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2282', "⊂"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2283', "⊃"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2284', "⊄"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2286', "⊆"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2287', "⊇"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2295', "⊕"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2297', "⊗"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u22A5', "⊥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u22C5', "⋅"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2308', "⌈"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2309', "⌉"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u230A', "⌊"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u230B', "⌋"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2329', "⟨"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u232A', "⟩"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u25CA', "◊"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2660', "♠"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2663', "♣"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2665', "♥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2666', "♦"); + + Set<Map.Entry<Character, String>> aggresive_entries = AGGRESSIVE_HTML_ENCODE_MAP.entrySet(); + for (Map.Entry<Character, String> entry : aggresive_entries) + { + HTML_DECODE_MAP.put(entry.getValue(), entry.getKey()); + } + + Set<Map.Entry<Character, String>> defensive_entries = DEFENSIVE_HTML_ENCODE_MAP.entrySet(); + for (Map.Entry<Character, String> entry : defensive_entries) + { + HTML_DECODE_MAP.put(entry.getValue(), entry.getKey()); + } + + XML_ENCODE_MAP.put('\u0026', "&"); + XML_ENCODE_MAP.put('\'', "'"); + XML_ENCODE_MAP.put('\u0022', """); + XML_ENCODE_MAP.put('\u003C', "<"); + XML_ENCODE_MAP.put('\u003E', ">"); + + SQL_ENCODE_MAP.put('\'', "''"); + + STRING_ENCODE_MAP.put('\\', "\\\\"); + STRING_ENCODE_MAP.put('\n', "\\n"); + STRING_ENCODE_MAP.put('\r', "\\r"); + STRING_ENCODE_MAP.put('\t', "\\t"); + STRING_ENCODE_MAP.put('"', "\\\""); + + LATEX_ENCODE_MAP.put('\\', "\\\\"); + LATEX_ENCODE_MAP.put('#', "\\#"); + LATEX_ENCODE_MAP.put('$', "\\$"); + LATEX_ENCODE_MAP.put('%', "\\%"); + LATEX_ENCODE_MAP.put('&', "\\&"); + LATEX_ENCODE_MAP.put('~', "\\~"); + LATEX_ENCODE_MAP.put('_', "\\_"); + LATEX_ENCODE_MAP.put('^', "\\^"); + LATEX_ENCODE_MAP.put('{', "\\{"); + LATEX_ENCODE_MAP.put('}', "\\}"); + LATEX_ENCODE_MAP.put('\u00A1', "!'"); + LATEX_ENCODE_MAP.put('\u00BF', "?'"); + LATEX_ENCODE_MAP.put('\u00C0', "\\`{A}"); + LATEX_ENCODE_MAP.put('\u00C1', "\\'{A}"); + LATEX_ENCODE_MAP.put('\u00C2', "\\^{A}"); + LATEX_ENCODE_MAP.put('\u00C3', "\\H{A}"); + LATEX_ENCODE_MAP.put('\u00C4', "\\\"{A}"); + LATEX_ENCODE_MAP.put('\u00C5', "\\AA"); + LATEX_ENCODE_MAP.put('\u00C6', "\\AE"); + LATEX_ENCODE_MAP.put('\u00C7', "\\c{C}"); + LATEX_ENCODE_MAP.put('\u00C8', "\\`{E}"); + LATEX_ENCODE_MAP.put('\u00C9', "\\'{E}"); + LATEX_ENCODE_MAP.put('\u00CA', "\\^{E}"); + LATEX_ENCODE_MAP.put('\u00CB', "\\\"{E}"); + LATEX_ENCODE_MAP.put('\u00CC', "\\`{I}"); + LATEX_ENCODE_MAP.put('\u00CD', "\\'{I}"); + LATEX_ENCODE_MAP.put('\u00CE', "\\^{I}"); + LATEX_ENCODE_MAP.put('\u00CF', "\\\"{I}"); +// todo \u00D0 + LATEX_ENCODE_MAP.put('\u00D1', "\\H{N}"); + LATEX_ENCODE_MAP.put('\u00D2', "\\`{O}"); + LATEX_ENCODE_MAP.put('\u00D3', "\\'{O}"); + LATEX_ENCODE_MAP.put('\u00D4', "\\^{O}"); + LATEX_ENCODE_MAP.put('\u00D5', "\\H{O}"); + LATEX_ENCODE_MAP.put('\u00D6', "\\\"{O}"); +// todo \u00D7 + LATEX_ENCODE_MAP.put('\u00D8', "\\O"); + LATEX_ENCODE_MAP.put('\u00D9', "\\`{U}"); + LATEX_ENCODE_MAP.put('\u00DA', "\\'{U}"); + LATEX_ENCODE_MAP.put('\u00DB', "\\^{U}"); + LATEX_ENCODE_MAP.put('\u00DC', "\\\"{U}"); + LATEX_ENCODE_MAP.put('\u00DD', "\\'{Y}"); +// todo \u00DE + LATEX_ENCODE_MAP.put('\u00DF', "\\ss"); + LATEX_ENCODE_MAP.put('\u00E0', "\\`{a}"); + LATEX_ENCODE_MAP.put('\u00E1', "\\'{a}"); + LATEX_ENCODE_MAP.put('\u00E2', "\\^{a}"); + LATEX_ENCODE_MAP.put('\u00E3', "\\H{a}"); + LATEX_ENCODE_MAP.put('\u00E4', "\\\"{a}"); + LATEX_ENCODE_MAP.put('\u00E5', "\\aa"); + LATEX_ENCODE_MAP.put('\u00E6', "\\ae"); + LATEX_ENCODE_MAP.put('\u00E7', "\\c{c}"); + LATEX_ENCODE_MAP.put('\u00E8', "\\`{e}"); + LATEX_ENCODE_MAP.put('\u00E9', "\\'{e}"); + LATEX_ENCODE_MAP.put('\u00EA', "\\^{e}"); + LATEX_ENCODE_MAP.put('\u00EB', "\\\"{e}"); + LATEX_ENCODE_MAP.put('\u00EC', "\\`{i}"); + LATEX_ENCODE_MAP.put('\u00ED', "\\'{i}"); + LATEX_ENCODE_MAP.put('\u00EE', "\\^{i}"); + LATEX_ENCODE_MAP.put('\u00EF', "\\\"{i}"); +// todo \u00F0 + LATEX_ENCODE_MAP.put('\u00F1', "\\H{n}"); + LATEX_ENCODE_MAP.put('\u00F2', "\\`{o}"); + LATEX_ENCODE_MAP.put('\u00F3', "\\'{o}"); + LATEX_ENCODE_MAP.put('\u00F4', "\\^{o}"); + LATEX_ENCODE_MAP.put('\u00F5', "\\H{o}"); + LATEX_ENCODE_MAP.put('\u00F6', "\\\"{o}"); +// todo \u00F7 + LATEX_ENCODE_MAP.put('\u00F8', "\\o"); + LATEX_ENCODE_MAP.put('\u00F9', "\\`{u}"); + LATEX_ENCODE_MAP.put('\u00FA', "\\'{u}"); + LATEX_ENCODE_MAP.put('\u00FB', "\\^{u}"); + LATEX_ENCODE_MAP.put('\u00FC', "\\\"{u}"); + LATEX_ENCODE_MAP.put('\u00FD', "\\'{y}"); +// todo \u00FE + LATEX_ENCODE_MAP.put('\u00FF', "\\\"{y}"); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid characters for a java class name. + * + * @param name The string that has to be transformed into a valid class + * name. + * @return The encoded <code>String</code> object. + * @see #encodeUrl(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeClassname(String name) + { + if (null == name) + { + return null; + } + + Pattern pattern = Pattern.compile("[^\\w]"); + Matcher matcher = pattern.matcher(name); + + return matcher.replaceAll("_"); + } + + private static boolean needsUrlEncoding(String source) + { + if (null == source) + { + return false; + } + + // check if the string needs encoding first since + // the URLEncoder always allocates a StringBuffer, even when the + // string is returned as-is + boolean encode = false; + char ch; + for (int i = 0; i < source.length(); i++) + { + ch = source.charAt(i); + + if (ch >= 'a' && ch <= 'z' || + ch >= 'A' && ch <= 'Z' || + ch >= '0' && ch <= '9' || + ch == '-' || ch == '_' || ch == '.' || ch == '*') + { + continue; + } + + encode = true; + break; + } + + return encode; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid URL characters. + * + * @param source The string that has to be transformed into a valid URL + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeUrl(String source) + { + if (!needsUrlEncoding(source)) + { + return source; + } + + try + { + return URLEncoder.encode(source, ENCODING_ISO_8859_1); + } + ///CLOVER:OFF + catch (UnsupportedEncodingException e) + { + // this should never happen, ISO-8859-1 is a standard encoding + throw new RuntimeException(e); + } + ///CLOVER:ON + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * only pure US Ascii strings are preserved and URL encoded in a regular + * way. Strings with characters from other encodings will be encoded in a + * RIFE-specific manner to allow international data to passed along the + * query string. + * + * @param source The string that has to be transformed into a valid URL + * parameter string. + * @return The encoded <code>String</code> object. + * @see #decodeUrlValue(String) + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeUrlValue(String source) + { + if (!needsUrlEncoding(source)) + { + return source; + } + + // check if the string is valid US-ASCII encoding + boolean valid = true; + CharsetEncoder encoder = CHARSET_US_ASCII.newEncoder(); + try + { + encoder.encode(CharBuffer.wrap(source)); + } + catch (CharacterCodingException e) + { + valid = false; + } + + try + { + // if it is valid US-ASCII, use the regular URL encoding method + if (valid) + { + return URLEncoder.encode(source, ENCODING_US_ASCII); + } + // otherwise, base-64 encode the UTF-8 bytes and mark the string + // as being encoded in a special way + else + { + StringBuilder encoded = new StringBuilder("%02%02"); + String base64 = Base64.encodeToString(source.getBytes(ENCODING_UTF_8), false); + String base64_urlsafe = replace(base64, "=", "%3D"); + encoded.append(base64_urlsafe); + + return encoded.toString(); + } + } + ///CLOVER:OFF + catch (UnsupportedEncodingException e) + { + // this should never happen, ISO-8859-1 is a standard encoding + throw new RuntimeException(e); + } + ///CLOVER:ON + } + + /** + * Decodes a <code>String</code> that has been encoded in a RIFE-specific + * manner for URL usage.. Before calling this method, you should first + * verify if the value needs decoding by using the + * <code>doesUrlValueNeedDecoding(String)</code> method. + * + * @param source the value that has been encoded for URL usage in a + * RIFE-specific way + * @return The decoded <code>String</code> object. + * @see #encodeUrlValue(String) + * @see #doesUrlValueNeedDecoding(String) + * @since 1.0 + */ + public static String decodeUrlValue(String source) + { + try + { + byte[] decoded = Base64.decode(source.substring(2)); + if (null == decoded) + { + return null; + } else + { + return new String(decoded, StringUtils.ENCODING_UTF_8); + } + } + ///CLOVER:OFF + catch (UnsupportedEncodingException e) + { + // this should never happen, UTF-8 is a standard encoding + throw new RuntimeException(e); + } + ///CLOVER:ON + } + + /** + * Checks if a <code>String</code> is encoded in a RIFE-specific manner + * for URL usage. + * + * @param source the value that might have been encoded for URL usage in a + * RIFE-specific way + * @return <code>true</code> if the value is encoded in the RIFE-specific + * format; and + * <p><code>false</code> otherwise + * @see #encodeUrlValue(String) + * @see #decodeUrlValue(String) + * @since 1.0 + */ + public static boolean doesUrlValueNeedDecoding(String source) + { + if (source != null && + source.length() > 2 && + source.startsWith("\u0002\u0002")) + { + return true; + } + + return false; + } + + private static boolean needsHtmlEncoding(String source, boolean defensive) + { + if (null == source) + { + return false; + } + + boolean encode = false; + char ch; + for (int i = 0; i < source.length(); i++) + { + ch = source.charAt(i); + + if ((defensive || (ch != '\u0022' && ch != '\u0026' && ch != '\u003C' && ch != '\u003E')) && + ch < '\u00A0') + { + continue; + } + + encode = true; + break; + } + + return encode; + } + + /** + * @since 1.6 + */ + public static String decodeHtml(String source) + { + if (null == source || + 0 == source.length()) + { + return source; + } + + int current_index = 0; + int delimiter_start_index = 0; + int delimiter_end_index = 0; + + StringBuilder result = null; + + while (current_index <= source.length()) + { + delimiter_start_index = source.indexOf('&', current_index); + if (delimiter_start_index != -1) + { + delimiter_end_index = source.indexOf(';', delimiter_start_index + 1); + if (delimiter_end_index != -1) + { + // ensure that the string builder is setup correctly + if (null == result) + { + result = new StringBuilder(); + } + + // add the text that leads up to this match + if (delimiter_start_index > current_index) + { + result.append(source.substring(current_index, delimiter_start_index)); + } + + // add the decoded entity + String entity = source.substring(delimiter_start_index, delimiter_end_index + 1); + + current_index = delimiter_end_index + 1; + + // try to decoded numeric entities + if (entity.charAt(1) == '#') + { + int start = 2; + int radix = 10; + // check if the number is hexadecimal + if (entity.charAt(2) == 'X' || entity.charAt(2) == 'x') + { + start++; + radix = 16; + } + try + { + Character c = new Character((char) Integer.parseInt(entity.substring(start, entity.length() - 1), radix)); + result.append(c); + } + // when the number of the entity can't be parsed, add the entity as-is + catch (NumberFormatException e) + { + result.append(entity); + } + } else + { + // try to decode the entity as a literal + Character decoded = HTML_DECODE_MAP.get(entity); + if (decoded != null) + { + result.append(decoded); + } + // if there was no match, add the entity as-is + else + { + result.append(entity); + } + } + } else + { + break; + } + } else + { + break; + } + } + + if (null == result) + { + return source; + } else if (current_index < source.length()) + { + result.append(source.substring(current_index)); + } + + return result.toString(); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid Html characters. + * + * @param source The string that has to be transformed into a valid Html + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeHtml(String source) + { + if (needsHtmlEncoding(source, false)) + { + return encode(source, HTML_ENCODER_FALLBACK, AGGRESSIVE_HTML_ENCODE_MAP, DEFENSIVE_HTML_ENCODE_MAP); + } + return source; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing as much as possible Html characters. It is safe to already + * feed existing Html to this method since &, < and > will not + * be encoded. + * + * @param source The string that has to be transformed into a valid Html + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeHtmlDefensive(String source) + { + if (needsHtmlEncoding(source, true)) + { + return encode(source, null, DEFENSIVE_HTML_ENCODE_MAP); + } + return source; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid XML characters. + * + * @param source The string that has to be transformed into a valid XML + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeXml(String source) + { + return encode(source, null, XML_ENCODE_MAP); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid <code>String</code> characters. + * + * @param source The string that has to be transformed into a valid + * sequence of <code>String</code> characters. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeString(String source) + { + return encode(source, null, STRING_ENCODE_MAP); + } + + /** + * Transforms a provided <code>String</code> object into a series of + * unicode escape codes. + * + * @param source The string that has to be transformed into a valid + * sequence of unicode escape codes + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeUnicode(String source) + { + if (null == source) + { + return null; + } + + StringBuilder encoded = new StringBuilder(); + String hexstring = null; + for (int i = 0; i < source.length(); i++) + { + hexstring = Integer.toHexString((int) source.charAt(i)).toUpperCase(); + encoded.append("\\u"); + // fill with zeros + for (int j = hexstring.length(); j < 4; j++) + { + encoded.append("0"); + } + encoded.append(hexstring); + } + + return encoded.toString(); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid Sql characters. + * + * @param source The string that has to be transformed into a valid Sql + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeSql(String source) + { + return encode(source, null, SQL_ENCODE_MAP); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid LaTeX characters. + * + * @param source The string that has to be transformed into a valid LaTeX + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeLatex(String source) + { + if (null == source) + { + return null; + } + + source = encode(source, null, LATEX_ENCODE_MAP); + source = StringUtils.replace(source, "latex", "\\LaTeX", false); + + return source; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * using the mapping that are provided through the supplied encoding + * table. + * + * @param source The string that has to be transformed into a valid + * string, using the mappings that are provided through the supplied + * encoding table. + * @param encodingTables A <code>Map</code> object containing the mappings + * to transform characters into valid entities. The keys of this map + * should be <code>Character</code> objects and the values + * <code>String</code> objects. + * @return The encoded <code>String</code> object. + * @since 1.0 + */ + private static String encode(String source, EncoderFallbackHandler fallbackHandler, Map<Character, String>... encodingTables) + { + if (null == source) + { + return null; + } + + if (null == encodingTables || + 0 == encodingTables.length) + { + return source; + } + + StringBuilder encoded_string = null; + char[] string_to_encode_array = source.toCharArray(); + int last_match = -1; + + for (int i = 0; i < string_to_encode_array.length; i++) + { + char char_to_encode = string_to_encode_array[i]; + for (Map<Character, String> encoding_table : encodingTables) + { + if (encoding_table.containsKey(char_to_encode)) + { + encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array); + + encoded_string.append(encoding_table.get(char_to_encode)); + last_match = i; + } + } + + if (fallbackHandler != null && + last_match < i && + fallbackHandler.hasFallback(char_to_encode)) + { + encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array); + + fallbackHandler.appendFallback(encoded_string, char_to_encode); + last_match = i; + } + } + + if (null == encoded_string) + { + return source; + } else + { + int difference = string_to_encode_array.length - (last_match + 1); + if (difference > 0) + { + encoded_string.append(string_to_encode_array, last_match + 1, difference); + } + return encoded_string.toString(); + } + } + + private static StringBuilder prepareEncodedString(String source, StringBuilder encodedString, int i, int lastMatch, char[] stringToEncodeArray) + { + if (null == encodedString) + { + encodedString = new StringBuilder(source.length()); + } + + int difference = i - (lastMatch + 1); + if (difference > 0) + { + encodedString.append(stringToEncodeArray, lastMatch + 1, difference); + } + + return encodedString; + } + + private static interface EncoderFallbackHandler + { + abstract boolean hasFallback(char character); + + abstract void appendFallback(StringBuilder encodedBuffer, char character); + } + + private static class HtmlEncoderFallbackHandler implements EncoderFallbackHandler + { + private final static String PREFIX = "&#"; + private final static String SUFFIX = ";"; + + public boolean hasFallback(char character) + { + if (character < '\u00A0') + { + return false; + } + + return true; + } + + public void appendFallback(StringBuilder encodedBuffer, char character) + { + encodedBuffer.append(PREFIX); + encodedBuffer.append((int) character); + encodedBuffer.append(SUFFIX); + } + } + + /** + * Transforms a provided <code>String</code> object into a literal that can + * be included into a regular expression {@link Pattern} as-is. None of the + * regular expression escapes in the string will be functional anymore. + * + * @param source The string that has to be escaped as a literal + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @since 1.3 + */ + public static String encodeRegexp(String source) + { + int regexp_quote_start = source.indexOf("\\E"); + if (-1 == regexp_quote_start) + { + return "\\Q" + source + "\\E"; + } + + StringBuilder buffer = new StringBuilder(source.length() * 2); + buffer.append("\\Q"); + + regexp_quote_start = 0; + + int current = 0; + while (-1 == (regexp_quote_start = source.indexOf("\\E", current))) + { + buffer.append(source.substring(current, regexp_quote_start)); + current = regexp_quote_start + 2; + buffer.append("\\E\\\\E\\Q"); + } + + buffer.append(source.substring(current, source.length())); + buffer.append("\\E"); + + return buffer.toString(); + } + + /** + * Counts the number of times a substring occures in a provided string in + * a case-sensitive manner. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @return An <code>int</code> value containing the number of occurances + * of the substring. + * @since 1.0 + */ + public static int count(String source, String substring) + { + return count(source, substring, true); + } + + /** + * Counts the number of times a substring occures in a provided string. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>int</code> value containing the number of occurances + * of the substring. + * @since 1.0 + */ + public static int count(String source, String substring, boolean matchCase) + { + if (null == source) + { + return 0; + } + + if (null == substring) + { + return 0; + } + + int current_index = 0; + int substring_index = 0; + int count = 0; + + if (!matchCase) + { + source = source.toLowerCase(); + substring = substring.toLowerCase(); + } + + while (current_index < source.length() - 1) + { + substring_index = source.indexOf(substring, current_index); + + if (-1 == substring_index) + { + break; + } else + { + current_index = substring_index + substring.length(); + count++; + } + } + + return count; + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries in a case-sensitive manner. The + * seperator will not be included in the list of parts. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return An <code>ArrayList</code> containing the parts as + * <code>String</code> objects. + * @since 1.0 + */ + public static ArrayList<String> split(String source, String seperator) + { + return split(source, seperator, true); + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries. The seperator will not be included in + * the list of parts. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>ArrayList</code> containing the parts as + * <code>String</code> objects. + * @since 1.0 + */ + public static ArrayList<String> split(String source, String seperator, boolean matchCase) + { + ArrayList<String> substrings = new ArrayList<String>(); + + if (null == source) + { + return substrings; + } + + if (null == seperator) + { + substrings.add(source); + return substrings; + } + + int current_index = 0; + int delimiter_index = 0; + String element = null; + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + seperator = seperator.toLowerCase(); + } else + { + source_lookup_reference = source; + } + + while (current_index <= source_lookup_reference.length()) + { + delimiter_index = source_lookup_reference.indexOf(seperator, current_index); + + if (-1 == delimiter_index) + { + element = new String(source.substring(current_index, source.length())); + substrings.add(element); + current_index = source.length() + 1; + } else + { + element = new String(source.substring(current_index, delimiter_index)); + substrings.add(element); + current_index = delimiter_index + seperator.length(); + } + } + + return substrings; + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries in a case-sensitive manner. The + * seperator will not be included in the parts array. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return A <code>String[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static String[] splitToArray(String source, String seperator) + { + return splitToArray(source, seperator, true); + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries. The seperator will not be included in + * the parts array. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A <code>String[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static String[] splitToArray(String source, String seperator, boolean matchCase) + { + ArrayList<String> substrings = split(source, seperator, matchCase); + String[] substrings_array = new String[substrings.size()]; + substrings_array = substrings.toArray(substrings_array); + + return substrings_array; + } + + /** + * Splits a string into integers, using a seperator string to detect the + * seperation boundaries in a case-sensitive manner. If a part couldn't be + * converted to an integer, it will be omitted from the resulting array. + * + * @param source The string that will be split into integers. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return An <code>int[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static int[] splitToIntArray(String source, String seperator) + { + return splitToIntArray(source, seperator, true); + } + + /** + * Splits a string into integers, using a seperator string to detect the + * seperation boundaries. If a part couldn't be converted to an integer, + * it will be omitted from the resulting array. + * + * @param source The string that will be split into integers. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>int[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static int[] splitToIntArray(String source, String seperator, boolean matchCase) + { + ArrayList<String> string_parts = split(source, seperator, matchCase); + int number_of_valid_parts = 0; + + for (String string_part : string_parts) + { + try + { + Integer.parseInt(string_part); + number_of_valid_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + int[] string_parts_int = (int[]) Array.newInstance(int.class, number_of_valid_parts); + int added_parts = 0; + + for (String string_part : string_parts) + { + try + { + string_parts_int[added_parts] = Integer.parseInt(string_part); + added_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + return string_parts_int; + } + + /** + * Splits a string into bytes, using a seperator string to detect the + * seperation boundaries in a case-sensitive manner. If a part couldn't be + * converted to a <code>byte</code>, it will be omitted from the resulting + * array. + * + * @param source The string that will be split into bytes. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return A <code>byte[]</code> array containing the bytes. + * @since 1.0 + */ + public static byte[] splitToByteArray(String source, String seperator) + { + return splitToByteArray(source, seperator, true); + } + + /** + * Splits a string into bytes, using a seperator string to detect the + * seperation boundaries. If a part couldn't be converted to a + * <code>byte</code>, it will be omitted from the resulting array. + * + * @param source The string that will be split into bytes. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A <code>byte[]</code> array containing the bytes. + * @since 1.0 + */ + public static byte[] splitToByteArray(String source, String seperator, boolean matchCase) + { + ArrayList<String> string_parts = split(source, seperator, matchCase); + int number_of_valid_parts = 0; + for (String string_part : string_parts) + { + try + { + Byte.parseByte(string_part); + number_of_valid_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + byte[] string_parts_byte = (byte[]) Array.newInstance(byte.class, number_of_valid_parts); + int added_parts = 0; + for (String string_part : string_parts) + { + try + { + string_parts_byte[added_parts] = Byte.parseByte(string_part); + added_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + return string_parts_byte; + } + + /** + * Removes all occurances of a string from the front of another string in + * a case-sensitive manner. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the front. + * @return A new <code>String</code> containing the stripped result. + * @since 1.0 + */ + public static String stripFromFront(String source, String stringToStrip) + { + return stripFromFront(source, stringToStrip, true); + } + + /** + * Removes all occurances of a string from the front of another string. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the front. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A new <code>String</code> containing the stripping result. + * @since 1.0 + */ + public static String stripFromFront(String source, String stringToStrip, boolean matchCase) + { + if (null == source) + { + return null; + } + + if (null == stringToStrip) + { + return source; + } + + int strip_length = stringToStrip.length(); + int new_index = 0; + int last_index = 0; + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + stringToStrip = stringToStrip.toLowerCase(); + } else + { + source_lookup_reference = source; + } + + new_index = source_lookup_reference.indexOf(stringToStrip); + if (0 == new_index) + { + do + { + last_index = new_index; + new_index = source_lookup_reference.indexOf(stringToStrip, new_index + strip_length); + } + while (new_index != -1 && + new_index == last_index + strip_length); + + return source.substring(last_index + strip_length); + } else + { + return source; + } + } + + /** + * Removes all occurances of a string from the end of another string in a + * case-sensitive manner. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the end. + * @return A new <code>String</code> containing the stripped result. + * @since 1.0 + */ + public static String stripFromEnd(String source, String stringToStrip) + { + return stripFromEnd(source, stringToStrip, true); + } + + /** + * Removes all occurances of a string from the end of another string. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the end. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A new <code>String</code> containing the stripped result. + * @since 1.0 + */ + public static String stripFromEnd(String source, String stringToStrip, boolean matchCase) + { + if (null == source) + { + return null; + } + + if (null == stringToStrip) + { + return source; + } + + int strip_length = stringToStrip.length(); + int new_index = 0; + int last_index = 0; + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + stringToStrip = stringToStrip.toLowerCase(); + } else + { + source_lookup_reference = source; + } + + new_index = source_lookup_reference.lastIndexOf(stringToStrip); + if (new_index != -1 && + source.length() == new_index + strip_length) + { + do + { + last_index = new_index; + new_index = source_lookup_reference.lastIndexOf(stringToStrip, last_index - 1); + } + while (new_index != -1 && + new_index == last_index - strip_length); + + return source.substring(0, last_index); + } else + { + return source; + } + } + + /** + * Searches for a string within a specified string in a case-sensitive + * manner and replaces every match with another string. + * + * @param source The string in which the matching parts will be replaced. + * @param stringToReplace The string that will be searched for. + * @param replacementString The string that will replace each matching + * part. + * @return A new <code>String</code> object containing the replacement + * result. + * @since 1.0 + */ + public static String replace(String source, String stringToReplace, String replacementString) + { + return replace(source, stringToReplace, replacementString, true); + } + + /** + * Searches for a string within a specified string and replaces every + * match with another string. + * + * @param source The string in which the matching parts will be replaced. + * @param stringToReplace The string that will be searched for. + * @param replacementString The string that will replace each matching + * part. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A new <code>String</code> object containing the replacement + * result. + * @since 1.0 + */ + public static String replace(String source, String stringToReplace, String replacementString, boolean matchCase) + { + if (null == source) + { + return null; + } + + if (null == stringToReplace) + { + return source; + } + + if (null == replacementString) + { + return source; + } + + Iterator<String> string_parts = split(source, stringToReplace, matchCase).iterator(); + StringBuilder new_string = new StringBuilder(); + + while (string_parts.hasNext()) + { + String string_part = string_parts.next(); + new_string.append(string_part); + if (string_parts.hasNext()) + { + new_string.append(replacementString); + } + } + + return new_string.toString(); + } + + /** + * Creates a new string that contains the provided string a number of + * times. + * + * @param source The string that will be repeated. + * @param count The number of times that the string will be repeated. + * @return A new <code>String</code> object containing the repeated + * concatenation result. + * @since 1.0 + */ + public static String repeat(String source, int count) + { + if (null == source) + { + return null; + } + + StringBuilder new_string = new StringBuilder(); + while (count > 0) + { + new_string.append(source); + count--; + } + + return new_string.toString(); + } + + /** + * Creates a new array of <code>String</code> objects, containing the + * elements of a supplied <code>Iterator</code>. + * + * @param iterator The iterator containing the elements to create the + * array with. + * @return The new <code>String</code> array. + * @since 1.0 + */ + public static String[] toStringArray(Iterator<String> iterator) + { + if (null == iterator) + { + return new String[0]; + } + + ArrayList<String> strings = new ArrayList<String>(); + + while (iterator.hasNext()) + { + strings.add(iterator.next()); + } + + String[] string_array = new String[strings.size()]; + strings.toArray(string_array); + + return string_array; + } + + /** + * Creates a new <code>ArrayList</code>, containing the elements of a + * supplied array of <code>String</code> objects. + * + * @param stringArray The array of <code>String</code> objects that have + * to be converted. + * @return The new <code>ArrayList</code> with the elements of the + * <code>String</code> array. + * @since 1.0 + */ + public static ArrayList<String> toArrayList(String[] stringArray) + { + ArrayList<String> strings = new ArrayList<String>(); + + if (null == stringArray) + { + return strings; + } + + for (String element : stringArray) + { + strings.add(element); + } + + return strings; + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied <code>Collection</code> of <code>String</code> objects joined + * by a given seperator. + * + * @param collection The <code>Collection</code> containing the elements + * to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Collection collection, String seperator) + { + if (null == collection) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == collection.size()) + { + return ""; + } else + { + StringBuilder result = new StringBuilder(); + for (Object element : collection) + { + result.append(String.valueOf(element)); + result.append(seperator); + } + + result.setLength(result.length() - seperator.length()); + return result.toString(); + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The object array containing the elements to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Object[] array, String seperator) + { + return join(array, seperator, null, false); + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The object array containing the elements to join. + * @param seperator The seperator used to join the string elements. + * @param delimiter The delimiter used to surround the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Object[] array, String seperator, String delimiter) + { + return join(array, seperator, delimiter, false); + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The object array containing the elements to join. + * @param seperator The seperator used to join the string elements. + * @param delimiter The delimiter used to surround the string elements. + * @param encodeStrings Indicates whether the characters of the string + * representation of the Array values should be encoded. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Object[] array, String seperator, String delimiter, boolean encodeStrings) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (null == delimiter) + { + delimiter = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String array_value = null; + StringBuilder result = new StringBuilder(); + while (current_index < array.length - 1) + { + if (null == array[current_index]) + { + result.append("null"); + } else + { + array_value = String.valueOf(array[current_index]); + if (encodeStrings) + { + array_value = encodeString(array_value); + } + result.append(delimiter); + result.append(array_value); + result.append(delimiter); + } + result.append(seperator); + current_index++; + } + + if (null == array[current_index]) + { + result.append("null"); + } else + { + array_value = String.valueOf(array[current_index]); + if (encodeStrings) + { + array_value = encodeString(array_value); + } + result.append(delimiter); + result.append(array_value); + result.append(delimiter); + } + return result.toString(); + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The boolean array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(boolean[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The byte array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(byte[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The double array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(double[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The float array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(float[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The integer array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(int[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The long array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(long[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The short array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(short[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The char array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(char[] array, String seperator) + { + return join(array, seperator, null); + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The char array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @param delimiter The delimiter used to surround the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(char[] array, String seperator, String delimiter) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (null == delimiter) + { + delimiter = ""; + } + + if (0 == array.length) + { + return ""; + } else + { + int current_index = 0; + StringBuilder result = new StringBuilder(); + while (current_index < array.length - 1) + { + result.append(delimiter); + result.append(array[current_index]); + result.append(delimiter); + result.append(seperator); + current_index++; + } + + result.append(delimiter); + result.append(String.valueOf(array[current_index])); + result.append(delimiter); + return result.toString(); + } + } + + /** + * Returns an array that contains all the occurances of a substring in a + * string in the correct order. The search will be performed in a + * case-sensitive manner. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @return An <code>int[]</code> array containing the indices of the + * substring. + * @since 1.0 + */ + public static int[] indicesOf(String source, String substring) + { + return indicesOf(source, substring, true); + } + + /** + * Returns an array that contains all the occurances of a substring in a + * string in the correct order. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>int[]</code> array containing the indices of the + * substring. + * @since 1.0 + */ + public static int[] indicesOf(String source, String substring, boolean matchCase) + { + if (null == source || + null == substring) + { + return new int[0]; + } + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + substring = substring.toLowerCase(); + } else + { + source_lookup_reference = source; + } + + int current_index = 0; + int substring_index = 0; + int count = count(source_lookup_reference, substring); + int[] indices = new int[count]; + int counter = 0; + + while (current_index < source.length() - 1) + { + substring_index = source_lookup_reference.indexOf(substring, current_index); + + if (-1 == substring_index) + { + break; + } else + { + current_index = substring_index + substring.length(); + indices[counter] = substring_index; + counter++; + } + } + + return indices; + } + + /** + * Matches a collection of regular expressions against a string. + * + * @param value The <code>String</code> that will be checked. + * @param regexps The collection of regular expressions against which the + * match will be performed. + * @return The <code>Matcher</code> instance that corresponds to the + * <code>String</code> that returned a successful match; or + * <p><code>null</code> if no match could be found. + * @since 1.0 + */ + public static Matcher getMatchingRegexp(String value, Collection<Pattern> regexps) + { + if (value != null && + value.length() > 0 && + regexps != null && + regexps.size() > 0) + { + Matcher matcher = null; + for (Pattern regexp : regexps) + { + matcher = regexp.matcher(value); + if (matcher.matches()) + { + return matcher; + } + } + } + + return null; + } + + /** + * Matches a collection of strings against a regular expression. + * + * @param values The <code>Collection</code> of <code>String</code> + * objects that will be checked. + * @param regexp The regular expression <code>Pattern</code> against which + * the matches will be performed. + * @return The <code>Matcher</code> instance that corresponds to the + * <code>String</code> that returned a successful match; or + * <p><code>null</code> if no match could be found. + * @since 1.0 + */ + public static Matcher getRegexpMatch(Collection<String> values, Pattern regexp) + { + if (values != null && + values.size() > 0 && + regexp != null) + { + Matcher matcher = null; + for (String value : values) + { + matcher = regexp.matcher(value); + if (matcher.matches()) + { + return matcher; + } + } + } + + return null; + } + + /** + * Checks if the name filters through an including and an excluding + * regular expression. + * + * @param name The <code>String</code> that will be filtered. + * @param included The regular expressions that needs to succeed + * @param excluded The regular expressions that needs to fail + * @return <code>true</code> if the name filtered through correctly; or + * <p><code>false</code> otherwise. + * @since 1.0 + */ + public static boolean filter(String name, Pattern included, Pattern excluded) + { + Pattern[] included_array = null; + if (included != null) + { + included_array = new Pattern[]{included}; + } + + Pattern[] excluded_array = null; + if (excluded != null) + { + excluded_array = new Pattern[]{excluded}; + } + + return filter(name, included_array, excluded_array); + } + + /** + * Checks if the name filters through a series of including and excluding + * regular expressions. + * + * @param name The <code>String</code> that will be filtered. + * @param included An array of regular expressions that need to succeed + * @param excluded An array of regular expressions that need to fail + * @return <code>true</code> if the name filtered through correctly; or + * <p><code>false</code> otherwise. + * @since 1.0 + */ + public static boolean filter(String name, Pattern[] included, Pattern[] excluded) + { + if (null == name) + { + return false; + } + + boolean accepted = false; + + // retain only the includes + if (null == included) + { + accepted = true; + } else + { + for (Pattern pattern : included) + { + if (pattern != null && + pattern.matcher(name).matches()) + { + accepted = true; + break; + } + } + } + + // remove the excludes + if (accepted && + excluded != null) + { + for (Pattern pattern : excluded) + { + if (pattern != null && + pattern.matcher(name).matches()) + { + accepted = false; + break; + } + } + } + + return accepted; + } + + /** + * Ensure that the first character of the provided string is upper case. + * + * @param source The <code>String</code> to capitalize. + * @return The capitalized <code>String</code>. + * @since 1.0 + */ + public static String capitalize(String source) + { + if (source == null || source.length() == 0) + { + return source; + } + + if (source.length() > 1 && + Character.isUpperCase(source.charAt(0))) + { + return source; + } + + char chars[] = source.toCharArray(); + chars[0] = Character.toUpperCase(chars[0]); + return new String(chars); + } + + /** + * Ensure that the first character of the provided string lower case. + * + * @param source The <code>String</code> to uncapitalize. + * @return The uncapitalized <code>String</code>. + * @since 1.5 + */ + public static String uncapitalize(String source) + { + if (source == null || source.length() == 0) + { + return source; + } + + if (source.length() > 1 && + Character.isLowerCase(source.charAt(0))) + { + return source; + } + + char chars[] = source.toCharArray(); + chars[0] = Character.toLowerCase(chars[0]); + return new String(chars); + } + + private static String convertUrl(String source, Pattern pattern, boolean shorten, boolean sanitize, boolean no_follow) + { + int max_length = 1024; + + String result = source; + + Matcher url_matcher = pattern.matcher(source); + boolean found = url_matcher.find(); + if (found) + { + String visual_url = null; + String actual_url = null; + int last = 0; + StringBuilder sb = new StringBuilder(); + do + { + actual_url = url_matcher.group(1); + if (url_matcher.groupCount() > 1) + { + visual_url = url_matcher.group(2); + } else + { + visual_url = actual_url; + } + + if (sanitize) + { + // defang javascript + actual_url = StringUtils.replace(actual_url, "javascript:", ""); + + // fill in http:// for URLs that don't begin with / + if ((actual_url.indexOf("://") == -1) && + (!actual_url.startsWith("/"))) + { + actual_url = "http://" + actual_url; + } + } + + if (pattern.equals(BBCODE_BAREURL)) + { + sb.append(source.substring(last, url_matcher.start(1))); + } else + { + sb.append(source.substring(last, url_matcher.start(0))); + } + sb.append("<a href=\""); + sb.append(actual_url); + sb.append("\""); + if (actual_url.startsWith("http://") || + actual_url.startsWith("https://")) + { + sb.append(" target=\"_blank\""); + } + if (no_follow) + { + sb.append(" rel=\"nofollow\""); + } + sb.append(">"); + if (visual_url.length() <= max_length || !shorten) + { + sb.append(visual_url); + } else + { + String ellipsis = "..."; + int query_index = visual_url.indexOf("?"); + + // hack query string off + // keep '?' + if (query_index != -1) + { + visual_url = visual_url.substring(0, query_index + 1) + ellipsis; + } + + if (visual_url.length() >= max_length) + { + int last_slash = visual_url.lastIndexOf("/"); + int start_slash = visual_url.indexOf("/", visual_url.indexOf("://") + 3); + + if (last_slash != start_slash) + { + visual_url = visual_url.substring(0, start_slash + 1) + ellipsis + visual_url.substring(last_slash); + } + } + + sb.append(visual_url); + } + sb.append("</a>"); + + if (pattern.equals(BBCODE_BAREURL)) + { + last = url_matcher.end(1); + } else + { + last = url_matcher.end(0); + } + + found = url_matcher.find(); + } + while (found); + + sb.append(source.substring(last)); + result = sb.toString(); + } + + return result; + } + + private static String parseBBCode(String source, boolean shorten, boolean sanitize, boolean convert_bare, boolean no_follow) + { + String result = source; + + result = StringUtils.replace(result, "[b]", "<b>", false); + result = StringUtils.replace(result, "[/b]", "</b>", false); + result = StringUtils.replace(result, "[u]", "<u>", false); + result = StringUtils.replace(result, "[/u]", "</u>", false); + result = StringUtils.replace(result, "[i]", "<i>", false); + result = StringUtils.replace(result, "[/i]", "</i>", false); + result = StringUtils.replace(result, "[pre]", "<pre>", false); + result = StringUtils.replace(result, "[/pre]", "</pre>", false); + + String resultCopy = result; + String resultLowerCopy = result.toLowerCase(); + StringBuilder buffer = new StringBuilder(); + int startIndex; + int endIndex; + while (-1 != (startIndex = resultLowerCopy.indexOf("[*]"))) + { + int begin = resultLowerCopy.indexOf("[list]", startIndex + 3); + int end = resultLowerCopy.indexOf("[/list]", startIndex + 3); + int next = resultLowerCopy.indexOf("[*]", startIndex + 3); // 3 == sizeof [*] + + if (begin == -1) + { + begin = Integer.MAX_VALUE; + } + + if (end == -1) + { + end = Integer.MAX_VALUE; + } + + if (next == -1) + { + next = Integer.MAX_VALUE; + } + + if (next < begin && next < end) + { + endIndex = next; + } else if (begin < next && begin < end) + { + endIndex = begin; + } else if (end < next && end < begin) + { + endIndex = end; + } else + { + endIndex = resultLowerCopy.length(); + } + + buffer + .append(resultCopy.substring(0, startIndex)) + .append("<li>") + .append(resultCopy.substring(startIndex + 3, endIndex)) // 3 == sizeof [*] + .append("</li>"); + + resultCopy = resultCopy.substring(endIndex); + resultLowerCopy = resultLowerCopy.substring(endIndex); + } + buffer.append(resultCopy.substring(0)); + + result = buffer.toString(); + + result = StringUtils.replace(result, "[list]", "<ul>", false); + result = StringUtils.replace(result, "[/list]", "</ul>", false); + + Matcher color_matcher = BBCODE_COLOR.matcher(result); + result = color_matcher.replaceAll("<font color=\"$1\">"); + result = StringUtils.replace(result, "[/color]", "</font>", false); + + Matcher size_matcher = BBCODE_SIZE.matcher(result); + result = size_matcher.replaceAll("<font size=\"$1\">"); + result = StringUtils.replace(result, "[/size]", "</font>", false); + + result = convertUrl(result, BBCODE_URL_SHORT, shorten, sanitize, no_follow); + result = convertUrl(result, BBCODE_URL_LONG, shorten, sanitize, no_follow); + + if (convert_bare) + { + result = convertUrl(result, BBCODE_BAREURL, shorten, sanitize, no_follow); + } + + Matcher img_matcher = BBCODE_IMG.matcher(result); + result = img_matcher.replaceAll("<div class=\"bbcode_img\"><img src=\"$1\" border=\"0\" alt=\"\" /></div>"); + + Matcher quote_matcher_long = BBCODE_QUOTE_LONG.matcher(result); + result = quote_matcher_long.replaceAll("<div class=\"quoteaccount\">$1:</div><div class=\"quotebody\">"); + result = StringUtils.replace(result, "[quote]", "<div class=\"quotebody\">", false); + result = StringUtils.replace(result, "[/quote]", "</div>", false); + + result = StringUtils.replace(result, "\r\n", "<br />\r"); + result = StringUtils.replace(result, "\n", "<br />\n"); + result = StringUtils.replace(result, "\r", "\r\n"); + + // remove the BR that could be added due to code formatting ppl + // use to format lists + result = StringUtils.replace(result, "ul><br />\r\n", "ul>\r\n"); + result = StringUtils.replace(result, "ul><br />\n", "ul>\n"); + + return result; + } + + /** + * Converts a <code>String</code> to a <code>boolean</code> value. + * + * @param value The <code>String</code> to convert. + * @return The corresponding <code>boolean</code> value. + * @since 1.0 + */ + public static boolean convertToBoolean(String value) + { + if (null == value) + { + return false; + } + + if (value.equals("1") || + value.equalsIgnoreCase("t") || + value.equalsIgnoreCase("true") || + value.equalsIgnoreCase("y") || + value.equalsIgnoreCase("yes") || + value.equalsIgnoreCase("on")) + { + return true; + } + + return false; + } + + /** + * Converts all tabs on a line to spaces according to the provided tab + * width. + * + * @param line The line whose tabs have to be converted. + * @param tabWidth The tab width. + * @return A new <code>String</code> object containing the line with the + * replaced tabs. + * @since 1.0 + */ + public static String convertTabsToSpaces(String line, int tabWidth) + { + StringBuilder result = new StringBuilder(); + int tab_index = -1; + int last_tab_index = 0; + int added_chars = 0; + int tab_size; + while ((tab_index = line.indexOf("\t", last_tab_index)) != -1) + { + tab_size = tabWidth - ((tab_index + added_chars) % tabWidth); + if (0 == tab_size) + { + tab_size = tabWidth; + } + added_chars += tab_size - 1; + result.append(line.substring(last_tab_index, tab_index)); + result.append(StringUtils.repeat(" ", tab_size)); + last_tab_index = tab_index + 1; + } + if (0 == last_tab_index) + { + return line; + } else + { + result.append(line.substring(last_tab_index)); + } + + return result.toString(); + } + + /** + * Ensures that all whitespace is removed from a <code>String</code>. + * <p>It also works with a <code>null</code> argument. + * + * @param source The <code>String</code> to trim. + * @return The trimmed <code>String</code>. + * @since 1.0 + */ + public static String trim(String source) + { + if (source == null || source.length() == 0) + { + return source; + } + + return source.trim(); + } + + /** + * Reformats a string where lines that are longer than <tt>width</tt> + * are split apart at the earliest wordbreak or at maxLength, whichever is + * sooner. If the width specified is less than 5 or greater than the input + * Strings length the string will be returned as is. + * <p/> + * Please note that this method can be lossy - trailing spaces on wrapped + * lines may be trimmed. + * + * @param input the String to reformat. + * @param width the maximum length of any one line. + * @return a new String with reformatted as needed. + */ + public static String wordWrap(String input, int width, Locale locale) + { + // handle invalid input + if (input == null) + { + return ""; + } else if (width < 5) + { + return input; + } else if (width >= input.length()) + { + return input; + } + + // default locale + if (locale == null) + { + locale = Locale.US; + } + + StringBuilder buffer = new StringBuilder(input.length()); + int current_index = 0; + int delimiter_index = 0; + String seperator = "\n"; + String line; + + // go over the input string and jump from line to line + while (current_index <= input.length()) + { + // look for the next linebreak + delimiter_index = input.indexOf(seperator, current_index); + + // get the line that corresponds to it + if (-1 == delimiter_index) + { + line = new String(input.substring(current_index, input.length())); + current_index = input.length() + 1; + } + else + { + line = new String(input.substring(current_index, delimiter_index)); + current_index = delimiter_index + seperator.length(); + } + + // handle the wrapping of the line + BreakIterator breaks = BreakIterator.getLineInstance(locale); + breaks.setText(line); + + int line_start = 0; + int start = breaks.first(); + int end = breaks.next(); + while (end != BreakIterator.DONE) + { + // check if the width has been exceeded + if (end - 1 - line_start >= width) + { + boolean break_line = true; + + // first check if the last characters were spaces, + // if they were and by removing them the width is not + // exceeded, just continue + if (Character.isWhitespace(line.charAt(end - 1))) + { + for (int j = end - 1; j >= 0; j--) + { + if (!Character.isWhitespace(line.charAt(j))) + { + if (j - line_start < width) + { + break_line = false; + } + + break; + } + } + } + + if (break_line) + { + String line_breaked = line.substring(line_start, start); + // this can happen with trailing whitespace + if (line_breaked.length() > width) + { + line_breaked = line_breaked.substring(0, width); + } + buffer.append(line_breaked); + + buffer.append("\n"); + + line_start = start; + } + } + + start = end; + end = breaks.next(); + } + + if (line_start < line.length()) + { + buffer.append(line.substring(line_start)); + } + + if (delimiter_index != -1) + { + buffer.append("\n"); + } + } + + return buffer.toString(); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java new file mode 100644 index 0000000..a4989d8 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java @@ -0,0 +1,758 @@ +package com.ximple.eofms.util; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +public abstract class TPCLIDConverter +{ + private final static int SX1200 = 800; + private final static int SY1200 = 500; + + public static String CoordinateToTpclId(Coordinate dp) + { + long orgX, orgY; + int mapX, mapY; + int shiftX, shiftY; + int dx1, dy1; + int dx2, dy2; + + if (dp == null) + { + return null; + } + + double X = dp.x; + double Y = dp.y; + + String CoordToTPCLID = ""; + + char mapID = CoordinateToSingleMapID(dp); + + if (mapID == 'w') + { + return ""; + } + + /* get the origin point of mapID */ + Coordinate Point = getOriginPoint("" + mapID, Integer.MAX_VALUE); + + if (Point == null) + { + return null; + } + + orgX = (long) Point.x; + orgY = (long) Point.y; + + mapX = intDivision((X - orgX), SX1200); + + if (mapID == 'Z' && mapX >= 100) + { + mapX = mapX - 100; + } + mapY = intDivision((Y - orgY), SY1200); + shiftX = (int) (X - orgX) % SX1200; + shiftY = (int) (Y - orgY) % SY1200; + dx1 = intDivision((shiftX % 100), 10); + dy1 = intDivision((shiftY % 100), 10); + dx2 = (shiftX % 100) % 10; + dy2 = (shiftY % 100) % 10; + + + CoordToTPCLID = "" + mapID; + CoordToTPCLID = CoordToTPCLID + dataFormat(mapX); + CoordToTPCLID = CoordToTPCLID + dataFormat(mapY); + CoordToTPCLID = CoordToTPCLID + intToAscii(shiftX / 100 + asciiToInt("A")); + CoordToTPCLID = CoordToTPCLID + intToAscii(shiftY / 100 + asciiToInt("A")); + CoordToTPCLID = CoordToTPCLID + dx1 + dy1 + dx2 + dy2; + + return CoordToTPCLID; + } + + public static char CoordinateToSingleMapID(Coordinate dp) + { + char mapID = 'w'; + + String[] strY = StringUtils.splitToArray(Double.toString(dp.y), "."); + String[] strX = StringUtils.splitToArray(Double.toString(dp.x), "."); + + int intY = Integer.parseInt(strY[0]); + int intX = Integer.parseInt(strX[0]); + + if (intY > 2944000) + { + return mapID; + } + if (intY >= 2894000 && intY <= 2944000 && intX >= 10000 && intX <= 90000) + { + mapID = 'S'; + return mapID; + } + if (intY >= 2614000 && intY <= 2664000 && intX >= 10000 && intX <= 66000) + { + mapID = 'X'; + return mapID; + } + if (intY >= 2564000 && intY <= 2614000 && intX >= 10000 && intX <= 66000) + { + mapID = 'Y'; + return mapID; + } + if (intY >= 2675800 && intY <= 2725800 && intX >= 10000 && intX <= 170000) + { + mapID = 'Z'; + return mapID; + } + if (intY > 2800000) + { + return mapID; + } + if (intY >= 2750000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'A'; + return mapID; + } + if (intX < 330000) + { + mapID = 'B'; + return mapID; + } + if (intX < 410000) + { + mapID = 'C'; + return mapID; + } + return mapID; + } + if (intY >= 2700000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'D'; + return mapID; + } + if (intX < 330000) + { + mapID = 'E'; + return mapID; + } + if (intX < 410000) + { + mapID = 'F'; + return mapID; + } + return mapID; + } + if (intY >= 2650000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'G'; + return mapID; + } + if (intX < 330000) + { + mapID = 'H'; + return mapID; + } + if (intX < 410000) + { + mapID = 'I'; + return mapID; + } + return mapID; + } + if (intY >= 2600000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'J'; + return mapID; + } + if (intX < 250000) + { + mapID = 'K'; + return mapID; + } + if (intX < 330000) + { + mapID = 'L'; + return mapID; + } + return mapID; + } + if (intY >= 2550000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'M'; + return mapID; + } + + if (intX < 250000) + { + mapID = 'N'; + return mapID; + } + if (intX < 330000) + { + mapID = 'O'; + return mapID; + } + return mapID; + } + if (intY >= 2500000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'P'; + return mapID; + } + if (intX < 250000) + { + mapID = 'Q'; + return mapID; + } + if (intX < 330000) + { + mapID = 'R'; + return mapID; + } + return mapID; + } + if (intY >= 2450000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'S'; + return mapID; + } + if (intX < 250000) + { + mapID = 'T'; + return mapID; + } + if (intX < 330000) + { + mapID = 'U'; + return mapID; + } + return mapID; + } + if (intY >= 2400000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'V'; + return mapID; + } + if (intX < 330000) + { + mapID = 'W'; + return mapID; + } + return mapID; + } + return mapID; + } + + public static Envelope convertTpclIdToEnvelope(String tpclid) + { + String tempString = ""; + + Coordinate point = null; + Coordinate tempPoint = null; + double width, height; + + if (tpclid.length() < 5) + { + return null; + } + + tempString = tpclid.substring(0, 1); + int xmapid = Integer.parseInt(tpclid.substring(1, 3)); + + // Get the origin point + point = getOriginPoint(tempString, xmapid); + + if (point == null) + { + return null; + } + + + tempString = tpclid.substring(1, 5); + width = SX1200; + height = SY1200; + + tempPoint = twoNumberScale(tempString, 800, 500); + if (tempPoint != null) + { + point.x = (point.x + tempPoint.x); + point.y = (point.y + tempPoint.y); + } + + if (tpclid.length() >= 7) + { + tempString = (asciiToInt(tpclid.substring(5, 6)) - 65) + "" + (asciiToInt(tpclid.substring(6, 7)) - 65); + tempPoint = twoNumberScale(tempString, 100); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + width = 100.0; + height = 100.0; + } + + if (tpclid.length() >= 9) + { + tempString = tpclid.substring(7, 8); + tempPoint = twoNumberScale(tempString, 10); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + width = 10.0; + height = 10.0; + } + + if (tpclid.length() >= 11) + { + tempString = tpclid.substring(10); + tempPoint = twoNumberScale(tempString, 1); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + width = 1.0; + height = 1.0; + } + + Coordinate pt2 = new Coordinate(point); + pt2.x += width; + pt2.y += height; + return new Envelope(point, pt2); + } + + public static Coordinate convertTpclIdToCoordinate(String tpclid) + { + String tempString = ""; + + Coordinate point = null; + Coordinate tempPoint = null; + + if (tpclid.length() < 5) + { + return null; + } + + tempString = tpclid.substring(0, 1); + int xmapid = Integer.parseInt(tpclid.substring(1, 3)); + + // Get the origin point + point = getOriginPoint(tempString, xmapid); + + if (point == null) + { + return null; + } + + + tempString = tpclid.substring(1, 5); + + tempPoint = twoNumberScale(tempString, 800, 500); + if (tempPoint != null) + { + point.x = (point.x + tempPoint.x); + point.y = (point.y + tempPoint.y); + } + + if (tpclid.length() >= 7) + { + tempString = (asciiToInt(tpclid.substring(5, 6)) - 65) + "" + (asciiToInt(tpclid.substring(6, 7)) - 65); + tempPoint = twoNumberScale(tempString, 100); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + } + + if (tpclid.length() >= 9) + { + tempString = tpclid.substring(7, 9); + tempPoint = twoNumberScale(tempString, 10); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + } + + if (tpclid.length() >= 11) + { + tempString = tpclid.substring(10); + tempPoint = twoNumberScale(tempString, 1); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + } + return point; + } + + + private static int intDivision(double p1, int p2) + { + double resultValue = 0.0; + String result; + resultValue = p1 / p2; + result = Double.toString(resultValue); + String[] temp = StringUtils.splitToArray(result, "."); + result = temp[0]; + return Integer.parseInt(result); + } + + + private static Coordinate twoNumberScale(String number, int scaleX, int scaleY) + { + Coordinate tempPoint = new Coordinate(); + + if (number.length() == 2) + { + tempPoint.x = Double.parseDouble(number.substring(0, 1)) * scaleX; + tempPoint.y = Double.parseDouble(number.substring(1, 2)) * scaleY; + } else if (number.length() == 1) + { + tempPoint.x = Double.parseDouble(number.substring(0, 1)) * scaleX; + tempPoint.y = 0; + } else if (number.length() == 4) + { + tempPoint.x = Double.parseDouble(number.substring(0, 2)) * scaleX; + tempPoint.y = Double.parseDouble(number.substring(2, 4)) * scaleY; + } else + { + tempPoint.x = 0; + tempPoint.y = 0; + } + return tempPoint; + } + + + private static int asciiToInt(String p1) + { + if (p1.endsWith("A")) return 65; + if (p1.endsWith("B")) return 66; + if (p1.endsWith("C")) return 67; + if (p1.endsWith("D")) return 68; + if (p1.endsWith("E")) return 69; + if (p1.endsWith("F")) return 70; + if (p1.endsWith("G")) return 71; + if (p1.endsWith("H")) return 72; + if (p1.endsWith("I")) return 73; + if (p1.endsWith("J")) return 74; + if (p1.endsWith("K")) return 75; + if (p1.endsWith("L")) return 76; + if (p1.endsWith("M")) return 77; + if (p1.endsWith("N")) return 78; + if (p1.endsWith("O")) return 79; + if (p1.endsWith("P")) return 80; + if (p1.endsWith("Q")) return 81; + if (p1.endsWith("R")) return 82; + if (p1.endsWith("S")) return 83; + if (p1.endsWith("T")) return 84; + if (p1.endsWith("U")) return 85; + if (p1.endsWith("V")) return 86; + if (p1.endsWith("W")) return 87; + if (p1.endsWith("X")) return 88; + if (p1.endsWith("Y")) return 89; + if (p1.endsWith("Z")) return 90; + return 0; + } + + + private static char intToAscii(int p1) + { + switch (p1) + { + case 65: + return 'A'; + case 66: + return 'B'; + case 67: + return 'C'; + case 68: + return 'D'; + case 69: + return 'E'; + case 70: + return 'F'; + case 71: + return 'G'; + case 72: + return 'H'; + case 73: + return 'I'; + case 74: + return 'J'; + case 75: + return 'K'; + case 76: + return 'L'; + case 77: + return 'M'; + case 78: + return 'N'; + case 79: + return 'O'; + case 80: + return 'P'; + case 81: + return 'Q'; + case 82: + return 'R'; + case 83: + return 'S'; + case 84: + return 'T'; + case 85: + return 'U'; + case 86: + return 'V'; + case 87: + return 'W'; + case 88: + return 'X'; + case 89: + return 'Y'; + case 90: + return 'Z'; + default: + return '1'; + } + } + + + private static Coordinate getOriginPoint(String letter, int xMapId) + { + int aSwitch = asciiToInt(letter); + Coordinate Point = new Coordinate(); + switch (aSwitch) + { + case 65: //A + { + Point.x = 170000; + Point.y = 2750000; + break; + } + case 66: //B + { + Point.x = 250000; + Point.y = 2750000; + break; + } + case 67: //C + { + Point.x = 330000; + Point.y = 2750000; + break; + } + case 68: //D + { + Point.x = 170000; + Point.y = 2700000; + break; + } + case 69: //E + { + Point.x = 250000; + Point.y = 2700000; + break; + } + case 70: //F + { + Point.x = 330000; + Point.y = 2700000; + break; + } + case 71: //G + { + Point.x = 170000; + Point.y = 2650000; + break; + } + case 72: //H + { + Point.x = 250000; + Point.y = 2650000; + break; + } + case 73: //I + { + Point.x = 330000; + Point.y = 2650000; + break; + } + case 74: //J + { + Point.x = 90000; + Point.y = 2600000; + break; + } + case 75: //K + { + Point.x = 170000; + Point.y = 2600000; + break; + } + case 76: //L + { + Point.x = 250000; + Point.y = 2600000; + break; + } + case 77: //M + { + Point.x = 90000; + Point.y = 2550000; + break; + } + case 78: //N + { + Point.x = 170000; + Point.y = 2550000; + break; + } + case 79: //O + { + Point.x = 250000; + Point.y = 2550000; + break; + } + case 80: //P + { + Point.x = 90000; + Point.y = 2500000; + break; + } + case 81: //Q + { + Point.x = 170000; + Point.y = 2500000; + break; + } + case 82: //R + { + Point.x = 250000; + Point.y = 2500000; + break; + } + case 83: //���� S + { + Point.x = 10000; + Point.y = 2894000; + break; + } + case 84: //T + { + Point.x = 170000; + Point.y = 2450000; + break; + } + case 85: //U + { + Point.x = 250000; + Point.y = 2450000; + break; + } + case 86: //V + { + Point.x = 170000; + Point.y = 2400000; + break; + } + case 87: // W + { + Point.x = 250000; + Point.y = 2400000; + break; + } + case 88: //��� X + { + Point.x = 10000; + Point.y = 2614000; + break; + } + case 89: //��� Y + { + Point.x = 10000; + Point.y = 2564000; + break; + } + case 90: //���� ��Z + { + Point.x = (xMapId < 51) ? 90000 : 10000; + Point.y = 2675800; + break; + } + default: + { + return null; + } + } + return Point; + } + + + private static Coordinate twoNumberScale(String number, int scale) + { + return twoNumberScale(number, scale, scale); + } + + + private static String dataFormat(int p1) + { + String s1 = Integer.toString(p1); + if (s1.length() < 2) + s1 = "0" + s1; + return s1; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWD97GeometryConverterDecorator.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWD97GeometryConverterDecorator.java new file mode 100644 index 0000000..0cb12d5 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWD97GeometryConverterDecorator.java @@ -0,0 +1,68 @@ +package com.ximple.eofms.util; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.CoordinateSequenceFilter; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.util.Assert; + +import com.ximple.io.dgn7.GeometryConverter; + +public class TWD97GeometryConverterDecorator implements GeometryConverter +{ + private GeometryConverter converter; + private TWD97ConvertFilter coordinatesFilter = new TWD97ConvertFilter(); + + public TWD97GeometryConverterDecorator() + { + } + + public GeometryConverter getConverter() + { + return converter; + } + + public void setConverter(GeometryConverter converter) + { + this.converter = converter; + } + + public Geometry toGeometry(GeometryFactory factory) + { + if (converter == null) Assert.shouldNeverReachHere(); + + coordinatesFilter.reset(); + + Geometry geom = converter.toGeometry(factory); + if (geom == null) return null; + geom.apply(coordinatesFilter); + return geom; + } + + class TWD97ConvertFilter implements CoordinateSequenceFilter + { + public void filter(CoordinateSequence coordinateSequence, int i) + { + Coordinate pt = coordinateSequence.getCoordinate(i); + Coordinate pt97 = TWDDatumConverter.fromTM2ToTWD97(pt); + pt.x = pt97.x; + pt.y = pt97.y; + pt.z = pt97.z; + } + + public boolean isDone() + { + return false; + } + + public boolean isGeometryChanged() + { + return true; + } + + public void reset() + { + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java new file mode 100644 index 0000000..0971069 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java @@ -0,0 +1,509 @@ +package com.ximple.eofms.util; + +import com.vividsolutions.jts.geom.Coordinate; + +/** + * TWDDatumConverter + * User: Ulysses + * Date: 2007/10/8 + * Time: �U�� 01:35:03 + * To change this template use File | Settings | File Templates. + */ +public abstract class TWDDatumConverter +{ + /* + * Definition of math related value + */ + private static final double COS67_5 = 0.3826834323650897717284599840304e0; + private static final double PI = 3.14159265358979323e0; + private static final double HALF_PI = 1.570796326794896615e0; + private static final double DEG_RAD = 0.01745329251994329572e0; + private static final double RAD_DEG = 57.295779513082321031e0; + + /* + * Definition of datum related value + */ + private static final double AD_C = 1.0026000e0; + private static final double TWD67_A = 6378160.0e0; + private static final double TWD67_B = 6356774.7192e0; + private static final double TWD67_ECC = 0.00669454185458e0; + private static final double TWD67_ECC2 = 0.00673966079586e0; + + // different from garmin and already knowned value, but those all value only + private static final double TWD67_DX = -752.32e0; + + // got 5-15m accuracy. the real offical value is holded by somebody and not + private static final double TWD67_DY = -361.32e0; + + // release to public. if can got more enough twd67/twd97 control point coordinare, + private static final double TWD67_DZ = -180.51e0; + private static final double TWD67_RX = -0.00000117e0; // then we can calculate a better value than now. + private static final double TWD67_RY = 0.00000184e0; // + private static final double TWD67_RZ = 0.00000098e0; // and, also lack twd67/twd97 altitude convertion value... + private static final double TWD67_S = 0.00002329e0; // + private static final double TWD97_A = 6378137.0e0; + private static final double TWD97_B = 6356752.3141e0; + private static final double TWD97_ECC = 0.00669438002290e0; + private static final double TWD97_ECC2 = 0.00673949677556e0; + private static final double TWD67_TM2 = 0.9999e0; // TWD67->TM2 scale + private static final double TWD97_TM2 = 0.9999e0; // TWD97->TM2 scale + + /* + * datum convert function + */ + public static Coordinate toTWD97(Coordinate pt) + { + double newX, newY, newZ; + double r, pole, sin_lat, cos_lat; + double lat, lon, height; + double x1, y1, z1, x2, y2, z2; + double q, q2, t, t1, s, s1, sum, sin_b, cos_b, sin_p, cos_p; + + lon = pt.x * DEG_RAD; + lat = pt.y * DEG_RAD; + height = pt.z * DEG_RAD; + + if ((lat < -HALF_PI) && (lat > -1.001 * HALF_PI)) + { + lat = -HALF_PI; + } else if ((lat > HALF_PI) && (lat < 1.001 * HALF_PI)) + { + lat = HALF_PI; + } else if ((lat < -HALF_PI) || (lat > HALF_PI)) + { + return null; + } + + if (lon > PI) + { + lon -= (2 * PI); + } + + sin_lat = Math.sin(lat); + cos_lat = Math.cos(lat); + r = TWD67_A / (Math.sqrt(1.0 - TWD67_ECC * sin_lat * sin_lat)); + x1 = (r + height) * cos_lat * Math.cos(lon); + y1 = (r + height) * cos_lat * Math.sin(lon); + z1 = ((r * (1 - TWD67_ECC)) + height) * sin_lat; + x2 = x1 + TWD67_DX + TWD67_S * (lon + TWD67_RZ * lat - TWD67_RY * height); + y2 = y1 + TWD67_DY + TWD67_S * (-TWD67_RZ * lon + lat + TWD67_RX * height); + z2 = z1 + TWD67_DZ + TWD67_S * (TWD67_RY * lon - TWD67_RX * lat + height); + pole = 0.0; + + if (x2 != 0.0) + { + lon = Math.atan2(y2, x2); + } else + { + if (y2 > 0) + { + lon = HALF_PI; + } else if (y2 < 0) + { + lon = -HALF_PI; + } else + { + pole = 1; + lon = 0; + + if (z2 > 0) + { + lat = HALF_PI; + } else if (z2 < 0) + { + lat = -HALF_PI; + } else + { + lat = HALF_PI; + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = -TWD97_B; + + return new Coordinate(newX, newY, newZ); + } + } + } + + q2 = x2 * x2 + y2 * y2; + q = Math.sqrt(q2); + t = z2 * AD_C; + s = Math.sqrt(t * t + q2); + sin_b = t / s; + cos_b = q / s; + t1 = z2 + TWD97_B * TWD97_ECC2 * sin_b * sin_b * sin_b; + sum = q - TWD97_A * TWD97_ECC * cos_b * cos_b * cos_b; + s1 = Math.sqrt(t1 * t1 + sum * sum); + sin_p = t1 / s1; + cos_p = sum / s1; + r = TWD97_A / Math.sqrt(1.0 - TWD97_ECC * sin_p * sin_p); + + if (cos_p >= COS67_5) + { + height = q / cos_p - r; + } else if (cos_p <= -COS67_5) + { + height = q / -cos_p - r; + } else + { + height = z2 / sin_p + r * (TWD97_ECC - 1.0); + } + + if (pole != 0.0) + { + lat = Math.atan(sin_p / cos_p); + } + + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = height; + return new Coordinate(newX, newY, newZ); + } + + public static Coordinate toTWD67(Coordinate pt) + { + double newX, newY, newZ; + double r, pole, sin_lat, cos_lat; + double lat, lon, height; + double x1, y1, z1, x2, y2, z2; + double q, q2, t, t1, s, s1, sum, sin_b, cos_b, sin_p, cos_p; + + lon = pt.x * DEG_RAD; + lat = pt.y * DEG_RAD; + height = pt.z * DEG_RAD; + + if ((lat < -HALF_PI) && (lat > -1.001 * HALF_PI)) + { + lat = -HALF_PI; + } else if ((lat > HALF_PI) && (lat < 1.001 * HALF_PI)) + { + lat = HALF_PI; + } else if ((lat < -HALF_PI) || (lat > HALF_PI)) + { + return null; + } + + if (lon > PI) + { + lon -= (2 * PI); + } + + sin_lat = Math.sin(lat); + cos_lat = Math.cos(lat); + r = TWD97_A / (Math.sqrt(1.0 - TWD97_ECC * sin_lat * sin_lat)); + x1 = (r + height) * cos_lat * Math.cos(lon); + y1 = (r + height) * cos_lat * Math.sin(lon); + z1 = ((r * (1 - TWD97_ECC)) + height) * sin_lat; + x2 = x1 - TWD67_DX - TWD67_S * (lon + TWD67_RZ * lat - TWD67_RY * height); + y2 = y1 - TWD67_DY - TWD67_S * (-TWD67_RZ * lon + lat + TWD67_RX * height); + z2 = z1 - TWD67_DZ - TWD67_S * (TWD67_RY * lon - TWD67_RX * lat + height); + pole = 0; + + if (x2 != 0.0) + { + lon = Math.atan2(y2, x2); + } else + { + if (y2 > 0) + { + lon = HALF_PI; + } else if (y2 < 0) + { + lon = -HALF_PI; + } else + { + pole = 1; + lon = 0; + + if (z2 > 0) + { + lat = HALF_PI; + } else if (z2 < 0) + { + lat = -HALF_PI; + } else + { + lat = HALF_PI; + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = -TWD67_B; + + return new Coordinate(newX, newY, newZ); + } + } + } + + q2 = x2 * x2 + y2 * y2; + q = Math.sqrt(q2); + t = z2 * AD_C; + s = Math.sqrt(t * t + q2); + sin_b = t / s; + cos_b = q / s; + t1 = z2 + TWD67_B * TWD67_ECC2 * sin_b * sin_b * sin_b; + sum = q - TWD67_A * TWD67_ECC * cos_b * cos_b * cos_b; + s1 = Math.sqrt(t1 * t1 + sum * sum); + sin_p = t1 / s1; + cos_p = sum / s1; + r = TWD67_A / Math.sqrt(1.0 - TWD67_ECC * sin_p * sin_p); + + if (cos_p >= COS67_5) + { + height = q / cos_p - r; + } else if (cos_p <= -COS67_5) + { + height = q / -cos_p - r; + } else + { + height = z2 / sin_p + r * (TWD67_ECC - 1.0); + } + + if (pole != 0.0) + { + lat = Math.atan(sin_p / cos_p); + } + + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = height; + return new Coordinate(newX, newY, newZ); + } + + public static Coordinate toTM2(double a, double ecc, double ecc2, double lat, double lon, double scale, double x, double y) + { + double x0, y0, x1, y1, m0, m1; + double n, t, c, A; + double newX, newY; + + x0 = x * DEG_RAD; + y0 = y * DEG_RAD; + x1 = lon * DEG_RAD; + y1 = lat * DEG_RAD; + m0 = mercator(y1, a, ecc); + m1 = mercator(y0, a, ecc); + n = a / Math.sqrt(1 - ecc * Math.pow(Math.sin(y0), 2.0)); + t = Math.pow(Math.tan(y0), 2.0); + c = ecc2 * Math.pow(Math.cos(y0), 2.0); + A = (x0 - x1) * Math.cos(y0); + newX = scale * n + * (A + (1.0 - t + c) * A * A * A / 6.0 + + (5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * ecc2) * Math.pow(A, 5.0) / 120.0); + newY = scale + * (m1 - m0 + + n * Math.tan(y0) + * (A * A / 2.0 + (5.0 - t + 9.0 * c + 4 * c * c) * Math.pow(A, 4.0) / 24.0 + + (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * ecc2) * Math.pow(A, 6.0) / 720.0)); + return new Coordinate(newX, newY); + } + + public static Coordinate fromTM2(double a, double ecc, double ecc2, double lat, double lon, double scale, double x, double y) + { + double newX, newY; + double x0, y0, x1, y1, phi, m, m0, mu, e1; + double c1, t1, n1, r1, d; + + x0 = x; + y0 = y; + x1 = lon * DEG_RAD; + y1 = lat * DEG_RAD; + m0 = mercator(y1, a, ecc); + m = m0 + y0 / scale; + e1 = (1.0 - Math.sqrt(1.0 - ecc)) / (1.0 + Math.sqrt(1.0 - ecc)); + mu = m / (a * (1.0 - ecc / 4.0 - 3.0 * ecc * ecc / 64.0 - 5.0 * ecc * ecc * ecc / 256.0)); + phi = mu + (3.0 * e1 / 2.0 - 27.0 * Math.pow(e1, 3.0) / 32.0) * Math.sin(2.0 * mu) + + (21.0 * e1 * e1 / 16.0 - 55.0 * Math.pow(e1, 4.0) / 32.0) * Math.sin(4.0 * mu) + + 151.0 * Math.pow(e1, 3.0) / 96.0 * Math.sin(6.0 * mu) + 1097.0 * Math.pow(e1, 4.0) / 512.0 * Math.sin(8.0 * mu); + c1 = ecc2 * Math.pow(Math.cos(phi), 2.0); + t1 = Math.pow(Math.tan(phi), 2.0); + n1 = a / Math.sqrt(1 - ecc * Math.pow(Math.sin(phi), 2.0)); + r1 = a * (1.0 - ecc) / Math.pow(1.0 - ecc * Math.pow(Math.sin(phi), 2.0), 1.5); + d = x0 / (n1 * scale); + newX = (x1 + (d - (1.0 + 2.0 * t1 + c1) * Math.pow(d, 3.0) / 6.0 + + (5.0 - 2.0 * c1 + 28.0 * t1 - 3.0 * c1 * c1 + 8.0 * ecc2 + 24.0 * t1 * t1) * Math.pow(d, 5.0) + / 120.0) / Math.cos(phi)) * RAD_DEG; + newY = (phi + - n1 * Math.tan(phi) / r1 + * (d * d / 2.0 - (5.0 + 3.0 * t1 + 10.0 * c1 - 4.0 * c1 * c1 - 9.0 * ecc2) * Math.pow(d, 4.0) / 24.0 + + (61.0 + 90.0 * t1 + 298.0 * c1 + 45.0 * t1 * t1 - 252.0 * ecc2 - 3.0 * c1 * c1) * Math.pow(d, 6.0) + / 72.0)) * RAD_DEG; + return new Coordinate(newX, newY); + } + + private static double mercator(double y, double a, double ecc) + { + if (y == 0.0) + { + return 0.0; + } else + { + return a * ((1.0 - ecc / 4.0 - 3.0 * ecc * ecc / 64.0 - 5.0 * ecc * ecc * ecc / 256.0) * y + - (3.0 * ecc / 8.0 + 3.0 * ecc * ecc / 32.0 + 45.0 * ecc * ecc * ecc / 1024.0) * Math.sin(2.0 * y) + + (15.0 * ecc * ecc / 256.0 + 45.0 * ecc * ecc * ecc / 1024.0) * Math.sin(4.0 * y) + - (35.0 * ecc * ecc * ecc / 3072.0) * Math.sin(6.0 * y)); + } + } + + /** + * + * Sample code below, using coordinate in Dan Jacob's website. + * + * + * int main() + * { + * double x1, y1, z1, x2, y2, z2; + * double tx1, ty1, tx2, ty2; + * double dx, dy, dz, dx1, dy1; + * + * x1 = 120.85788004; // TWD67 + * y1 = 24.18347242; + * z1 = 777; + * + * x2 = 120.86603958; // TWD97 + * y2 = 24.18170479; + * z2 = 777; + * + * tx1 = 235561; // TWD67->TM2 + * ty1 = 2675359; + * + * tx2 = 236389.849; // TWD97->TM2 + * ty2 = 2675153.168; + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD67->TM2 + * / + * / + * //////////////////////////////////////////// + * + * dx = x1; + * dy = y1; + * + * toTM2(TWD67_A, TWD67_ECC, TWD67_ECC2, 0, 121, TWD67_TM2, &dx, &dy); + * // center longitude of taiwan is 121, for penghu is 119 + * + * dx += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD67->TM2nTWD67 (%f, %f)nConvert (%.3f, %.3f)nOrigin (%.3f, %.3f)n", x1, y1, dx, dy, tx1, ty1); + * printf("Acuuracy (%.3f, X:%.3f, Y:%.3f)nn", sqrt((dx-tx1)*(dx-tx1)+(dy-ty1)*(dy-ty1)), (dx-tx1), (dy-ty1)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD97->TM2 + * / + * / + * //////////////////////////////////////////// + * + * dx = x2; + * dy = y2; + * + * toTM2(TWD97_A, TWD97_ECC, TWD97_ECC2, 0, 121, TWD97_TM2, &dx, &dy); + * // center longitude of taiwan is 121, for penghu is 119 + * + * dx += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD97->TM2nTWD97 (%f, %f)nConvert (%.3f, %.3f)nOrigin (%.3f, %.3f)n", x2, y2, dx, dy, tx2, ty2); + * printf("Acuuracy (%.3f, X:%.3f, Y:%.3f)nn", sqrt((dx-tx2)*(dx-tx2)+(dy-ty2)*(dy-ty2)), (dx-tx2), (dy-ty2)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TM2->TWD67 + * / + * / + * //////////////////////////////////////////// + * + * dx = tx1-250000; // should minus 250000 first in Taiwan + * dy = ty1; + * + * fromTM2(TWD67_A, TWD67_ECC, TWD67_ECC2, 0, 121, TWD67_TM2, &dx, &dy); + * + * printf("TM2->TWD67nTM2 (%f, %f)nConvert (%.9f, %.9f)nOrigin (%.9f, %.9f)n", tx1, ty1, dx, dy, x1, y1); + * printf("Acuuracy (%.9f, X:%.9f, Y:%.9f)nn", sqrt((dx-x1)*(dx-x1)+(dy-y1)*(dy-y1)), (dx-x1), (dy-y1)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TM2->TWD97 + * / + * / + * //////////////////////////////////////////// + * + * dx = tx2-250000; // should minus 250000 first in Taiwan + * dy = ty2; + * + * fromTM2(TWD97_A, TWD97_ECC, TWD97_ECC2, 0, 121, TWD97_TM2, &dx, &dy); + * + * printf("TM2->TWD97nTM2 (%f, %f)nConvert (%.9f, %.9f)\nOrigin (%.9f, %.9f)\n", tx2, ty2, dx, dy, x2, y2); + * printf("Acuuracy (%.9f, X:%.9f, Y:%.9f)nn", sqrt((dx-x2)*(dx-x2)+(dy-y2)*(dy-y2)), (dx-x2), (dy-y2)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD67->TWD97 + * / + * / + * //////////////////////////////////////////// + * + * dx = x1; + * dy = y1; + * dz = z1; + * + * toTWD97(&dx, &dy, &dz); + * + * dx1 = dx; + * dy1 = dy; + * + * toTM2(TWD97_A, TWD97_ECC, TWD97_ECC2, 0, 121, TWD97_TM2, &dx1, &dy1); + * + * dx1 += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD67->TWD97\nTWD67 (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x1, y1, z1, tx1, ty1); + * printf("Convert (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", dx, dy, dz, dx1, dy1); + * printf("Origin (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x2, y2, z2, tx2, ty2); + * printf("Acuuracy (%.4f, X:%.4f, Y:%.4f)nn", sqrt((dx1-tx2)*(dx1-tx2)+(dy1-ty2)*(dy1-ty2)), (dx1-tx2), (dy1-ty2)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD97->TWD67 + * / + * / + * //////////////////////////////////////////// + * + * dx = x2; + * dy = y2; + * dz = z2; + * + * toTWD67(&dx, &dy, &dz); + * + * dx1 = dx; + * dy1 = dy; + * + * toTM2(TWD67_A, TWD67_ECC, TWD67_ECC2, 0, 121, TWD67_TM2, &dx1, &dy1); + * + * dx1 += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD97->TWD67nTWD97 (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x2, y2, z2, tx2, ty2); + * printf("Convert (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", dx, dy, dz, dx1, dy1); + * printf("Origin (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x1, y1, z1, tx1, ty1); + * printf("Acuuracy (%.4f, X:%.4f, Y:%.4f)nn", sqrt((dx1-tx1)*(dx1-tx1)+(dy1-ty1)*(dy1-ty1)), (dx1-tx1), (dy1-ty1)); + * } + */ + + /** + * ��TM2�y���ഫ��TWD97�y�� + * + * @param pt TM2��m + * @return �s��TWD97�y�� + */ + public static Coordinate fromTM2ToTWD97(Coordinate pt) + { + Coordinate ptTWD67 = fromTM2(TWD67_A, TWD67_ECC, TWD67_ECC2, 0, 121, TWD67_TM2, pt.x - 250000.0, pt.y); + ptTWD67.z = 0; + Coordinate ptTWD97 = toTWD97(ptTWD67); + Coordinate pt97TM2 = toTM2(TWD97_A, TWD97_ECC, TWD97_ECC2, 0, 121, TWD97_TM2, ptTWD97.x, ptTWD97.y); + pt97TM2.x += 250000.0; + pt97TM2.y -= 200.0; + return pt97TM2; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java new file mode 100644 index 0000000..ebbcd74 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java @@ -0,0 +1,339 @@ +package com.ximple.eofms.util.postjts; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; + +public class JTSShape implements Shape +{ + static GeometryFactory fac = new GeometryFactory(); + + Geometry geom; + + final static LinearRing[] NOSHELLS = {}; + + public JTSShape(Geometry _geom) + { + this.geom = _geom; + } + + public JTSShape(JtsGeometry _geom) + { + this(_geom.getGeometry()); + } + + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + public boolean contains(double x, double y) + { + Coordinate c = new Coordinate(x, y); + Point p = fac.createPoint(c); + return geom.contains(p); + } + + public boolean contains(Rectangle2D r) + { + return contains(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); + } + + public boolean contains(double x, double y, double w, double h) + { + Polygon p = createRect(x, y, w, h); + return geom.contains(p); + } + + protected Polygon createRect(double x, double y, double w, double h) + { + double[] arr = {x, y, x + w, y, x + w, y + h, x, y + h, x, y}; + PackedCoordinateSequence shell = new PackedCoordinateSequence.Double(arr, 2); + Polygon p = fac.createPolygon(fac.createLinearRing(shell), NOSHELLS); + return p; + } + + public Rectangle2D getBounds2D() + { + Envelope env = geom.getEnvelopeInternal(); + return new Rectangle2D.Double(env.getMinX(), env.getMaxX(), env.getWidth(), env.getHeight()); + } + + public Rectangle getBounds() + { + // We deal simple code for efficiency here, the getBounds() rounding + // rules are ugly... + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(AffineTransform at) + { + return getPathIterator(geom, at); + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + // we don't have much work here, as we only have linear segments, no + // "flattening" necessary. + return getPathIterator(at); + } + + public boolean intersects(Rectangle2D r) + { + return intersects(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); + } + + public boolean intersects(double x, double y, double w, double h) + { + Polygon p = createRect(x, y, w, h); + return geom.intersects(p); + } + + public static GeometryPathIterator getPathIterator(Geometry geometry, AffineTransform _at) + { + if (geometry instanceof Point) + { + return new PointPathIterator((Point) geometry, _at); + } else if (geometry instanceof LineString) + { + return new LineStringPathIterator((LineString) geometry, _at); + } else if (geometry instanceof Polygon) + { + return new PolygonPathIterator((Polygon) geometry, _at); + } else + { + return new GeometryCollectionPathIterator((GeometryCollection) geometry, _at); + } + } + + public static abstract class GeometryPathIterator implements PathIterator + { + + protected final AffineTransform at; + protected int index = 0; + + GeometryPathIterator(AffineTransform _at) + { + this.at = _at; + } + + public final int getWindingRule() + { + return PathIterator.WIND_EVEN_ODD; + } + + public void next() + { + index++; + } + } + + public static class PointPathIterator extends GeometryPathIterator + { + final Point p; + + public PointPathIterator(Point _p, AffineTransform _at) + { + super(_at); + p = _p; + } + + public int currentSegment(float[] coords) + { + switch (index) + { + case 0: + coords[0] = (float) p.getX(); + coords[1] = (float) p.getY(); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + case 1: + return PathIterator.SEG_CLOSE; + default: + throw new IllegalStateException(); + } + } + + public int currentSegment(double[] coords) + { + switch (index) + { + case 0: + coords[0] = p.getX(); + coords[1] = p.getY(); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + case 1: + return PathIterator.SEG_CLOSE; + default: + throw new IllegalStateException(); + } + } + + public boolean isDone() + { + return index > 1; + } + } + + public static class LineStringPathIterator extends GeometryPathIterator + { + CoordinateSequence cs; + + final boolean isRing; + + public LineStringPathIterator(LineString ls, AffineTransform _at) + { + super(_at); + cs = ls.getCoordinateSequence(); + isRing = ls instanceof LinearRing; + } + + /** + * only to be called from PolygonPathIterator subclass + */ + protected void reInit(CoordinateSequence _cs) + { + cs = _cs; + index = 0; + } + + public int currentSegment(float[] coords) + { + if (index == 0) + { + coords[0] = (float) cs.getOrdinate(index, 0); + coords[1] = (float) cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + } else if (index < cs.size()) + { + coords[0] = (float) cs.getOrdinate(index, 0); + coords[1] = (float) cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_LINETO; + } else if (isRing && index == cs.size()) + { + return PathIterator.SEG_CLOSE; + } else + { + throw new IllegalStateException(); + } + } + + public int currentSegment(double[] coords) + { + if (index == 0) + { + coords[0] = cs.getOrdinate(index, 0); + coords[1] = cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + } else if (index < cs.size()) + { + coords[0] = cs.getOrdinate(index, 0); + coords[1] = cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_LINETO; + } else if (isRing && index == cs.size()) + { + return PathIterator.SEG_CLOSE; + } else + { + throw new IllegalStateException(); + } + } + + public boolean isDone() + { + return isRing ? index > cs.size() : index >= cs.size(); + } + } + + public static class PolygonPathIterator extends LineStringPathIterator + { + final Polygon pg; + int outerindex = -1; + + public PolygonPathIterator(Polygon _pg, AffineTransform _at) + { + super(_pg.getExteriorRing(), _at); + pg = _pg; + index = -1; + } + + public boolean isDone() + { + return outerindex >= pg.getNumInteriorRing(); + } + + public void next() + { + super.next(); + if (super.isDone()) + { + outerindex++; + if (outerindex < pg.getNumInteriorRing()) + { + super.reInit(pg.getInteriorRingN(outerindex).getCoordinateSequence()); + } + } + } + } + + public static class GeometryCollectionPathIterator extends GeometryPathIterator + { + final GeometryCollection coll; + GeometryPathIterator current; + + public GeometryCollectionPathIterator(GeometryCollection _coll, AffineTransform _at) + { + super(_at); + coll = _coll; + current = getPathIterator(coll.getGeometryN(index), _at); + } + + public boolean isDone() + { + return index > coll.getNumGeometries(); + } + + public void next() + { + current.next(); + if (current.isDone()) + { + index++; + if (index < coll.getNumGeometries()) + { + current = getPathIterator(coll.getGeometryN(index), at); + } + } + } + + public int currentSegment(float[] coords) + { + return current.currentSegment(coords); + } + + public int currentSegment(double[] coords) + { + return current.currentSegment(coords); + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java new file mode 100644 index 0000000..1ee359a --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java @@ -0,0 +1,287 @@ +/* + * JtsBinaryParser.java + * + * Binary Parser for JTS - relies on org.postgis V1.0.0+ package. + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ +package com.ximple.eofms.util.postjts; + +import org.postgis.binary.ByteGetter; +import org.postgis.binary.ByteGetter.BinaryByteGetter; +import org.postgis.binary.ByteGetter.StringByteGetter; +import org.postgis.binary.ValueGetter; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; + +/** + * Parse binary representation of geometries. Currently, only text rep (hexed) + * implementation is tested. + * <p/> + * It should be easy to add char[] and CharSequence ByteGetter instances, + * although the latter one is not compatible with older jdks. + * <p/> + * I did not implement real unsigned 32-bit integers or emulate them with long, + * as both java Arrays and Strings currently can have only 2^31-1 elements + * (bytes), so we cannot even get or build Geometries with more than approx. + * 2^28 coordinates (8 bytes each). + * + * @author Markus Schaber, markus.schaber@logix-tt.com + */ +public class JtsBinaryParser +{ + + /** + * Get the appropriate ValueGetter for my endianness + * + * @param bytes The appropriate Byte Getter + * @return the ValueGetter + */ + public static ValueGetter valueGetterForEndian(ByteGetter bytes) + { + if (bytes.get(0) == ValueGetter.XDR.NUMBER) + { // XDR + return new ValueGetter.XDR(bytes); + } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) + { + return new ValueGetter.NDR(bytes); + } else + { + throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); + } + } + + /** + * Parse a hex encoded geometry + */ + public Geometry parse(String value) + { + StringByteGetter bytes = new ByteGetter.StringByteGetter(value); + return parseGeometry(valueGetterForEndian(bytes)); + } + + /** + * Parse a binary encoded geometry. + */ + public Geometry parse(byte[] value) + { + BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value); + return parseGeometry(valueGetterForEndian(bytes)); + } + + /** + * Parse a geometry starting at offset. + */ + protected Geometry parseGeometry(ValueGetter data) + { + return parseGeometry(data, 0, false); + } + + /** + * Parse with a known geometry factory + */ + protected Geometry parseGeometry(ValueGetter data, int srid, boolean inheritSrid) + { + byte endian = data.getByte(); // skip and test endian flag + if (endian != data.endian) + { + throw new IllegalArgumentException("Endian inconsistency!"); + } + int typeword = data.getInt(); + + int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits + + boolean haveZ = (typeword & 0x80000000) != 0; + boolean haveM = (typeword & 0x40000000) != 0; + boolean haveS = (typeword & 0x20000000) != 0; + + if (haveS) + { + int newsrid = data.getInt(); + if (inheritSrid && newsrid != srid) + { + throw new IllegalArgumentException("Inconsistent srids in complex geometry: " + srid + ", " + newsrid); + } else + { + srid = newsrid; + } + } else if (!inheritSrid) + { + srid = -1; + } + + Geometry result; + switch (realtype) + { + case org.postgis.Geometry.POINT: + result = parsePoint(data, haveZ, haveM); + break; + case org.postgis.Geometry.LINESTRING: + result = parseLineString(data, haveZ, haveM); + break; + case org.postgis.Geometry.POLYGON: + result = parsePolygon(data, haveZ, haveM, srid); + break; + case org.postgis.Geometry.MULTIPOINT: + result = parseMultiPoint(data, srid); + break; + case org.postgis.Geometry.MULTILINESTRING: + result = parseMultiLineString(data, srid); + break; + case org.postgis.Geometry.MULTIPOLYGON: + result = parseMultiPolygon(data, srid); + break; + case org.postgis.Geometry.GEOMETRYCOLLECTION: + result = parseCollection(data, srid); + break; + default: + throw new IllegalArgumentException("Unknown Geometry Type!"); + } + + result.setSRID(srid); + + return result; + } + + private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) + { + double X = data.getDouble(); + double Y = data.getDouble(); + Point result; + if (haveZ) + { + double Z = data.getDouble(); + result = JtsGeometry.geofac.createPoint(new Coordinate(X, Y, Z)); + } else + { + result = JtsGeometry.geofac.createPoint(new Coordinate(X, Y)); + } + + if (haveM) + { // skip M value + data.getDouble(); + } + + return result; + } + + /** + * Parse an Array of "full" Geometries + */ + private void parseGeometryArray(ValueGetter data, Geometry[] container, int srid) + { + for (int i = 0; i < container.length; i++) + { + container[i] = parseGeometry(data, srid, true); + } + } + + /** + * Parse an Array of "slim" Points (without endianness and type, part of + * LinearRing and Linestring, but not MultiPoint! + * + * @param haveZ + * @param haveM + */ + private CoordinateSequence parseCS(ValueGetter data, boolean haveZ, boolean haveM) + { + int count = data.getInt(); + int dims = haveZ ? 3 : 2; + CoordinateSequence cs = new PackedCoordinateSequence.Double(count, dims); + + for (int i = 0; i < count; i++) + { + for (int d = 0; d < dims; d++) + { + cs.setOrdinate(i, d, data.getDouble()); + } + if (haveM) + { // skip M value + data.getDouble(); + } + } + return cs; + } + + private MultiPoint parseMultiPoint(ValueGetter data, int srid) + { + Point[] points = new Point[data.getInt()]; + parseGeometryArray(data, points, srid); + return JtsGeometry.geofac.createMultiPoint(points); + } + + private LineString parseLineString(ValueGetter data, boolean haveZ, boolean haveM) + { + return JtsGeometry.geofac.createLineString(parseCS(data, haveZ, haveM)); + } + + private LinearRing parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) + { + return JtsGeometry.geofac.createLinearRing(parseCS(data, haveZ, haveM)); + } + + private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM, int srid) + { + int holecount = data.getInt() - 1; + LinearRing[] rings = new LinearRing[holecount]; + LinearRing shell = parseLinearRing(data, haveZ, haveM); + shell.setSRID(srid); + for (int i = 0; i < holecount; i++) + { + rings[i] = parseLinearRing(data, haveZ, haveM); + rings[i].setSRID(srid); + } + return JtsGeometry.geofac.createPolygon(shell, rings); + } + + private MultiLineString parseMultiLineString(ValueGetter data, int srid) + { + int count = data.getInt(); + LineString[] strings = new LineString[count]; + parseGeometryArray(data, strings, srid); + return JtsGeometry.geofac.createMultiLineString(strings); + } + + private MultiPolygon parseMultiPolygon(ValueGetter data, int srid) + { + int count = data.getInt(); + Polygon[] polys = new Polygon[count]; + parseGeometryArray(data, polys, srid); + return JtsGeometry.geofac.createMultiPolygon(polys); + } + + private GeometryCollection parseCollection(ValueGetter data, int srid) + { + int count = data.getInt(); + Geometry[] geoms = new Geometry[count]; + parseGeometryArray(data, geoms, srid); + return JtsGeometry.geofac.createGeometryCollection(geoms); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java new file mode 100644 index 0000000..36a9d7b --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java @@ -0,0 +1,469 @@ +/* + * JtsBinaryWriter.java + * + * PostGIS extension for PostgreSQL JDBC driver - Binary Writer + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ +package com.ximple.eofms.util.postjts; + +import org.postgis.binary.ByteSetter; +import org.postgis.binary.ValueSetter; + +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; + +/** + * Create binary representation of geometries. Currently, only text rep (hexed) + * implementation is tested. Supports only 2 dimensional geometries. + * <p/> + * It should be easy to add char[] and CharSequence ByteGetter instances, + * although the latter one is not compatible with older jdks. + * <p/> + * I did not implement real unsigned 32-bit integers or emulate them with long, + * as both java Arrays and Strings currently can have only 2^31-1 elements + * (bytes), so we cannot even get or build Geometries with more than approx. + * 2^28 coordinates (8 bytes each). + * + * @author markus.schaber@logi-track.com + */ +public class JtsBinaryWriter +{ + + /** + * Get the appropriate ValueGetter for my endianness + * + * @param bytes The appropriate Byte Getter + * @return the ValueGetter + */ + public static ValueSetter valueSetterForEndian(ByteSetter bytes, byte endian) + { + if (endian == ValueSetter.XDR.NUMBER) + { // XDR + return new ValueSetter.XDR(bytes); + } else if (endian == ValueSetter.NDR.NUMBER) + { + return new ValueSetter.NDR(bytes); + } else + { + throw new IllegalArgumentException("Unknown Endian type:" + endian); + } + } + + /** + * Write a hex encoded geometry + * <p/> + * Currently, geometries with more than 2 dimensions and measures are not + * cleanly supported, but SRID is honored. + */ + public String writeHexed(Geometry geom, byte REP) + { + int length = estimateBytes(geom); + ByteSetter.StringByteSetter bytes = new ByteSetter.StringByteSetter(length); + writeGeometry(geom, valueSetterForEndian(bytes, REP)); + return bytes.result(); + } + + public String writeHexed(Geometry geom) + { + return writeHexed(geom, ValueSetter.NDR.NUMBER); + } + + /** + * Write a binary encoded geometry. + * <p/> + * Currently, geometries with more than 2 dimensions and measures are not + * cleanly supported, but SRID is honored. + */ + public byte[] writeBinary(Geometry geom, byte REP) + { + int length = estimateBytes(geom); + ByteSetter.BinaryByteSetter bytes = new ByteSetter.BinaryByteSetter(length); + writeGeometry(geom, valueSetterForEndian(bytes, REP)); + return bytes.result(); + } + + public byte[] writeBinary(Geometry geom) + { + return writeBinary(geom, ValueSetter.NDR.NUMBER); + } + + /** + * Parse a geometry starting at offset. + */ + protected void writeGeometry(Geometry geom, ValueSetter dest) + { + final int dimension; + if (geom == null) + { + throw new NullPointerException(); + } else if (geom.isEmpty()) + { + // don't set any flag bits + dimension = 0; + } else + { + dimension = getCoordDim(geom); + if (dimension < 2 || dimension > 4) + { + throw new IllegalArgumentException("Unsupported geometry dimensionality: " + dimension); + } + } + // write endian flag + dest.setByte(dest.endian); + + // write typeword + final int plaintype = getWKBType(geom); + int typeword = plaintype; + if (dimension == 3 || dimension == 4) + { + typeword |= 0x80000000; + } + if (dimension == 4) + { + typeword |= 0x40000000; + } + + final boolean haveSrid = checkSrid(geom); + if (haveSrid) + { + typeword |= 0x20000000; + } + + dest.setInt(typeword); + + if (haveSrid) + { + dest.setInt(geom.getSRID()); + } + + switch (plaintype) + { + case org.postgis.Geometry.POINT: + writePoint((Point) geom, dest); + break; + case org.postgis.Geometry.LINESTRING: + writeLineString((LineString) geom, dest); + break; + case org.postgis.Geometry.POLYGON: + writePolygon((Polygon) geom, dest); + break; + case org.postgis.Geometry.MULTIPOINT: + writeMultiPoint((MultiPoint) geom, dest); + break; + case org.postgis.Geometry.MULTILINESTRING: + writeMultiLineString((MultiLineString) geom, dest); + break; + case org.postgis.Geometry.MULTIPOLYGON: + writeMultiPolygon((MultiPolygon) geom, dest); + break; + case org.postgis.Geometry.GEOMETRYCOLLECTION: + writeCollection((GeometryCollection) geom, dest); + break; + default: + throw new IllegalArgumentException("Unknown Geometry Type: " + plaintype); + } + } + + public static int getWKBType(Geometry geom) + { + // We always write emtpy geometries as emtpy collections - for OpenGIS + // conformance + if (geom.isEmpty()) + { + return org.postgis.Geometry.GEOMETRYCOLLECTION; + } else if (geom instanceof Point) + { + return org.postgis.Geometry.POINT; + } else if (geom instanceof com.vividsolutions.jts.geom.LineString) + { + return org.postgis.Geometry.LINESTRING; + } else if (geom instanceof com.vividsolutions.jts.geom.Polygon) + { + return org.postgis.Geometry.POLYGON; + } else if (geom instanceof MultiPoint) + { + return org.postgis.Geometry.MULTIPOINT; + } else if (geom instanceof MultiLineString) + { + return org.postgis.Geometry.MULTILINESTRING; + } else if (geom instanceof com.vividsolutions.jts.geom.MultiPolygon) + { + return org.postgis.Geometry.MULTIPOLYGON; + } + if (geom instanceof com.vividsolutions.jts.geom.GeometryCollection) + { + return org.postgis.Geometry.GEOMETRYCOLLECTION; + } else + { + throw new IllegalArgumentException("Unknown Geometry Type: " + geom.getClass().getName()); + } + } + + /** + * Writes a "slim" Point (without endiannes, srid ant type, only the + * ordinates and measure. Used by writeGeometry. + */ + private void writePoint(Point geom, ValueSetter dest) + { + writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); + } + + /** + * Write a Coordinatesequence, part of LinearRing and Linestring, but not + * MultiPoint! + */ + private void writeCoordinates(CoordinateSequence seq, int dims, ValueSetter dest) + { + for (int i = 0; i < seq.size(); i++) + { + for (int d = 0; d < dims; d++) + { + dest.setDouble(seq.getOrdinate(i, d)); + } + } + } + + private void writeMultiPoint(MultiPoint geom, ValueSetter dest) + { + dest.setInt(geom.getNumPoints()); + for (int i = 0; i < geom.getNumPoints(); i++) + { + writeGeometry(geom.getGeometryN(i), dest); + } + } + + private void writeLineString(LineString geom, ValueSetter dest) + { + dest.setInt(geom.getNumPoints()); + writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); + } + + private void writePolygon(Polygon geom, ValueSetter dest) + { + dest.setInt(geom.getNumInteriorRing() + 1); + writeLineString(geom.getExteriorRing(), dest); + for (int i = 0; i < geom.getNumInteriorRing(); i++) + { + writeLineString(geom.getInteriorRingN(i), dest); + } + } + + private void writeMultiLineString(MultiLineString geom, ValueSetter dest) + { + writeGeometryArray(geom, dest); + } + + private void writeMultiPolygon(MultiPolygon geom, ValueSetter dest) + { + writeGeometryArray(geom, dest); + } + + private void writeCollection(GeometryCollection geom, ValueSetter dest) + { + writeGeometryArray(geom, dest); + } + + private void writeGeometryArray(Geometry geom, ValueSetter dest) + { + dest.setInt(geom.getNumGeometries()); + for (int i = 0; i < geom.getNumGeometries(); i++) + { + writeGeometry(geom.getGeometryN(i), dest); + } + } + + /** + * Estimate how much bytes a geometry will need in WKB. + */ + protected int estimateBytes(Geometry geom) + { + int result = 0; + + // write endian flag + result += 1; + + // write typeword + result += 4; + + if (checkSrid(geom)) + { + result += 4; + } + + switch (getWKBType(geom)) + { + case org.postgis.Geometry.POINT: + result += estimatePoint((Point) geom); + break; + case org.postgis.Geometry.LINESTRING: + result += estimateLineString((LineString) geom); + break; + case org.postgis.Geometry.POLYGON: + result += estimatePolygon((Polygon) geom); + break; + case org.postgis.Geometry.MULTIPOINT: + result += estimateMultiPoint((MultiPoint) geom); + break; + case org.postgis.Geometry.MULTILINESTRING: + result += estimateMultiLineString((MultiLineString) geom); + break; + case org.postgis.Geometry.MULTIPOLYGON: + result += estimateMultiPolygon((MultiPolygon) geom); + break; + case org.postgis.Geometry.GEOMETRYCOLLECTION: + result += estimateCollection((GeometryCollection) geom); + break; + default: + throw new IllegalArgumentException("Unknown Geometry Type: " + getWKBType(geom)); + } + return result; + } + + private boolean checkSrid(Geometry geom) + { + final int srid = geom.getSRID(); + // SRID is default 0 with jts geometries + return (srid != -1) && (srid != 0); + } + + private int estimatePoint(Point geom) + { + return 8 * getCoordDim(geom); + } + + /** + * Write an Array of "full" Geometries + */ + private int estimateGeometryArray(Geometry container) + { + int result = 0; + for (int i = 0; i < container.getNumGeometries(); i++) + { + result += estimateBytes(container.getGeometryN(i)); + } + return result; + } + + /** + * Estimate an array of "fat" Points + */ + private int estimateMultiPoint(MultiPoint geom) + { + // int size + int result = 4; + if (geom.getNumGeometries() > 0) + { + // We can shortcut here, compared to estimateGeometryArray, as all + // subgeoms have the same fixed size + result += geom.getNumGeometries() * estimateBytes(geom.getGeometryN(0)); + } + return result; + } + + private int estimateLineString(LineString geom) + { + if (geom == null || geom.getNumGeometries() == 0) + { + return 0; + } else + { + return 4 + 8 * getCoordSequenceDim(geom.getCoordinateSequence()) * geom.getCoordinateSequence().size(); + } + } + + private int estimatePolygon(Polygon geom) + { + // int length + int result = 4; + result += estimateLineString(geom.getExteriorRing()); + for (int i = 0; i < geom.getNumInteriorRing(); i++) + { + result += estimateLineString(geom.getInteriorRingN(i)); + } + return result; + } + + private int estimateMultiLineString(MultiLineString geom) + { + // 4-byte count + subgeometries + return 4 + estimateGeometryArray(geom); + } + + private int estimateMultiPolygon(MultiPolygon geom) + { + // 4-byte count + subgeometries + return 4 + estimateGeometryArray(geom); + } + + private int estimateCollection(GeometryCollection geom) + { + // 4-byte count + subgeometries + return 4 + estimateGeometryArray(geom); + } + + public static final int getCoordDim(Geometry geom) + { + if (geom.isEmpty()) + { + return 0; + } + if (geom instanceof Point) + { + return getCoordSequenceDim(((Point) geom).getCoordinateSequence()); + } else if (geom instanceof LineString) + { + return getCoordSequenceDim(((LineString) geom).getCoordinateSequence()); + } else if (geom instanceof Polygon) + { + return getCoordSequenceDim(((Polygon) geom).getExteriorRing().getCoordinateSequence()); + } else + { + return getCoordDim(geom.getGeometryN(0)); + } + } + + public static final int getCoordSequenceDim(CoordinateSequence coords) + { + if (coords == null || coords.size() == 0) + return 0; + // JTS has a really strange way to handle dimensions! + // Just have a look at PackedCoordinateSequence and + // CoordinateArraySequence + int dimensions = coords.getDimension(); + if (dimensions == 3) + { + // CoordinateArraySequence will always return 3, so we have to + // check, if + // the third ordinate contains NaN, then the geom is actually + // 2-dimensional + return Double.isNaN(coords.getOrdinate(0, CoordinateSequence.Z)) ? 2 : 3; + } else + { + return dimensions; + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java new file mode 100644 index 0000000..18a6295 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java @@ -0,0 +1,187 @@ +/* + * JtsGeometry.java + * + * Wrapper for PostgreSQL JDBC driver to allow transparent reading and writing + * of JTS geometries + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package com.ximple.eofms.util.postjts; + +import java.sql.SQLException; + +import org.postgresql.util.PGobject; + +import com.vividsolutions.jts.geom.CoordinateSequenceFactory; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.PrecisionModel; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory; +import com.vividsolutions.jts.io.WKTReader; + +/** + * JTS Geometry SQL wrapper. Supports PostGIS 1.x (lwgeom hexwkb) for writing + * and both PostGIS 0.x (EWKT) and 1.x (lwgeom hexwkb) for reading. + * + * @author Markus Schaber + */ + +public class JtsGeometry extends PGobject +{ + /* JDK 1.5 Serialization */ + private static final long serialVersionUID = 0x100; + + Geometry geom; + + final static JtsBinaryParser bp = new JtsBinaryParser(); + + final static JtsBinaryWriter bw = new JtsBinaryWriter(); + + final static PrecisionModel prec = new PrecisionModel(); + + final static CoordinateSequenceFactory csfac = PackedCoordinateSequenceFactory.DOUBLE_FACTORY; + + final static GeometryFactory geofac = new GeometryFactory(prec, 0, csfac); + + static final WKTReader reader = new WKTReader(geofac); + + /** + * Constructor called by JDBC drivers + */ + public JtsGeometry() + { + setType("geometry"); + } + + public JtsGeometry(Geometry geom) + { + this(); + this.geom = geom; + } + + public JtsGeometry(String value) throws SQLException + { + this(); + setValue(value); + } + + public void setValue(String value) throws SQLException + { + geom = geomFromString(value); + } + + public static Geometry geomFromString(String value) throws SQLException + { + try + { + value = value.trim(); + if (value.startsWith("00") || value.startsWith("01")) + { + return bp.parse(value); + } else + { + Geometry result; + // no srid := 0 in JTS world + int srid = 0; + // break up geometry into srid and wkt + if (value.startsWith("SRID=")) + { + String[] temp = value.split(";"); + value = temp[1].trim(); + srid = Integer.parseInt(temp[0].substring(5)); + } + + result = reader.read(value); + setSridRecurse(result, srid); + return result; + } + } catch (Exception E) + { + E.printStackTrace(); + throw new SQLException("Error parsing SQL data:" + E); + } + } + + /** + * Recursively set a srid for the geometry and all subgeometries + */ + public static void setSridRecurse(final Geometry geom, final int srid) + { + geom.setSRID(srid); + if (geom instanceof GeometryCollection) + { + final int subcnt = geom.getNumGeometries(); + for (int i = 0; i < subcnt; i++) + { + setSridRecurse(geom.getGeometryN(i), srid); + } + } else if (geom instanceof Polygon) + { + Polygon poly = (Polygon) geom; + poly.getExteriorRing().setSRID(srid); + final int subcnt = poly.getNumInteriorRing(); + for (int i = 0; i < subcnt; i++) + { + poly.getInteriorRingN(i).setSRID(srid); + } + } + } + + public Geometry getGeometry() + { + return geom; + } + + public String toString() + { + return geom.toString(); + } + + public String getValue() + { + return bw.writeHexed(getGeometry()); + } + + public Object clone() + { + JtsGeometry obj = new JtsGeometry(geom); + obj.setType(type); + return obj; + } + + public boolean equals(Object obj) + { + if ((obj != null) && (obj instanceof JtsGeometry)) + { + Geometry other = ((JtsGeometry) obj).geom; + if (this.geom == other) + { // handles identity as well as both + // ==null + return true; + } else if (this.geom != null && other != null) + { + return other.equals(this.geom); + } + } + return false; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java new file mode 100644 index 0000000..1af43b4 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java @@ -0,0 +1,173 @@ +/* + * JtsWrapper.java + * + * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver + * connected to a PostGIS enabled PostgreSQL server. + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package com.ximple.eofms.util.postjts; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +import org.postgresql.Driver; +import org.postgresql.PGConnection; + +/** + * JtsGisWrapper + * <p/> + * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. + * <p/> + * This method currently works with J2EE DataSource implementations, and with + * DriverManager framework. + * <p/> + * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_JTS" in the + * jdbc URL. + * + * @author markus.schaber@logix-tt.com + */ +public class JtsGisWrapper extends Driver +{ + + private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; + private static final String POSTGIS_PROTOCOL = "jdbc:postgresql_JTS:"; + public static final String REVISION = "$Revision: 1977 $"; + + public JtsGisWrapper() + { + super(); + } + + static + { + try + { + // Analogy to org.postgresql.Driver + java.sql.DriverManager.registerDriver(new JtsGisWrapper()); + } catch (SQLException e) + { + e.printStackTrace(); + } + } + + /** + * Creates a postgresql connection, and then adds the PostGIS data types to + * it calling addpgtypes() + * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection arguments + * @return a connection to the URL or null if it isnt us + * @throws SQLException if a database access error occurs + * @see java.sql.Driver#connect + * @see org.postgresql.Driver + */ + public java.sql.Connection connect(String url, Properties info) throws SQLException + { + url = mangleURL(url); + Connection result = super.connect(url, info); + addGISTypes((PGConnection) result); + return result; + } + + /** + * adds the JTS/PostGIS Data types to a PG Connection. + * + * @param pgconn + * @throws SQLException + */ + public static void addGISTypes(PGConnection pgconn) throws SQLException + { + pgconn.addDataType("geometry", JtsGeometry.class); + pgconn.addDataType("box3d", org.postgis.PGbox3d.class); + pgconn.addDataType("box2d", org.postgis.PGbox2d.class); + } + + /** + * Mangles the PostGIS URL to return the original PostGreSQL URL + * @param url url + * @return string + * @throws java.sql.SQLException error + */ + public static String mangleURL(String url) throws SQLException + { + if (url.startsWith(POSTGIS_PROTOCOL)) + { + return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); + } else + { + throw new SQLException("Unknown protocol or subprotocol in url " + url); + } + } + + /** + * Returns true if the driver thinks it can open a connection to the given + * URL. Typically, drivers will return true if they understand the + * subprotocol specified in the URL and false if they don't. Our protocols + * start with jdbc:postgresql_postGIS: + * + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @throws SQLException if a database-access error occurs (Dont know why + * it would *shrug*) + * @see java.sql.Driver#acceptsURL + */ + public boolean acceptsURL(String url) throws SQLException + { + try + { + url = mangleURL(url); + } catch (SQLException e) + { + return false; + } + return super.acceptsURL(url); + } + + /** + * Gets the underlying drivers major version number + * + * @return the drivers major version number + */ + + public int getMajorVersion() + { + return super.getMajorVersion(); + } + + /** + * Get the underlying drivers minor version number + * + * @return the drivers minor version number + */ + public int getMinorVersion() + { + return super.getMinorVersion(); + } + + /** + * Returns our own CVS version plus postgres Version + */ + public static String getVersion() + { + return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java new file mode 100644 index 0000000..b87f551 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java @@ -0,0 +1,180 @@ +/* + * JtsWrapper.java + * + * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver + * connected to a PostGIS enabled PostgreSQL server. + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package com.ximple.eofms.util.postjts; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.postgresql.Driver; +import org.postgresql.PGConnection; + +/** + * DriverWrapper + * <p/> + * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. + * <p/> + * This method currently works with J2EE DataSource implementations, and with + * DriverManager framework. + * <p/> + * Simply replace the "jdbc:postgresql:" with a "jdbc:postgres_jts:" in the jdbc + * URL. + * <p/> + * When using the drivermanager, you need to initialize JtsWrapper instead of + * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource + * implementation, set the driver class property in the datasource config, the + * following works for jboss: + * <p/> + * <driver-class>org.postgis.jts.PostGisWrapper</driver-class> + * + * @author markus.schaber@logix-tt.com + */ +public class JtsWrapper extends Driver +{ + + protected static final Logger logger = Logger.getLogger("org.postgis.DriverWrapper"); + + private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; + private static final String POSTGIS_PROTOCOL = "jdbc:postgres_jts:"; + public static final String REVISION = "$Revision: 2570 $"; + + public JtsWrapper() + { + super(); + } + + static + { + try + { + // Try to register ourself to the DriverManager + java.sql.DriverManager.registerDriver(new JtsWrapper()); + } catch (SQLException e) + { + logger.log(Level.WARNING, "Error registering PostgreSQL Jts Wrapper Driver", e); + } + } + + /** + * Creates a postgresql connection, and then adds the JTS GIS data types to + * it calling addpgtypes() + * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection arguments + * @return a connection to the URL or null if it isnt us + * @throws SQLException if a database access error occurs + * @see java.sql.Driver#connect + * @see org.postgresql.Driver + */ + public java.sql.Connection connect(String url, Properties info) throws SQLException + { + url = mangleURL(url); + Connection result = super.connect(url, info); + addGISTypes((PGConnection) result); + return result; + } + + /** + * adds the JTS/PostGIS Data types to a PG Connection. + * + * @param pgconn postgres connection + * @throws SQLException error + */ + public static void addGISTypes(PGConnection pgconn) throws SQLException + { + pgconn.addDataType("geometry", JtsGeometry.class); + } + + /** + * Mangles the PostGIS URL to return the original PostGreSQL URL + * @param url url + * @return string + * @throws java.sql.SQLException erroe + */ + public static String mangleURL(String url) throws SQLException + { + if (url.startsWith(POSTGIS_PROTOCOL)) + { + return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); + } else + { + throw new SQLException("Unknown protocol or subprotocol in url " + url); + } + } + + /** + * Check whether the driver thinks he can handle the given URL. + * + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @throws SQLException Passed through from the underlying PostgreSQL + * driver, should not happen. + * @see java.sql.Driver#acceptsURL + */ + public boolean acceptsURL(String url) throws SQLException + { + try + { + url = mangleURL(url); + } catch (SQLException e) + { + return false; + } + return super.acceptsURL(url); + } + + /** + * Gets the underlying drivers major version number + * + * @return the drivers major version number + */ + + public int getMajorVersion() + { + return super.getMajorVersion(); + } + + /** + * Get the underlying drivers minor version number + * + * @return the drivers minor version number + */ + public int getMinorVersion() + { + return super.getMinorVersion(); + } + + /** + * Returns our own CVS version plus postgres Version + * @return version + */ + public static String getVersion() + { + return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml b/xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml new file mode 100644 index 0000000..9686501 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml @@ -0,0 +1,176 @@ +<?xml version='1.0' encoding="big5"?> +<!DOCTYPE digester-rules PUBLIC "-//Jakarta Apache //DTD digester-rules XML V1.0//EN" "digester-rules.dtd"> +<digester-rules> + <pattern value="ElementDispatcherRules"> + <object-create-rule classname="com.ximple.eofms.filter.ElementDispatcher"/> + <set-properties-rule/> + <pattern value="TypeFilter"> + <object-create-rule classname="com.ximple.eofms.filter.TypeIdDispatchableFilter"/> + <set-next-rule methodname="addRule" paramtype="com.ximple.eofms.filter.ElementDispatchableFilter"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="name"/> + <bean-property-setter-rule pattern="description"/> + <bean-property-setter-rule pattern="elmtype"/> + <bean-property-setter-rule pattern="tid"/> + <pattern value="LineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="TextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="SymbolCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateSymbolStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="LineTextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ArcLineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateArcLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="EllipseShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateEllipseShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ComplexChainCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateComplexChainStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + </pattern> + <pattern value="TypeCompFilter"> + <object-create-rule classname="com.ximple.eofms.filter.TypeCompIdDispatchableFilter"/> + <set-next-rule methodname="addRule" paramtype="com.ximple.eofms.filter.ElementDispatchableFilter"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="name"/> + <bean-property-setter-rule pattern="description"/> + <!-- <bean-property-setter-rule pattern="elmtype"/> --> + <bean-property-setter-rule pattern="tid"/> + <bean-property-setter-rule pattern="cid"/> + <pattern value="elementCriterion"> + <object-create-rule classname="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-next-rule methodname="addCriterion" paramtype="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="elementType"/> + </pattern> + <pattern value="LineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="TextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="SymbolCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateSymbolStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="LineTextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ArcLineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateArcLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="EllipseShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateEllipseShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ComplexChainCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateComplexChainStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + </pattern> + <pattern value="TypeCompLevelFilter"> + <object-create-rule classname="com.ximple.eofms.filter.TypeCompLevelIdDispatchableFilter"/> + <set-next-rule methodname="addRule" paramtype="com.ximple.eofms.filter.ElementDispatchableFilter"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="name"/> + <bean-property-setter-rule pattern="description"/> + <!-- <bean-property-setter-rule pattern="elmtype"/> --> + <bean-property-setter-rule pattern="tid"/> + <bean-property-setter-rule pattern="cid"/> + <!-- <bean-property-setter-rule pattern="lid"/> --> + <pattern value="elementCriterion"> + <object-create-rule classname="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-next-rule methodname="addCriterion" paramtype="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="elementType"/> + </pattern> + <pattern value="elementLayerCriterion"> + <object-create-rule classname="com.ximple.eofms.filter.ElementLevelCriterion"/> + <set-next-rule methodname="addLayerCriterion" paramtype="com.ximple.eofms.filter.ElementLevelCriterion"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="elementLayer"/> + </pattern> + <pattern value="LineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="TextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="SymbolCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateSymbolStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="LineTextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ArcLineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateArcLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="EllipseShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateEllipseShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ComplexChainCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateComplexChainStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + </pattern> + </pattern> +</digester-rules> \ No newline at end of file diff --git a/xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/FeatureClassificationRules.xml b/xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/FeatureClassificationRules.xml new file mode 100644 index 0000000..e925ce6 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/FeatureClassificationRules.xml @@ -0,0 +1,16 @@ +<?xml version='1.0' encoding="big5"?> +<!DOCTYPE digester-rules PUBLIC "-//Jakarta Apache //DTD digester-rules XML V1.0//EN" "digester-rules.dtd"> +<digester-rules> + <pattern value="FeatureClassificationRules"> + <object-create-rule classname="com.ximple.eofms.collector.FeatureClassification"/> + <set-properties-rule/> + <pattern value="FeatureTypeCollector"> + <object-create-rule classname="com.ximple.eofms.collector.FeatureTypeCollector"/> + <set-next-rule methodname="addCollector" paramtype="com.ximple.eofms.collector.FeatureTypeCollector"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="name"/> + <bean-property-setter-rule pattern="description"/> + <bean-property-setter-rule pattern="featuretypeList"/> + </pattern> + </pattern> +</digester-rules> \ No newline at end of file diff --git a/xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml b/xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml new file mode 100644 index 0000000..a9c3849 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="big5" ?> +<ElementDispatcherRules> + <!-- High Voltage Features --> + <TypeCompLevelFilter name="FSC-106.C-0"> + <tid>106</tid> + <cid>0</cid> + <description>�D�����u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <elementLevelCriterion> + <elementLevel>1</elementLevel> + </elementLevelCriterion> + <LineCreateStrategy/> + </TypeCompLevelFilter> + +</ElementDispatcherRules> diff --git a/xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultConvertShpFilter.xml b/xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultConvertShpFilter.xml new file mode 100644 index 0000000..7e23b2c --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultConvertShpFilter.xml @@ -0,0 +1,1465 @@ +<?xml version="1.0" encoding="big5" ?> +<ElementDispatcherRules> + <!-- High Voltage Features --> + <TypeCompFilter name="FSC-106.C-0"> + <tid>106</tid> + <cid>0</cid> + <description>�D�����u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-106.C-1"> + <tid>106</tid> + <cid>1</cid> + <description>�����u�u</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-106.C-2"> + <tid>106</tid> + <cid>2</cid> + <description>�����u�u���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-106.C-4"> + <tid>106</tid> + <cid>4</cid> + <description>�����u�X�u�N���u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-402.C-0"> + <tid>402</tid> + <cid>0</cid> + <description>�ܹq��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-402.C-1"> + <tid>402</tid> + <cid>1</cid> + <description>�ܹq�ҵ��O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-402.C-2"> + <tid>402</tid> + <cid>2</cid> + <description>�ܹq�Ҥ�����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-0"> + <tid>411</tid> + <cid>0</cid> + <description>�t�q��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-1"> + <tid>411</tid> + <cid>1</cid> + <description>�t�q�����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-2"> + <tid>411</tid> + <cid>2</cid> + <description>�t�q��-1/600</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-3"> + <tid>411</tid> + <cid>3</cid> + <description>�t�q�����O-1/600</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-7"> + <tid>411</tid> + <cid>7</cid> + <description>�t�q��1/600�ޤW�U�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-420.C-0"> + <tid>420</tid> + <cid>0</cid> + <description>��</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-420.C-1"> + <tid>420</tid> + <cid>1</cid> + <description>�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-421.C-0"> + <tid>421</tid> + <cid>0</cid> + <description>�@�P�D</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-421.C-1"> + <tid>421</tid> + <cid>1</cid> + <description>�@�P�D���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-423.C-0"> + <tid>423</tid> + <cid>0</cid> + <description>���_��</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-423.C-1"> + <tid>423</tid> + <cid>1</cid> + <description>���_���u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-424.C-0"> + <tid>424</tid> + <cid>0</cid> + <description>�S��u�k�X�вŸ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-501.C-0"> + <tid>501</tid> + <cid>0</cid> + <description>��ê���X</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-501.C-1"> + <tid>501</tid> + <cid>1</cid> + <description>��ê���X��r���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-502.C-0"> + <tid>502</tid> + <cid>0</cid> + <description>���D���X</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-502.C-1"> + <tid>502</tid> + <cid>1</cid> + <description>���D���X��r���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-503.C-0"> + <tid>503</tid> + <cid>0</cid> + <description>��r���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-0"> + <tid>407</tid> + <cid>0</cid> + <description>�q��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-1"> + <tid>407</tid> + <cid>1</cid> + <description>�q����O</description> + <elementCriterion> + <elementType>17</elementType> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-2"> + <tid>407</tid> + <cid>2</cid> + <description>�q��-1/600</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-3"> + <tid>407</tid> + <cid>3</cid> + <description>�q��-1/600���O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-7"> + <tid>407</tid> + <cid>7</cid> + <description>1/600�q��ޤW�U�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-8"> + <tid>407</tid> + <cid>8</cid> + <description>1/1200�q��ޤW�U�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-9"> + <tid>407</tid> + <cid>9</cid> + <description>�q�������u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>17</elementType> + </elementCriterion> + <LineTextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-10"> + <tid>407</tid> + <cid>10</cid> + <description>�q��츹</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-11"> + <tid>407</tid> + <cid>11</cid> + <description>�q�������u���\</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-0"> + <tid>114</tid> + <cid>0</cid> + <description>�}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-1"> + <tid>114</tid> + <cid>1</cid> + <description>�}���j�����O</description> + <elementCriterion> + <elementType>17</elementType> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-2"> + <tid>114</tid> + <cid>2</cid> + <description>�}���p�P��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-3"> + <tid>114</tid> + <cid>3</cid> + <description>�}���j�P��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-122.C-0"> + <tid>122</tid> + <cid>0</cid> + <description>�����s��</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + <elementType>17</elementType> + </elementCriterion> + <LineTextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-122.C-1"> + <tid>122</tid> + <cid>1</cid> + <description>�����s�����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-107.C-0"> + <tid>107</tid> + <cid>0</cid> + <description>�����Τ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-107.C-2"> + <tid>107</tid> + <cid>2</cid> + <description>�����Τᤤ����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-117.C-0"> + <tid>117</tid> + <cid>0</cid> + <description>Tie������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-105.C-0"> + <tid>105</tid> + <cid>0</cid> + <description>�������Y</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-105.C-1"> + <tid>105</tid> + <cid>1</cid> + <description>�������Y���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-101.C-0"> + <tid>101</tid> + <cid>0</cid> + <description>�y��</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-120.C-0"> + <tid>120</tid> + <cid>0</cid> + <description>�`�I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-150.C-0"> + <tid>150</tid> + <cid>0</cid> + <description>����}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-130.C-0"> + <tid>130</tid> + <cid>0</cid> + <description>�ɽu��e</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-131.C-0"> + <tid>131</tid> + <cid>0</cid> + <description>�ɽu�ܧ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-109.C-0"> + <tid>109</tid> + <cid>0</cid> + <description>���u�s��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-116.C-0"> + <tid>116</tid> + <cid>0</cid> + <description>������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-108.C-0"> + <tid>108</tid> + <cid>0</cid> + <description>�_����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-108.C-1"> + <tid>108</tid> + <cid>1</cid> + <description>�_�������O</description> + <elementCriterion> + <elementType>17</elementType> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-119.C-0"> + <tid>119</tid> + <cid>0</cid> + <description>�q��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-0"> + <tid>115</tid> + <cid>0</cid> + <description>������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-1"> + <tid>115</tid> + <cid>1</cid> + <description>���������O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-2"> + <tid>115</tid> + <cid>2</cid> + <description>���O�t�ι�������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-3"> + <tid>115</tid> + <cid>3</cid> + <description>���O�t�ι����������O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-4"> + <tid>115</tid> + <cid>4</cid> + <description>�C���t�ι�������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-5"> + <tid>115</tid> + <cid>5</cid> + <description>�C���t�ι����������O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-6"> + <tid>115</tid> + <cid>6</cid> + <description>�C���t�ι�-�t�q�Ǯy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-7"> + <tid>115</tid> + <cid>7</cid> + <description>�C���t�ι�-�t�q�Ǯy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-8"> + <tid>115</tid> + <cid>8</cid> + <description>�[��������(�a�U�C����)���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-118.C-0"> + <tid>118</tid> + <cid>0</cid> + <description>�D������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-102.C-0"> + <tid>102</tid> + <cid>0</cid> + <description>�q�e��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-100.C-0"> + <tid>100</tid> + <cid>0</cid> + <description>�p��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-0"> + <tid>140</tid> + <cid>0</cid> + <description>�����u��(�u���ϥ�)</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-1"> + <tid>140</tid> + <cid>1</cid> + <description>�u(�u���ϥ�)</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-2"> + <tid>140</tid> + <cid>2</cid> + <description>�ɽu���O(�u���ϥ�)</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-3"> + <tid>140</tid> + <cid>3</cid> + <description>�X�u�N���u(�u���ϥ�)</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-4"> + <tid>140</tid> + <cid>4</cid> + <description>�X�u�N�����O(�u���ϥ�)</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-151.C-0"> + <tid>150</tid> + <cid>0</cid> + <description>�`���}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <!-- Low Voltage Features --> + <TypeCompFilter name="FSC-200.C-0"> + <tid>200</tid> + <cid>0</cid> + <description>�C���`�I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <!-- *****�C��****** --> + <TypeCompFilter name="FSC-201.C-0"> + <tid>201</tid> + <cid>0</cid> + <description>����u</description> + <elementCriterion> + <elementType>12</elementType> + <elementType>17</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-201.C-1"> + <tid>201</tid> + <cid>1</cid> + <description>����u���O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-201.C-2"> + <tid>201</tid> + <cid>2</cid> + <description>����u�����O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-202.C-0"> + <tid>202</tid> + <cid>0</cid> + <description>�����I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-202.C-1"> + <tid>202</tid> + <cid>1</cid> + <description>�����I���P���O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-203.C-0"> + <tid>203</tid> + <cid>0</cid> + <description>���O�d�������I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-203.C-1"> + <tid>203</tid> + <cid>1</cid> + <description>���O�d�������I���O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-204.C-0"> + <tid>204</tid> + <cid>0</cid> + <description>�C�����u</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-205.C-0"> + <tid>205</tid> + <cid>0</cid> + <description>�C���ɽu</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-205.C-1"> + <tid>205</tid> + <cid>1</cid> + <description>�C���ɽu���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-205.C-2"> + <tid>205</tid> + <cid>2</cid> + <description>�C���ɽu�����O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-206.C-0"> + <tid>206</tid> + <cid>0</cid> + <description>�C�������c</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-206.C-1"> + <tid>206</tid> + <cid>1</cid> + <description>�C�������c���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-206.C-2"> + <tid>206</tid> + <cid>2</cid> + <description>�C�������c���P���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-207.C-0"> + <tid>207</tid> + <cid>0</cid> + <description>�C��ĵ����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-207.C-1"> + <tid>207</tid> + <cid>1</cid> + <description>�C��ĵ�������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-207.C-2"> + <tid>207</tid> + <cid>2</cid> + <description>�C��ĵ�������P���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-208.C-0"> + <tid>208</tid> + <cid>0</cid> + <description>�C����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-209.C-0"> + <tid>209</tid> + <cid>0</cid> + <description>�C����q���x</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-209.C-1"> + <tid>209</tid> + <cid>1</cid> + <description>�C����q���x���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-0"> + <tid>210</tid> + <cid>0</cid> + <description>�C���a�U�ɽu</description> + <elmtype>12</elmtype> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-1"> + <tid>210</tid> + <cid>1</cid> + <description>�C���a�U�ɽu���I�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-2"> + <tid>210</tid> + <cid>2</cid> + <description>�C���a�U�ɽu�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-3"> + <tid>210</tid> + <cid>3</cid> + <description>�C���a�U�ɽu�Ÿ�</description> + <elmtype>4</elmtype> + <elmtype>12</elmtype> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-4"> + <tid>210</tid> + <cid>4</cid> + <description>�C���a�U�ɽu���O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-211.C-0"> + <tid>211</tid> + <cid>0</cid> + <description>�C���[�ű���u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-211.C-1"> + <tid>211</tid> + <cid>1</cid> + <description>�C���[�ű���u</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-211.C-2"> + <tid>211</tid> + <cid>2</cid> + <description>�C���[�ű���u�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-212.C-0"> + <tid>212</tid> + <cid>0</cid> + <description>�C���[�ųs������u</description> + <elementCriterion> + <elementType>4</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-212.C-1"> + <tid>212</tid> + <cid>1</cid> + <description>�C���[�ųs������u���O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-212.C-2"> + <tid>212</tid> + <cid>2</cid> + <description>�C���[�ųs������u�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-213.C-0"> + <tid>213</tid> + <cid>0</cid> + <description>�C���a�U�s������u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-213.C-1"> + <tid>213</tid> + <cid>1</cid> + <description>�C���a�U�s������u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-213.C-2"> + <tid>213</tid> + <cid>2</cid> + <description>�C���a�U�s������u�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-215.C-0"> + <tid>215</tid> + <cid>0</cid> + <description>�C���۰ʭt�������}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-216.C-0"> + <tid>216</tid> + <cid>0</cid> + <description>�a�U�C���ʵ���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-216.C-1"> + <tid>216</tid> + <cid>1</cid> + <description>�C���ʵ������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-216.C-2"> + <tid>216</tid> + <cid>2</cid> + <description>�C���ʵ������P���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-217.C-0"> + <tid>217</tid> + <cid>0</cid> + <description>�C���a�U���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <!-- ���l --> + <TypeCompFilter name="FSC-300.C-0"> + <tid>300</tid> + <cid>0</cid> + <description>�q�T���l�u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-1"> + <tid>300</tid> + <cid>1</cid> + <description>���ֹq�l����(����)���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-2"> + <tid>300</tid> + <cid>2</cid> + <description>���ֹq�l��r�������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-3"> + <tid>300</tid> + <cid>3</cid> + <description>���ֹq�l�u�Ÿ�</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-4"> + <tid>300</tid> + <cid>4</cid> + <description>���ֹq�l���I�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-301.C-0"> + <tid>301</tid> + <cid>0</cid> + <description>���O����u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-301.C-1"> + <tid>301</tid> + <cid>1</cid> + <description>���O����u�u�Ÿ�</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-301.C-3"> + <tid>301</tid> + <cid>3</cid> + <description>���O����u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-999.C-0"> + <tid>999</tid> + <cid>0</cid> + <description>���O</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-113.C-0"> + <tid>113</tid> + <cid>0</cid> + <description>�����a�U���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-0"> + <tid>403</tid> + <cid>0</cid> + <description>���C���H���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-1"> + <tid>403</tid> + <cid>1</cid> + <description>���C���H��ծy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-2"> + <tid>403</tid> + <cid>2</cid> + <description>���C���H��ն��Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-4"> + <tid>403</tid> + <cid>4</cid> + <description>���O�ն��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-5"> + <tid>403</tid> + <cid>5</cid> + <description>���O�ծy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-6"> + <tid>403</tid> + <cid>6</cid> + <description>���֤ն��Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-7"> + <tid>403</tid> + <cid>7</cid> + <description>���l�ծy�е��O(���l�ϥ�)</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-0"> + <tid>401</tid> + <cid>0</cid> + <description>��</description> + <elementCriterion> + <elementType>12</elementType> + <elementType>16</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-1"> + <tid>401</tid> + <cid>1</cid> + <description>���u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-2"> + <tid>401</tid> + <cid>2</cid> + <description>���U</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-3"> + <tid>401</tid> + <cid>3</cid> + <description>����r�������O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-5"> + <tid>401</tid> + <cid>5</cid> + <description>���_���Ϭq�Ϲj</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-302.C-0"> + <tid>302</tid> + <cid>0</cid> + <description>���O�t���u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-302.C-1"> + <tid>302</tid> + <cid>1</cid> + <description>���O�t���u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-303.C-0"> + <tid>303</tid> + <cid>0</cid> + <description>���O�ާ@�u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-303.C-1"> + <tid>303</tid> + <cid>1</cid> + <description>���O�ާ@�u�u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-303.C-3"> + <tid>303</tid> + <cid>3</cid> + <description>���O�ާ@�u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-305.C-0"> + <tid>305</tid> + <cid>0</cid> + <description>���O�I����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-306.C-0"> + <tid>306</tid> + <cid>0</cid> + <description>���O�ɱ��}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-307.C-0"> + <tid>307</tid> + <cid>0</cid> + <description>���O���[�I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-308.C-0"> + <tid>308</tid> + <cid>0</cid> + <description>���O��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-311.C-0"> + <tid>311</tid> + <cid>0</cid> + <description>���O�x�b</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-311.C-1"> + <tid>311</tid> + <cid>1</cid> + <description>���O�x�b�ϸ�(�e�q.����)���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-314.C-0"> + <tid>314</tid> + <cid>0</cid> + <description>�[�Ÿ��O�t���u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-314.C-1"> + <tid>314</tid> + <cid>1</cid> + <description>�[�Ÿ��O�t���u���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-315.C-0"> + <tid>315</tid> + <cid>0</cid> + <description>�[�Ÿ��O����u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-315.C-1"> + <tid>315</tid> + <cid>1</cid> + <description>�[�Ÿ��O����u���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-316.C-0"> + <tid>316</tid> + <cid>0</cid> + <description>���O����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-317.C-0"> + <tid>317</tid> + <cid>0</cid> + <description>���O����}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-317.C-1"> + <tid>317</tid> + <cid>1</cid> + <description>���O����}�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-318.C-0"> + <tid>318</tid> + <cid>0</cid> + <description>���O�y��</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-319.C-0"> + <tid>319</tid> + <cid>0</cid> + <description>���֦��e</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-320.C-0"> + <tid>320</tid> + <cid>0</cid> + <description>���ֳq�T���Y</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-323.C-0"> + <tid>323</tid> + <cid>0</cid> + <description>���q�ഫ��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-324.C-0"> + <tid>324</tid> + <cid>0</cid> + <description>�۰ʤƻ�����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-324.C-1"> + <tid>324</tid> + <cid>1</cid> + <description>�۰ʤƻ��������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <!-- Dummy + <TypeCompLevelFilter name="DemoFeature3"> + <tid>999</tid> + <cid>2</cid> + <lid>34</lid> + <description>DemoFilter for DemoFeature</description> + <TextCreateStrategy-None/> + </TypeCompLevelFilter> + --> +</ElementDispatcherRules> diff --git a/xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultMapGroups.xml b/xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultMapGroups.xml new file mode 100644 index 0000000..27626b3 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/resources/conf/DefaultMapGroups.xml @@ -0,0 +1,91 @@ +<FeatureClassificationRules> + <FeatureTypeCollector name="22KVSUBHV"> + <featuretypeList> + tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-999.C-0_62_1,tpc:FSC-503.C-0_1_2,tpc:FSC-411.C-0_27_1,tpc:FSC-411.C-1_37_1,tpc:FSC-114.C-3_60_1,tpc:FSC-114.C-2_24_1,tpc:FSC-114.C-0_24_1,tpc:FSC-114.C-1_34_1,tpc:FSC-106.C-2_4_1,tpc:FSC-106.C-0_4_1,tpc:FSC-115.C-6_48_1,tpc:FSC-115.C-0_48_1,tpc:FSC-122.C-0_24_1,tpc:FSC-122.C-1_34_1,tpc:FSC-105.C-0_39_1,tpc:FSC-106.C-0_3_1,tpc:FSC-115.C-6_48_1,tpc:FSC-115.C-0_56_1,tpc:FSC-115.C-1_56_1,tpc:FSC-411.C-0_8_1,tpc:FSC-411.C-1_18_1,tpc:FSC-107.C-0_26_1,tpc:FSC-107.C-2_36_1,tpc:FSC-120.C-0_52_1,tpc:FSC-101.C-0_51_0,tpc:FSC-407.C-0_10_1,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-9_10_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="11KVHVOH"> + <featuretypeList>tpc:FSC-115.C-0_46_1,tpc:FSC-115.C-0_46_2,tpc:FSC-115.C-1_46_1,tpc:FSC-115.C-1_46_2,tpc:FSC-106.C-2_1_1,tpc:FSC-106.C-2_1_2,tpc:FSC-106.C-4_1_1,tpc:FSC-106.C-4_1_2,tpc:FSC-106.C-0_1_1,tpc:FSC-106.C-0_1_2,tpc:FSC-140.C-2_51_1,tpc:FSC-140.C-2_51_2,tpc:FSC-140.C-0_51_1,tpc:FSC-140.C-0_51_2,tpc:FSC-130.C-0_11_1,tpc:FSC-130.C-0_11_2,tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-108.C-0_44_2,tpc:FSC-108.C-1_54_2,tpc:FSC-119.C-0_61_2,tpc:FSC-118.C-0_49_2,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-8_9_1,tpc:FSC-407.C-8_9_2,tpc:FSC-407.C-9_9_1,tpc:FSC-407.C-9_9_2,tpc:FSC-407.C-10_9_1,tpc:FSC-407.C-11_9_1,tpc:FSC-114.C-0_21_1,tpc:FSC-114.C-0_21_2,tpc:FSC-114.C-2_21_0,tpc:FSC-114.C-2_21_1,tpc:FSC-114.C-2_21_2,tpc:FSC-107.C-2_37_1,tpc:FSC-107.C-0_27_1,tpc:FSC-117.C-0_27_2,tpc:FSC-120.C-0_42_1,tpc:FSC-120.C-0_42_2,tpc:FSC-131.C-0_12_1,tpc:FSC-131.C-0_12_2,tpc:FSC-109.C-0_13_1,tpc:FSC-109.C-0_13_2,tpc:FSC-109.C-0_13_3,tpc:FSC-116.C-0_14_1,tpc:FSC-116.C-0_14_2,tpc:FSC-102.C-0_30_2,tpc:FSC-102.C-0_40_1,tpc:FSC-100.C-0_59_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-999.C-0_62_1,tpc:FSC-503.C-0_1_2</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="CLS"> + <featuretypeList>tpc:FSC-203.C-1_37_1,tpc:FSC-203.C-0_37_1,tpc:FSC-203.C-1_38_1,tpc:FSC-203.C-0_38_1,tpc:FSC-311.C-0_45_1,tpc:FSC-311.C-1_45_0,tpc:FSC-311.C-1_45_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="LVOH"> + <featuretypeList>tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-407.C-0_10_1,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-1_9_1,tpc:FSC-407.C-1_9_2,tpc:FSC-407.C-8_9_1,tpc:FSC-407.C-8_9_2,tpc:FSC-407.C-9_10_1,tpc:FSC-407.C-9_9_1,tpc:FSC-407.C-9_9_2,tpc:FSC-115.C-2_50_2,tpc:FSC-115.C-3_50_1,tpc:FSC-115.C-7_58_1,tpc:FSC-200.C-0_28_1,tpc:FSC-200.C-0_30_1,tpc:FSC-202.C-1_36_0,tpc:FSC-202.C-0_36_1,tpc:FSC-203.C-1_38_1,tpc:FSC-204.C-0_49_1,tpc:FSC-205.C-2_41_1,tpc:FSC-205.C-0_39_1,tpc:FSC-208.C-0_44_1,tpc:FSC-209.C-0_46_1,tpc:FSC-211.C-0_32_1,tpc:FSC-212.C-1_34_0,tpc:FSC-303.C-0_29_1,tpc:FSC-305.C-0_34_1,tpc:FSC-306.C-0_36_1,tpc:FSC-307.C-0_38_1,tpc:FSC-308.C-0_40_1,tpc:FSC-314.C-0_26_1,tpc:FSC-314.C-1_28_0,tpc:FSC-315.C-0_26_1,tpc:FSC-315.C-1_28_0,tpc:FSC-316.C-0_54_1,tpc:FSC-317.C-0_32_1,tpc:FSC-317.C-1_32_1,tpc:FSC-318.C-0_54_4,tpc:FSC-503.C-0_1_2,tpc:FSC-502.C-0_1_1,tpc:FSC-502.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-999.C-0_62_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="HICUSTOMER"> + <featuretypeList>tpc:FSC-107.C-0_25_1,tpc:FSC-107.C-0_25_2,tpc:FSC-107.C-0_26_1,tpc:FSC-107.C-0_26_2,tpc:FSC-107.C-0_27_1,tpc:FSC-107.C-2_0_1,tpc:FSC-107.C-2_25_1,tpc:FSC-107.C-2_26_1,tpc:FSC-107.C-2_35_1,tpc:FSC-107.C-2_35_2,tpc:FSC-107.C-2_36_1,tpc:FSC-107.C-2_36_2,tpc:FSC-107.C-2_37_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="22KVHVUG"> + <featuretypeList>tpc:FSC-113.C-0_4_1,tpc:FSC-403.C-2_14_1,tpc:FSC-403.C-2_15_1,tpc:FSC-403.C-1_22_1,tpc:FSC-403.C-1_23_1,tpc:FSC-403.C-1_24_1,tpc:FSC-403.C-1_4_1,tpc:FSC-403.C-1_13_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-101.C-0_51_0,tpc:FSC-101.C-0_51_1,tpc:FSC-140.C-1_54_0,tpc:FSC-140.C-1_54_1,tpc:FSC-140.C-2_54_1,tpc:FSC-140.C-2_54_2,tpc:FSC-140.C-0_54_1,tpc:FSC-140.C-0_54_2,tpc:FSC-140.C-3_54_0,tpc:FSC-140.C-4_54_1,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-411.C-0_27_1,tpc:FSC-411.C-0_27_2,tpc:FSC-411.C-0_8_1,tpc:FSC-411.C-0_8_2,tpc:FSC-411.C-1_37_1,tpc:FSC-411.C-1_37_2,tpc:FSC-411.C-1_18_1,tpc:FSC-411.C-1_18_2,tpc:FSC-118.C-0_50_2,tpc:FSC-115.C-0_48_1,tpc:FSC-115.C-0_48_2,tpc:FSC-114.C-3_60_1,tpc:FSC-114.C-3_60_2,tpc:FSC-114.C-2_24_1,tpc:FSC-114.C-2_24_2,tpc:FSC-114.C-0_24_1,tpc:FSC-114.C-0_24_2,tpc:FSC-114.C-1_34_1,tpc:FSC-114.C-1_34_2,tpc:FSC-122.C-0_24_1,tpc:FSC-122.C-1_34_1,tpc:FSC-107.C-0_26_1,tpc:FSC-107.C-0_26_2,tpc:FSC-117.C-0_27_2,tpc:FSC-105.C-0_39_1,tpc:FSC-105.C-0_39_2,tpc:FSC-120.C-0_52_1,tpc:FSC-120.C-0_52_2,tpc:FSC-108.C-0_45_2,tpc:FSC-108.C-1_55_2,tpc:FSC-119.C-0_62_2</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="11KVSUBHV"> + <featuretypeList>tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-999.C-0_62_1,tpc:FSC-503.C-0_1_2,tpc:FSC-114.C-3_60_1,tpc:FSC-114.C-2_23_1,tpc:FSC-114.C-0_23_1,tpc:FSC-114.C-1_33_1,tpc:FSC-106.C-2_2_1,tpc:FSC-106.C-0_2_1,tpc:FSC-106.C-2_1_1,tpc:FSC-106.C-0_1_1,tpc:FSC-106.C-4_1_1,tpc:FSC-115.C-0_47_1,tpc:FSC-115.C-1_57_1,tpc:FSC-122.C-0_23_1,tpc:FSC-122.C-1_33_1,tpc:FSC-105.C-0_29_1,tpc:FSC-114.C-0_21_1,tpc:FSC-115.C-6_47_1,tpc:FSC-115.C-0_46_1,tpc:FSC-115.C-1_46_1,tpc:FSC-411.C-0_7_1,tpc:FSC-411.C-1_17_1,tpc:FSC-107.C-2_35_1,tpc:FSC-107.C-0_25_1,tpc:FSC-107.C-2_37_1,tpc:FSC-107.C-0_27_1,tpc:FSC-116.C-0_14_1,tpc:FSC-120.C-0_42_1,tpc:FSC-101.C-0_41_0,tpc:FSC-109.C-0_13_1,tpc:FSC-102.C-0_40_1,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-8_9_1,tpc:FSC-407.C-9_9_1,tpc:FSC-407.C-10_9_1,tpc:FSC-407.C-11_9_1,tpc:FSC-130.C-0_11_1,tpc:FSC-131.C-0_12_1,tpc:FSC-411.C-0_27_1,tpc:FSC-411.C-1_37_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="FIBER"> + <featuretypeList>tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-1_16_2,tpc:FSC-300.C-3_11_1,tpc:FSC-300.C-2_11_1,tpc:FSC-300.C-0_10_2,tpc:FSC-319.C-0_12_1,tpc:FSC-320.C-0_13_1,tpc:FSC-323.C-0_1_1,tpc:FSC-324.C-1_2_1,tpc:FSC-324.C-0_1_1,tpc:FSC-403.C-6_45_1,tpc:FSC-403.C-7_45_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="LINEFEATURE"> + <featuretypeList>tpc:FSC-115.C-0_46_1,tpc:FSC-115.C-0_46_2,tpc:FSC-115.C-0_56_1,tpc:FSC-115.C-1_46_1,tpc:FSC-115.C-1_46_2,tpc:FSC-115.C-1_56_1,tpc:FSC-115.C-0_47_1,tpc:FSC-115.C-0_47_2,tpc:FSC-115.C-0_48_1,tpc:FSC-115.C-0_48_2,tpc:FSC-102.C-0_30_2,tpc:FSC-102.C-0_40_1,tpc:FSC-117.C-0_27_2</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="22KVMAINHV"> + <featuretypeList>tpc:FSC-117.C-0_27_2,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-999.C-0_62_1,tpc:FSC-503.C-0_1_2,tpc:FSC-118.C-0_50_2,tpc:FSC-114.C-3_60_2,tpc:FSC-114.C-2_24_2,tpc:FSC-114.C-0_24_2,tpc:FSC-114.C-1_34_2,tpc:FSC-106.C-0_4_2,tpc:FSC-115.C-0_48_2,tpc:FSC-105.C-0_39_2,tpc:FSC-411.C-0_8_2,tpc:FSC-411.C-1_18_2,tpc:FSC-107.C-0_26_2,tpc:FSC-107.C-2_36_2,tpc:FSC-120.C-0_52_2,tpc:FSC-101.C-0_51_1,tpc:FSC-119.C-0_62_2,tpc:FSC-108.C-0_45_2,tpc:FSC-108.C-1_55_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-1_37_2,tpc:FSC-100.C-0_60_2</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="SLS"> + <featuretypeList>tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-115.C-3_50_1,tpc:FSC-115.C-3_51_1,tpc:FSC-115.C-2_50_2,tpc:FSC-115.C-2_51_2,tpc:FSC-115.C-7_55_1,tpc:FSC-115.C-7_58_1,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-0_10_1,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-8_9_1,tpc:FSC-407.C-8_9_2,tpc:FSC-203.C-0_37_1,tpc:FSC-203.C-0_38_1,tpc:FSC-203.C-1_37_1,tpc:FSC-203.C-1_38_1,tpc:FSC-303.C-0_29_1,tpc:FSC-303.C-1_43_0,tpc:FSC-303.C-3_43_0,tpc:FSC-301.C-0_21_1,tpc:FSC-301.C-1_23_0,tpc:FSC-301.C-3_23_0,tpc:FSC-305.C-0_33_1,tpc:FSC-305.C-0_34_1,tpc:FSC-306.C-0_35_1,tpc:FSC-306.C-0_36_1,tpc:FSC-307.C-0_46_1,tpc:FSC-307.C-0_37_1,tpc:FSC-307.C-0_38_1,tpc:FSC-308.C-0_39_1,tpc:FSC-308.C-0_40_1,tpc:FSC-314.C-0_26_1,tpc:FSC-314.C-1_28_0,tpc:FSC-315.C-0_26_1,tpc:FSC-315.C-1_28_0,tpc:FSC-316.C-0_53_1,tpc:FSC-316.C-0_54_1,tpc:FSC-317.C-0_31_1,tpc:FSC-317.C-0_32_1,tpc:FSC-318.C-0_53_4,tpc:FSC-318.C-0_54_4,tpc:FSC-302.C-0_25_1,tpc:FSC-302.C-1_27_0,tpc:FSC-317.C-1_31_1,tpc:FSC-317.C-1_32_1,tpc:FSC-403.C-4_44_1,tpc:FSC-403.C-5_44_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-0_1_1,tpc:FSC-502.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-501.C-1_2_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="OMS"> + <featuretypeList>tpc:FSC-101.C-0_41_0,tpc:FSC-503.C-0_1_2,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-0_1_1,tpc:FSC-411.C-1_37_2,tpc:FSC-411.C-1_37_1,tpc:FSC-411.C-1_18_2,tpc:FSC-411.C-1_18_1,tpc:FSC-411.C-1_17_2,tpc:FSC-411.C-1_17_1,tpc:FSC-411.C-0_8_2,tpc:FSC-411.C-0_8_1,tpc:FSC-411.C-0_7_2,tpc:FSC-411.C-0_7_1,tpc:FSC-411.C-0_27_2,tpc:FSC-411.C-0_27_1,tpc:FSC-407.C-8_9_2,tpc:FSC-407.C-8_9_1,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-0_10_1,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-1_27_2,tpc:FSC-402.C-1_16_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-0_27_2,tpc:FSC-131.C-0_12_2,tpc:FSC-131.C-0_12_1,tpc:FSC-130.C-0_11_2,tpc:FSC-130.C-0_11_1,tpc:FSC-122.C-1_34_1,tpc:FSC-122.C-1_33_2,tpc:FSC-122.C-1_33_1,tpc:FSC-122.C-0_24_1,tpc:FSC-122.C-0_23_2,tpc:FSC-122.C-0_23_1,tpc:FSC-120.C-0_52_2,tpc:FSC-120.C-0_52_1,tpc:FSC-120.C-0_42_2,tpc:FSC-120.C-0_42_1,tpc:FSC-119.C-0_62_2,tpc:FSC-119.C-0_61_2,tpc:FSC-118.C-0_50_2,tpc:FSC-118.C-0_49_2,tpc:FSC-115.C-0_56_1,tpc:FSC-115.C-0_56_1,tpc:FSC-115.C-0_48_2,tpc:FSC-115.C-0_48_1,tpc:FSC-115.C-0_47_2,tpc:FSC-115.C-0_47_1,tpc:FSC-115.C-0_46_2,tpc:FSC-115.C-0_46_1,tpc:FSC-114.C-3_60_2,tpc:FSC-114.C-3_60_1,tpc:FSC-114.C-2_24_2,tpc:FSC-114.C-2_24_1,tpc:FSC-114.C-2_23_2,tpc:FSC-114.C-2_23_1,tpc:FSC-114.C-2_21_2,tpc:FSC-114.C-2_21_1,tpc:FSC-114.C-2_21_0,tpc:FSC-114.C-1_34_2,tpc:FSC-114.C-1_34_1,tpc:FSC-114.C-1_33_2,tpc:FSC-114.C-1_33_1,tpc:FSC-114.C-0_24_2,tpc:FSC-114.C-0_24_1,tpc:FSC-114.C-0_23_2,tpc:FSC-114.C-0_23_1,tpc:FSC-114.C-0_21_2,tpc:FSC-114.C-0_21_1,tpc:FSC-109.C-0_13_3,tpc:FSC-109.C-0_13_2,tpc:FSC-109.C-0_13_1,tpc:FSC-108.C-1_55_2,tpc:FSC-108.C-1_54_2,tpc:FSC-108.C-0_45_2,tpc:FSC-108.C-0_44_2,tpc:FSC-107.C-2_36_2,tpc:FSC-107.C-2_36_1,tpc:FSC-107.C-2_35_2,tpc:FSC-107.C-2_35_1,tpc:FSC-107.C-0_27_1,tpc:FSC-107.C-0_26_2,tpc:FSC-107.C-0_26_1,tpc:FSC-107.C-0_25_2,tpc:FSC-107.C-0_25_1,tpc:FSC-106.C-0_4_1,tpc:FSC-106.C-0_3_1,tpc:FSC-106.C-0_2_2,tpc:FSC-106.C-0_2_1,tpc:FSC-106.C-0_1_2,tpc:FSC-106.C-0_1_1,tpc:FSC-102.C-0_40_1,tpc:FSC-102.C-0_30_2,tpc:FSC-101.C-0_51_1,tpc:FSC-101.C-0_51_0,tpc:FSC-101.C-0_41_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="LVPIPE"> + <featuretypeList>tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-411.C-2_7_1,tpc:FSC-411.C-2_7_2,tpc:FSC-411.C-2_8_1,tpc:FSC-411.C-2_8_2,tpc:FSC-411.C-3_17_1,tpc:FSC-411.C-3_17_2,tpc:FSC-411.C-3_37_1,tpc:FSC-411.C-3_37_2,tpc:FSC-411.C-3_18_1,tpc:FSC-411.C-3_18_2,tpc:FSC-411.C-7_7_1,tpc:FSC-411.C-7_7_2,tpc:FSC-411.C-7_8_1,tpc:FSC-407.C-2_9_1,tpc:FSC-407.C-2_9_2,tpc:FSC-407.C-2_10_1,tpc:FSC-407.C-2_10_1,tpc:FSC-407.C-3_19_1,tpc:FSC-407.C-3_19_2,tpc:FSC-407.C-3_20_1,tpc:FSC-407.C-7_10_1,tpc:FSC-407.C-7_9_1,tpc:FSC-407.C-7_9_2,tpc:FSC-202.C-1_35_0,tpc:FSC-202.C-0_35_1,tpc:FSC-203.C-1_37_1,tpc:FSC-203.C-0_37_1,tpc:FSC-206.C-2_1_0,tpc:FSC-206.C-1_1_1,tpc:FSC-206.C-0_1_1,tpc:FSC-207.C-1_1_0,tpc:FSC-207.C-0_1_1,tpc:FSC-209.C-0_45_1,tpc:FSC-216.C-2_1_0,tpc:FSC-216.C-1_1_1,tpc:FSC-216.C-0_1_1,tpc:FSC-401.C-1_11_0,tpc:FSC-401.C-0_11_1,tpc:FSC-401.C-2_11_1,tpc:FSC-401.C-3_11_0,tpc:FSC-403.C-0_11_1,tpc:FSC-403.C-1_11_1,tpc:FSC-403.C-0_3_1,tpc:FSC-403.C-1_3_1,tpc:FSC-403.C-0_22_1,tpc:FSC-403.C-0_23_1,tpc:FSC-403.C-0_24_1,tpc:FSC-403.C-1_22_1,tpc:FSC-403.C-1_23_1,tpc:FSC-403.C-1_24_1,tpc:FSC-420.C-0_54_3,tpc:FSC-420.C-1_2_1,tpc:FSC-421.C-1_2_1,tpc:FSC-421.C-0_1_3,tpc:FSC-424.C-0_1_1,tpc:FSC-503.C-0_1_2,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-999.C-0_62_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="POLE"> + <featuretypeList>tpc:FSC-407.C-0_10_1,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-1_9_1,tpc:FSC-407.C-1_9_2</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="22KVHVOH"> + <featuretypeList>tpc:FSC-115.C-0_56_1,tpc:FSC-115.C-1_56_1,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-407.C-0_10_1,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-9_10_1,tpc:FSC-117.C-0_27_2,tpc:FSC-118.C-0_50_2,tpc:FSC-108.C-1_55_2,tpc:FSC-119.C-0_62_2,tpc:FSC-100.C-0_60_2,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="11KVHVUG"> + <featuretypeList>tpc:FSC-113.C-0_4_1,tpc:FSC-122.C-0_23_1,tpc:FSC-122.C-0_23_2,tpc:FSC-122.C-1_33_1,tpc:FSC-122.C-1_33_2,tpc:FSC-140.C-1_52_0,tpc:FSC-140.C-1_52_1,tpc:FSC-140.C-2_52_2,tpc:FSC-140.C-2_52_1,tpc:FSC-140.C-0_52_2,tpc:FSC-140.C-0_52_1,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-411.C-1_17_1,tpc:FSC-411.C-1_17_2,tpc:FSC-411.C-1_37_1,tpc:FSC-411.C-1_37_2,tpc:FSC-411.C-0_7_1,tpc:FSC-411.C-0_7_1,tpc:FSC-107.C-2_35_1,tpc:FSC-107.C-2_35_2,tpc:FSC-107.C-0_25_1,tpc:FSC-107.C-0_25_2,tpc:FSC-107.C-0_27_1,tpc:FSC-105.C-0_29_1,tpc:FSC-105.C-0_29_2,tpc:FSC-101.C-0_41_0,tpc:FSC-101.C-0_41_1,tpc:FSC-130.C-0_11_1,tpc:FSC-130.C-0_11_2,tpc:FSC-108.C-0_44_2,tpc:FSC-108.C-1_54_2,tpc:FSC-119.C-0_61_2,tpc:FSC-115.C-0_47_1,tpc:FSC-115.C-0_47_2,tpc:FSC-118.C-0_49_2,tpc:FSC-403.C-2_14_1,tpc:FSC-403.C-2_15_1,tpc:FSC-403.C-1_22_1,tpc:FSC-403.C-1_23_1,tpc:FSC-403.C-1_24_1,tpc:FSC-403.C-1_4_1,tpc:FSC-403.C-1_13_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-114.C-1_33_1,tpc:FSC-114.C-1_33_2,tpc:FSC-114.C-3_60_1,tpc:FSC-114.C-3_60_2,tpc:FSC-114.C-2_23_1,tpc:FSC-114.C-0_23_1,tpc:FSC-114.C-0_23_2</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="11KVMAINHV"> + <featuretypeList>tpc:FSC-117.C-0_27_2,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-999.C-0_62_1,tpc:FSC-503.C-0_1_2,tpc:FSC-118.C-0_49_2,tpc:FSC-114.C-3_60_2,tpc:FSC-114.C-2_23_2,tpc:FSC-114.C-1_33_2,tpc:FSC-106.C-2_2_2,tpc:FSC-106.C-0_2_2,tpc:FSC-115.C-0_47_2,tpc:FSC-122.C-0_23_2,tpc:FSC-122.C-1_33_2,tpc:FSC-105.C-0_29_2,tpc:FSC-114.C-2_21_2,tpc:FSC-114.C-0_21_2,tpc:FSC-106.C-2_1_2,tpc:FSC-106.C-0_1_2,tpc:FSC-106.C-4_1_2,tpc:FSC-115.C-6_47_2,tpc:FSC-115.C-0_46_2,tpc:FSC-115.C-1_46_2,tpc:FSC-411.C-0_7_2,tpc:FSC-411.C-1_17_2,tpc:FSC-107.C-2_35_2,tpc:FSC-107.C-0_25_2,tpc:FSC-116.C-0_14_2,tpc:FSC-120.C-0_42_2,tpc:FSC-101.C-0_41_1,tpc:FSC-109.C-0_13_2,tpc:FSC-102.C-0_30_2,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-8_9_2,tpc:FSC-407.C-9_9_2,tpc:FSC-119.C-0_61_2,tpc:FSC-130.C-0_11_2,tpc:FSC-131.C-0_12_2,tpc:FSC-108.C-0_44_2,tpc:FSC-108.C-1_54_2,tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-100.C-0_59_1,tpc:FSC-411.C-0_27_2,tpc:FSC-411.C-1_37_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="ALL"> + <featuretypeList>tpc:FSC-100.C-0_59_1,tpc:FSC-100.C-0_60_2,tpc:FSC-101.C-0_41_0,tpc:FSC-101.C-0_41_1,tpc:FSC-101.C-0_51_0,tpc:FSC-101.C-0_51_1,tpc:FSC-102.C-0_30_2,tpc:FSC-102.C-0_40_1,tpc:FSC-105.C-0_29_1,tpc:FSC-105.C-0_29_2,tpc:FSC-105.C-0_39_1,tpc:FSC-105.C-0_39_2,tpc:FSC-105.C-0_60_2,tpc:FSC-106.C-0_19_2,tpc:FSC-106.C-0_1_1,tpc:FSC-106.C-0_1_2,tpc:FSC-106.C-0_24_2,tpc:FSC-106.C-0_2_1,tpc:FSC-106.C-0_2_2,tpc:FSC-106.C-0_3_1,tpc:FSC-106.C-0_4_1,tpc:FSC-106.C-0_4_2,tpc:FSC-106.C-2_1_1,tpc:FSC-106.C-2_1_2,tpc:FSC-106.C-2_2_1,tpc:FSC-106.C-2_2_2,tpc:FSC-106.C-2_3_1,tpc:FSC-106.C-2_4_1,tpc:FSC-106.C-4_1_1,tpc:FSC-106.C-4_1_2,tpc:FSC-107.C-0_25_1,tpc:FSC-107.C-0_25_2,tpc:FSC-107.C-0_26_1,tpc:FSC-107.C-0_26_2,tpc:FSC-107.C-0_27_1,tpc:FSC-107.C-2_0_1,tpc:FSC-107.C-2_25_1,tpc:FSC-107.C-2_26_1,tpc:FSC-107.C-2_35_1,tpc:FSC-107.C-2_35_2,tpc:FSC-107.C-2_36_1,tpc:FSC-107.C-2_36_2,tpc:FSC-107.C-2_37_1,tpc:FSC-108.C-0_44_2,tpc:FSC-108.C-0_45_2,tpc:FSC-108.C-1_0_2,tpc:FSC-108.C-1_54_2,tpc:FSC-108.C-1_55_2,tpc:FSC-109.C-0_13_1,tpc:FSC-109.C-0_13_2,tpc:FSC-109.C-0_13_3,tpc:FSC-113.C-0_4_1,tpc:FSC-114.C-0_21_1,tpc:FSC-114.C-0_21_2,tpc:FSC-114.C-0_23_1,tpc:FSC-114.C-0_23_2,tpc:FSC-114.C-0_24_1,tpc:FSC-114.C-0_24_2,tpc:FSC-114.C-1_23_1,tpc:FSC-114.C-1_23_2,tpc:FSC-114.C-1_24_1,tpc:FSC-114.C-1_24_2,tpc:FSC-114.C-1_33_1,tpc:FSC-114.C-1_33_2,tpc:FSC-114.C-1_34_1,tpc:FSC-114.C-1_34_2,tpc:FSC-114.C-2_21_0,tpc:FSC-114.C-2_21_1,tpc:FSC-114.C-2_21_2,tpc:FSC-114.C-2_23_1,tpc:FSC-114.C-2_23_2,tpc:FSC-114.C-2_24_1,tpc:FSC-114.C-2_24_2,tpc:FSC-114.C-2_60_1,tpc:FSC-114.C-2_60_2,tpc:FSC-114.C-3_33_1,tpc:FSC-114.C-3_33_2,tpc:FSC-114.C-3_34_1,tpc:FSC-114.C-3_34_2,tpc:FSC-114.C-3_60_1,tpc:FSC-114.C-3_60_2,tpc:FSC-115.C-0_46_1,tpc:FSC-115.C-0_46_2,tpc:FSC-115.C-0_47_1,tpc:FSC-115.C-0_47_2,tpc:FSC-115.C-0_48_1,tpc:FSC-115.C-0_48_2,tpc:FSC-115.C-0_56_1,tpc:FSC-115.C-1_46_1,tpc:FSC-115.C-1_46_2,tpc:FSC-115.C-1_56_1,tpc:FSC-115.C-1_57_1,tpc:FSC-115.C-2_50_2,tpc:FSC-115.C-2_51_2,tpc:FSC-115.C-3_50_1,tpc:FSC-115.C-3_51_1,tpc:FSC-115.C-4_13_2,tpc:FSC-115.C-4_14_2,tpc:FSC-115.C-4_51_2,tpc:FSC-115.C-4_60_2,tpc:FSC-115.C-5_13_1,tpc:FSC-115.C-5_14_1,tpc:FSC-115.C-5_51_1,tpc:FSC-115.C-5_60_1,tpc:FSC-115.C-6_13_1,tpc:FSC-115.C-6_14_1,tpc:FSC-115.C-6_47_1,tpc:FSC-115.C-6_47_2,tpc:FSC-115.C-6_48_1,tpc:FSC-115.C-6_51_1,tpc:FSC-115.C-6_56_1,tpc:FSC-115.C-6_58_1,tpc:FSC-115.C-6_60_1,tpc:FSC-115.C-7_55_1,tpc:FSC-115.C-7_58_1,tpc:FSC-115.C-8_47_1,tpc:FSC-115.C-8_47_2,tpc:FSC-115.C-8_48_1,tpc:FSC-116.C-0_14_1,tpc:FSC-116.C-0_14_2,tpc:FSC-117.C-0_27_2,tpc:FSC-118.C-0_49_2,tpc:FSC-118.C-0_50_2,tpc:FSC-119.C-0_61_2,tpc:FSC-119.C-0_62_2,tpc:FSC-120.C-0_42_1,tpc:FSC-120.C-0_42_2,tpc:FSC-120.C-0_52_1,tpc:FSC-120.C-0_52_2,tpc:FSC-122.C-0_23_1,tpc:FSC-122.C-0_23_2,tpc:FSC-122.C-0_24_1,tpc:FSC-122.C-1_23_1,tpc:FSC-122.C-1_24_1,tpc:FSC-122.C-1_33_1,tpc:FSC-122.C-1_33_2,tpc:FSC-122.C-1_34_1,tpc:FSC-130.C-0_11_1,tpc:FSC-130.C-0_11_2,tpc:FSC-131.C-0_12_1,tpc:FSC-131.C-0_12_2,tpc:FSC-140.C-0_51_1,tpc:FSC-140.C-0_51_2,tpc:FSC-140.C-0_52_1,tpc:FSC-140.C-0_52_2,tpc:FSC-140.C-0_54_1,tpc:FSC-140.C-0_54_2,tpc:FSC-140.C-0_60_1,tpc:FSC-140.C-0_60_2,tpc:FSC-140.C-1_52_0,tpc:FSC-140.C-1_52_1,tpc:FSC-140.C-1_54_0,tpc:FSC-140.C-1_54_1,tpc:FSC-140.C-2_51_1,tpc:FSC-140.C-2_51_2,tpc:FSC-140.C-2_52_1,tpc:FSC-140.C-2_52_2,tpc:FSC-140.C-2_54_1,tpc:FSC-140.C-2_54_2,tpc:FSC-140.C-3_54_0,tpc:FSC-140.C-4_54_1,tpc:FSC-200.C-0_28_1,tpc:FSC-200.C-0_29_1,tpc:FSC-200.C-0_30_1,tpc:FSC-200.C-0_60_1,tpc:FSC-201.C-0_31_1,tpc:FSC-201.C-0_40_1,tpc:FSC-201.C-1_33_0,tpc:FSC-201.C-1_40_0,tpc:FSC-202.C-0_35_1,tpc:FSC-202.C-0_36_1,tpc:FSC-202.C-0_56_1,tpc:FSC-202.C-1_13_0,tpc:FSC-202.C-1_35_0,tpc:FSC-202.C-1_36_0,tpc:FSC-202.C-1_53_0,tpc:FSC-202.C-1_56_0,tpc:FSC-202.C-1_60_0,tpc:FSC-203.C-0_37_1,tpc:FSC-203.C-0_38_1,tpc:FSC-203.C-1_13_1,tpc:FSC-203.C-1_37_1,tpc:FSC-203.C-1_38_1,tpc:FSC-204.C-0_49_1,tpc:FSC-205.C-0_39_1,tpc:FSC-205.C-2_41_1,tpc:FSC-206.C-0_1_1,tpc:FSC-206.C-1_1_1,tpc:FSC-206.C-2_1_0,tpc:FSC-207.C-0_1_1,tpc:FSC-207.C-1_1_0,tpc:FSC-207.C-2_1_1,tpc:FSC-208.C-0_43_1,tpc:FSC-208.C-0_44_1,tpc:FSC-209.C-0_45_1,tpc:FSC-209.C-0_46_1,tpc:FSC-209.C-1_45_1,tpc:FSC-209.C-1_46_1,tpc:FSC-210.C-4_42_0,tpc:FSC-211.C-0_32_1,tpc:FSC-212.C-1_34_0,tpc:FSC-213.C-0_31_1,tpc:FSC-213.C-1_33_0,tpc:FSC-215.C-0_45_1,tpc:FSC-216.C-0_1_1,tpc:FSC-216.C-1_1_1,tpc:FSC-216.C-2_1_0,tpc:FSC-217.C-0_11_1,tpc:FSC-300.C-0_10_2,tpc:FSC-300.C-2_11_1,tpc:FSC-300.C-3_11_1,tpc:FSC-301.C-0_21_1,tpc:FSC-301.C-0_60_1,tpc:FSC-301.C-1_23_0,tpc:FSC-301.C-1_60_0,tpc:FSC-301.C-3_23_0,tpc:FSC-301.C-3_60_0,tpc:FSC-302.C-0_25_1,tpc:FSC-302.C-1_27_0,tpc:FSC-303.C-0_29_1,tpc:FSC-303.C-1_43_0,tpc:FSC-303.C-3_43_0,tpc:FSC-305.C-0_33_1,tpc:FSC-305.C-0_34_1,tpc:FSC-306.C-0_35_1,tpc:FSC-306.C-0_36_1,tpc:FSC-307.C-0_37_1,tpc:FSC-307.C-0_38_1,tpc:FSC-307.C-0_46_1,tpc:FSC-308.C-0_39_1,tpc:FSC-308.C-0_40_1,tpc:FSC-311.C-0_45_1,tpc:FSC-311.C-0_60_1,tpc:FSC-311.C-0_63_1,tpc:FSC-311.C-1_45_0,tpc:FSC-311.C-1_45_1,tpc:FSC-311.C-1_60_1,tpc:FSC-311.C-1_63_1,tpc:FSC-314.C-0_26_1,tpc:FSC-314.C-1_28_0,tpc:FSC-315.C-0_26_1,tpc:FSC-315.C-1_28_0,tpc:FSC-316.C-0_53_1,tpc:FSC-316.C-0_54_1,tpc:FSC-317.C-0_31_1,tpc:FSC-317.C-0_32_1,tpc:FSC-317.C-1_31_1,tpc:FSC-317.C-1_32_1,tpc:FSC-318.C-0_53_4,tpc:FSC-318.C-0_54_4,tpc:FSC-319.C-0_12_1,tpc:FSC-320.C-0_13_1,tpc:FSC-323.C-0_1_1,tpc:FSC-324.C-0_1_1,tpc:FSC-324.C-1_2_1,tpc:FSC-401.C-0_11_1,tpc:FSC-401.C-0_4_2,tpc:FSC-401.C-0_60_1,tpc:FSC-401.C-1_11_0,tpc:FSC-401.C-1_4_0,tpc:FSC-401.C-2_11_1,tpc:FSC-401.C-2_4_1,tpc:FSC-401.C-3_11_0,tpc:FSC-401.C-3_4_1,tpc:FSC-401.C-5_4_1,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-1_16_2,tpc:FSC-402.C-1_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-1_5_2,tpc:FSC-402.C-1_6_2,tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-2_37_2,tpc:FSC-403.C-0_11_1,tpc:FSC-403.C-0_13_1,tpc:FSC-403.C-0_22_1,tpc:FSC-403.C-0_23_1,tpc:FSC-403.C-0_24_1,tpc:FSC-403.C-0_3_1,tpc:FSC-403.C-0_4_1,tpc:FSC-403.C-1_11_1,tpc:FSC-403.C-1_13_1,tpc:FSC-403.C-1_14_1,tpc:FSC-403.C-1_22_1,tpc:FSC-403.C-1_23_1,tpc:FSC-403.C-1_24_1,tpc:FSC-403.C-1_3_1,tpc:FSC-403.C-1_4_1,tpc:FSC-403.C-1_60_1,tpc:FSC-403.C-2_13_1,tpc:FSC-403.C-2_14_1,tpc:FSC-403.C-2_15_1,tpc:FSC-403.C-2_20_1,tpc:FSC-403.C-2_60_1,tpc:FSC-403.C-4_11_1,tpc:FSC-403.C-4_44_1,tpc:FSC-403.C-5_11_1,tpc:FSC-403.C-5_44_1,tpc:FSC-403.C-5_60_1,tpc:FSC-403.C-6_45_1,tpc:FSC-403.C-7_45_1,tpc:FSC-407.C-0_10_1,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-10_9_1,tpc:FSC-407.C-11_9_1,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-1_9_1,tpc:FSC-407.C-1_9_2,tpc:FSC-407.C-2_10_1,tpc:FSC-407.C-2_9_1,tpc:FSC-407.C-2_9_2,tpc:FSC-407.C-3_19_1,tpc:FSC-407.C-3_19_2,tpc:FSC-407.C-3_20_1,tpc:FSC-407.C-7_10_1,tpc:FSC-407.C-7_9_1,tpc:FSC-407.C-7_9_2,tpc:FSC-407.C-8_9_1,tpc:FSC-407.C-8_9_2,tpc:FSC-407.C-9_10_1,tpc:FSC-407.C-9_9_1,tpc:FSC-407.C-9_9_2,tpc:FSC-411.C-0_27_1,tpc:FSC-411.C-0_27_2,tpc:FSC-411.C-0_7_1,tpc:FSC-411.C-0_7_2,tpc:FSC-411.C-0_8_1,tpc:FSC-411.C-0_8_2,tpc:FSC-411.C-1_17_1,tpc:FSC-411.C-1_17_2,tpc:FSC-411.C-1_18_1,tpc:FSC-411.C-1_18_2,tpc:FSC-411.C-1_37_1,tpc:FSC-411.C-1_37_2,tpc:FSC-411.C-1_7_1,tpc:FSC-411.C-1_7_2,tpc:FSC-411.C-1_8_1,tpc:FSC-411.C-1_8_2,tpc:FSC-411.C-2_27_1,tpc:FSC-411.C-2_27_2,tpc:FSC-411.C-2_7_1,tpc:FSC-411.C-2_7_2,tpc:FSC-411.C-2_8_1,tpc:FSC-411.C-2_8_2,tpc:FSC-411.C-3_17_1,tpc:FSC-411.C-3_17_2,tpc:FSC-411.C-3_18_1,tpc:FSC-411.C-3_18_2,tpc:FSC-411.C-3_37_1,tpc:FSC-411.C-3_37_2,tpc:FSC-411.C-7_7_1,tpc:FSC-411.C-7_7_2,tpc:FSC-411.C-7_8_1,tpc:FSC-420.C-0_54_3,tpc:FSC-420.C-1_2_1,tpc:FSC-421.C-0_1_3,tpc:FSC-421.C-1_2_1,tpc:FSC-423.C-1_4_1,tpc:FSC-424.C-0_1_1,tpc:FSC-501.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-502.C-1_2_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="LVUG"> + <featuretypeList>tpc:FSC-217.C-0_11_1,tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-407.C-2_10_1,tpc:FSC-407.C-2_9_1,tpc:FSC-407.C-2_9_2,tpc:FSC-407.C-3_19_1,tpc:FSC-407.C-3_19_2,tpc:FSC-407.C-3_20_1,tpc:FSC-407.C-7_10_1,tpc:FSC-407.C-7_9_1,tpc:FSC-407.C-7_9_2,tpc:FSC-411.C-7_7_1,tpc:FSC-411.C-7_7_2,tpc:FSC-411.C-7_8_1,tpc:FSC-115.C-8_47_1,tpc:FSC-115.C-8_47_2,tpc:FSC-115.C-8_48_1,tpc:FSC-115.C-6_47_1,tpc:FSC-115.C-6_47_2,tpc:FSC-115.C-2_51_2,tpc:FSC-115.C-3_51_1,tpc:FSC-115.C-4_51_2,tpc:FSC-115.C-5_51_1,tpc:FSC-115.C-6_56_1,tpc:FSC-115.C-7_55_1,tpc:FSC-200.C-0_28_1,tpc:FSC-200.C-0_29_1,tpc:FSC-201.C-0_31_1,tpc:FSC-201.C-1_33_0,tpc:FSC-202.C-1_35_0,tpc:FSC-202.C-0_35_1,tpc:FSC-203.C-1_37_1,tpc:FSC-203.C-0_37_1,tpc:FSC-206.C-2_1_0,tpc:FSC-206.C-1_1_1,tpc:FSC-206.C-0_1_1,tpc:FSC-207.C-1_1_0,tpc:FSC-207.C-0_1_1,tpc:FSC-208.C-0_43_1,tpc:FSC-209.C-0_45_1,tpc:FSC-210.C-4_42_0,tpc:FSC-213.C-0_31_1,tpc:FSC-213.C-1_33_0,tpc:FSC-215.C-0_45_1,tpc:FSC-216.C-2_1_0,tpc:FSC-216.C-0_1_1,tpc:FSC-216.C-1_1_1,tpc:FSC-301.C-1_23_0,tpc:FSC-301.C-0_21_1,tpc:FSC-301.C-1_23_0,tpc:FSC-301.C-3_23_0,tpc:FSC-303.C-0_29_1,tpc:FSC-303.C-1_43_0,tpc:FSC-303.C-3_43_0,tpc:FSC-307.C-0_46_1,tpc:FSC-307.C-0_37_1,tpc:FSC-302.C-0_25_1,tpc:FSC-302.C-1_27_0,tpc:FSC-305.C-0_33_1,tpc:FSC-306.C-0_35_1,tpc:FSC-308.C-0_39_1,tpc:FSC-316.C-0_53_1,tpc:FSC-317.C-1_31_1,tpc:FSC-318.C-0_53_4,tpc:FSC-403.C-2_20_1,tpc:FSC-403.C-2_15_1,tpc:FSC-403.C-1_22_1,tpc:FSC-403.C-1_23_1,tpc:FSC-403.C-1_24_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-501.C-0_1_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="OHS"> + <featuretypeList>tpc:FSC-106.C-2_1_1,tpc:FSC-106.C-2_1_2,tpc:FSC-106.C-4_1_1,tpc:FSC-106.C-4_1_2,tpc:FSC-106.C-0_1_1,tpc:FSC-106.C-0_1_2,tpc:FSC-106.C-2_3_1,tpc:FSC-106.C-0_3_1,tpc:FSC-140.C-2_51_1,tpc:FSC-140.C-2_51_2,tpc:FSC-140.C-0_51_1,tpc:FSC-140.C-0_51_2,tpc:FSC-402.C-2_15_2,tpc:FSC-403.C-2_15_1,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-407.C-0_9_1,tpc:FSC-407.C-0_9_2,tpc:FSC-407.C-0_10_1,tpc:FSC-407.C-1_19_1,tpc:FSC-407.C-1_19_2,tpc:FSC-407.C-1_20_1,tpc:FSC-407.C-9_9_1,tpc:FSC-407.C-9_9_2,tpc:FSC-407.C-9_10_1,tpc:FSC-407.C-10_9_1,tpc:FSC-407.C-11_9_1,tpc:FSC-118.C-0_49_2,tpc:FSC-118.C-0_50_2,tpc:FSC-407.C-8_9_1,tpc:FSC-407.C-8_9_2,tpc:FSC-114.C-0_21_1,tpc:FSC-114.C-0_21_2,tpc:FSC-114.C-2_21_0,tpc:FSC-114.C-2_21_1,tpc:FSC-114.C-2_21_2,tpc:FSC-115.C-0_46_1,tpc:FSC-115.C-0_46_2,tpc:FSC-115.C-0_56_1,tpc:FSC-115.C-1_46_1,tpc:FSC-115.C-1_46_2,tpc:FSC-115.C-1_56_1,tpc:FSC-115.C-2_50_2,tpc:FSC-115.C-2_51_2,tpc:FSC-115.C-3_51_1,tpc:FSC-115.C-3_50_1,tpc:FSC-115.C-7_58_1,tpc:FSC-115.C-7_55_1,tpc:FSC-107.C-2_35_1,tpc:FSC-107.C-2_35_2,tpc:FSC-107.C-0_25_1,tpc:FSC-107.C-0_25_2,tpc:FSC-107.C-2_36_1,tpc:FSC-107.C-2_36_2,tpc:FSC-107.C-0_26_1,tpc:FSC-107.C-0_26_2,tpc:FSC-107.C-2_37_1,tpc:FSC-107.C-0_27_1,tpc:FSC-117.C-0_27_2,tpc:FSC-120.C-0_42_1,tpc:FSC-120.C-0_42_2,tpc:FSC-120.C-0_52_1,tpc:FSC-120.C-0_52_2,tpc:FSC-130.C-0_11_1,tpc:FSC-130.C-0_11_2,tpc:FSC-131.C-0_12_1,tpc:FSC-131.C-0_12_2,tpc:FSC-109.C-0_13_1,tpc:FSC-109.C-0_13_2,tpc:FSC-109.C-0_13_3,tpc:FSC-116.C-0_14_1,tpc:FSC-116.C-0_14_2,tpc:FSC-102.C-0_30_2,tpc:FSC-100.C-0_59_1,tpc:FSC-100.C-0_60_2,tpc:FSC-502.C-0_1_1,tpc:FSC-502.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-503.C-0_1_2,tpc:FSC-999.C-0_62_1,tpc:FSC-200.C-0_30_1,tpc:FSC-200.C-0_28_1,tpc:FSC-202.C-1_36_0,tpc:FSC-202.C-0_36_1,tpc:FSC-203.C-1_38_1,tpc:FSC-203.C-0_38_1,tpc:FSC-205.C-2_41_1,tpc:FSC-205.C-0_39_1,tpc:FSC-208.C-0_44_1,tpc:FSC-209.C-0_46_1,tpc:FSC-211.C-0_32_1,tpc:FSC-212.C-1_34_0,tpc:FSC-303.C-1_43_0,tpc:FSC-303.C-0_29_1,tpc:FSC-303.C-3_43_0,tpc:FSC-305.C-0_34_1,tpc:FSC-306.C-0_36_1,tpc:FSC-307.C-0_46_1,tpc:FSC-307.C-0_38_1,tpc:FSC-308.C-0_40_1,tpc:FSC-314.C-0_26_1,tpc:FSC-314.C-1_28_0,tpc:FSC-315.C-0_26_1,tpc:FSC-315.C-1_28_0,tpc:FSC-316.C-0_54_1,tpc:FSC-317.C-0_32_1,tpc:FSC-317.C-1_32_1,tpc:FSC-318.C-0_54_4</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="HVPIPE"> + <featuretypeList>tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-411.C-2_7_1,tpc:FSC-411.C-2_7_2,tpc:FSC-411.C-2_27_1,tpc:FSC-411.C-2_27_2,tpc:FSC-411.C-2_8_1,tpc:FSC-411.C-2_8_2,tpc:FSC-411.C-3_17_1,tpc:FSC-411.C-3_17_2,tpc:FSC-411.C-3_37_1,tpc:FSC-411.C-3_37_2,tpc:FSC-411.C-3_18_1,tpc:FSC-411.C-3_18_2,tpc:FSC-411.C-7_7_1,tpc:FSC-411.C-7_7_2,tpc:FSC-411.C-7_8_1,tpc:FSC-407.C-2_9_1,tpc:FSC-407.C-2_9_2,tpc:FSC-407.C-2_10_1,tpc:FSC-407.C-3_19_1,tpc:FSC-407.C-3_19_2,tpc:FSC-407.C-3_20_1,tpc:FSC-407.C-7_10_1,tpc:FSC-407.C-7_9_1,tpc:FSC-407.C-7_9_2,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-1_2_1,tpc:FSC-502.C-0_1_1,tpc:FSC-501.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-420.C-0_54_3,tpc:FSC-420.C-1_2_1,tpc:FSC-423.C-1_4_1,tpc:FSC-401.C-1_4_0,tpc:FSC-401.C-3_4_1,tpc:FSC-401.C-0_4_2,tpc:FSC-401.C-2_4_1,tpc:FSC-401.C-5_4_1,tpc:FSC-403.C-0_4_1,tpc:FSC-403.C-0_13_1,tpc:FSC-403.C-0_3_1,tpc:FSC-403.C-1_3_1,tpc:FSC-403.C-1_4_1,tpc:FSC-403.C-1_13_1,tpc:FSC-403.C-0_22_1,tpc:FSC-403.C-0_23_1,tpc:FSC-403.C-0_24_1,tpc:FSC-403.C-1_22_1,tpc:FSC-403.C-1_23_1,tpc:FSC-403.C-1_24_1,tpc:FSC-503.C-0_1_2,tpc:FSC-421.C-0_1_3,tpc:FSC-421.C-1_2_1,tpc:FSC-424.C-0_1_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> + <FeatureTypeCollector name="HLVPIPE"> + <featuretypeList>tpc:FSC-402.C-2_15_2,tpc:FSC-402.C-0_5_2,tpc:FSC-402.C-1_15_2,tpc:FSC-402.C-2_37_2,tpc:FSC-402.C-0_27_2,tpc:FSC-402.C-1_37_2,tpc:FSC-402.C-2_16_2,tpc:FSC-402.C-0_6_2,tpc:FSC-402.C-1_16_2,tpc:FSC-411.C-2_7_1,tpc:FSC-411.C-2_7_2,tpc:FSC-411.C-2_27_1,tpc:FSC-411.C-2_27_2,tpc:FSC-411.C-2_8_1,tpc:FSC-411.C-2_8_2,tpc:FSC-411.C-3_17_1,tpc:FSC-411.C-3_17_2,tpc:FSC-411.C-3_37_1,tpc:FSC-411.C-3_37_2,tpc:FSC-411.C-3_18_1,tpc:FSC-411.C-3_18_2,tpc:FSC-411.C-7_7_1,tpc:FSC-411.C-7_7_2,tpc:FSC-411.C-7_8_1,tpc:FSC-407.C-2_9_1,tpc:FSC-407.C-2_9_2,tpc:FSC-407.C-2_10_1,tpc:FSC-407.C-3_19_1,tpc:FSC-407.C-3_19_2,tpc:FSC-407.C-3_20_1,tpc:FSC-407.C-7_10_1,tpc:FSC-407.C-7_9_1,tpc:FSC-407.C-7_9_2,tpc:FSC-202.C-1_35_0,tpc:FSC-202.C-0_35_1,tpc:FSC-203.C-1_37_1,tpc:FSC-203.C-0_37_1,tpc:FSC-206.C-2_1_0,tpc:FSC-206.C-1_1_1,tpc:FSC-206.C-0_1_1,tpc:FSC-207.C-1_1_0,tpc:FSC-209.C-0_45_1,tpc:FSC-216.C-2_1_0,tpc:FSC-216.C-1_1_1,tpc:FSC-216.C-0_1_1,tpc:FSC-401.C-0_11_1,tpc:FSC-401.C-0_4_2,tpc:FSC-401.C-1_11_0,tpc:FSC-401.C-3_11_0,tpc:FSC-401.C-2_11_1,tpc:FSC-401.C-1_4_0,tpc:FSC-401.C-3_4_1,tpc:FSC-401.C-2_4_1,tpc:FSC-401.C-5_4_1,tpc:FSC-403.C-0_3_1,tpc:FSC-403.C-0_4_1,tpc:FSC-403.C-0_13_1,tpc:FSC-403.C-1_3_1,tpc:FSC-403.C-1_11_1,tpc:FSC-403.C-1_4_1,tpc:FSC-403.C-1_13_1,tpc:FSC-403.C-0_22_1,tpc:FSC-403.C-0_23_1,tpc:FSC-403.C-0_24_1,tpc:FSC-403.C-1_22_1,tpc:FSC-403.C-1_23_1,tpc:FSC-403.C-1_24_1,tpc:FSC-421.C-0_1_3,tpc:FSC-421.C-1_2_1,tpc:FSC-423.C-1_4_1,tpc:FSC-424.C-0_1_1,tpc:FSC-999.C-0_62_1,tpc:FSC-502.C-0_1_1,tpc:FSC-502.C-1_2_1,tpc:FSC-501.C-0_1_1,tpc:FSC-501.C-1_2_1,tpc:FSC-420.C-0_54_3,tpc:FSC-420.C-1_2_1</featuretypeList> + <featuretypeList/> + </FeatureTypeCollector> +</FeatureClassificationRules> diff --git a/xdgnjobs/ximple-spatialjob/src/test/java/com/ximple/eofms/filter/ElementDispatcherTest.java b/xdgnjobs/ximple-spatialjob/src/test/java/com/ximple/eofms/filter/ElementDispatcherTest.java new file mode 100644 index 0000000..7b21d8a --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/test/java/com/ximple/eofms/filter/ElementDispatcherTest.java @@ -0,0 +1,69 @@ +package com.ximple.eofms.filter; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.xmlrules.DigesterLoader; +import org.geotools.TestData; +import org.testng.Assert; +import org.testng.annotations.Test; +import org.xml.sax.SAXException; + +public class ElementDispatcherTest +{ + private static final String TestRulesName = "testRules.xml"; + private static final String TestConfigName = "testElementFilter.xml"; + + @Test + public void testLoadRules() throws IOException + { + File rules = TestData.file(this, TestRulesName); + Digester digester = DigesterLoader.createDigester(rules.toURI().toURL()); + // File config = TestData.file(this, TestConfigName); + // ElementDispatcher ed = (ElementDispatcher) digester.parse(config); + Assert.assertNotNull(digester); + } + + @Test + public void testLoadConfig() throws IOException, SAXException + { + File rules = TestData.file(this, TestRulesName); + Digester digester = DigesterLoader.createDigester(rules.toURI().toURL()); + File config = TestData.file(this, TestConfigName); + ElementDispatcher ed = (ElementDispatcher) digester.parse(config); + Assert.assertNotNull(ed); + // Assert.assertEquals(ed.getRules().size(), 3); + + + ElementDispatchableFilter filter = ed.getRules().get(0); + /* + Assert.assertTrue(filter instanceof TypeIdDispatchableFilter); + TypeIdDispatchableFilter tFilter = (TypeIdDispatchableFilter) filter; + Assert.assertEquals(tFilter.getName(), "DemoFeature1"); + Assert.assertEquals(tFilter.getTid(), 106); + Assert.assertEquals(tFilter.getElmtype(), 7); + Assert.assertNotNull(tFilter.getCreateStrategy()); + Assert.assertTrue(tFilter.getCreateStrategy() instanceof CreateLineStringStrategy); + */ + + filter = ed.getRules().get(1); + Assert.assertTrue(filter instanceof TypeCompIdDispatchableFilter); + TypeCompIdDispatchableFilter tcFilter = (TypeCompIdDispatchableFilter) filter; + Assert.assertEquals(tcFilter.getName(), "DemoFeature2"); + Assert.assertEquals(tcFilter.getTid(), 107); + Assert.assertEquals(tcFilter.getCid(), 11); + Assert.assertNotNull(tcFilter.getCreateStrategy()); + Assert.assertTrue(tcFilter.getCreateStrategy() instanceof CreateLineTextStrategy); + /* + filter = ed.getRules().get(2); + Assert.assertTrue(filter instanceof TypeCompLevelIdDispatchableFilter); + TypeCompLevelIdDispatchableFilter tclFilter = (TypeCompLevelIdDispatchableFilter) filter; + Assert.assertEquals(tclFilter.getName(), "DemoFeature3"); + Assert.assertEquals(tclFilter.getTid(), 108); + Assert.assertEquals(tclFilter.getCid(), 2); + Assert.assertEquals(tclFilter.getLid(), 34); + Assert.assertNull(tclFilter.getCreateStrategy()); + */ + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testElementFilter.xml b/xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testElementFilter.xml new file mode 100644 index 0000000..4721538 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testElementFilter.xml @@ -0,0 +1,1406 @@ +<?xml version="1.0" encoding="big5" ?> +<ElementDispatcherRules> + <!-- High Voltage Features --> + <TypeCompFilter name="FSC-106.C-0"> + <tid>106</tid> + <cid>0</cid> + <description>�D�����u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-106.C-1"> + <tid>106</tid> + <cid>1</cid> + <description>�����u�u</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-106.C-2"> + <tid>106</tid> + <cid>2</cid> + <description>�����u�u���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-106.C-4"> + <tid>106</tid> + <cid>4</cid> + <description>�����u�X�u�N���u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-402.C-0"> + <tid>402</tid> + <cid>0</cid> + <description>�ܹq��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-402.C-1"> + <tid>402</tid> + <cid>1</cid> + <description>�ܹq�ҵ��O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-402.C-2"> + <tid>402</tid> + <cid>2</cid> + <description>�ܹq�Ҥ�����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-0"> + <tid>411</tid> + <cid>0</cid> + <description>�t�q��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-1"> + <tid>411</tid> + <cid>1</cid> + <description>�t�q�����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-2"> + <tid>411</tid> + <cid>2</cid> + <description>�t�q��-1/600</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-3"> + <tid>411</tid> + <cid>3</cid> + <description>�t�q�����O-1/600</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-411.C-7"> + <tid>411</tid> + <cid>7</cid> + <description>�t�q��1/600�ޤW�U�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-420.C-0"> + <tid>420</tid> + <cid>0</cid> + <description>��</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-420.C-1"> + <tid>420</tid> + <cid>1</cid> + <description>�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-421.C-0"> + <tid>421</tid> + <cid>0</cid> + <description>�@�P�D</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-421.C-1"> + <tid>421</tid> + <cid>1</cid> + <description>�@�P�D���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-423.C-0"> + <tid>423</tid> + <cid>0</cid> + <description>���_��</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-423.C-1"> + <tid>423</tid> + <cid>1</cid> + <description>���_���u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-424.C-0"> + <tid>424</tid> + <cid>0</cid> + <description>�S��u�k�X�вŸ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-501.C-0"> + <tid>501</tid> + <cid>0</cid> + <description>��ê���X</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-501.C-1"> + <tid>501</tid> + <cid>1</cid> + <description>��ê���X��r���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-502.C-0"> + <tid>502</tid> + <cid>0</cid> + <description>���D���X</description> + <elementCriterion> + <elementType>6</elementType> + </elementCriterion> + <ShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-502.C-1"> + <tid>502</tid> + <cid>1</cid> + <description>���D���X��r���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-503.C-0"> + <tid>503</tid> + <cid>0</cid> + <description>��r���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-0"> + <tid>407</tid> + <cid>0</cid> + <description>�q��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-1"> + <tid>407</tid> + <cid>1</cid> + <description>�q����O</description> + <elementCriterion> + <elementType>17</elementType> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-2"> + <tid>407</tid> + <cid>2</cid> + <description>�q��-1/600</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-3"> + <tid>407</tid> + <cid>3</cid> + <description>�q��-1/600���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-7"> + <tid>407</tid> + <cid>7</cid> + <description>1/600�q��ޤW�U�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-8"> + <tid>407</tid> + <cid>8</cid> + <description>1/1200�q��ޤW�U�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-9"> + <tid>407</tid> + <cid>9</cid> + <description>�q�������u</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-10"> + <tid>407</tid> + <cid>10</cid> + <description>�q��츹</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-407.C-11"> + <tid>407</tid> + <cid>11</cid> + <description>�q�������u���\</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-0"> + <tid>114</tid> + <cid>0</cid> + <description>�}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-1"> + <tid>114</tid> + <cid>1</cid> + <description>�}���j�����O</description> + <elementCriterion> + <elementType>17</elementType> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-2"> + <tid>114</tid> + <cid>2</cid> + <description>�}���p�P��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-114.C-3"> + <tid>114</tid> + <cid>3</cid> + <description>�}���j�P��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-122.C-0"> + <tid>122</tid> + <cid>0</cid> + <description>�����s��</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + <elementType>17</elementType> + </elementCriterion> + <LineTextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-122.C-1"> + <tid>122</tid> + <cid>1</cid> + <description>�����s�����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-107.C-0"> + <tid>107</tid> + <cid>0</cid> + <description>�����Τ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-107.C-2"> + <tid>107</tid> + <cid>2</cid> + <description>�����Τᤤ����O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-117.C-0"> + <tid>117</tid> + <cid>0</cid> + <description>Tie������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-105.C-0"> + <tid>105</tid> + <cid>0</cid> + <description>�������Y</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-105.C-1"> + <tid>105</tid> + <cid>1</cid> + <description>�������Y���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-101.C-0"> + <tid>101</tid> + <cid>0</cid> + <description>�y��</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-120.C-0"> + <tid>120</tid> + <cid>0</cid> + <description>�`�I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-150.C-0"> + <tid>150</tid> + <cid>0</cid> + <description>����}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-130.C-0"> + <tid>130</tid> + <cid>0</cid> + <description>�ɽu��e</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-131.C-0"> + <tid>131</tid> + <cid>0</cid> + <description>�ɽu�ܧ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-109.C-0"> + <tid>109</tid> + <cid>0</cid> + <description>���u�s��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-116.C-0"> + <tid>116</tid> + <cid>0</cid> + <description>������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-108.C-0"> + <tid>108</tid> + <cid>0</cid> + <description>�_����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-108.C-1"> + <tid>108</tid> + <cid>1</cid> + <description>�_�������O</description> + <elementCriterion> + <elementType>17</elementType> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-119.C-0"> + <tid>119</tid> + <cid>0</cid> + <description>�q��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-0"> + <tid>115</tid> + <cid>0</cid> + <description>������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-1"> + <tid>115</tid> + <cid>1</cid> + <description>���������O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-2"> + <tid>115</tid> + <cid>2</cid> + <description>���O�t�ι�������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-3"> + <tid>115</tid> + <cid>3</cid> + <description>���O�t�ι����������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-4"> + <tid>115</tid> + <cid>4</cid> + <description>�C���t�ι�������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-5"> + <tid>115</tid> + <cid>5</cid> + <description>�C���t�ι����������O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-6"> + <tid>115</tid> + <cid>6</cid> + <description>�C���t�ι�-�t�q�Ǯy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-7"> + <tid>115</tid> + <cid>7</cid> + <description>�C���t�ι�-�t�q�Ǯy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-115.C-8"> + <tid>115</tid> + <cid>8</cid> + <description>�[��������(�a�U�C����)���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-118.C-0"> + <tid>118</tid> + <cid>0</cid> + <description>�D������</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-102.C-0"> + <tid>102</tid> + <cid>0</cid> + <description>�q�e��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-100.C-0"> + <tid>100</tid> + <cid>0</cid> + <description>�p��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-0"> + <tid>140</tid> + <cid>0</cid> + <description>�����u��(�u���ϥ�)</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-1"> + <tid>140</tid> + <cid>1</cid> + <description>�u(�u���ϥ�)</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-2"> + <tid>140</tid> + <cid>2</cid> + <description>�ɽu���O(�u���ϥ�)</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-3"> + <tid>140</tid> + <cid>3</cid> + <description>�X�u�N���u(�u���ϥ�)</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-140.C-4"> + <tid>140</tid> + <cid>4</cid> + <description>�X�u�N�����O(�u���ϥ�)</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-151.C-0"> + <tid>150</tid> + <cid>0</cid> + <description>�`���}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <!-- Low Voltage Features --> + <TypeCompFilter name="FSC-200.C-0"> + <tid>200</tid> + <cid>0</cid> + <description>�C���`�I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <!-- *****�C��****** --> + <TypeCompFilter name="FSC-201.C-0"> + <tid>201</tid> + <cid>0</cid> + <description>����u</description> + <elementCriterion> + <elementType>12</elementType> + <elementType>17</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-201.C-1"> + <tid>201</tid> + <cid>1</cid> + <description>����u���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-201.C-2"> + <tid>201</tid> + <cid>2</cid> + <description>����u�����O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-202.C-0"> + <tid>202</tid> + <cid>0</cid> + <description>�����I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-202.C-1"> + <tid>202</tid> + <cid>1</cid> + <description>�����I���P���O</description> + <elementCriterion> + <elementType>7</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-203.C-0"> + <tid>203</tid> + <cid>0</cid> + <description>���O�d�������I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-203.C-1"> + <tid>203</tid> + <cid>1</cid> + <description>���O�d�������I���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-204.C-0"> + <tid>204</tid> + <cid>0</cid> + <description>�C�����u</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-205.C-0"> + <tid>205</tid> + <cid>0</cid> + <description>�C���ɽu</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-205.C-1"> + <tid>205</tid> + <cid>1</cid> + <description>�C���ɽu���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-205.C-2"> + <tid>205</tid> + <cid>2</cid> + <description>�C���ɽu�����O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-206.C-0"> + <tid>206</tid> + <cid>0</cid> + <description>�C�������c</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-207.C-0"> + <tid>207</tid> + <cid>0</cid> + <description>�C��ĵ����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-208.C-0"> + <tid>208</tid> + <cid>0</cid> + <description>�C����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-209.C-0"> + <tid>209</tid> + <cid>0</cid> + <description>�C����q���x</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-0"> + <tid>210</tid> + <cid>0</cid> + <description>�C���a�U�ɽu</description> + <elmtype>12</elmtype> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-1"> + <tid>210</tid> + <cid>1</cid> + <description>�C���a�U�ɽu���I�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-2"> + <tid>210</tid> + <cid>2</cid> + <description>�C���a�U�ɽu�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-3"> + <tid>210</tid> + <cid>3</cid> + <description>�C���a�U�ɽu�Ÿ�</description> + <elmtype>4</elmtype> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-210.C-4"> + <tid>210</tid> + <cid>4</cid> + <description>�C���a�U�ɽu���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-211.C-0"> + <tid>211</tid> + <cid>0</cid> + <description>�C���[�ű���u</description> + <elementCriterion> + <elementType>4</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-211.C-1"> + <tid>211</tid> + <cid>1</cid> + <description>�C���[�ű���u</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-211.C-2"> + <tid>211</tid> + <cid>2</cid> + <description>�C���[�ű���u�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-212.C-0"> + <tid>212</tid> + <cid>0</cid> + <description>�C���[�ųs������u</description> + <elementCriterion> + <elementType>4</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-212.C-1"> + <tid>212</tid> + <cid>1</cid> + <description>�C���[�ųs������u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-212.C-2"> + <tid>212</tid> + <cid>2</cid> + <description>�C���[�ųs������u�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-213.C-0"> + <tid>213</tid> + <cid>0</cid> + <description>�C���a�U�s������u</description> + <elementCriterion> + <elementType>4</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-213.C-1"> + <tid>213</tid> + <cid>1</cid> + <description>�C���a�U�s������u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-213.C-2"> + <tid>213</tid> + <cid>2</cid> + <description>�C���a�U�s������u�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-215.C-0"> + <tid>215</tid> + <cid>0</cid> + <description>�C���۰ʭt�������}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-216.C-0"> + <tid>216</tid> + <cid>0</cid> + <description>�a�U�C���ʵ���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-216.C-1"> + <tid>216</tid> + <cid>1</cid> + <description>�C���ʵ������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-216.C-2"> + <tid>216</tid> + <cid>2</cid> + <description>�C���ʵ������P���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-217.C-0"> + <tid>217</tid> + <cid>0</cid> + <description>�C���a�U���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <!-- ���l --> + <TypeCompFilter name="FSC-300.C-0"> + <tid>300</tid> + <cid>0</cid> + <description>�q�T���l�u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-1"> + <tid>300</tid> + <cid>1</cid> + <description>���ֹq�l����(����)���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-2"> + <tid>300</tid> + <cid>2</cid> + <description>���ֹq�l��r�������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-3"> + <tid>300</tid> + <cid>3</cid> + <description>���ֹq�l�u�Ÿ�</description> + <elementCriterion> + <elementType>4</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-300.C-4"> + <tid>300</tid> + <cid>4</cid> + <description>���ֹq�l���I�Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-301.C-0"> + <tid>301</tid> + <cid>0</cid> + <description>���O����u</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-301.C-1"> + <tid>301</tid> + <cid>1</cid> + <description>���O����u�u�Ÿ�</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-301.C-3"> + <tid>301</tid> + <cid>3</cid> + <description>���O����u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-999.C-0"> + <tid>999</tid> + <cid>0</cid> + <description>���O</description> + <elementCriterion> + <elementType>4</elementType> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-113.C-0"> + <tid>113</tid> + <cid>0</cid> + <description>�����a�U���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-0"> + <tid>403</tid> + <cid>0</cid> + <description>���C���H���</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-1"> + <tid>403</tid> + <cid>1</cid> + <description>���C���H��ծy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-2"> + <tid>403</tid> + <cid>2</cid> + <description>���C���H��ն��Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <EllipseShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-4"> + <tid>403</tid> + <cid>4</cid> + <description>���O�ն��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <EllipseShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-5"> + <tid>403</tid> + <cid>5</cid> + <description>���O�ծy�е��O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-6"> + <tid>403</tid> + <cid>6</cid> + <description>���֤ն��Ÿ�</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <EllipseShapeCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-403.C-7"> + <tid>403</tid> + <cid>7</cid> + <description>���l�ծy�е��O(���l�ϥ�)</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-0"> + <tid>401</tid> + <cid>0</cid> + <description>��</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-1"> + <tid>401</tid> + <cid>1</cid> + <description>���u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-2"> + <tid>401</tid> + <cid>2</cid> + <description>���U</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-3"> + <tid>401</tid> + <cid>3</cid> + <description>����r�������O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-401.C-5"> + <tid>401</tid> + <cid>5</cid> + <description>���_���Ϭq�Ϲj</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-302.C-0"> + <tid>302</tid> + <cid>0</cid> + <description>���O�t���u</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-302.C-1"> + <tid>302</tid> + <cid>1</cid> + <description>���O�t���u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-303.C-0"> + <tid>303</tid> + <cid>0</cid> + <description>���O�ާ@�u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-303.C-1"> + <tid>303</tid> + <cid>1</cid> + <description>���O�ާ@�u�u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-303.C-3"> + <tid>303</tid> + <cid>3</cid> + <description>���O�ާ@�u���O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-305.C-0"> + <tid>305</tid> + <cid>0</cid> + <description>���O�I����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-306.C-0"> + <tid>306</tid> + <cid>0</cid> + <description>���O�ɱ��}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-307.C-0"> + <tid>307</tid> + <cid>0</cid> + <description>���O���[�I</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-308.C-0"> + <tid>308</tid> + <cid>0</cid> + <description>���O��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-311.C-0"> + <tid>311</tid> + <cid>0</cid> + <description>���O�x�b</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-311.C-1"> + <tid>311</tid> + <cid>1</cid> + <description>���O�x�b�ϸ�(�e�q.����)���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-314.C-0"> + <tid>314</tid> + <cid>0</cid> + <description>�[�Ÿ��O�t���u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-314.C-1"> + <tid>314</tid> + <cid>1</cid> + <description>�[�Ÿ��O�t���u���O</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-315.C-0"> + <tid>315</tid> + <cid>0</cid> + <description>�[�Ÿ��O����u</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-315.C-1"> + <tid>315</tid> + <cid>1</cid> + <description>�[�Ÿ��O����u</description> + <elementCriterion> + <elementType>7</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-316.C-0"> + <tid>316</tid> + <cid>0</cid> + <description>���O����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-317.C-0"> + <tid>317</tid> + <cid>0</cid> + <description>���O����}��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-317.C-1"> + <tid>317</tid> + <cid>1</cid> + <description>���O����}�����O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-318.C-0"> + <tid>318</tid> + <cid>0</cid> + <description>���O�y��</description> + <elementCriterion> + <elementType>12</elementType> + </elementCriterion> + <LineCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-319.C-0"> + <tid>319</tid> + <cid>0</cid> + <description>���֦��e</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-320.C-0"> + <tid>320</tid> + <cid>0</cid> + <description>���ֳq�T���Y</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-323.C-0"> + <tid>323</tid> + <cid>0</cid> + <description>���q�ഫ��</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-324.C-0"> + <tid>324</tid> + <cid>0</cid> + <description>�۰ʤƻ�����</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <SymbolCreateStrategy/> + </TypeCompFilter> + <TypeCompFilter name="FSC-324.C-1"> + <tid>324</tid> + <cid>1</cid> + <description>�۰ʤƻ��������O</description> + <elementCriterion> + <elementType>17</elementType> + </elementCriterion> + <TextCreateStrategy/> + </TypeCompFilter> + <!-- Dummy + <TypeCompLevelFilter name="DemoFeature3"> + <tid>999</tid> + <cid>2</cid> + <lid>34</lid> + <description>DemoFilter for DemoFeature</description> + <TextCreateStrategy-None/> + </TypeCompLevelFilter> + --> +</ElementDispatcherRules> diff --git a/xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testRules.xml b/xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testRules.xml new file mode 100644 index 0000000..0272b88 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/test/resources/com/ximple/eofms/filter/test-data/testRules.xml @@ -0,0 +1,161 @@ +<?xml version='1.0' encoding="big5"?> +<!DOCTYPE digester-rules PUBLIC "-//Jakarta Apache //DTD digester-rules XML V1.0//EN" "digester-rules.dtd"> +<digester-rules> + <pattern value="ElementDispatcherRules"> + <object-create-rule classname="com.ximple.eofms.filter.ElementDispatcher"/> + <set-properties-rule/> + <pattern value="TypeFilter"> + <object-create-rule classname="com.ximple.eofms.filter.TypeIdDispatchableFilter"/> + <set-next-rule methodname="addRule" paramtype="com.ximple.eofms.filter.ElementDispatchableFilter"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="name"/> + <bean-property-setter-rule pattern="description"/> + <bean-property-setter-rule pattern="elmtype"/> + <bean-property-setter-rule pattern="tid"/> + <pattern value="LineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="TextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="SymbolCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateSymbolStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="LineTextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ArcLineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateArcLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="EllipseShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateEllipseShapeLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + </pattern> + <pattern value="TypeCompFilter"> + <object-create-rule classname="com.ximple.eofms.filter.TypeCompIdDispatchableFilter"/> + <set-next-rule methodname="addRule" paramtype="com.ximple.eofms.filter.ElementDispatchableFilter"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="name"/> + <bean-property-setter-rule pattern="description"/> + <!-- <bean-property-setter-rule pattern="elmtype"/> --> + <bean-property-setter-rule pattern="tid"/> + <bean-property-setter-rule pattern="cid"/> + <pattern value="elementCriterion"> + <object-create-rule classname="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-next-rule methodname="addCriterion" paramtype="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="elementType"/> + </pattern> + <pattern value="LineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="TextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="SymbolCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateSymbolStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="LineTextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ArcLineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateArcLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="EllipseShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateEllipseShapeLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + </pattern> + <pattern value="TypeCompLevelFilter"> + <object-create-rule classname="com.ximple.eofms.filter.TypeCompLevelIdDispatchableFilter"/> + <set-next-rule methodname="addRule" paramtype="com.ximple.eofms.filter.ElementDispatchableFilter"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="name"/> + <bean-property-setter-rule pattern="description"/> + <!-- <bean-property-setter-rule pattern="elmtype"/> --> + <bean-property-setter-rule pattern="tid"/> + <bean-property-setter-rule pattern="cid"/> + <!-- <bean-property-setter-rule pattern="lid"/> --> + <pattern value="elementCriterion"> + <object-create-rule classname="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-next-rule methodname="addCriterion" paramtype="com.ximple.eofms.filter.ElementTypeCriterion"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="elementType"/> + </pattern> + <pattern value="elementLayerCriterion"> + <object-create-rule classname="com.ximple.eofms.filter.ElementLevelCriterion"/> + <set-next-rule methodname="addLayerCriterion" paramtype="com.ximple.eofms.filter.ElementLevelCriterion"/> + <set-properties-rule/> + <bean-property-setter-rule pattern="elementLayer"/> + </pattern> + <pattern value="LineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="TextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="SymbolCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateSymbolStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="LineTextCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateLineTextStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateShapeStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="ArcLineCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateArcLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + <pattern value="EllipseShapeCreateStrategy"> + <object-create-rule classname="com.ximple.eofms.filter.CreateEllipseShapeLineStringStrategy"/> + <set-next-rule methodname="setCreateStrategy" paramtype="com.ximple.eofms.filter.CreateFeatureTypeStrategy"/> + <set-properties-rule/> + </pattern> + </pattern> + </pattern> +</digester-rules> \ No newline at end of file -- Gitblit v0.0.0-SNAPSHOT