diff --git a/cots/ll.netcdf.linux32/.classpath b/cots/ll.netcdf.linux32/.classpath new file mode 100644 index 0000000000..bc74aabe31 --- /dev/null +++ b/cots/ll.netcdf.linux32/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/cots/ll.netcdf.linux32/.project b/cots/ll.netcdf.linux32/.project new file mode 100644 index 0000000000..7c683207f1 --- /dev/null +++ b/cots/ll.netcdf.linux32/.project @@ -0,0 +1,28 @@ + + + ll.netcdf.linux32 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/cots/ll.netcdf.linux32/.settings/org.eclipse.jdt.core.prefs b/cots/ll.netcdf.linux32/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/cots/ll.netcdf.linux32/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/cots/ll.netcdf.linux32/META-INF/MANIFEST.MF b/cots/ll.netcdf.linux32/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..f60cf67f5f --- /dev/null +++ b/cots/ll.netcdf.linux32/META-INF/MANIFEST.MF @@ -0,0 +1,8 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: NetCDF JNI Linux32 +Bundle-SymbolicName: ll.netcdf.linux32 +Bundle-Version: 1.0.0.qualifier +Fragment-Host: ll.netcdf;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Eclipse-PlatformFilter: (& (osgi.os=linux) (osgi.arch=x86)) diff --git a/cots/ll.netcdf.linux32/build.properties b/cots/ll.netcdf.linux32/build.properties new file mode 100644 index 0000000000..4073c9385f --- /dev/null +++ b/cots/ll.netcdf.linux32/build.properties @@ -0,0 +1,12 @@ +bin.includes = META-INF/,\ + .,\ + libhdf5.so,\ + libnetcdf.so.7.2.0,\ + libnetcdf.so.7,\ + libnetcdf.so,\ + libllnetcdf.so,\ + libhdf5_hl.so.7.0.3,\ + libhdf5_hl.so.7,\ + libhdf5_hl.so,\ + libhdf5.so.7.0.3,\ + libhdf5.so.7 diff --git a/cots/ll.netcdf.linux32/libhdf5.so b/cots/ll.netcdf.linux32/libhdf5.so new file mode 100644 index 0000000000..edfdbac1eb Binary files /dev/null and b/cots/ll.netcdf.linux32/libhdf5.so differ diff --git a/cots/ll.netcdf.linux32/libhdf5.so.7 b/cots/ll.netcdf.linux32/libhdf5.so.7 new file mode 100644 index 0000000000..edfdbac1eb Binary files /dev/null and b/cots/ll.netcdf.linux32/libhdf5.so.7 differ diff --git a/cots/ll.netcdf.linux32/libhdf5.so.7.0.3 b/cots/ll.netcdf.linux32/libhdf5.so.7.0.3 new file mode 100644 index 0000000000..edfdbac1eb Binary files /dev/null and b/cots/ll.netcdf.linux32/libhdf5.so.7.0.3 differ diff --git a/cots/ll.netcdf.linux32/libhdf5_hl.so b/cots/ll.netcdf.linux32/libhdf5_hl.so new file mode 100644 index 0000000000..cac51b0637 Binary files /dev/null and b/cots/ll.netcdf.linux32/libhdf5_hl.so differ diff --git a/cots/ll.netcdf.linux32/libhdf5_hl.so.7 b/cots/ll.netcdf.linux32/libhdf5_hl.so.7 new file mode 100644 index 0000000000..cac51b0637 Binary files /dev/null and b/cots/ll.netcdf.linux32/libhdf5_hl.so.7 differ diff --git a/cots/ll.netcdf.linux32/libhdf5_hl.so.7.0.3 b/cots/ll.netcdf.linux32/libhdf5_hl.so.7.0.3 new file mode 100644 index 0000000000..cac51b0637 Binary files /dev/null and b/cots/ll.netcdf.linux32/libhdf5_hl.so.7.0.3 differ diff --git a/cots/ll.netcdf.linux32/libllnetcdf.so b/cots/ll.netcdf.linux32/libllnetcdf.so new file mode 100644 index 0000000000..2a7f743229 Binary files /dev/null and b/cots/ll.netcdf.linux32/libllnetcdf.so differ diff --git a/cots/ll.netcdf.linux32/libnetcdf.so b/cots/ll.netcdf.linux32/libnetcdf.so new file mode 100644 index 0000000000..3112ef516b Binary files /dev/null and b/cots/ll.netcdf.linux32/libnetcdf.so differ diff --git a/cots/ll.netcdf.linux32/libnetcdf.so.7 b/cots/ll.netcdf.linux32/libnetcdf.so.7 new file mode 100644 index 0000000000..3112ef516b Binary files /dev/null and b/cots/ll.netcdf.linux32/libnetcdf.so.7 differ diff --git a/cots/ll.netcdf.linux32/libnetcdf.so.7.2.0 b/cots/ll.netcdf.linux32/libnetcdf.so.7.2.0 new file mode 100644 index 0000000000..3112ef516b Binary files /dev/null and b/cots/ll.netcdf.linux32/libnetcdf.so.7.2.0 differ diff --git a/cots/ll.netcdf.linux64/.classpath b/cots/ll.netcdf.linux64/.classpath new file mode 100644 index 0000000000..bc74aabe31 --- /dev/null +++ b/cots/ll.netcdf.linux64/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/cots/ll.netcdf.linux64/.project b/cots/ll.netcdf.linux64/.project new file mode 100644 index 0000000000..7f1e2c048a --- /dev/null +++ b/cots/ll.netcdf.linux64/.project @@ -0,0 +1,28 @@ + + + ll.netcdf.linux64 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/cots/ll.netcdf.linux64/.settings/org.eclipse.jdt.core.prefs b/cots/ll.netcdf.linux64/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/cots/ll.netcdf.linux64/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/cots/ll.netcdf.linux64/META-INF/MANIFEST.MF b/cots/ll.netcdf.linux64/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..3bc7e5b42c --- /dev/null +++ b/cots/ll.netcdf.linux64/META-INF/MANIFEST.MF @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: NetCDF JNI Linux64 +Bundle-SymbolicName: ll.netcdf.linux64 +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: Raytheon-bundled OSS +Fragment-Host: ll.netcdf;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Eclipse-PlatformFilter: (& (osgi.os=linux) (osgi.arch=x86_64)) diff --git a/cots/ll.netcdf.linux64/build.properties b/cots/ll.netcdf.linux64/build.properties new file mode 100644 index 0000000000..f54a1a241d --- /dev/null +++ b/cots/ll.netcdf.linux64/build.properties @@ -0,0 +1,15 @@ +bin.includes = META-INF/,\ + .,\ + libz.so.1.2.7,\ + libz.so.1,\ + libz.so,\ + libnetcdf.so.7.2.0,\ + libnetcdf.so.7,\ + libnetcdf.so,\ + libllnetcdf.so,\ + libhdf5_hl.so.7.0.3,\ + libhdf5_hl.so.7,\ + libhdf5_hl.so,\ + libhdf5.so.7.0.3,\ + libhdf5.so.7,\ + libhdf5.so diff --git a/cots/ll.netcdf.linux64/libhdf5.so b/cots/ll.netcdf.linux64/libhdf5.so new file mode 100755 index 0000000000..60f9577492 Binary files /dev/null and b/cots/ll.netcdf.linux64/libhdf5.so differ diff --git a/cots/ll.netcdf.linux64/libhdf5.so.7 b/cots/ll.netcdf.linux64/libhdf5.so.7 new file mode 100755 index 0000000000..60f9577492 Binary files /dev/null and b/cots/ll.netcdf.linux64/libhdf5.so.7 differ diff --git a/cots/ll.netcdf.linux64/libhdf5.so.7.0.3 b/cots/ll.netcdf.linux64/libhdf5.so.7.0.3 new file mode 100755 index 0000000000..60f9577492 Binary files /dev/null and b/cots/ll.netcdf.linux64/libhdf5.so.7.0.3 differ diff --git a/cots/ll.netcdf.linux64/libhdf5_hl.so b/cots/ll.netcdf.linux64/libhdf5_hl.so new file mode 100755 index 0000000000..06028d1994 Binary files /dev/null and b/cots/ll.netcdf.linux64/libhdf5_hl.so differ diff --git a/cots/ll.netcdf.linux64/libhdf5_hl.so.7 b/cots/ll.netcdf.linux64/libhdf5_hl.so.7 new file mode 100755 index 0000000000..06028d1994 Binary files /dev/null and b/cots/ll.netcdf.linux64/libhdf5_hl.so.7 differ diff --git a/cots/ll.netcdf.linux64/libhdf5_hl.so.7.0.3 b/cots/ll.netcdf.linux64/libhdf5_hl.so.7.0.3 new file mode 100755 index 0000000000..06028d1994 Binary files /dev/null and b/cots/ll.netcdf.linux64/libhdf5_hl.so.7.0.3 differ diff --git a/cots/ll.netcdf.linux64/libllnetcdf.so b/cots/ll.netcdf.linux64/libllnetcdf.so new file mode 100755 index 0000000000..e2d591c708 Binary files /dev/null and b/cots/ll.netcdf.linux64/libllnetcdf.so differ diff --git a/cots/ll.netcdf.linux64/libnetcdf.so b/cots/ll.netcdf.linux64/libnetcdf.so new file mode 100755 index 0000000000..122cc4f7dd Binary files /dev/null and b/cots/ll.netcdf.linux64/libnetcdf.so differ diff --git a/cots/ll.netcdf.linux64/libnetcdf.so.7 b/cots/ll.netcdf.linux64/libnetcdf.so.7 new file mode 100755 index 0000000000..122cc4f7dd Binary files /dev/null and b/cots/ll.netcdf.linux64/libnetcdf.so.7 differ diff --git a/cots/ll.netcdf.linux64/libnetcdf.so.7.2.0 b/cots/ll.netcdf.linux64/libnetcdf.so.7.2.0 new file mode 100755 index 0000000000..122cc4f7dd Binary files /dev/null and b/cots/ll.netcdf.linux64/libnetcdf.so.7.2.0 differ diff --git a/cots/ll.netcdf.linux64/libz.so b/cots/ll.netcdf.linux64/libz.so new file mode 100755 index 0000000000..fb2e462128 Binary files /dev/null and b/cots/ll.netcdf.linux64/libz.so differ diff --git a/cots/ll.netcdf.linux64/libz.so.1 b/cots/ll.netcdf.linux64/libz.so.1 new file mode 100755 index 0000000000..fb2e462128 Binary files /dev/null and b/cots/ll.netcdf.linux64/libz.so.1 differ diff --git a/cots/ll.netcdf.linux64/libz.so.1.2.7 b/cots/ll.netcdf.linux64/libz.so.1.2.7 new file mode 100755 index 0000000000..fb2e462128 Binary files /dev/null and b/cots/ll.netcdf.linux64/libz.so.1.2.7 differ diff --git a/cots/ll.netcdf/.classpath b/cots/ll.netcdf/.classpath new file mode 100644 index 0000000000..a4ab395a1d --- /dev/null +++ b/cots/ll.netcdf/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/cots/ll.netcdf/.project b/cots/ll.netcdf/.project new file mode 100644 index 0000000000..741a9d78c3 --- /dev/null +++ b/cots/ll.netcdf/.project @@ -0,0 +1,28 @@ + + + ll.netcdf + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/cots/ll.netcdf/.settings/org.eclipse.jdt.core.prefs b/cots/ll.netcdf/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..409930d32a --- /dev/null +++ b/cots/ll.netcdf/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Fri Mar 01 16:54:04 CST 2013 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/cots/ll.netcdf/META-INF/MANIFEST.MF b/cots/ll.netcdf/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..cdb4d07563 --- /dev/null +++ b/cots/ll.netcdf/META-INF/MANIFEST.MF @@ -0,0 +1,11 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Netcdf +Bundle-SymbolicName: ll.netcdf +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: Raytheon-bundled OSS +Require-Bundle: org.eclipse.core.runtime +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: ll-netcdf-jni-1.3.jar +Export-Package: edu.mit.ll.netcdf +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 diff --git a/cots/ll.netcdf/build.properties b/cots/ll.netcdf/build.properties new file mode 100644 index 0000000000..b9d793fd7b --- /dev/null +++ b/cots/ll.netcdf/build.properties @@ -0,0 +1,3 @@ +bin.includes = META-INF/,\ + .,\ + ll-netcdf-jni-1.3.jar diff --git a/cots/ll.netcdf/ll-netcdf-jni-1.3.jar b/cots/ll.netcdf/ll-netcdf-jni-1.3.jar new file mode 100644 index 0000000000..741a52c33b Binary files /dev/null and b/cots/ll.netcdf/ll-netcdf-jni-1.3.jar differ diff --git a/cots/net.opengis/.classpath b/cots/net.opengis/.classpath index fb9aeaaecc..94e54d9176 100644 --- a/cots/net.opengis/.classpath +++ b/cots/net.opengis/.classpath @@ -1,17 +1,30 @@ + + + + + + + + + + + + + + + + - - - diff --git a/cots/net.opengis/META-INF/MANIFEST.MF b/cots/net.opengis/META-INF/MANIFEST.MF index e8c25f14b1..418483b236 100644 --- a/cots/net.opengis/META-INF/MANIFEST.MF +++ b/cots/net.opengis/META-INF/MANIFEST.MF @@ -6,30 +6,59 @@ Bundle-Version: 1.0.2 Bundle-ClassPath: filter-v_1_0_0-schema-1.0.2.jar, filter-v_1_1_0-schema-1.0.2.jar, gml-v_2_1_2-schema-1.0.2.jar, - gml-v_3_1_1-schema-1.0.2.jar, jaxb2-basics-runtime-0.6.0.jar, kml-v_2_2_0-schema-1.0.3.jar, ows-v_1_0_0-schema-1.0.2.jar, - ows-v_1_1_0-schema-1.0.2.jar, se-v_1_1_0-schema-1.0.2.jar, sld-v_1_0_0-schema-1.0.2.jar, sld-v_1_1_0-schema-1.0.2.jar, - wcs-v_1_1_2-schema-1.0.2.jar, wfs-v_1_1_0-schema-1.0.2.jar, wms-v_1_3_0-schema-1.0.2.jar, - wmts-v_1_0_0-schema-1.0.3.1.jar -Export-Package: net.opengis.filter.v_1_0_0, + wmts-v_1_0_0-schema-1.0.3.1.jar, + filter-v_2_0_0-schema-1.0.4-SNAPSHOT.jar, + gml-v_3_2_1-schema-1.0.4-SNAPSHOT.jar, + ows-v_1_1_0-schema-1.0.4-SNAPSHOT.jar, + wfs-v_2_0_0-schema-1.0.0.jar, + avwx-v_1_1_1-1.0.0.jar, + cv-v_0_2_2_gml32-1.0.0.jar, + om-v_1_0_0_gml32-1.0.0.jar, + sml-v_1_0_1_gml32-1.0.0.jar, + swe-v_1_0_1_gml32-1.0.0.jar, + wx-v_1_1_1-1.0.0.jar, + filter-v_2_0_0-schema-1.0.0.jar, + ic-v_2_0-schema-1.0.3.jar, + owsnt-v_1_1_0.jar, + ws-notification-schema-1.0.4.jar, + ws-addressing-schema-1.0.4.jar, + owsnt-v_1_1_0-1.0.0.jar, + gml-v_3_1_1-schema-1.1.0.jar, + wcs-v_1_1_2-schema-1.1.0.jar +Export-Package: com.eurocontrol.avwx.v_1_1_1, + com.eurocontrol.wx.v_1_1_1, + net.oasis.wsn.b2, + net.oasis.wsn.bf2, + net.oasis.wsn.br2, + net.oasis.wsn.t1, + net.opengis.cv.v_0_2_2_gml32, + net.opengis.filter.v_1_0_0, net.opengis.filter.v_1_1_0, + net.opengis.filter.v_2_0_0, net.opengis.gml.v_2_1_2, net.opengis.gml.v_3_1_1, + net.opengis.gml.v_3_2_1, net.opengis.kml.v_2_2_0, + net.opengis.om.v_1_0_0_gml32, net.opengis.ows.v_1_0_0, net.opengis.ows.v_1_1_0, + net.opengis.owsnt.v1, net.opengis.se.v_1_1_0, + net.opengis.sensorml.v_1_0_1_gml32, net.opengis.sld.v_1_0_0, net.opengis.sld.v_1_1_0, + net.opengis.swe.v_1_0_1_gml32, net.opengis.wcs.v_1_1_2, net.opengis.wfs.v_1_1_0, + net.opengis.wfs.v_2_0_0, net.opengis.wms.v_1_3_0, net.opengis.wmts.v_1_0_0, oasis.names.tc.ciq.xsdschema.xal._2, @@ -40,5 +69,7 @@ Export-Package: net.opengis.filter.v_1_0_0, org.jvnet.jaxb2_commons.xml.bind, org.jvnet.jaxb2_commons.xml.bind.annotation.adapters, org.w3.smil.v_2_0, - org.w3.smil.v_2_0.language + org.w3.smil.v_2_0.language, + org.w3c.ws_addressing, + us.gov.ic.ism.v_2_0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 diff --git a/cots/net.opengis/avwx-v_1_1_1-1.0.0.jar b/cots/net.opengis/avwx-v_1_1_1-1.0.0.jar new file mode 100644 index 0000000000..7ae63738e3 Binary files /dev/null and b/cots/net.opengis/avwx-v_1_1_1-1.0.0.jar differ diff --git a/cots/net.opengis/build.properties b/cots/net.opengis/build.properties index 325c31687d..41bb41e84d 100644 --- a/cots/net.opengis/build.properties +++ b/cots/net.opengis/build.properties @@ -3,15 +3,28 @@ bin.includes = META-INF/,\ filter-v_1_0_0-schema-1.0.2.jar,\ filter-v_1_1_0-schema-1.0.2.jar,\ gml-v_2_1_2-schema-1.0.2.jar,\ - gml-v_3_1_1-schema-1.0.2.jar,\ jaxb2-basics-runtime-0.6.0.jar,\ kml-v_2_2_0-schema-1.0.3.jar,\ - ows-v_1_0_0-schema-1.0.2.jar,\ - ows-v_1_1_0-schema-1.0.2.jar,\ se-v_1_1_0-schema-1.0.2.jar,\ sld-v_1_0_0-schema-1.0.2.jar,\ sld-v_1_1_0-schema-1.0.2.jar,\ - wcs-v_1_1_2-schema-1.0.2.jar,\ wfs-v_1_1_0-schema-1.0.2.jar,\ wms-v_1_3_0-schema-1.0.2.jar,\ - wmts-v_1_0_0-schema-1.0.3.1.jar + wmts-v_1_0_0-schema-1.0.3.1.jar,\ + gml-v_3_2_1-schema-1.0.4-SNAPSHOT.jar,\ + ows-v_1_1_0-schema-1.0.4-SNAPSHOT.jar,\ + wfs-v_2_0_0-schema-1.0.0.jar,\ + avwx-v_1_1_1-1.0.0.jar,\ + cv-v_0_2_2_gml32-1.0.0.jar,\ + om-v_1_0_0_gml32-1.0.0.jar,\ + sml-v_1_0_1_gml32-1.0.0.jar,\ + swe-v_1_0_1_gml32-1.0.0.jar,\ + wx-v_1_1_1-1.0.0.jar,\ + filter-v_2_0_0-schema-1.0.0.jar,\ + ic-v_2_0-schema-1.0.3.jar,\ + ws-notification-schema-1.0.4.jar,\ + ws-addressing-schema-1.0.4.jar,\ + owsnt-v_1_1_0-1.0.0.jar,\ + gml-v_3_1_1-schema-1.1.0.jar,\ + wcs-v_1_1_2-schema-1.1.0.jar,\ + ows-v_1_0_0-schema-1.0.2.jar diff --git a/cots/net.opengis/cv-v_0_2_2_gml32-1.0.0.jar b/cots/net.opengis/cv-v_0_2_2_gml32-1.0.0.jar new file mode 100644 index 0000000000..34af70c7fa Binary files /dev/null and b/cots/net.opengis/cv-v_0_2_2_gml32-1.0.0.jar differ diff --git a/cots/net.opengis/filter-v_2_0_0-schema-1.0.0.jar b/cots/net.opengis/filter-v_2_0_0-schema-1.0.0.jar new file mode 100644 index 0000000000..e4e3fd1539 Binary files /dev/null and b/cots/net.opengis/filter-v_2_0_0-schema-1.0.0.jar differ diff --git a/cots/net.opengis/gml-v_3_1_1-schema-1.1.0.jar b/cots/net.opengis/gml-v_3_1_1-schema-1.1.0.jar new file mode 100644 index 0000000000..372424f993 Binary files /dev/null and b/cots/net.opengis/gml-v_3_1_1-schema-1.1.0.jar differ diff --git a/cots/net.opengis/gml-v_3_2_1-schema-1.0.4-SNAPSHOT.jar b/cots/net.opengis/gml-v_3_2_1-schema-1.0.4-SNAPSHOT.jar new file mode 100644 index 0000000000..9e3d007322 Binary files /dev/null and b/cots/net.opengis/gml-v_3_2_1-schema-1.0.4-SNAPSHOT.jar differ diff --git a/cots/net.opengis/ic-v_2_0-schema-1.0.3.jar b/cots/net.opengis/ic-v_2_0-schema-1.0.3.jar new file mode 100644 index 0000000000..a2cb612cab Binary files /dev/null and b/cots/net.opengis/ic-v_2_0-schema-1.0.3.jar differ diff --git a/cots/net.opengis/om-v_1_0_0_gml32-1.0.0.jar b/cots/net.opengis/om-v_1_0_0_gml32-1.0.0.jar new file mode 100644 index 0000000000..0648fea7fb Binary files /dev/null and b/cots/net.opengis/om-v_1_0_0_gml32-1.0.0.jar differ diff --git a/cots/net.opengis/ows-v_1_1_0-schema-1.0.4-SNAPSHOT.jar b/cots/net.opengis/ows-v_1_1_0-schema-1.0.4-SNAPSHOT.jar new file mode 100644 index 0000000000..f4c6f27996 Binary files /dev/null and b/cots/net.opengis/ows-v_1_1_0-schema-1.0.4-SNAPSHOT.jar differ diff --git a/cots/net.opengis/owsnt-v_1_1_0-1.0.0.jar b/cots/net.opengis/owsnt-v_1_1_0-1.0.0.jar new file mode 100644 index 0000000000..c2bdd5a67c Binary files /dev/null and b/cots/net.opengis/owsnt-v_1_1_0-1.0.0.jar differ diff --git a/cots/net.opengis/sml-v_1_0_1_gml32-1.0.0.jar b/cots/net.opengis/sml-v_1_0_1_gml32-1.0.0.jar new file mode 100644 index 0000000000..71317a3e23 Binary files /dev/null and b/cots/net.opengis/sml-v_1_0_1_gml32-1.0.0.jar differ diff --git a/cots/net.opengis/swe-v_1_0_1_gml32-1.0.0.jar b/cots/net.opengis/swe-v_1_0_1_gml32-1.0.0.jar new file mode 100644 index 0000000000..b62e655b0e Binary files /dev/null and b/cots/net.opengis/swe-v_1_0_1_gml32-1.0.0.jar differ diff --git a/cots/net.opengis/wcs-v_1_1_2-schema-1.1.0.jar b/cots/net.opengis/wcs-v_1_1_2-schema-1.1.0.jar new file mode 100644 index 0000000000..61001f6db5 Binary files /dev/null and b/cots/net.opengis/wcs-v_1_1_2-schema-1.1.0.jar differ diff --git a/cots/net.opengis/wfs-v_2_0_0-schema-1.0.0.jar b/cots/net.opengis/wfs-v_2_0_0-schema-1.0.0.jar new file mode 100644 index 0000000000..b121621196 Binary files /dev/null and b/cots/net.opengis/wfs-v_2_0_0-schema-1.0.0.jar differ diff --git a/cots/net.opengis/ws-addressing-schema-1.0.4.jar b/cots/net.opengis/ws-addressing-schema-1.0.4.jar new file mode 100644 index 0000000000..38afcfaf85 Binary files /dev/null and b/cots/net.opengis/ws-addressing-schema-1.0.4.jar differ diff --git a/cots/net.opengis/ws-notification-schema-1.0.4.jar b/cots/net.opengis/ws-notification-schema-1.0.4.jar new file mode 100644 index 0000000000..f4af81c874 Binary files /dev/null and b/cots/net.opengis/ws-notification-schema-1.0.4.jar differ diff --git a/cots/net.opengis/wx-v_1_1_1-1.0.0.jar b/cots/net.opengis/wx-v_1_1_1-1.0.0.jar new file mode 100644 index 0000000000..1d71c35b87 Binary files /dev/null and b/cots/net.opengis/wx-v_1_1_1-1.0.0.jar differ diff --git a/cots/org.w3.XMLSchema/.classpath b/cots/org.w3.XMLSchema/.classpath new file mode 100644 index 0000000000..75db50d64f --- /dev/null +++ b/cots/org.w3.XMLSchema/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/cots/org.w3.XMLSchema/.project b/cots/org.w3.XMLSchema/.project new file mode 100644 index 0000000000..7b7e2e2679 --- /dev/null +++ b/cots/org.w3.XMLSchema/.project @@ -0,0 +1,28 @@ + + + org.w3.XMLSchema + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/cots/org.w3.XMLSchema/.settings/org.eclipse.jdt.core.prefs b/cots/org.w3.XMLSchema/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c38765ff99 --- /dev/null +++ b/cots/org.w3.XMLSchema/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Wed Oct 10 14:13:24 CDT 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/cots/org.w3.XMLSchema/META-INF/MANIFEST.MF b/cots/org.w3.XMLSchema/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..e8ad70a202 --- /dev/null +++ b/cots/org.w3.XMLSchema/META-INF/MANIFEST.MF @@ -0,0 +1,8 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: XMLSchema +Bundle-SymbolicName: org.w3.XMLSchema +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ClassPath: org.w3.XMLSchema.jar +Export-Package: org.w3.xmlschema diff --git a/cots/org.w3.XMLSchema/build.properties b/cots/org.w3.XMLSchema/build.properties new file mode 100644 index 0000000000..05a87bde68 --- /dev/null +++ b/cots/org.w3.XMLSchema/build.properties @@ -0,0 +1,3 @@ +bin.includes = META-INF/,\ + .,\ + org.w3.XMLSchema.jar diff --git a/cots/org.w3.XMLSchema/org.w3.XMLSchema.jar b/cots/org.w3.XMLSchema/org.w3.XMLSchema.jar new file mode 100644 index 0000000000..15fea08697 Binary files /dev/null and b/cots/org.w3.XMLSchema/org.w3.XMLSchema.jar differ diff --git a/edexOsgi/build.edex/esb/conf/modes.xml b/edexOsgi/build.edex/esb/conf/modes.xml index d177c07359..ac23d2cb29 100644 --- a/edexOsgi/build.edex/esb/conf/modes.xml +++ b/edexOsgi/build.edex/esb/conf/modes.xml @@ -330,9 +330,15 @@ request-router.xml utility-request.xml dpa-datadelivery.xml + + harvester-datadelivery-standalone.xml + ogc-common.xml .*-ogc-request.xml + .*-ogc-rest-request.xml + .*-ogc-soap-request.xml + .*-ogc-soap-wsdl.xml purge-spring.xml purge-spring-impl.xml @@ -342,10 +348,10 @@ dataProviderAgentTemplate - madis-common.xml pointdata-common.xml - madis-dpa-ingest.xml + madis-common.xml madis-ogc.xml + madis-ogc-registry.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.json/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.json/META-INF/MANIFEST.MF index efe9461c96..06b49fb56c 100644 --- a/edexOsgi/com.raytheon.uf.common.json/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.json/META-INF/MANIFEST.MF @@ -7,10 +7,10 @@ Bundle-Vendor: RAYTHEON Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Require-Bundle: org.codehaus.jackson;bundle-version="1.7.3", org.geotools;bundle-version="2.6.4", - org.apache.commons.pool;bundle-version="1.3.0" + org.apache.commons.pool;bundle-version="1.3.0", + com.raytheon.uf.common.status;bundle-version="1.12.1174" Export-Package: com.raytheon.uf.common.json, com.raytheon.uf.common.json.geo, com.raytheon.uf.common.json.impl, com.raytheon.uf.common.json.jackson, com.raytheon.uf.common.json.jackson.util -Import-Package: org.apache.commons.logging diff --git a/edexOsgi/com.raytheon.uf.common.json/src/com/raytheon/uf/common/json/impl/JsonSrvImpl.java b/edexOsgi/com.raytheon.uf.common.json/src/com/raytheon/uf/common/json/impl/JsonSrvImpl.java index b84e68f284..8e19d57238 100644 --- a/edexOsgi/com.raytheon.uf.common.json/src/com/raytheon/uf/common/json/impl/JsonSrvImpl.java +++ b/edexOsgi/com.raytheon.uf.common.json/src/com/raytheon/uf/common/json/impl/JsonSrvImpl.java @@ -33,14 +33,14 @@ import java.io.OutputStream; import java.util.Map; import java.util.TreeMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectWriter; import com.raytheon.uf.common.json.JsonException; import com.raytheon.uf.common.json.JsonService; import com.raytheon.uf.common.json.jackson.JacksonPool; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; /** * @author bclement @@ -50,7 +50,7 @@ public class JsonSrvImpl implements JsonService { private JacksonPool pool; - private Log log = LogFactory.getLog(this.getClass()); + private IUFStatusHandler log = UFStatus.getHandler(this.getClass()); public JsonSrvImpl() { pool = new JacksonPool(); diff --git a/edexOsgi/com.raytheon.uf.common.nc4/.classpath b/edexOsgi/com.raytheon.uf.common.nc4/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.nc4/.project b/edexOsgi/com.raytheon.uf.common.nc4/.project new file mode 100644 index 0000000000..90f0fdf163 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.common.nc4 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.common.nc4/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.common.nc4/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..1b879432d4 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Tue Mar 05 10:11:29 CST 2013 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.common.nc4/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.nc4/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..8e1c53b539 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Nc4 +Bundle-SymbolicName: com.raytheon.uf.common.nc4 +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: com.raytheon.uf.common.nc4, + com.raytheon.uf.common.nc4.cf +Require-Bundle: ll.netcdf;bundle-version="1.0.0", + org.apache.commons.lang;bundle-version="2.3.0", + com.raytheon.uf.common.status;bundle-version="1.12.1174" diff --git a/edexOsgi/com.raytheon.uf.common.nc4/META-INF/nc4-CF-grid-mapping.properties b/edexOsgi/com.raytheon.uf.common.nc4/META-INF/nc4-CF-grid-mapping.properties new file mode 100644 index 0000000000..0e9ee18662 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/META-INF/nc4-CF-grid-mapping.properties @@ -0,0 +1,2 @@ +central_meridian=longitude_of_central_meridian +latitude_of_origin=latitude_of_projection_origin \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.nc4/build.properties b/edexOsgi/com.raytheon.uf.common.nc4/build.properties new file mode 100644 index 0000000000..aaefddf8d4 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + bin/ diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcBase.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcBase.java new file mode 100644 index 0000000000..873de732fe --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcBase.java @@ -0,0 +1,229 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4; + +import java.util.Arrays; + +import org.apache.commons.lang.ArrayUtils; + +import edu.mit.ll.netcdf.LLNetcdfAttrJNI; +import edu.mit.ll.netcdf.LLNetcdfException; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 7, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class NcBase { + + protected int fileId; + + protected int varId; + + protected final LLNetcdfAttrJNI attrs = new LLNetcdfAttrJNI(); + + protected void init(int fileId, int varId) { + this.fileId = fileId; + this.varId = varId; + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * name of attribute + * @param value + * value of attribute + * @throws NetcdfException + */ + public void putBytesAttribute(String name, byte[] value) + throws NetcdfException { + try { + attrs.writeByteArrayAttr(fileId, varId, name, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * name of attribute + * @param value + * value of attribute + * @throws NetcdfException + */ + public void putStringAttribute(String name, String value) + throws NetcdfException { + try { + attrs.writeStringAttr(fileId, varId, name, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * name of attribute + * @param value + * value of attribute + * @throws NetcdfException + */ + public void putStringsAttribute(String name, String[] value) + throws NetcdfException { + try { + attrs.writeStringArrayAttr(fileId, varId, name, value.length, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * name of attribute + * @param value + * value of attribute + * @throws NetcdfException + */ + public void putFloatsAttribute(String name, float[] value) + throws NetcdfException { + try { + attrs.writeFloatArrayAttr(fileId, varId, name, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * name of attribute + * @param value + * value of attribute + * @throws NetcdfException + */ + public void putDoublesAttribute(String name, double[] value) + throws NetcdfException { + try { + attrs.writeDoubleArrayAttr(fileId, varId, name, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * name of attribute + * @param value + * value of attribute + * @throws NetcdfException + */ + public void putShortsAttribute(String name, short[] value) + throws NetcdfException { + try { + attrs.writeShortArrayAttr(fileId, varId, name, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * name of attribute + * @param value + * value of attribute + * @throws NetcdfException + */ + public void putIntsAttribute(String name, int[] value) + throws NetcdfException { + try { + attrs.writeIntegerArrayAttr(fileId, varId, name, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Add attribute. This method can only be called when file is in define mode + * before {@link Netcdf#endFileDefinition()} is called. + * + * @param name + * @param value + * @throws NetcdfException + */ + public void putNumberAttribute(String name, Number[] value) + throws NetcdfException { + if (value.length < 1) { + throw new NetcdfException("Unable to write empty attribute array"); + } + Class c = value[0].getClass(); + if (c.equals(Byte.class)) { + Byte[] tmp = Arrays.copyOf(value, value.length, Byte[].class); + putBytesAttribute(name, ArrayUtils.toPrimitive((tmp))); + } else if (c.equals(Short.class)) { + Short[] tmp = Arrays.copyOf(value, value.length, Short[].class); + putShortsAttribute(name, ArrayUtils.toPrimitive((tmp))); + } else if (c.equals(Integer.class)) { + Integer[] tmp = Arrays.copyOf(value, value.length, Integer[].class); + putIntsAttribute(name, ArrayUtils.toPrimitive((tmp))); + } else if (c.equals(Float.class)) { + Float[] tmp = Arrays.copyOf(value, value.length, Float[].class); + putFloatsAttribute(name, ArrayUtils.toPrimitive((tmp))); + } else if (c.equals(Double.class)) { + Double[] tmp = Arrays.copyOf(value, value.length, Double[].class); + putDoublesAttribute(name, ArrayUtils.toPrimitive((tmp))); + } else { + throw new NetcdfException("Unable to write attribute of type: " + c); + } + } + + /** + * @return the fileId + */ + public int getFileId() { + return fileId; + } + + /** + * @return the varId + */ + public int getVarId() { + return varId; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcConstants.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcConstants.java new file mode 100644 index 0000000000..8e9323c804 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcConstants.java @@ -0,0 +1,495 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Constants used in Netcdf library + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 5, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class NcConstants { + + public static final Map ERROR_MAP; + + /** Attribute id to put/get a global attribute. */ + public static final int NC_GLOBAL = -1; + + /** No Error */ + public static final int NC_NOERR = 0; + + /** Returned for all errors in the v2 API. */ + public static final int NC2_ERR = (-1); + + /** + * Not a netcdf id. + * + * The specified netCDF ID does not refer to an open netCDF dataset. + */ + public static final int NC_EBADID = (-33); + + /** Too many netcdfs open */ + public static final int NC_ENFILE = (-34); + + /** netcdf file exists && NC_NOCLOBBER */ + public static final int NC_EEXIST = (-35); + + /** Invalid Argument */ + public static final int NC_EINVAL = (-36); + + /** Write to read only */ + public static final int NC_EPERM = (-37); + + + + /** + * Operation not allowed in data mode. This is returned for netCDF classic + * or 64-bit offset files, or for netCDF-4 files, when they have been + * created with ::NC_CLASSIC_MODEL flag in nc_create(). + */ + public static final int NC_ENOTINDEFINE = (-38); + + /** + * Operation not allowed in define mode. + * + * The specified netCDF is in define mode rather than data mode. + * + * With netCDF-4/HDF5 files, this error will not occur, unless + * ::NC_CLASSIC_MODEL was used in nc_create(). + */ + public static final int NC_EINDEFINE = (-39); + + /** + * Index exceeds dimension bound. + * + * The specified corner indices were out of range for the rank of the + * specified variable. For example, a negative index or an index that is + * larger than the corresponding dimension length will cause an error. + */ + public static final int NC_EINVALCOORDS = (-40); + + /** NC_MAX_DIMS exceeded */ + public static final int NC_EMAXDIMS = (-41); + + /** String match to name in use */ + public static final int NC_ENAMEINUSE = (-42); + + /** Attribute not found */ + public static final int NC_ENOTATT = (-43); + + /** NC_MAX_ATTRS exceeded */ + public static final int NC_EMAXATTS = (-44); + + /** Not a netcdf data type */ + public static final int NC_EBADTYPE = (-45); + + /** Invalid dimension id or name */ + public static final int NC_EBADDIM = (-46); + + /** NC_UNLIMITED in the wrong index */ + public static final int NC_EUNLIMPOS = (-47); + + + + /** + * NC_MAX_VARS exceeded. Max number of variables exceeded in a classic or + * 64-bit offset file, or an netCDF-4 file with ::NC_CLASSIC_MODEL on. + */ + public static final int NC_EMAXVARS = (-48); + + /** + * Variable not found. The variable ID is invalid for the specified netCDF + * dataset. + */ + public static final int NC_ENOTVAR = (-49); + + /** Action prohibited on NC_GLOBAL varid */ + public static final int NC_EGLOBAL = (-50); + + /** Not a netcdf file */ + + public static final int NC_ENOTNC = (-51); + + /** In Fortran, string too short */ + public static final int NC_ESTS = (-52); + + /** NC_MAX_NAME exceeded */ + public static final int NC_EMAXNAME = (-53); + + /** NC_UNLIMITED size already in use */ + public static final int NC_EUNLIMIT = (-54); + + /** nc_rec op when there are no record vars */ + public static final int NC_ENORECVARS = (-55); + + /** Attempt to convert between text & numbers */ + public static final int NC_ECHAR = (-56); + + + + /** Start+count exceeds dimension bound. + + The specified edge lengths added to the specified corner would have + referenced data out of range for the rank of the specified + variable. For example, an edge length that is larger than the + corresponding dimension length minus the corner index will cause an + error. */ + public static final int NC_EEDGE = (-57); + + /** Illegal stride */ + public static final int NC_ESTRIDE = (-58); + + /** Attribute or variable name contains illegal characters */ + public static final int NC_EBADNAME = (-59); + + + + /** Math result not representable. + + One or more of the values are out of the range of values representable + by the desired type. */ + public static final int NC_ERANGE = (-60); + + /** Memory allocation (malloc) failure */ + public static final int NC_ENOMEM = (-61); + + /** One or more variable sizes violate format constraints */ + public static final int NC_EVARSIZE = (-62); + + /** Invalid dimension size */ + public static final int NC_EDIMSIZE = (-63); + + /** File likely truncated or possibly corrupted */ + public static final int NC_ETRUNC = (-64); + + /** Unknown axis type. */ + public static final int NC_EAXISTYPE = (-65); + + + /** Generic DAP error */ + public static final int NC_EDAP = (-66); + + /** Generic libcurl error */ + public static final int NC_ECURL = (-67); + + /** Generic IO error */ + public static final int NC_EIO = (-68); + + /** Attempt to access variable with no data */ + public static final int NC_ENODATA = (-69); + + /** DAP server error */ + public static final int NC_EDAPSVC = (-70); + + /** Malformed or inaccessible DAS */ + public static final int NC_EDAS = (-71); + + /** Malformed or inaccessible DDS */ + public static final int NC_EDDS = (-72); + + /** Malformed or inaccessible DATADDS */ + public static final int NC_EDATADDS = (-73); + + /** Malformed DAP URL */ + public static final int NC_EDAPURL = (-74); + + /** Malformed DAP Constraint */ + public static final int NC_EDAPCONSTRAINT = (-75); + + /** Untranslatable construct */ + public static final int NC_ETRANSLATION = (-76); + + /* + * The following was added in support of netcdf-4. Make all netcdf-4 error + * codes-100 so that errors can be added to netcdf-3 if needed. + */ + + /** Error at HDF5 layer. */ + public static final int NC_EHDFERR = (-101); + + /** Can't read. */ + public static final int NC_ECANTREAD = (-102); + + /** Can't write. */ + public static final int NC_ECANTWRITE = (-103); + + /** Can't create. */ + public static final int NC_ECANTCREATE = (-104); + + /** Problem with file metadata. */ + public static final int NC_EFILEMETA = (-105); + + /** Problem with dimension metadata. */ + public static final int NC_EDIMMETA = (-106); + + /** Problem with attribute metadata. */ + public static final int NC_EATTMETA = (-107); + + /** Problem with variable metadata. */ + public static final int NC_EVARMETA = (-108); + + /** Not a compound type. */ + public static final int NC_ENOCOMPOUND = (-109); + + /** Attribute already exists. */ + public static final int NC_EATTEXISTS = (-110); + + /** Attempting netcdf-4 operation on netcdf-3 file. */ + public static final int NC_ENOTNC4 = (-111); + + + + /** Attempting netcdf-4 operation on strict nc3 netcdf-4 file. */ + public static final int NC_ESTRICTNC3 = (-112); + + /** Attempting netcdf-3 operation on netcdf-4 file. */ + public static final int NC_ENOTNC3 = (-113); + + /** Parallel operation on file opened for non-parallel access. */ + public static final int NC_ENOPAR = (-114); + + /** Error initializing for parallel access. */ + public static final int NC_EPARINIT = (-115); + + /** Bad group ID. */ + public static final int NC_EBADGRPID = (-116); + + /** Bad type ID. */ + public static final int NC_EBADTYPID = (-117); + + /** Type has already been defined and may not be edited. */ + public static final int NC_ETYPDEFINED = (-118); + + /** Bad field ID. */ + public static final int NC_EBADFIELD = (-119); + + /** Bad class. */ + public static final int NC_EBADCLASS = (-120); + + /** Mapped access for atomic types only. */ + public static final int NC_EMAPTYPE = (-121); + + /** Attempt to define fill value when data already exists. */ + public static final int NC_ELATEFILL = (-122); + + /** Attempt to define var properties, like deflate, after enddef. */ + public static final int NC_ELATEDEF = (-123); + + /** Probem with HDF5 dimscales. */ + public static final int NC_EDIMSCALE = (-124); + + /** No group found. */ + public static final int NC_ENOGRP = (-125); + + /** Can't specify both contiguous and chunking. */ + public static final int NC_ESTORAGE = (-126); + + /** Bad chunksize. */ + public static final int NC_EBADCHUNK = (-127); + + /** Attempt to use feature that was not turned on when netCDF was built. */ + public static final int NC_ENOTBUILT = (-128); + + /** Error in using diskless access. */ + public static final int NC_EDISKLESS = (-129); + + /** Set read-only access for nc_open(). */ + public static final int NC_NOWRITE = 0x0000; + + /** Set read-write access for nc_open(). */ + public static final int NC_WRITE = 0x0001; + + /** Destroy existing file. Mode flag for nc_create(). */ + public static final int NC_CLOBBER = 0x0000; + + /** Don't destroy existing file. Mode flag for nc_create(). */ + public static final int NC_NOCLOBBER = 0x0004; + + /** Use diskless file. Mode flag for nc_open() or nc_create(). */ + public static final int NC_DISKLESS = 0x0008; + + /** Use diskless file with mmap. Mode flag for nc_open() or nc_create(). */ + public static final int NC_MMAP = 0x0010; + + /** Enforce classic model. Mode flag for nc_create(). */ + public static final int NC_CLASSIC_MODEL = 0x0100; + + /** Use large (64-bit) file offsets. Mode flag for nc_create(). */ + public static final int NC_64BIT_OFFSET = 0x0200; + + + + /** + * deprecated The following flag currently is ignored, but use in nc_open() + * or nc_create() may someday support use of advisory locking to prevent + * multiple writers from clobbering a file + */ + public static final int NC_LOCK = 0x0400; + + /** Share updates, limit cacheing. + Use this in mode flags for both nc_create() and nc_open(). */ + public static final int NC_SHARE = 0x0800; + + /** Use netCDF-4/HDF5 format. Mode flag for nc_create(). */ + public static final int NC_NETCDF4 = 0x1000; + + + + /** Turn on MPI I/O. + Use this in mode flags for both nc_create() and nc_open(). */ + public static final int NC_MPIIO = 0x2000; + /** Turn on MPI POSIX I/O. + Use this in mode flags for both nc_create() and nc_open(). */ + public static final int NC_MPIPOSIX = 0x4000; + + /** Use parallel-netcdf library. Mode flag for nc_open(). */ + public static final int NC_PNETCDF = 0x8000; + + /** + * Let nc__create() or nc__open() figure out as suitable chunk size. + */ + public static final int NC_SIZEHINT_DEFAULT = 0; + + /** signed 1 byte integer */ + public static final int NC_BYTE = 1; + + /** ISO/ASCII character */ + public static final int NC_CHAR = 2; + + /** signed 2 byte integer */ + public static final int NC_SHORT = 3; + + /** signed 4 byte integer */ + public static final int NC_INT = 4; + + /** single precision floating point number */ + public static final int NC_FLOAT = 5; + + /** double precision floating point number */ + public static final int NC_DOUBLE = 6; + + /** signed 8-byte int */ + public static final int NC_INT64 = 10; + + + static { + HashMap map = new HashMap(); + map.put(NC_NOERR, "No Error "); + map.put(NC2_ERR, "Returned for all errors in the v2 API. "); + + map.put(NC_EBADID, "Not a netcdf id. "); + map.put(NC_ENFILE, "Too many netcdfs open "); + map.put(NC_EEXIST, "netcdf file exists && NC_NOCLOBBER "); + map.put(NC_EINVAL, "Invalid Argument "); + map.put(NC_EPERM, "Write to read only "); + + map.put(NC_ENOTINDEFINE, "Operation not allowed in data mode. "); + map.put(NC_EINDEFINE, "Operation not allowed in define mode. "); + + map.put(NC_EINVALCOORDS, "Index exceeds dimension bound. "); + map.put(NC_EMAXDIMS, "NC_MAX_DIMS exceeded "); + map.put(NC_ENAMEINUSE, "String match to name in use "); + map.put(NC_ENOTATT, "Attribute not found "); + map.put(NC_EMAXATTS, "NC_MAX_ATTRS exceeded "); + map.put(NC_EBADTYPE, "Not a netcdf data type "); + map.put(NC_EBADDIM, "Invalid dimension id or name "); + map.put(NC_EUNLIMPOS, "NC_UNLIMITED in the wrong index "); + + map.put(NC_EMAXVARS, "NC_MAX_VARS exceeded. "); + + map.put(NC_ENOTVAR, "Variable not found. "); + map.put(NC_EGLOBAL, "Action prohibited on NC_GLOBAL varid "); + map.put(NC_ENOTNC, "Not a netcdf file "); + map.put(NC_ESTS, "In Fortran, string too short "); + map.put(NC_EMAXNAME, "NC_MAX_NAME exceeded "); + map.put(NC_EUNLIMIT, "NC_UNLIMITED size already in use "); + map.put(NC_ENORECVARS, "nc_rec op when there are no record vars "); + map.put(NC_ECHAR, "Attempt to convert between text & numbers "); + + map.put(NC_EEDGE, "Start+count exceeds dimension bound. "); + map.put(NC_ESTRIDE, "Illegal stride "); + map.put(NC_EBADNAME, + "Attribute or variable name contains illegal characters "); + + map.put(NC_ERANGE, + "One or more of the values are out of the range of values representable by the desired type. "); + map.put(NC_ENOMEM, "Memory allocation (malloc) failure "); + map.put(NC_EVARSIZE, + "One or more variable sizes violate format constraints "); + map.put(NC_EDIMSIZE, "Invalid dimension size "); + map.put(NC_ETRUNC, "File likely truncated or possibly corrupted "); + map.put(NC_EAXISTYPE, "Unknown axis type. "); + + map.put(NC_EDAP, "Generic DAP error "); + map.put(NC_ECURL, "Generic libcurl error "); + map.put(NC_EIO, "Generic IO error "); + map.put(NC_ENODATA, "Attempt to access variable with no data "); + map.put(NC_EDAPSVC, "DAP server error "); + map.put(NC_EDAS, "Malformed or inaccessible DAS "); + map.put(NC_EDDS, "Malformed or inaccessible DDS "); + map.put(NC_EDATADDS, "Malformed or inaccessible DATADDS "); + map.put(NC_EDAPURL, "Malformed DAP URL "); + map.put(NC_EDAPCONSTRAINT, "Malformed DAP Constraint"); + map.put(NC_ETRANSLATION, "Untranslatable construct "); + + map.put(NC_EHDFERR, "Error at HDF5 layer. "); + map.put(NC_ECANTREAD, "Can't read. "); + map.put(NC_ECANTWRITE, "Can't write. "); + map.put(NC_ECANTCREATE, "Can't create. "); + map.put(NC_EFILEMETA, "Problem with file metadata. "); + map.put(NC_EDIMMETA, "Problem with dimension metadata. "); + map.put(NC_EATTMETA, "Problem with attribute metadata. "); + map.put(NC_EVARMETA, "Problem with variable metadata. "); + map.put(NC_ENOCOMPOUND, "Not a compound type. "); + map.put(NC_EATTEXISTS, "Attribute already exists. "); + map.put(NC_ENOTNC4, "Attempting netcdf-4 operation on netcdf-3 file. "); + + map.put(NC_ESTRICTNC3, + "Attempting netcdf-4 operation on strict nc3 netcdf-4 file. "); + map.put(NC_ENOTNC3, "Attempting netcdf-3 operation on netcdf-4 file. "); + map.put(NC_ENOPAR, + "Parallel operation on file opened for non-parallel access. "); + map.put(NC_EPARINIT, "Error initializing for parallel access. "); + map.put(NC_EBADGRPID, "Bad group ID. "); + map.put(NC_EBADTYPID, "Bad type ID. "); + map.put(NC_ETYPDEFINED, + "Type has already been defined and may not be edited. "); + map.put(NC_EBADFIELD, "Bad field ID. "); + map.put(NC_EBADCLASS, "Bad class. "); + map.put(NC_EMAPTYPE, "Mapped access for atomic types only. "); + map.put(NC_ELATEFILL, + "Attempt to define fill value when data already exists. "); + map.put(NC_ELATEDEF, + "Attempt to define var properties, like deflate, after enddef. "); + map.put(NC_EDIMSCALE, "Probem with HDF5 dimscales. "); + map.put(NC_ENOGRP, "No group found. "); + map.put(NC_ESTORAGE, "Can't specify both contiguous and chunking. "); + map.put(NC_EBADCHUNK, "Bad chunksize. "); + map.put(NC_ENOTBUILT, + "Attempt to use feature that was not turned on when netCDF was built. "); + map.put(NC_EDISKLESS, "Error in using diskless access. "); + + ERROR_MAP = Collections.unmodifiableMap(map); + } +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcDimension.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcDimension.java new file mode 100644 index 0000000000..c8cc1b6c68 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcDimension.java @@ -0,0 +1,217 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4; + +import edu.mit.ll.netcdf.LLNetcdfDimJNI; +import edu.mit.ll.netcdf.LLNetcdfException; +import edu.mit.ll.netcdf.LLNetcdfVarJNI; + +/** + * Wrapper to NetCDF Dimension native library calls + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 5, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class NcDimension extends NcBase { + + protected final int dimId; + + protected final String name; + + protected final int len; + + protected final int dataType; + + protected final LLNetcdfDimJNI dims = new LLNetcdfDimJNI(); + + protected final LLNetcdfVarJNI vars = new LLNetcdfVarJNI(); + + /** + * @param fileId + * @param name + * @param len + * @param dataType + * @throws NetcdfException + */ + public NcDimension(int fileId, String name, int len, int dataType) + throws NetcdfException { + this.name = name; + this.len = len; + this.dataType = dataType; + try { + this.dimId = dims.defineDim(fileId, name, len); + int dimVar = vars.defineVar(fileId, name, dataType, 1, + new int[] { dimId }); + init(fileId, dimVar); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + public static class ShortDimension extends NcDimension { + + /** + * @param fileId + * @param name + * @param len + * @throws NetcdfException + */ + public ShortDimension(int fileId, String name, int len) + throws NetcdfException { + super(fileId, name, len, NcConstants.NC_SHORT); + } + + /** + * Write dimension axis values. This method can only be called when file + * is in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param values + * @throws NetcdfException + */ + public void putDim(short[] values) throws NetcdfException { + try { + vars.writeShortArrayVar(fileId, varId, new int[] { 0 }, + new int[] { values.length }, values); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + } + + public static class IntDimension extends NcDimension { + + /** + * @param fileId + * @param name + * @param len + * @throws NetcdfException + */ + public IntDimension(int fileId, String name, int len) + throws NetcdfException { + super(fileId, name, len, NcConstants.NC_INT); + } + + /** + * Write dimension axis values. This method can only be called when file + * is in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param values + * @throws NetcdfException + */ + public void putDim(int[] values) throws NetcdfException { + try { + vars.writeIntegerArrayVar(fileId, varId, new int[] { 0 }, + new int[] { values.length }, values); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + } + + public static class FloatDimension extends NcDimension { + + /** + * @param fileId + * @param name + * @param len + * @throws NetcdfException + */ + public FloatDimension(int fileId, String name, int len) + throws NetcdfException { + super(fileId, name, len, NcConstants.NC_FLOAT); + } + + /** + * Write dimension axis values. This method can only be called when file + * is in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param values + * @throws NetcdfException + */ + public void putDim(float[] values) throws NetcdfException { + try { + vars.writeFloatArrayVar(fileId, varId, new int[] { 0 }, + new int[] { values.length }, values); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + } + + public static class DoubleDimension extends NcDimension { + + /** + * @param fileId + * @param name + * @param len + * @throws NetcdfException + */ + public DoubleDimension(int fileId, String name, int len) + throws NetcdfException { + super(fileId, name, len, NcConstants.NC_DOUBLE); + } + + /** + * Write dimension axis values. This method can only be called when file + * is in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param values + * @throws NetcdfException + */ + public void putDim(double[] values) throws NetcdfException { + try { + vars.writeDoubleArrayVar(fileId, varId, new int[] { 0 }, + new int[] { values.length }, values); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the len + */ + public int getLen() { + return len; + } + + + /** + * @return the dimId + */ + public int getDimId() { + return dimId; + } + + /** + * @return the dataType + */ + public int getDataType() { + return dataType; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcFactory.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcFactory.java new file mode 100644 index 0000000000..e7b38b78a7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcFactory.java @@ -0,0 +1,76 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ConcurrentHashMap; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 6, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class NcFactory { + + private static final ConcurrentHashMap, Constructor> cmap = new ConcurrentHashMap, Constructor>(); + + @SuppressWarnings("unchecked") + public static T createDim(int fileId, String name, + int len, Class dimClass) throws SecurityException, + NoSuchMethodException, IllegalArgumentException, + InstantiationException, IllegalAccessException, + InvocationTargetException { + Constructor constructor = (Constructor) cmap.get(dimClass); + if (constructor == null) { + synchronized (cmap) { + constructor = (Constructor) cmap.get(dimClass); + if (constructor == null) { + constructor = dimClass.getConstructor(int.class, + String.class, int.class); + cmap.put(dimClass, constructor); + } + } + } + return constructor.newInstance(fileId, name, len); + } + + @SuppressWarnings("unchecked") + public static T createVar(int fileId, String name, + NcDimension[] dims, Class varClass) throws SecurityException, + NoSuchMethodException, IllegalArgumentException, + InstantiationException, IllegalAccessException, + InvocationTargetException { + Constructor constructor = (Constructor) cmap.get(varClass); + if (constructor == null) { + synchronized (cmap) { + constructor = (Constructor) cmap.get(varClass); + if (constructor == null) { + constructor = varClass.getConstructor(int.class, + String.class, NcDimension[].class); + cmap.put(varClass, constructor); + } + } + } + return constructor.newInstance(fileId, name, dims); + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcVariable.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcVariable.java new file mode 100644 index 0000000000..9ae9240b82 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NcVariable.java @@ -0,0 +1,274 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4; + +import edu.mit.ll.netcdf.LLNetcdfException; +import edu.mit.ll.netcdf.LLNetcdfVarJNI; + +/** + * Wrapper for NetCDF variable native library + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 5, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class NcVariable extends NcBase { + + protected final String name; + + protected final NcDimension[] dims; + + protected final int dataType; + + protected final LLNetcdfVarJNI vars = new LLNetcdfVarJNI(); + + /** + * @param fileId + * @param name + * @param dataType + * @param dims + * @throws NetcdfException + */ + public NcVariable(int fileId, String name, int dataType, NcDimension[] dims) + throws NetcdfException { + this.name = name; + this.dims = dims; + this.dataType = dataType; + int[] dimIds = new int[dims.length]; + for (int i = 0; i < dims.length; ++i) { + dimIds[i] = dims[i].getDimId(); + } + try { + int varId = vars.defineVar(fileId, name, dataType, dims.length, + dimIds); + init(fileId, varId); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + public static class ByteVariable extends NcVariable { + + /** + * @param fileId + * @param name + * @param dataType + * @param dims + * @throws NetcdfException + */ + public ByteVariable(int fileId, String name, NcDimension[] dims) + throws NetcdfException { + super(fileId, name, NcConstants.NC_BYTE, dims); + } + + /** + * Write data to variable. This method can only be called when file is + * in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param startIndex + * starting indexes for each dimension + * @param shape + * length of each dimension in value + * @param value + * data to be written + * @throws NetcdfException + */ + public void putVar(int[] startIndex, int[] shape, byte[] value) + throws NetcdfException { + try { + vars.writeByteArrayVar(fileId, varId, startIndex, shape, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + } + + public static class ShortVariable extends NcVariable { + + /** + * @param fileId + * @param name + * @param dataType + * @param dims + * @throws NetcdfException + */ + public ShortVariable(int fileId, String name, NcDimension[] dims) + throws NetcdfException { + super(fileId, name, NcConstants.NC_SHORT, dims); + } + + /** + * Write data to variable. This method can only be called when file is + * in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param startIndex + * starting indexes for each dimension + * @param shape + * length of each dimension in value + * @param value + * data to be written + * @throws NetcdfException + */ + public void putVar(int[] startIndex, int[] shape, short[] value) + throws NetcdfException { + try { + vars.writeShortArrayVar(fileId, varId, startIndex, shape, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + } + + public static class IntVariable extends NcVariable { + + /** + * @param fileId + * @param name + * @param dataType + * @param dims + * @throws NetcdfException + */ + public IntVariable(int fileId, String name, NcDimension[] dims) + throws NetcdfException { + super(fileId, name, NcConstants.NC_INT, dims); + } + + /** + * Write data to variable. This method can only be called when file is + * in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param startIndex + * starting indexes for each dimension + * @param shape + * length of each dimension in value + * @param value + * data to be written + * @throws NetcdfException + */ + public void putVar(int[] startIndex, int[] shape, int[] value) + throws NetcdfException { + try { + vars.writeIntegerArrayVar(fileId, varId, startIndex, shape, + value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + } + + public static class FloatVariable extends NcVariable { + + /** + * @param fileId + * @param name + * @param dataType + * @param dims + * @throws NetcdfException + */ + public FloatVariable(int fileId, String name, NcDimension[] dims) + throws NetcdfException { + super(fileId, name, NcConstants.NC_FLOAT, dims); + } + + /** + * Write data to variable. This method can only be called when file is + * in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param startIndex + * starting indexes for each dimension + * @param shape + * length of each dimension in value + * @param value + * data to be written + * @throws NetcdfException + */ + public void putVar(int[] startIndex, int[] shape, float[] value) + throws NetcdfException { + try { + vars.writeFloatArrayVar(fileId, varId, startIndex, shape, value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + } + + public static class DoubleVariable extends NcVariable { + + /** + * @param fileId + * @param name + * @param dataType + * @param dims + * @throws NetcdfException + */ + public DoubleVariable(int fileId, String name, NcDimension[] dims) + throws NetcdfException { + super(fileId, name, NcConstants.NC_DOUBLE, dims); + } + + /** + * Write data to variable. This method can only be called when file is + * in data mode after {@link Netcdf#endFileDefinition()} is called. + * + * @param startIndex + * starting indexes for each dimension + * @param shape + * length of each dimension in value + * @param value + * data to be written + * @throws NetcdfException + */ + public void putVar(int[] startIndex, int[] shape, double[] value) + throws NetcdfException { + try { + vars.writeDoubleArrayVar(fileId, varId, startIndex, shape, + value); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the dims + */ + public NcDimension[] getDims() { + return dims; + } + + /** + * @return the dataType + */ + public int getDataType() { + return dataType; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/Netcdf.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/Netcdf.java new file mode 100644 index 0000000000..13d2b28398 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/Netcdf.java @@ -0,0 +1,171 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4; + +import edu.mit.ll.netcdf.LLNetcdfException; +import edu.mit.ll.netcdf.LLNetcdfJNI; + +/** + * Wrapper to NetCDF 4 native library. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 5, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class Netcdf extends NcBase { + + protected final LLNetcdfJNI ncfile = new LLNetcdfJNI(); + + /** + * create mode for NetCDF 4 using classic model + */ + public static final int NETCDF4_CLASSIC_MODE = NcConstants.NC_CLASSIC_MODEL + | NcConstants.NC_NETCDF4; + + + /** + * @param path + * absolute path of file + * @throws NetcdfException + */ + public Netcdf(String path) throws NetcdfException { + this(path, NcConstants.NC_CLOBBER); + } + + /** + * @param path + * absolute path of file + * @param mode + * create mode passed to nc_open + * @throws NetcdfException + */ + public Netcdf(String path, int mode) throws NetcdfException { + this(path, mode, NcConstants.NC_SIZEHINT_DEFAULT, + NcConstants.NC_SIZEHINT_DEFAULT); + } + + /** + * @param path + * absolute path of file + * @param mode + * create mode passed to nc__open + * @param initialSize + * initial size hint passed to nc__open + * @param chunkSizeHint + * buffer size hint passed to nc__open + * @throws NetcdfException + */ + public Netcdf(String path, int mode, int initialSize, int chunkSizeHint) + throws NetcdfException { + try { + int fileId = ncfile.createFile(path, mode, initialSize, + chunkSizeHint); + init(fileId, NcConstants.NC_GLOBAL); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Define a NetCDF dimension in file. The return value can be used to + * populate the dimension axis values after {@link #endFileDefinition()} is + * called + * + * @param + * data type specific {@link NcDimension} sub class + * @param name + * name of dimension + * @param len + * length of dimension + * @param dimClass + * class object for {@link NcDimension} sub class + * @return datatype specific {@link NcDimension} object + * @throws NetcdfException + */ + public T defineDim(String name, int len, + Class dimClass) throws NetcdfException { + try { + return NcFactory.createDim(fileId, name, len, dimClass); + } catch (Exception e) { + throw new NetcdfException("Unable to create dimension", e); + } + } + + /** + * Define a NetCDF variable in file. The return value can be used to + * populate the variable values after {@link #endFileDefinition()} is called + * + * @param + * data type specific {@link NcVariable} sub class + * @param name + * name of variable + * @param dims + * array of dimensions for this variable in proper order + * @param varClass + * class object for {@link NcVariable} sub class + * @return datatype specific {@link NcVariable} object + * @throws NetcdfException + */ + public T defineVar(String name, NcDimension[] dims, + Class varClass) throws NetcdfException { + try { + return NcFactory.createVar(fileId, name, dims, varClass); + } catch (Exception e) { + throw new NetcdfException("Unable to create variable", e); + } + } + + /** + * End definition stage of file creation and start data writing stage. After + * this method is called, return values of + * {@link #defineDim(String, int, Class)} and + * {@link #defineVar(String, NcDimension[], Class)} can be used to write + * data to file. + * + * @throws NetcdfException + */ + public void endFileDefinition() throws NetcdfException { + try { + ncfile.endFileDefinition(fileId); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * Called after all data has been written to file. + * + * @throws NetcdfException + */ + public void close() throws NetcdfException { + try { + ncfile.closeFile(fileId); + } catch (LLNetcdfException e) { + throw new NetcdfException(e); + } + } + + /** + * @return the ncid + */ + public int getFileId() { + return fileId; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NetcdfException.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NetcdfException.java new file mode 100644 index 0000000000..51399e51dc --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/NetcdfException.java @@ -0,0 +1,84 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4; + +import edu.mit.ll.netcdf.LLNetcdfException; + +/** + * Exception used in Netcdf interface + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 5, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class NetcdfException extends Exception{ + + private static final long serialVersionUID = -508018999572379516L; + + protected int errorCode; + + /** + * + */ + public NetcdfException(LLNetcdfException llex) { + this(llex.getError()); + } + + public NetcdfException(int errorCode) { + super(NcConstants.ERROR_MAP.get(errorCode)); + } + + /** + * @param message + * @param cause + */ + public NetcdfException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message + */ + public NetcdfException(String message) { + super(message); + } + + /** + * @param cause + */ + public NetcdfException(Throwable cause) { + super(cause); + } + + /** + * @return the errorCode + */ + public int getErrorCode() { + return errorCode; + } + + /** + * @param errorCode + * the errorCode to set + */ + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CFConventions.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CFConventions.java new file mode 100644 index 0000000000..446658006a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CFConventions.java @@ -0,0 +1,53 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4.cf; + +/** + * CF Conventions as described for NetCDF library 1.6 + * Place holder for convention descriptions and names + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 29, 2013            ekladstrup     Initial creation
+ *
+ * 
+ * + * @author ekladstrup + * @version 1.0 + */ + +public enum CFConventions { + + CF16("CF-1.6"); + + /** + * @param value + */ + private CFConventions(final String value) { + this.value = value; + } + + private final String value; + + /* + * (non-Javadoc) + * + * @see java.lang.Enum#toString() + */ + @Override + public String toString() { + return value; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfConstants.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfConstants.java new file mode 100644 index 0000000000..77fb2cf2da --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfConstants.java @@ -0,0 +1,170 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4.cf; + +/** + * CF Constants as described for NetCDF library 1.6 + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 7, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CfConstants { + + /** + * Global attribute {@link #CONVENTIONS_ATTR} value for version 1.6 + */ + public static final String CONVENTIONS1_6 = "CF-1.6"; + + /** + * Global attribute for conventions version + */ + public static final String CONVENTIONS_ATTR = "Conventions"; + + /** + * Variable attribute for standard name + */ + public static final String STANDARD_NAME_ATTR = "standard_name"; + + /** + * Variable attribute for long name + */ + public static final String LONG_NAME_ATTR = "long_name"; + + /** + * Variable attribute for units + */ + public static final String UNITS_ATTR = "units"; + + /** + * Variable attribute for cell methods + */ + public static final String CELL_METHODS_ATTR = "cell_methods"; + + /** + * Dimension attribute for axis label (x, y, z...) + */ + public static final String AXIS_ATTR = "axis"; + + /** + * Attribute value for {@link #AXIS_ATTR} for x axis + */ + public static final String X_AXIS = "X"; + + /** + * Attribute value for {@link #AXIS_ATTR} for y axis + */ + public static final String Y_AXIS = "Y"; + + /** + * Attribute value for {@link #AXIS_ATTR} for vertical axis + */ + public static final String Z_AXIS = "Z"; + + /** + * Attribute value for {@link #AXIS_ATTR} for time axis + */ + public static final String T_AXIS = "T"; + + /** + * Variable attribute for missing values + */ + public static final String MISSING_VAL_ATTR = "missing_value"; + + /** + * {@link #UNITS_ATTR} value for latitude dimension + */ + public static final String LAT_UNITS = "degrees_north"; + + /** + * {@link #UNITS_ATTR} value for longitude dimension + */ + public static final String LON_UNITS = "degrees_east"; + + /** + * Vertical dimension attribute to denote which direction is positive + */ + public static final String POS_ATTR = "positive"; + + /** + * {@link #POS_ATTR} value indicating that up is positive + */ + public static final String UP_POS = "up"; + + /** + * {@link #POS_ATTR} value indicating that down is positive + */ + public static final String DWN_POS = "down"; + + /** + * Calendar attribute for Time Dimensions + */ + public static final String CAL_ATTR = "calendar"; + + /** + * Default value for {@link #CAL_ATTR} + */ + public static final String GREG_CALENDAR = "gregorian"; + + /** + * {@link #UNITS_ATTR} value for time dimension that uses UNIX time + */ + public static final String UNIX_TIME_UNITS = "seconds since 1970-1-1 0:0:0"; + + /** + * attribute for coverage id + */ + public static final String COVERAGE_ID_ATTR = "coverage_id"; + + /** + * Grid mapping name attribute + */ + public static final String GRID_MAP_NAME_ATTR = "grid_mapping_name"; + + /** + * standard parallel attribute used in grid mapping variable + */ + public static final String STD_PARALLEL_ATTR = "standard_parallel"; + + /** + * central meridian longitude attribute used in grid mapping variable + */ + public static final String CENTRAL_MERID_LON_ATTR = "longitude_of_central_meridian"; + + /** + * projection origin latitude attribute used in grid mapping variable + */ + public static final String PROJ_ORIGIN_LAT_ATTR = "latitude_of_projection_origin"; + + /** + * attribute for list of variables that contain geographic coordinates + */ + public static final String COORDS_ATTR = "coordinates"; + + /** + * Standard name value for projected x dimension + */ + public static final String X_STD_NAME = "projection_x_coordinate"; + + /** + * Standard name value for projected y dimension + */ + public static final String Y_STD_NAME = "projection_y_coordinate"; + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfDimensions.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfDimensions.java new file mode 100644 index 0000000000..f742a7f144 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfDimensions.java @@ -0,0 +1,95 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4.cf; + +import java.util.Arrays; + +import com.raytheon.uf.common.nc4.NcDimension; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 3, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CfDimensions { + + private final CfHorizontalDims xyDims; + + private final T zDim; + + private final T tDim; + + /** + * @param xyDims + * @param zDim + * @param tDim + */ + public CfDimensions(CfHorizontalDims xyDims, T zDim, T tDim) { + this.xyDims = xyDims; + this.zDim = zDim; + this.tDim = tDim; + } + + /** + * @return the xyDims + */ + public CfHorizontalDims getXyDims() { + return xyDims; + } + + /** + * @return the zDim + */ + public T getzDim() { + return zDim; + } + + /** + * @return the tDim + */ + public T gettDim() { + return tDim; + } + + @SuppressWarnings("unchecked") + public T[] toArray() { + T[] a = (T[]) java.lang.reflect.Array + .newInstance(zDim.getClass(), 4); + fill(a); + return a; + } + + public T[] toArray(T[] a) { + if (a.length < 4) { + a = Arrays.copyOf(a, 4); + } + fill(a); + return a; + } + + private void fill(T[] a) { + a[0] = tDim; + a[1] = zDim; + a[2] = xyDims.getY(); + a[3] = xyDims.getX(); + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfGridMapper.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfGridMapper.java new file mode 100644 index 0000000000..1a4b09ef6a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfGridMapper.java @@ -0,0 +1,61 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4.cf; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 7, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CfGridMapper { + + private static final Properties ATTRIB_MAP = new Properties(); + + private static final IUFStatusHandler log = UFStatus + .getHandler(CfGridMapper.class); + + static { + ClassLoader loader = CfGridMapper.class.getClassLoader(); + InputStream res = loader + .getResourceAsStream("META-INF/nc4-CF-grid-mapping.properties"); + if (res == null) { + log.warn("Unable to find grid attribute map"); + } else { + try { + ATTRIB_MAP.load(res); + } catch (IOException e) { + log.error("Unable to load mapping properties", e); + } + } + } + + public static String getMappingAttributeName(String name) { + return ATTRIB_MAP.getProperty(name, name); + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfHorizontalDims.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfHorizontalDims.java new file mode 100644 index 0000000000..159dbe728d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfHorizontalDims.java @@ -0,0 +1,100 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4.cf; + +import com.raytheon.uf.common.nc4.NcDimension; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 3, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CfHorizontalDims { + + private final T x; + + private final T y; + + private final String coords; + + private final String gridMapping; + + private final boolean mapped; + + public CfHorizontalDims(T x, T y) { + this(x, y, null, null, false); + } + + /** + * @param dims + * @param coords + * @param gridMapping + */ + public CfHorizontalDims(T x, T y, String coords, + String gridMapping) { + this(x, y, coords, gridMapping, true); + } + + private CfHorizontalDims(T x, T y, String coords, + String gridMapping, boolean mapped) { + this.x = x; + this.y = y; + this.coords = coords; + this.gridMapping = gridMapping; + this.mapped = mapped; + } + + /** + * @return the x + */ + public T getX() { + return x; + } + + /** + * @return the y + */ + public T getY() { + return y; + } + + /** + * @return the coords + */ + public String getCoords() { + return coords; + } + + /** + * @return the gridMapping + */ + public String getGridMapping() { + return gridMapping; + } + + /** + * @return the mapped + */ + public boolean isMapped() { + return mapped; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfNetcdf.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfNetcdf.java new file mode 100644 index 0000000000..3e9347ad81 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfNetcdf.java @@ -0,0 +1,207 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4.cf; + +import com.raytheon.uf.common.nc4.NcDimension; +import com.raytheon.uf.common.nc4.Netcdf; +import com.raytheon.uf.common.nc4.NetcdfException; + +/** + * Climate and Forecast conventions wrapper for netcdf + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 7, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CfNetcdf extends Netcdf { + + /** + * @param path + * @throws NetcdfException + */ + public CfNetcdf(String path) throws NetcdfException { + super(path); + addDefaultAttributes(); + } + + /** + * @param path + * @param mode + * @throws NetcdfException + */ + public CfNetcdf(String path, int mode) throws NetcdfException { + super(path, mode); + addDefaultAttributes(); + } + + /** + * @param path + * @param mode + * @param initialSize + * @param chunkSizeHint + * @throws NetcdfException + */ + public CfNetcdf(String path, int mode, int initialSize, int chunkSizeHint) + throws NetcdfException { + super(path, mode, initialSize, chunkSizeHint); + addDefaultAttributes(); + } + + /** + * Add default global attributes for CF file + * + * @throws NetcdfException + */ + private void addDefaultAttributes() throws NetcdfException { + putStringAttribute(CfConstants.CONVENTIONS_ATTR, + CfConstants.CONVENTIONS1_6); + } + + /** + * Define the X dimension for file. If the X/Y axes are in Long/Lat the X + * dimension is longitude. The return value can be used to populate the + * dimension axis values after {@link #endFileDefinition()} is called + * + * @param + * data type specific {@link NcDimension} sub class + * @param name + * name of dimension + * @param longName + * long name of dimension + * @param len + * length of dimension + * @param units + * units that this axis is in + * @param dimClass + * class object for {@link NcDimension} sub class + * @return + * @throws NetcdfException + */ + public T defineXDim(String name, String longName, + int len, String units, Class dimClass) throws NetcdfException { + T rval = super.defineDim(name, len, dimClass); + setDimAttrs(rval, longName, units, CfConstants.X_AXIS); + return rval; + } + + /** + * Define the Y dimension for file. If the X/Y axes are in Long/Lat the Y + * dimension is latitude. The return value can be used to populate the + * dimension axis values after {@link #endFileDefinition()} is called + * + * @param + * data type specific {@link NcDimension} sub class + * @param name + * name of dimension + * @param longName + * long name of dimension + * @param len + * length of dimension + * @param units + * units that this axis is in + * @param dimClass + * class object for {@link NcDimension} sub class + * @return + * @throws NetcdfException + */ + public T defineYDim(String name, String longName, + int len, String units, Class dimClass) throws NetcdfException { + T rval = super.defineDim(name, len, dimClass); + setDimAttrs(rval, longName, units, CfConstants.Y_AXIS); + return rval; + } + + /** + * Define the Z dimension for file. This is the horizontal axis. The return + * value can be used to populate the dimension axis values after + * {@link #endFileDefinition()} is called + * + * @param + * data type specific {@link NcDimension} sub class + * @param name + * name of dimension + * @param longName + * long name of dimension + * @param len + * length of dimension + * @param units + * units that this axis is in + * @param upIsPositive + * true if increasing values on axis indicate an increase in + * horizontal distance + * @param dimClass + * class object for {@link NcDimension} sub class + * @return + * @throws NetcdfException + */ + public T defineZDim(String name, String longName, + int len, String units, boolean upIsPositive, Class dimClass) + throws NetcdfException { + T rval = super.defineDim(name, len, dimClass); + setDimAttrs(rval, longName, units, CfConstants.Z_AXIS); + String posVal = upIsPositive ? CfConstants.UP_POS : CfConstants.DWN_POS; + rval.putStringAttribute(CfConstants.POS_ATTR, posVal); + return rval; + } + + /** + * Define the T dimension for file. This is the temporal dimension. The + * return value can be used to populate the dimension axis values after + * {@link #endFileDefinition()} is called + * + * @param + * data type specific {@link NcDimension} sub class + * @param name + * name of dimension + * @param stdName + * standard name of dimension + * @param len + * length of dimension + * @param units + * units that this axis is in + * @param dimClass + * class object for {@link NcDimension} sub class + * @return + * @throws NetcdfException + */ + public T defineTimeDim(String name, String stdName, + int len, String units, Class dimClass) throws NetcdfException { + T rval = super.defineDim(name, len, dimClass); + setDimAttrs(rval, stdName, units, CfConstants.T_AXIS); + rval.putStringAttribute(CfConstants.CAL_ATTR, CfConstants.GREG_CALENDAR); + return rval; + } + + /** + * Set default dimension attributes + * + * @param dim + * @param stdName + * @param units + * @param axis + * @throws NetcdfException + */ + private void setDimAttrs(NcDimension dim, String stdName, String units, + String axis) throws NetcdfException { + dim.putStringAttribute(CfConstants.LONG_NAME_ATTR, stdName); + dim.putStringAttribute(CfConstants.STANDARD_NAME_ATTR, stdName); + dim.putStringAttribute(CfConstants.UNITS_ATTR, units); + dim.putStringAttribute(CfConstants.AXIS_ATTR, axis); + } +} diff --git a/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfUtils.java b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfUtils.java new file mode 100644 index 0000000000..48de686666 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc4/src/com/raytheon/uf/common/nc4/cf/CfUtils.java @@ -0,0 +1,38 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.common.nc4.cf; + +import java.util.regex.Pattern; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 7, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CfUtils { + + public static final Pattern CF_NAME_PATTERN = Pattern + .compile("^[a-zA-Z][a-zA-Z0-9_]*$"); + + public static boolean validName(String name) { + return CF_NAME_PATTERN.matcher(name).matches(); + } +} diff --git a/edexOsgi/com.raytheon.uf.common.serialization/src/com/raytheon/uf/common/serialization/JAXBManager.java b/edexOsgi/com.raytheon.uf.common.serialization/src/com/raytheon/uf/common/serialization/JAXBManager.java index d9d341f964..6e21e07ed5 100644 --- a/edexOsgi/com.raytheon.uf.common.serialization/src/com/raytheon/uf/common/serialization/JAXBManager.java +++ b/edexOsgi/com.raytheon.uf.common.serialization/src/com/raytheon/uf/common/serialization/JAXBManager.java @@ -51,6 +51,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority; * Sep 24, 2008 chammack Initial creation * Nov 13, 2008 njensen Added thrift methods * May 22, 2013 1917 rjpeter Added non-pretty print option to jaxb serialize methods. + * Aug 18, 2013 #2097 dhladky Allowed extension by OGCJAXBManager * * * @author chammack @@ -106,7 +107,7 @@ public class JAXBManager { private final JAXBContext jaxbContext; - private final Queue unmarshallers = new ConcurrentLinkedQueue(); + protected final Queue unmarshallers = new ConcurrentLinkedQueue(); protected final Queue marshallers = new ConcurrentLinkedQueue(); diff --git a/edexOsgi/com.raytheon.uf.common.spatial/src/com/raytheon/uf/common/spatial/reprojection/DataReprojector.java b/edexOsgi/com.raytheon.uf.common.spatial/src/com/raytheon/uf/common/spatial/reprojection/DataReprojector.java index ae208ad2a2..1186cb2239 100644 --- a/edexOsgi/com.raytheon.uf.common.spatial/src/com/raytheon/uf/common/spatial/reprojection/DataReprojector.java +++ b/edexOsgi/com.raytheon.uf.common.spatial/src/com/raytheon/uf/common/spatial/reprojection/DataReprojector.java @@ -48,6 +48,7 @@ import org.geotools.coverage.grid.ViewType; import org.geotools.coverage.processing.Operations; import org.geotools.geometry.DirectPosition2D; import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.referencing.CRS; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.metadata.spatial.PixelOrientation; @@ -157,6 +158,10 @@ public class DataReprojector { String reprojectedDataset, ISpatialObject spatial, CoordinateReferenceSystem crs, Request req) throws Exception { IDataRecord dataRecord; + if (CRS.equalsIgnoreMetadata(crs, spatial.getCrs())) { + // original dataset, no reproject + reprojectedDataset = dataSet; + } // check if data has already been reprojected if (!datasetExists(group, reprojectedDataset)) { // it hasn't lock and reproject @@ -452,7 +457,7 @@ public class DataReprojector { * @throws MismatchedDimensionException * @throws FactoryException */ - protected RequestWrapper getRequest(ISpatialObject spatial, + public static RequestWrapper getRequest(ISpatialObject spatial, ReferencedEnvelope nativeEnv, ReferencedEnvelope targetEnvelope) throws MismatchedDimensionException, TransformException, FactoryException { @@ -492,7 +497,8 @@ public class DataReprojector { * @throws MismatchedDimensionException * @throws TransformException */ - protected RequestWrapper getSubSlice(GridGeometry2D geom, Envelope env, + protected static RequestWrapper getSubSlice(GridGeometry2D geom, + Envelope env, int[] dims) throws MismatchedDimensionException, TransformException { RequestWrapper rval = new RequestWrapper(); MathTransform2D crsToGrid2D = geom @@ -517,7 +523,8 @@ public class DataReprojector { * @throws MismatchedDimensionException * @throws TransformException */ - protected ReferencedEnvelope transformGrid(MathTransform2D gridToCrs, + protected static ReferencedEnvelope transformGrid( + MathTransform2D gridToCrs, int[][] minmax, CoordinateReferenceSystem crs) throws MismatchedDimensionException, TransformException { int[] min = minmax[0]; @@ -545,7 +552,8 @@ public class DataReprojector { * @throws MismatchedDimensionException * @throws TransformException */ - protected int[][] transformEnv(MathTransform2D crsToGrid, Envelope env, + protected static int[][] transformEnv(MathTransform2D crsToGrid, + Envelope env, int[] dims) throws MismatchedDimensionException, TransformException { DirectPosition lower = new DirectPosition2D(env.getMinX(), env.getMinY()); diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml index e6ccfef95f..735acec18d 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml @@ -17,11 +17,9 @@ [Enter License Description here.] - - - - - + - - + + diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml index 9a0ad62bd5..54e4b0212b 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml @@ -74,5 +74,18 @@ install-size="0" version="0.0.0" unpack="false"/> + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/META-INF/MANIFEST.MF index a29b611ac6..dc9ed16838 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/META-INF/MANIFEST.MF @@ -23,6 +23,7 @@ Require-Bundle: com.raytheon.uf.common.datadelivery.retrieval;bundle-version="1. com.raytheon.uf.common.dataplugin.madis;bundle-version="1.0.0", com.raytheon.uf.edex.plugin.madis.ogc;bundle-version="1.0.0", com.raytheon.uf.edex.plugin.madis;bundle-version="1.0.0", - com.raytheon.uf.edex.wfs;bundle-version="1.0.0" + com.raytheon.uf.edex.wfs;bundle-version="1.0.0", + org.eclipse.xsd;bundle-version="2.8.1" Export-Package: com.raytheon.uf.edex.datadelivery.retrieval.wfs, com.raytheon.uf.edex.datadelivery.retrieval.wfs.metadata diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/src/com/raytheon/uf/edex/datadelivery/retrieval/wfs/WfsRequestBuilder.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/src/com/raytheon/uf/edex/datadelivery/retrieval/wfs/WfsRequestBuilder.java index 3039cc3688..2b2e10bf48 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/src/com/raytheon/uf/edex/datadelivery/retrieval/wfs/WfsRequestBuilder.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval.wfs/src/com/raytheon/uf/edex/datadelivery/retrieval/wfs/WfsRequestBuilder.java @@ -32,6 +32,7 @@ import com.vividsolutions.jts.geom.Coordinate; * May 31, 2013 2038 djohnson Move to correct repo. * Jun 11, 2013 1763 dhladky Made operational. * Jun 18, 2013 2120 dhladky Added times and max feature processing + * Aug 07, 2013 2097 dhladky Revamped WFS to use POST (still 1.1.0 WFS) * * * @@ -46,44 +47,55 @@ public class WfsRequestBuilder extends RequestBuilder { protected static ServiceConfig wfsServiceConfig; - public static final String separator = getServiceConfig().getConstantValue("COMMA"); + public static final String SEPERATOR = getServiceConfig().getConstantValue("COMMA"); - public static final String slash = getServiceConfig().getConstantValue("FORWARD_SLASH"); + public static final String SLASH = getServiceConfig().getConstantValue("FORWARD_SLASH"); - public static final String bbox = getServiceConfig().getConstantValue("BBOX_HEADER"); + public static final String BBOX = getServiceConfig().getConstantValue("BBOX_HEADER"); - public static final String srs = getServiceConfig().getConstantValue("SRSNAME_HEADER"); + public static final String SRS = getServiceConfig().getConstantValue("SRSNAME_HEADER"); - public static final String crs = getServiceConfig().getConstantValue("DEFAULT_CRS"); + public static final String CRS = getServiceConfig().getConstantValue("DEFAULT_CRS"); - public static final String time = getServiceConfig().getConstantValue("TIME_HEADER"); + public static final String TIME = getServiceConfig().getConstantValue("TIME_HEADER"); - public static final String equals = getServiceConfig().getConstantValue("EQUALS"); + public static final String EQUALS = getServiceConfig().getConstantValue("EQUALS"); - public static final String blank = getServiceConfig().getConstantValue("BLANK"); + public static final String BLANK = getServiceConfig().getConstantValue("BLANK"); - public static final String max = getServiceConfig().getConstantValue("MAX"); + public static final String MAX = getServiceConfig().getConstantValue("MAX"); - public static final String ampersand = "&"; + public static final String VERSION = getServiceConfig().getConstantValue("VERSION"); + + public static final String AMPERSAND = "&"; private final String wfsURL; - WfsRequestBuilder(WfsRetrievalAdapter adapter, + private String typeName = null; + + public WfsRequestBuilder(WfsRetrievalAdapter adapter, RetrievalAttribute attXML) { super(attXML); - // Create URL - // this works in this order - StringBuilder buffer = new StringBuilder(); - // apply the base WFS service URL - buffer.append(adapter.getProviderRetrievalXMl().getConnection() - .getUrl()); - // process the coverage bounding box - buffer.append(processCoverage()); - // process the time range you are trying to retrieve - buffer.append(processTime(getRetrievalAttribute().getTime())); - // max feature limit - buffer.append(processMax()); + // Create XML doc + this.typeName = attXML.getPlugin(); + StringBuilder buffer = new StringBuilder(256); + buffer.append(createHeader()); + buffer.append("\n"); + if (attXML.getCoverage() != null && attXML.getTime() != null) { + buffer.append("\n"); + } + + buffer.append(processTime(attXML.getTime())); + buffer.append(processCoverage()); + + if (attXML.getCoverage() != null && attXML.getTime() != null) { + buffer.append("\n"); + } + + buffer.append("\n"); + buffer.append(createFooter()); + this.wfsURL = buffer.toString().trim(); } @@ -98,92 +110,115 @@ public class WfsRequestBuilder extends RequestBuilder { return sdf; } }; + + /** + * Creates the WFS XML Query header + * @return + */ + private String createHeader() { + StringBuilder sb = new StringBuilder(256); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + + return sb.toString(); + } + + /** + * Creates the WFS XML Query Footer + * @return + */ + private String createFooter() { + String footer = "\n\n"; + return footer; + } + @Override public String processTime(Time inTime) { try { - if (inTime.getEndDate() != null && inTime.getStartDate() != null) { + if (inTime.getStartDate() != null) { Date sDate = inTime.getStartDate(); Date eDate = inTime.getEndDate(); String endDateString = ogcDateFormat.get().format(eDate); String startDateString = ogcDateFormat.get().format(sDate); - StringBuilder sb = new StringBuilder(); - sb.append(ampersand); - sb.append(time); - sb.append(equals); - sb.append(startDateString); - sb.append(slash); - - if (!endDateString.equals(startDateString)) { - sb.append(endDateString); + + StringBuilder sb = new StringBuilder(256); + sb.append("\n"); + sb.append("").append(typeName).append(":timeObs\n"); + sb.append("").append(startDateString).append("\n"); + sb.append("\n"); + + if (endDateString != null) { + sb.append("\n"); + sb.append("").append(typeName).append(":timeObs\n"); + sb.append("").append(endDateString).append("\n"); + sb.append("\n"); } return sb.toString(); } } catch (Exception e) { - statusHandler.error("Couldn't parse Time object." + e); + statusHandler.error("Couldn't parse Time object.", e); } - // no times, return blank - return blank; - + return BLANK; } @Override public String processCoverage() { - StringBuilder sb = new StringBuilder(); Coverage coverage = getRetrievalAttribute().getCoverage(); if (coverage != null) { + try { + StringBuilder sb = new StringBuilder(256); + ReferencedEnvelope re = coverage.getRequestEnvelope(); + Coordinate ll = EnvelopeUtils.getLowerLeftLatLon(re); + Coordinate ur = EnvelopeUtils.getUpperRightLatLon(re); + // manage the box + double lowerLon = ll.x; + double lowerLat = ll.y; + double upperLon = ur.x; + double upperLat = ur.y; - ReferencedEnvelope re = coverage.getRequestEnvelope(); - Coordinate ll = EnvelopeUtils.getLowerLeftLatLon(re); - Coordinate ur = EnvelopeUtils.getUpperRightLatLon(re); - // manage the box - double lowerLon = ll.x; - double lowerLat = ll.y; - double upperLon = ur.x; - double upperLat = ur.y; + sb.append("\n"); + sb.append("location/location\n"); + sb.append("\n"); + sb.append(""); + sb.append(lowerLon); + sb.append(" "); + sb.append(lowerLat); + sb.append("\n"); + sb.append(""); + sb.append(upperLon); + sb.append(" "); + sb.append(upperLat); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); - sb.append(ampersand); - sb.append(srs); - sb.append(equals); - sb.append(crs); - //TODO Revisit this when we have a better idea of how to switch them - //sb.append(coverage.getEnvelope().getCoordinateReferenceSystem() - // .getName()); - sb.append(ampersand); - sb.append(bbox); - sb.append(equals); - sb.append(lowerLon); - sb.append(separator); - sb.append(lowerLat); - sb.append(separator); - sb.append(upperLon); - sb.append(separator); - sb.append(upperLat); - - return sb.toString(); + return sb.toString(); + + } catch (Exception e) { + statusHandler.error("Couldn't parse Coverage object.", e); + } } - return blank; + return BLANK; } - /** - * constrain to max amount of features - * @return - */ - public String processMax() { - StringBuilder sb = new StringBuilder(); - sb.append(ampersand); - sb.append(max); - - return sb.toString(); - } - @Override public String getRequest() { return wfsURL; @@ -207,5 +242,5 @@ public class WfsRequestBuilder extends RequestBuilder { return wfsServiceConfig; } - + } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/WfsConnectionUtil.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/WfsConnectionUtil.java index 944fb2b1c6..5191d7b8fd 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/WfsConnectionUtil.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/WfsConnectionUtil.java @@ -3,7 +3,8 @@ package com.raytheon.uf.edex.datadelivery.retrieval.util; import java.net.URI; import java.net.URISyntaxException; -import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; import com.raytheon.uf.common.comm.HttpClient; import com.raytheon.uf.common.comm.HttpClient.HttpClientResponse; @@ -31,6 +32,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority; * Jun 18, 2013 2120 dhladky Times fixes and SSL changes * Jul 10, 2013 2180 dhladky Updated credential requests * Aug 23, 2013 2180 mpduff Implement changes to ProviderCredentialsUtil + * Aug 06, 2013 2097 dhladky WFS 2.0 compliance upgrade and switched to POST * * * @@ -54,16 +56,19 @@ public class WfsConnectionUtil { * The data provider's name * @return xml response */ - public static String wfsConnect(String url, Connection providerConn, + public static String wfsConnect(String request, Connection providerConn, String providerName) { + String xmlResponse = null; HttpClient http = null; + String rootUrl = null; try { - // TODO: consider using HTTP POST instead of GET + + rootUrl = providerConn.getUrl(); http = HttpClient.getInstance(); - HttpGet get = new HttpGet(); - URI uri = new URI(url); + URI uri = new URI(rootUrl); + HttpPost post = new HttpPost(uri); // check for the need to do a username password auth check ProviderCredentials creds = ProviderCredentialsUtil .retrieveCredentials(providerName); @@ -84,12 +89,13 @@ public class WfsConnectionUtil { userName, password); } - get.setURI(uri); - HttpClientResponse response = http.executeRequest(get); + post.setEntity(new StringEntity(request, "text/xml", "ISO-8859-1")); + HttpClientResponse response = http.executeRequest(post); xmlResponse = new String(response.data); + } catch (Exception e) { statusHandler.handle(Priority.PROBLEM, - "Couldn't connect to WFS server: " + url, e); + "Couldn't connect to WFS server: " + rootUrl, e); } return xmlResponse; diff --git a/edexOsgi/com.raytheon.uf.edex.dataprovideragent.feature/feature.xml b/edexOsgi/com.raytheon.uf.edex.dataprovideragent.feature/feature.xml index b52ce9f77f..e879c38096 100644 --- a/edexOsgi/com.raytheon.uf.edex.dataprovideragent.feature/feature.xml +++ b/edexOsgi/com.raytheon.uf.edex.dataprovideragent.feature/feature.xml @@ -17,15 +17,6 @@ [Enter License Description here.] - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + http://0.0.0.0:8080/notify + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/build.properties b/edexOsgi/com.raytheon.uf.edex.ogc.common/build.properties index 2377de7022..e016089273 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/build.properties +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/build.properties @@ -1,5 +1,4 @@ source.. = src/ -output.. = bin/ bin.includes = .project,\ .classpath,\ META-INF/,\ diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/overview.uml b/edexOsgi/com.raytheon.uf.edex.ogc.common/overview.uml new file mode 100644 index 0000000000..ffd32ce6f1 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/overview.uml @@ -0,0 +1,22 @@ +@startuml + +package "EDEX Common OGC" { + [Simple Dimension] as dim + [Simple Layer] as layer + [Abstract Layer Collector] as abscol +} + +node "EDEX Data Plug-in Adapter" { + [Plug-in Dimension] as pdim + [Plug-in Layer] as player + [Plug-in Layer Collector] as collector +} + +abscol <|-- collector +layer <|-- player +dim <|-- pdim + +collector o-left- "*"player +player o-left- "*" pdim + +@enduml \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/res/spring/ogc-common-convert.xml b/edexOsgi/com.raytheon.uf.edex.ogc.common/res/spring/ogc-common-convert.xml new file mode 100644 index 0000000000..59d85e0f55 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/res/spring/ogc-common-convert.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/res/spring/ogc-common.xml b/edexOsgi/com.raytheon.uf.edex.ogc.common/res/spring/ogc-common.xml index b69428c58e..bc7cd6bde5 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/res/spring/ogc-common.xml +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/res/spring/ogc-common.xml @@ -9,5 +9,9 @@ - + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractFSQueryStore.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractFSQueryStore.java new file mode 100644 index 0000000000..904b58be80 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractFSQueryStore.java @@ -0,0 +1,263 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.map.LRUMap; + +import com.raytheon.uf.common.spatial.reprojection.KeyLocker; +import com.raytheon.uf.common.spatial.reprojection.KeyLocker.KeyLock; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 15, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractFSQueryStore extends AbstractFsStore { + + /** + * @param storeLocation + */ + public AbstractFSQueryStore(File storeLocation) { + super(storeLocation); + } + + @SuppressWarnings("unchecked") + private final Map objCache = Collections + .synchronizedMap(new LRUMap(2)); + + @SuppressWarnings("unchecked") + private final Map strCache = Collections + .synchronizedMap(new LRUMap(2)); + + private final KeyLocker locker = new KeyLocker(); + + /** + * @param id + * @param query + * @throws Exception + */ + public void store(String id, T query) throws OgcException { + KeyLock lock = locker.getLock(id); + lock.lock(); + try { + storeObject(id, query); + } finally { + lock.unlock(); + lock.release(); + } + } + + /** + * This must be externally synchronized + * + * @param id + * @param query + * @throws Exception + */ + private void storeObject(String id, T query) throws OgcException { + objCache.put(id, query); + String xml = marshal(query); + storeString(id, xml); + } + + protected abstract String marshal(T query) throws OgcException; + + /** + * This must be externally synchronized + * + * @param id + * @param query + * @throws Exception + */ + private void storeString(String id, String query) throws OgcException { + OutputStreamWriter out = null; + strCache.put(id, query); + try { + File storage = getStorageFile(id); + out = new OutputStreamWriter(new FileOutputStream(storage)); + out.write(query); + } catch (Exception e) { + throw new OgcException(Code.InternalServerError, e); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.querystore.QueryStore#retrieve(java.lang.String) + */ + public T retrieve(String id) throws OgcException { + T rval; + KeyLock lock = locker.getLock(id); + lock.lock(); + try { + rval = retrieveObject(id); + } finally { + lock.unlock(); + lock.release(); + } + return rval; + } + + /** + * This must be externally synchronized + * + * @param id + * @return + * @throws Exception + */ + private T retrieveObject(String id) throws OgcException { + T rval = objCache.get(id); + if (rval == null) { + String xml = retrieveStringInternal(id); + if (xml != null) { + rval = unmarshal(xml); + objCache.put(id, rval); + } + } + return rval; + } + + /** + * This must be externally synchronized + * + * @param id + * @return + * @throws Exception + */ + private String retrieveStringInternal(String id) throws OgcException { + String rval = strCache.get(id); + if (rval == null) { + File storage = getStorageFile(id); + if (storage.exists()) { + InputStream in; + try { + in = new FileInputStream(storage); + } catch (FileNotFoundException e) { + throw new OgcException(Code.InternalServerError, e); + } + try { + rval = new java.util.Scanner(in).useDelimiter("\\A").next(); + strCache.put(id, rval); + } finally { + try { + in.close(); + } catch (IOException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + } + } + return rval; + } + + /** + * @param id + * @return + * @throws Exception + */ + protected String retrieveString(String id) throws OgcException { + KeyLock lock = locker.getLock(id); + lock.lock(); + try { + return retrieveStringInternal(id); + } finally { + lock.unlock(); + lock.release(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.querystore.QueryStore#remove(java.lang.String) + */ + public void remove(String id) { + KeyLock lock = locker.getLock(id); + lock.lock(); + try { + objCache.remove(id); + strCache.remove(id); + File storage = getStorageFile(id); + if (storage.exists()) { + storage.delete(); + } + } finally { + lock.unlock(); + lock.release(); + } + } + + /** + * @return + * @throws Exception + */ + public List list() throws OgcException { + // NOTE: this is only synched by the file system + File[] files = storeLocation.listFiles(new FileFilter() { + @Override + public boolean accept(File f) { + return f.isFile(); + } + }); + List rval = new ArrayList(files.length); + for (File f : files) { + String encoded = f.getName(); + rval.add(decode(encoded)); + } + return rval; + } + + /** + * @param id + * @return file for storage + */ + protected File getStorageFile(String id) { + return new File(storeLocation, encode(id)); + } + + protected abstract T unmarshal(String xml) throws OgcException; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractFsStore.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractFsStore.java new file mode 100644 index 0000000000..be155dc7d9 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractFsStore.java @@ -0,0 +1,133 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common; + +import java.io.File; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; + +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.PathManagerFactory; + +/** + * Abstract File store + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 4, 2013            bclement     Initial creation
+ * Aug 18, 2013  #2097    dhladky      Changed to configured
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class AbstractFsStore { + + protected static final char ESCAPE = '%'; + + protected static final String SPECIAL_CHARS = ESCAPE + "./\\?*:|\"<>~"; + + protected final File storeLocation; + + /** + * @param storeLocation + */ + public AbstractFsStore(File storeLocation) { + this.storeLocation = storeLocation; + ensureStorage(); + } + + protected static File findStore(String directoryName) { + IPathManager pathMgr = PathManagerFactory.getPathManager(); + LocalizationContext edexStaticCONFIGURED = pathMgr.getContext( + LocalizationContext.LocalizationType.EDEX_STATIC, + LocalizationContext.LocalizationLevel.CONFIGURED); + return pathMgr.getFile(edexStaticCONFIGURED, directoryName); + } + + /** + * Create storage location if necessary + * + * @throws IllegalArgumentException + * if unable to create storage directory or if provided location + * is not a directory + */ + private void ensureStorage() throws IllegalArgumentException { + if (!storeLocation.exists()) { + if (!storeLocation.mkdirs()) { + throw new IllegalArgumentException( + "Unable to create store directory: " + storeLocation); + } + } + if (!storeLocation.isDirectory()) { + throw new IllegalArgumentException( + "Provided storage location is not a directory: " + + storeLocation); + } + if (!storeLocation.canWrite()) { + throw new IllegalArgumentException( + "Unable to write to storage directory: " + storeLocation); + } + } + + /** + * Sanitize id for file system + * + * @param id + * @return + */ + protected static String encode(String id) { + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(id); + for (char ch = iter.first(); ch != CharacterIterator.DONE; ch = iter + .next()) { + if (SPECIAL_CHARS.indexOf(ch) != -1) { + sb.append(ESCAPE); + sb.append(String.format("%2h", ch)); + } else { + sb.append(ch); + } + } + return sb.toString(); + } + + /** + * de-sanitize file system name + * + * @param encoded + * @return + */ + protected static String decode(String encoded) { + StringBuilder sb = new StringBuilder(); + int index = 0; + int prev; + while (index < encoded.length()) { + prev = index; + index = encoded.indexOf(ESCAPE, prev); + if (index < 0) { + sb.append(encoded.substring(prev)); + break; + } + sb.append(encoded.substring(prev, index)); + String hex = encoded.substring(index + 1, index + 3); + char charNum = (char) Integer.parseInt(hex, 16); + sb.append(charNum); + index = index + 3; + } + return sb.toString(); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractOgcSource.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractOgcSource.java new file mode 100644 index 0000000000..a6c54bc10e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractOgcSource.java @@ -0,0 +1,69 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * base source for OGC + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 18, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractOgcSource { + + private final Map, Object> extensionMap = new ConcurrentHashMap, Object>(); + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.WfsSource#getExtension(java.lang.Class) + */ + @SuppressWarnings("unchecked") + public E getExtension(Class c) { + E rval = (E) extensionMap.get(c); + if (rval == null) { + for (Class key : extensionMap.keySet()) { + if (c.isAssignableFrom(key)) { + return (E) extensionMap.get(key); + } + } + } + return rval; + } + + /** + * @param extension + */ + public void setExtension(Object extension) { + extensionMap.put(extension.getClass(), extension); + } + + /** + * @param extensions + */ + public void setExtensions(Object[] extensions) { + for (Object obj : extensions) { + setExtension(obj); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractOpDescriber.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractOpDescriber.java new file mode 100644 index 0000000000..809b902460 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/AbstractOpDescriber.java @@ -0,0 +1,191 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.ows.v_1_1_0.AllowedValues; +import net.opengis.ows.v_1_1_0.DCP; +import net.opengis.ows.v_1_1_0.DomainType; +import net.opengis.ows.v_1_1_0.HTTP; +import net.opengis.ows.v_1_1_0.ObjectFactory; +import net.opengis.ows.v_1_1_0.Operation; +import net.opengis.ows.v_1_1_0.OperationsMetadata; +import net.opengis.ows.v_1_1_0.RequestMethodType; +import net.opengis.ows.v_1_1_0.ValueType; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 21, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractOpDescriber { + + protected ObjectFactory owsFactory = new ObjectFactory(); + + /** + * Get OWS operations metadata from service info + * + * @param serviceinfo + * @return + */ + public OperationsMetadata getOpData(OgcServiceInfo serviceinfo) { + OperationsMetadata rval = new OperationsMetadata(); + List operations = new LinkedList(); + for (OgcOperationInfo op : serviceinfo.getOperations()) { + Operation to = new Operation(); + to.setName(op.getType().toString()); + to.setDCP(getDcpList(op)); + to.setParameter(getOpParams(op)); + operations.add(to); + } + rval.setOperation(operations); + List params = getParams(serviceinfo); + if (params != null && !params.isEmpty()) { + rval.setParameter(params); + } + List constraints = getConstraints(serviceinfo); + if (constraints != null && !constraints.isEmpty()) { + rval.setConstraint(constraints); + } + Object extendedCapabilities = getExtendedCapabilities(serviceinfo); + if (extendedCapabilities != null) { + rval.setExtendedCapabilities(extendedCapabilities); + } + return rval; + } + + /** + * @param serviceinfo + * @return + */ + protected Object getExtendedCapabilities(OgcServiceInfo serviceinfo) { + return null; + } + + /** + * @param serviceinfo + * @return + */ + protected List getConstraints(OgcServiceInfo serviceinfo) { + return new ArrayList(0); + } + + /** + * Get global parameters + * + * @param serviceinfo + * @return + */ + protected abstract List getParams(OgcServiceInfo serviceinfo); + + /** + * Get HTTP endpoint information for operation + * + * @param op + * @return + */ + protected List getDcpList(OgcOperationInfo op) { + List rval = new LinkedList(); + DCP dcp = new DCP(); + HTTP http = new HTTP(); + List> value = new LinkedList>(); + if (op.hasHttpGet()) { + RequestMethodType req = getRequestType(op.getHttpGetRes(), "KVP"); + value.add(owsFactory.createHTTPGet(req)); + } + if (op.hasHttpPost()) { + RequestMethodType req = getRequestType(op.getHttpPostRes(), + op.getPostEncoding()); + value.add(owsFactory.createHTTPPost(req)); + } + http.setGetOrPost(value); + dcp.setHTTP(http); + rval.add(dcp); + return rval; + } + + /** + * Create request method object + * + * @param value + * @param postEncoding + * @return + */ + protected RequestMethodType getRequestType(String value, String postEncoding) { + RequestMethodType rval = owsFactory.createRequestMethodType(); + rval.setHref(value); + rval.setConstraint(Arrays.asList(getAsDomainType("PostEncoding", + Arrays.asList(postEncoding)))); + return rval; + } + + /** + * Get parameters for operation + * + * @param op + * @return + */ + protected abstract List getOpParams(OgcOperationInfo op); + + /** + * Get keyed values as domain object + * + * @param name + * @param values + * @return + */ + protected DomainType getAsDomainType(String name, String... values) { + return getAsDomainType(name, Arrays.asList(values)); + } + + /** + * Get keyed values as domain object + * + * @param name + * @param values + * @return + */ + protected DomainType getAsDomainType(String name, Collection values) { + DomainType rval = new DomainType(); + rval.setName(name); + + AllowedValues avs = new AllowedValues(); + + List toVals = new LinkedList(); + for (String val : values) { + ValueType vt = new ValueType(); + vt.setValue(val); + toVals.add(vt); + } + + avs.setValueOrRange(toVals); + rval.setAllowedValues(avs); + + return rval; + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/BasicFileStore.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/BasicFileStore.java new file mode 100644 index 0000000000..ddd7a65d53 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/BasicFileStore.java @@ -0,0 +1,225 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; + +import org.apache.cxf.helpers.IOUtils; + +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.PathManagerFactory; + +/** + * Basic File Store + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 11, 2013            bclement     Initial creation
+ * Aug 18, 2013  #2097     dhladky      Moved to configured
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class BasicFileStore { + + protected static final char ESCAPE = '%'; + + protected static final String SPECIAL_CHARS = ESCAPE + "./\\?*:|\"<>~"; + + private final Object fileMutex = new Object(); + + private final File storeLocation; + + /** + * @param storeName + */ + public BasicFileStore(String storeName) { + this(findStore(storeName)); + } + + /** + * @param storeLocation + */ + public BasicFileStore(File storeLocation) { + this.storeLocation = storeLocation; + ensureStorage(); + } + + /** + * Create storage location if necessary + * + * @throws IllegalArgumentException + * if unable to create storage directory or if provided location + * is not a directory + */ + private void ensureStorage() throws IllegalArgumentException { + if (!storeLocation.exists()) { + if (!storeLocation.mkdirs()) { + throw new IllegalArgumentException( + "Unable to create store directory: " + storeLocation); + } + } + if (!storeLocation.isDirectory()) { + throw new IllegalArgumentException( + "Provided storage location is not a directory: " + + storeLocation); + } + if (!storeLocation.canWrite()) { + throw new IllegalArgumentException( + "Unable to write to storage directory: " + storeLocation); + } + } + + /** + * @param directoryName + * @return + */ + protected static File findStore(String directoryName) { + IPathManager pathMgr = PathManagerFactory.getPathManager(); + LocalizationContext edexStaticCONFIGURED = pathMgr.getContext( + LocalizationContext.LocalizationType.EDEX_STATIC, + LocalizationContext.LocalizationLevel.CONFIGURED); + return pathMgr.getFile(edexStaticCONFIGURED, directoryName); + } + + /** + * @param id + * @return + */ + private File createPath(String id) { + return new File(storeLocation, encode(id)); + } + + /** + * Get file from store + * + * @param id + * @return null if file isn't in store + */ + public File getFile(String id) { + File rval = createPath(id); + if (!rval.exists()) { + return null; + } + return rval; + } + + /** + * Creates an empty file in store. This is used when data is written to the + * file outside of the store. This cannot be used with + * {@link #store(String, InputStream)} + * + * @param id + * @return + * @throws IOException + * if file already exists in store + */ + public File reserveFile(String id) throws IOException { + File f = createPath(id); + synchronized (fileMutex) { + if (!f.createNewFile()){ + throw new IOException("File already exists in store with id: " + + id); + } + } + return f; + } + + /** + * Delete file from store + * + * @param id + */ + public void remove(String id) { + File f = createPath(id); + synchronized (fileMutex) { + if (f.exists()) { + f.delete(); + } + } + } + + /** + * Put data in store. This should not be used with + * {@link #reserveFile(String)} + * + * @param id + * @param in + * @throws IOException + */ + public void store(String id, InputStream in) throws IOException { + File f = reserveFile(id); + FileOutputStream out = new FileOutputStream(f); + try { + IOUtils.copy(in, out); + } finally { + out.close(); + } + } + + /** + * Sanitize id for file system + * + * @param id + * @return + */ + protected static String encode(String id) { + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(id); + for (char ch = iter.first(); ch != CharacterIterator.DONE; ch = iter + .next()) { + if (SPECIAL_CHARS.indexOf(ch) != -1) { + sb.append(ESCAPE); + sb.append(String.format("%2h", ch)); + } else { + sb.append(ch); + } + } + return sb.toString(); + } + + /** + * de-sanitize file system name + * + * @param encoded + * @return + */ + protected static String decode(String encoded) { + StringBuilder sb = new StringBuilder(); + int index = 0; + int prev; + while (index < encoded.length()) { + prev = index; + index = encoded.indexOf(ESCAPE, prev); + if (index < 0) { + sb.append(encoded.substring(prev)); + break; + } + sb.append(encoded.substring(prev, index)); + String hex = encoded.substring(index + 1, index + 3); + char charNum = (char) Integer.parseInt(hex, 16); + sb.append(charNum); + index = index + 3; + } + return sb.toString(); + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/InvalidVersionException.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/InvalidVersionException.java new file mode 100644 index 0000000000..2620f05d4c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/InvalidVersionException.java @@ -0,0 +1,62 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 26, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class InvalidVersionException extends Exception { + + private static final long serialVersionUID = -7212986504698593811L; + + /** + * + */ + public InvalidVersionException() { + // TODO Auto-generated constructor stub + } + + /** + * @param message + */ + public InvalidVersionException(String message) { + super(message); + } + + /** + * @param cause + */ + public InvalidVersionException(Throwable cause) { + super(cause); + } + + /** + * @param message + * @param cause + */ + public InvalidVersionException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcException.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcException.java index acf73b3d7f..930b14bd18 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcException.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcException.java @@ -29,7 +29,7 @@ public class OgcException extends Exception { private static final long serialVersionUID = -5832661027013919871L; public enum Code { - InvalidFormat, InvalidCRS, LayerNotDefined, MissingDimensionValue, InvalidDimensionValue, OperationNotSupported, MissingParameterValue, InvalidParameterValue, InternalServerError + InvalidFormat, InvalidCRS, LayerNotDefined, MissingDimensionValue, InvalidDimensionValue, OperationNotSupported, MissingParameterValue, InvalidParameterValue, InternalServerError, InvalidRequest, VersionNegotiationFailed } protected Code code; diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcLayer.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcLayer.java index a902793615..098d5c3087 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcLayer.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcLayer.java @@ -30,6 +30,8 @@ import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang.StringUtils; + /** * @author bclement * @@ -66,7 +68,7 @@ public class OgcLayer { protected List dimensions; - protected static String keySeparator = "/"; + public static String keySeparator = "/"; public void addCRS(String crs) { this.crs = addToList(this.crs, crs); @@ -118,16 +120,23 @@ public class OgcLayer { return separateKey(layerName)[0]; } + public static String decodeLayerName(String layerName) { + if (layerName == null) { + return null; + } + try { + return URLDecoder.decode(layerName, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + public static String[] separateKey(String layerName) { - if (layerName == null) { - return null; - } - String lname; - try { - lname = URLDecoder.decode(layerName, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } + String lname = decodeLayerName(layerName); + if (lname == null) { + return null; + } + lname = StringUtils.strip(lname, OgcLayer.keySeparator); return lname.split(OgcLayer.keySeparator, 2); } @@ -135,7 +144,7 @@ public class OgcLayer { return getKey() + keySeparator + title; } - protected String createName(String key, String name) { + public static String createName(String key, String name) { try { return URLEncoder.encode(key + keySeparator + name, "UTF-8"); } catch (UnsupportedEncodingException e) { diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcNamespace.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcNamespace.java index e9dd68f0cb..7f81d270a0 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcNamespace.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcNamespace.java @@ -66,6 +66,8 @@ public class OgcNamespace { public static final String WCS112 = "http://www.opengis.net/wcs/1.1.2"; + public static final String WCS11 = "http://www.opengis.net/wcs/1.1"; + public static final String WMS = "http://www.opengis.net/wms"; public static final String WFS = "http://www.opengis.net/wfs"; @@ -78,4 +80,26 @@ public class OgcNamespace { public static final String WMTS100 = "http://www.opengis.net/wmts/1.0"; + public static final String WFS20 = "http://www.opengis.net/wfs/2.0"; + + public static final String FES20 = "http://www.opengis.net/fes/2.0"; + + public static final String GML32 = "http://www.opengis.net/gml/3.2"; + + public static final String SWE_GML32 = "http://www.opengis.net/swe/1.0/gml32"; + + public static final String AVWX11 = "http://www.eurocontrol.int/avwx/1.1"; + + public static final String OM_GML32 = "http://www.opengis.net/om/1.0/gml32"; + + public static final String SML_GML32 = "http://www.opengis.net/sensorML/1.0/gml32"; + + public static final String WX = "http://www.eurocontrol.int/wx/1.1"; + + public static final String WSNT = "http://docs.oasis-open.org/wsn/b-2"; + + public static final String WSA = "http://www.w3.org/2005/08/addressing"; + + public static final String OWSNT = "http://www.opengis.net/owsnt/1.1"; + } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcOperationInfo.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcOperationInfo.java index 7bc69e82ac..0f9341307e 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcOperationInfo.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcOperationInfo.java @@ -41,6 +41,8 @@ public class OgcOperationInfo { protected String httpPostRes; protected String httpGetRes; + + protected String postEncoding; protected List formats = new LinkedList(); @@ -206,4 +208,19 @@ public class OgcOperationInfo { this.interpolationtypes = interpolationtypes; } + /** + * @return the postEncoding + */ + public String getPostEncoding() { + return postEncoding; + } + + /** + * @param postEncoding + * the postEncoding to set + */ + public void setPostEncoding(String postEncoding) { + this.postEncoding = postEncoding; + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcPrefix.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcPrefix.java index d47160e3fa..6de9a09e2a 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcPrefix.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcPrefix.java @@ -37,7 +37,7 @@ public class OgcPrefix { */ public static final String GML = "gml"; - public static final String ISM = "ism"; + public static final String ISM = "icism"; /** * Open Geospatial Consortium @@ -109,4 +109,17 @@ public class OgcPrefix { public static final String SLD = "sld"; public static final String SE = "se"; + + public static final String WX = "wx"; + + public static final String AVWX = "avwx"; + + public static final String FES = "fes"; + + public static final String WSNT = "wsn-b"; + + public static final String WSA = "wsa"; + + public static final String OWSNT = "owsnt"; + } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java index 09b15f4bf5..f6a6b31624 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java @@ -24,12 +24,15 @@ **********************************************************************/ package com.raytheon.uf.edex.ogc.common; +import com.raytheon.uf.edex.ogc.common.http.MimeType; + public class OgcResponse { - public static final String TEXT_XML_MIME = "text/xml"; + public static final MimeType TEXT_XML_MIME = new MimeType("text/xml"); - public static final String TEXT_HTML_MIME = "text/html"; + public static final MimeType TEXT_HTML_MIME = new MimeType("text/html"); - public static final String APP_VND_OGC_SE_XML = "application/vnd.ogc.se_xml"; + public static final MimeType APP_VND_OGC_SE_XML = new MimeType( + "application/vnd.ogc.se_xml"); public enum TYPE { TEXT, IMAGE, BYTE, MULTIPART @@ -39,7 +42,7 @@ public class OgcResponse { NONE, BAD_REQ, INT_ERR, NOT_IMPLEMENTED }; - protected String mimetype; + protected MimeType mimetype; protected Object body; @@ -49,19 +52,19 @@ public class OgcResponse { protected ErrorType error = ErrorType.NONE; - private String exceptionFormat = OgcResponse.TEXT_XML_MIME; + private MimeType exceptionFormat = OgcResponse.TEXT_XML_MIME; - public OgcResponse(Object body, String mimetype, TYPE type) { + public OgcResponse(Object body, MimeType mimetype, TYPE type) { this.body = body; this.mimetype = mimetype; this.type = type; } - public String getMimetype() { + public MimeType getMimetype() { return mimetype; } - public void setMimetype(String mimetype) { + public void setMimetype(MimeType mimetype) { this.mimetype = mimetype; } @@ -85,14 +88,14 @@ public class OgcResponse { * @param exceptionFormat * the exceptionFormat to set */ - public void setExceptionFormat(String exceptionFormat) { + public void setExceptionFormat(MimeType exceptionFormat) { this.exceptionFormat = exceptionFormat; } /** * @return the exceptionFormat */ - public String getExceptionFormat() { + public MimeType getExceptionFormat() { return exceptionFormat; } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/PeekingIterator.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/PeekingIterator.java new file mode 100644 index 0000000000..aaaf5adc8c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/PeekingIterator.java @@ -0,0 +1,98 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common; + +import java.util.Iterator; + +/** + * Iterator that allows peeking at the next item without progressing + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 29, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class PeekingIterator implements Iterator { + + private final Iterator iter; + + private T next; + + private boolean dirty = false; + + /** + * @param iter + */ + public PeekingIterator(Iterator iter) { + this.iter = iter; + } + + /* + * (non-Javadoc) + * + * @see java.util.Iterator#hasNext() + */ + @Override + public boolean hasNext() { + if (dirty) { + return true; + } + return iter.hasNext(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Iterator#next() + */ + @Override + public T next() { + if (dirty) { + dirty = false; + return next; + } + return iter.next(); + } + + /** + * Look at next item without progressing. Will return the same item until + * {@link PeekingIterator#next()} is called. + * + * {@link PeekingIterator#hasNext()} should be called beforehand. + * + * @return + */ + public T peek(){ + if (dirty){ + return next; + } + next = iter.next(); + dirty = true; + return next; + } + + /** + * Unsupported. Throws {@link UnsupportedOperationException} + */ + @Override + public void remove() { + throw new UnsupportedOperationException( + "remove not supported on peeking iterator"); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/Version.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/Version.java new file mode 100644 index 0000000000..f1a7889182 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/Version.java @@ -0,0 +1,233 @@ +/********************************************************************** + * + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + **********************************************************************/ +package com.raytheon.uf.edex.ogc.common; + +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; + +@XmlAccessorType(XmlAccessType.NONE) +@DynamicSerialize +public class Version implements Comparable, Serializable { + + private transient static final long serialVersionUID = -7496995218051649871L; + + @DynamicSerializeElement + @XmlAttribute + protected int major = 0; + + @DynamicSerializeElement + @XmlAttribute + protected int minor = 0; + + @DynamicSerializeElement + @XmlAttribute + protected int micro = 0; + + @DynamicSerializeElement + @XmlAttribute + protected String qualifier; + + protected transient Pattern pattern = Pattern + .compile("^([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(\\.([^\\.,]+))?)?)?$"); + + public Version() { + } + + public Version(Version pv) { + this(pv.major, pv.minor, pv.micro, pv.qualifier); + } + + public Version(int major, int minor, int micro) { + this(major, minor, micro, null); + } + + public Version(int major, int minor, int micro, String qualifier) { + this.major = major; + this.micro = micro; + this.minor = minor; + this.qualifier = qualifier; + } + + public Version(String version) throws InvalidVersionException { + fromString(version); + } + + protected void fromString(String version) throws InvalidVersionException { + Matcher m = pattern.matcher(version.trim()); + if (m.matches()) { + major = parseInt(m.group(1)); + minor = parseInt(m.group(3)); + micro = parseInt(m.group(5)); + qualifier = m.group(7); + } else { + throw new InvalidVersionException("Invalid version string: '" + + version + "'"); + } + } + + public Version majorMinorOnly() { + return new Version(this.major, this.minor, 0); + } + + protected int parseInt(String str) { + int rval = 0; + if (str != null) { + rval = Integer.parseInt(str); + } + return rval; + } + + public int getMajor() { + return major; + } + + public void setMajor(int major) { + this.major = major; + } + + public int getMinor() { + return minor; + } + + public void setMinor(int minor) { + this.minor = minor; + } + + public int getMicro() { + return micro; + } + + public void setMicro(int micro) { + this.micro = micro; + } + + public String getQualifier() { + return qualifier; + } + + public void setQualifier(String qualifier) { + this.qualifier = qualifier; + } + + public String toString() { + String rval = String.format("%d.%d.%d", major, minor, micro); + if (this.qualifier != null && !this.qualifier.isEmpty()) { + rval += "." + qualifier; + } + return rval; + } + + @Override + public int compareTo(Version o) { + if (o == null) { + return 1; + } + if (o == this) { + return 0; + } + int res = major - o.major; + if (res != 0) { + return res; + } + res = minor - o.minor; + if (res != 0) { + return res; + } + res = micro - o.micro; + if (res != 0) { + return res; + } + if (qualifier == null) { + if (o.qualifier != null) { + return -1; + } + } else if (o.qualifier == null) { + return 1; + } else { + return qualifier.compareTo(o.qualifier); + } + + return 0; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + major; + result = prime * result + micro; + result = prime * result + minor; + result = prime * result + + ((qualifier == null) ? 0 : qualifier.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Version other = (Version) obj; + if (major != other.major) + return false; + if (micro != other.micro) + return false; + if (minor != other.minor) + return false; + if (qualifier == null) { + if (other.qualifier != null) + return false; + } else if (!qualifier.equals(other.qualifier)) + return false; + return true; + } + + /** + * @param other + * @return true if this and other have the same major and minor versions + */ + public boolean equalsMajorMinor(Version other) { + if (other == null) { + return false; + } + if (major != other.major) + return false; + if (minor != other.minor) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/colormap/StyleRuleLibrary.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/colormap/StyleRuleLibrary.java index bfddc05b81..8995e44779 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/colormap/StyleRuleLibrary.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/colormap/StyleRuleLibrary.java @@ -32,15 +32,12 @@ package com.raytheon.uf.edex.ogc.common.colormap; import java.io.InputStream; import java.text.ParseException; -import java.text.ParsePosition; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.measure.converter.UnitConverter; import javax.measure.unit.Unit; -import javax.measure.unit.UnitFormat; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; @@ -50,8 +47,12 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.edex.ogc.common.spatial.AltUtil; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalEnabled; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalSpatialFactory; /** * TODO Add Description @@ -66,8 +67,6 @@ public class StyleRuleLibrary { @XmlElements({ @XmlElement(name = "styleRule", type = StyleRule.class) }) private List rules; - private Log log = LogFactory.getLog(this.getClass()); - private Map> _ruleMap; public StyleRuleLibrary() { @@ -111,43 +110,51 @@ public class StyleRuleLibrary { return _ruleMap; } - /** - * @param rule - * @param dimensions - * @param levelUnits - * @return false if there was a range and it was out of bounds, true - * otherwise - * @throws ParseException - */ - protected boolean initRule(StyleRule rule, Map dimensions, - Map levelUnits) throws ParseException { + /** + * @param rule + * @param record + * @return false if there was a range and it was out of bounds, true + * otherwise + * @throws ParseException + */ + protected boolean initRule(StyleRule rule, PluginDataObject record) + throws ParseException { LevelRange range = rule.getLevelRange(); if (range != null) { // only accept if range is ok - return initRange(rule, dimensions, levelUnits); + return initRange(rule, record); } // if there is no range, we accept the rule return true; } - /** - * @param rule - * @param dimensions - * @param levelUnits - * @return true if range is in bounds - * @throws ParseException - */ - protected boolean initRange(StyleRule rule, Map dimensions, - Map levelUnits) throws ParseException { + /** + * @param rule + * @param record + * @return true if range is in bounds + * @throws ParseException + */ + @SuppressWarnings("unchecked") + protected boolean initRange(StyleRule rule, PluginDataObject record) + throws ParseException { LevelRange range = rule.getLevelRange(); - String level = range.getLevel(); - String levelValue = dimensions.get(level); - if (levelValue != null) { - Double lvlVal = Double.parseDouble(levelValue); - String styleLevelUnit = range.getUnit(); - lvlVal = convert(lvlVal, styleLevelUnit, styleLevelUnit, levelUnits); - if (lvlVal >= range.getLower() && lvlVal <= range.getUpper()) { - setupLevelRange(rule, lvlVal); + VerticalEnabled enabled; + if (record instanceof VerticalEnabled) { + enabled = (VerticalEnabled) record; + } else if ((enabled = (VerticalEnabled) VerticalSpatialFactory + .getEnabled(record.getClass())) != null) { + } else { + return false; + } + VerticalCoordinate vert = enabled.getVerticalCoordinate(record); + + if (vert != null) { + Unit styleLevelUnit = Unit.valueOf(range.getUnit()); + double levelValue = AltUtil.convert(styleLevelUnit, + Reference.UNKNOWN, vert).getValue(); + if (levelValue >= range.getLower() + && levelValue <= range.getUpper()) { + setupLevelRange(rule, levelValue); // range is in bounds return true; } @@ -156,43 +163,17 @@ public class StyleRuleLibrary { return false; } - protected Double convert(Double lvlVal, String styleLevelUnit, - String level, Map levelUnits) throws ParseException { - if (styleLevelUnit == null || levelUnits == null) { - return lvlVal; - } - String dataLevelUnit = levelUnits.get(level); - if (dataLevelUnit == null) { - return lvlVal; - } - UnitFormat formatter = UnitFormat.getInstance(); - try { - Unit ruleUnit = formatter.parseSingleUnit(styleLevelUnit, - new ParsePosition(0)); - Unit dataUnit = formatter.parseSingleUnit(dataLevelUnit, - new ParsePosition(0)); - - UnitConverter dataToRuleConv = dataUnit.getConverterTo(ruleUnit); - - return dataToRuleConv.convert(lvlVal.doubleValue()); - - } catch (ParseException e) { - log.error("Cannot convert units", e); - throw e; - } - } - - public StyleRule getMatchForLayer(String layer, - Map dimensions, Map levelUnits) + public StyleRule getMatchForLayer(PluginDataObject record) throws ParseException { - if (layer == null) { + if (record == null) { return null; } + String datauri = record.getDataURI(); for (StyleRule rule : rules) { String pattern = rule.getLayerRegex(); - if (layer.matches(pattern)) { + if (datauri.matches(pattern)) { // do not return rule if there is an invalid range - if (initRule(rule, dimensions, levelUnits)) { + if (initRule(rule, record)) { return rule; } } @@ -200,10 +181,22 @@ public class StyleRuleLibrary { return null; } - public StyleRule getLayerStyleWithNewCmap(String layer, - Map dimensions, Map levelUnits, + public StyleRule getMatchForLayer(String layerName) throws ParseException { + if (layerName == null) { + return null; + } + for (StyleRule rule : rules) { + String pattern = rule.getLayerRegex(); + if (layerName.matches(pattern)) { + return rule; + } + } + return null; + } + + public StyleRule getLayerStyleWithNewCmap(PluginDataObject record, String newColormap) throws ParseException { - StyleRule rule = getMatchForLayer(layer, dimensions, levelUnits); + StyleRule rule = getMatchForLayer(record); if (rule != null && newColormap != null) { rule.setColorMapName(newColormap); return rule; diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/CollectorAddonFactory.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/CollectorAddonFactory.java new file mode 100644 index 0000000000..89f073cfd6 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/CollectorAddonFactory.java @@ -0,0 +1,37 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.db; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; + +/** + * Factory for creating collector addons + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 18, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface CollectorAddonFactory, R extends PluginDataObject> { + + /** + * @return new instance of collector addon + */ + public ICollectorAddon create(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/DefaultLayerCollector.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/DefaultLayerCollector.java index 8c6aeaa877..ba2c908d33 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/DefaultLayerCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/DefaultLayerCollector.java @@ -1,73 +1,62 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ - /** - * SOFTWARE HISTORY +/* + * The following software products were developed by Raytheon: * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * Nov 1, 2011 bclement Initial creation + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software * - **/ - + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + */ package com.raytheon.uf.edex.ogc.common.db; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.database.DataAccessLayerException; +import com.raytheon.uf.edex.database.dao.CoreDao; +import com.raytheon.uf.edex.database.dao.DaoConfig; +import com.raytheon.uf.edex.database.query.DatabaseQuery; +import com.raytheon.uf.edex.ogc.common.OgcException; -/** - * - * Default Layer Collector - * - *
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * 08/09/2012   754       dhladky      initial creation, based on B Clements original
- * 04/01/2013   1746      dhladky      Updated for MADIS configuration
- * 05/27/2013   753       dhladky      Updated for wfs service
- * 
- * - * @author dhladky - * @version 1.0 - */ +public abstract class DefaultLayerCollector, R extends PluginDataObject> + extends LayerCollector { -public abstract class DefaultLayerCollector, R extends PluginDataObject> - extends LayerCollector { - - private static final IUFStatusHandler statusHandler = UFStatus + protected static final IUFStatusHandler log = UFStatus .getHandler(DefaultLayerCollector.class); - protected Class recordClass; + protected Map layerMap; - protected Class layerClass; + protected ReadWriteLock lock = new ReentrantReadWriteLock(); - public DefaultLayerCollector(LayerTransformer transformer, - Class layerClass, Class recordClass) { - super(transformer); - this.recordClass = recordClass; - this.layerClass = layerClass; + public DefaultLayerCollector(Class layerClass, Class recordClass, + ILayerStore store) { + super(layerClass, recordClass, store); } public void add(R... pdos) { @@ -76,17 +65,38 @@ public abstract class DefaultLayerCollector coll); - - @Override - protected L newLayer() { - try { - return layerClass.newInstance(); - } catch (Exception e) { - statusHandler - .error("Unable to instantiate class: " + layerClass, e); - throw new RuntimeException(e); + @SuppressWarnings("unchecked") + public void addAll(Collection coll) { + if (layerMap == null) { + initMap(); } + Lock write = lock.writeLock(); + write.lock(); + ICollectorAddon addon = getAddon(); + for (PluginDataObject pdo : coll) { + if (recordClass.equals(pdo.getClass())) { + R rec = (R) pdo; + String name = getLayerName(rec); + L layer = newLayer(); + layer.setName(name); + if (!initializeLayer(layer, rec)) { + continue; + } + addToTimes(layer, rec); + addToDims(layer, rec); + L oldLayer = layerMap.get(name); + if (oldLayer == null) { + oldLayer = newLayer(); + oldLayer.setName(name); + initializeLayer(oldLayer, rec); + layerMap.put(name, oldLayer); + } + oldLayer.update(layer); + addon.onCollect(layer, (R) pdo); + } + } + addon.onFinish(); + write.unlock(); } protected void addToTimes(L layer, R rec) { @@ -100,7 +110,101 @@ public abstract class DefaultLayerCollector()); + } catch (Exception e) { + log.error("Problem purging layers", e); + } + } + protected void clearLayersInternal() throws DataAccessLayerException { + Lock write = lock.writeLock(); + write.lock(); + if (layerMap != null) { + layerMap.clear(); + } + write.unlock(); + } + + @SuppressWarnings("unchecked") + protected void addFromDb() throws DataAccessLayerException { + DaoConfig conf = DaoConfig.forClass(recordClass); + CoreDao dao = new CoreDao(conf); + DatabaseQuery q = new DatabaseQuery(recordClass); + List recs = (List) dao.queryByCriteria(q); + addAll(recs); + } + + public void purgeAll() { + try { + clearLayersInternal(); + getAddon().onPurgeAll(); + } catch (Exception e) { + log.error("problem purging layers", e); + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.LayerCache#getLayers() + */ + @Override + public List getLayers() throws OgcException { + List rval; + if (layerMap == null) { + initMap(); + } + Lock read = lock.readLock(); + read.lock(); + rval = new ArrayList(layerMap.size()); + for (String key : layerMap.keySet()) { + rval.add(copy(layerMap.get(key))); + } + read.unlock(); + return rval; + } + + protected void initMap() { + Lock write = lock.writeLock(); + write.lock(); + if (layerMap == null) { + layerMap = new ConcurrentHashMap(); + try { + addFromDb(); + } catch (DataAccessLayerException e) { + log.error("Problem loading layers from db", e); + // if we throw an internal server exception here, it would kill + // the ogc request, better to just not add those layers to + // response + } + } + write.unlock(); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerCache#getLayer(java.lang.String) + */ + @Override + public L getLayer(String name) throws OgcException { + if (layerMap == null) { + initMap(); + } + L rval; + Lock read = lock.readLock(); + read.lock(); + rval = layerMap.get(name); + if (rval != null) { + rval = copy(layerMap.get(name)); + } + read.unlock(); + return rval; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/DefaultPointDataDimension.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/DefaultPointDataDimension.java new file mode 100644 index 0000000000..16bece1b67 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/DefaultPointDataDimension.java @@ -0,0 +1,51 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.HashSet; +import java.util.Set; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 24, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class DefaultPointDataDimension extends SimpleDimension { + + private static final long serialVersionUID = 2947254963150347405L; + + /** + * {@inheritDoc} + */ + @Override + public Set getValues() { + return new HashSet(0); + } + + /** + * {@inheritDoc} + */ + @Override + public String getDefaultValue(SimpleLayer layer) { + return null; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/FsLayerStore.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/FsLayerStore.java new file mode 100644 index 0000000000..e4bf12b8b6 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/FsLayerStore.java @@ -0,0 +1,368 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.db; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +import com.raytheon.uf.common.serialization.DynamicSerializationManager; +import com.raytheon.uf.common.serialization.DynamicSerializationManager.SerializationType; +import com.raytheon.uf.edex.ogc.common.AbstractFsStore; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; + +/** + * Simple Layer store using file system + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 4, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class FsLayerStore extends AbstractFsStore implements ILayerStore { + + private final DynamicSerializationManager serializer = DynamicSerializationManager + .getManager(SerializationType.Thrift); + + private final Map, ReentrantReadWriteLock> _lockMap = new HashMap, ReentrantReadWriteLock>(); + + /** + * @param storeLocation + */ + public FsLayerStore(File storeLocation) { + super(storeLocation); + } + + /** + * @param storeName + * name of store relative to edex static base + */ + public FsLayerStore(String storeName) { + this(findStore(storeName)); + } + + /** + * Get lock for class + * + * @param c + * @return + */ + private ReentrantReadWriteLock getLock(Class c) { + synchronized (_lockMap) { + ReentrantReadWriteLock rval = _lockMap.get(c); + if (rval == null) { + rval = new ReentrantReadWriteLock(); + _lockMap.put(c, rval); + } + return rval; + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.LayerStore#get(java.lang.String, + * java.lang.Class) + */ + @Override + public > L get( + String id, Class c) throws OgcException { + ReentrantReadWriteLock lock = getLock(c); + ReadLock readLock = lock.readLock(); + readLock.lock(); + try { + File layerFile = getLayerFileRead(id, c); + if (!layerFile.exists()) { + return null; + } + L rval = deserialize(layerFile, c); + return rval; + } finally { + readLock.unlock(); + } + } + + @SuppressWarnings("unchecked") + private > L deserialize( + File f, Class c) throws OgcException { + try { + return (L) serializer.deserialize(new FileInputStream(f)); + } catch (Exception e) { + throw new OgcException(Code.InternalServerError, e); + } + } + + /** + * Get store directory for class, read only + * + * must be synchronized externally + * + * @param c + * @return file object that isn't guaranteed to exist + * @throws OgcException + */ + private File getClassDirRead(Class c) throws OgcException { + File rval = new File(storeLocation, c.getName()); + + if (!rval.isDirectory()) { + throw new OgcException(Code.InternalServerError, + rval.getAbsolutePath() + " is not a directory"); + } + if (!rval.canRead()) { + throw new OgcException(Code.InternalServerError, + "Unable to read store directory: " + rval.getAbsolutePath()); + } + return rval; + } + + /** + * Get store directory for class for modification, creates if it doesn't + * exist + * + * must be synchronized externally + * + * @param c + * @param create + * true if method should create if non existent + * @return file object that is only guaranteed to exist if create is true + * @throws OgcException + */ + private File getClassDirWrite(Class c, boolean create) + throws OgcException { + File rval = new File(storeLocation, c.getName()); + if (!rval.exists()) { + if (!create) { + return rval; + } + if (!rval.mkdir()) { + throw new OgcException(Code.InternalServerError, + "Unable to create store directory: " + + rval.getAbsolutePath()); + } + } + if (!rval.isDirectory()) { + throw new OgcException(Code.InternalServerError, + rval.getAbsolutePath() + " is not a directory"); + } + if (!rval.canWrite()) { + throw new OgcException(Code.InternalServerError, + "Unable to write to store directory: " + + rval.getAbsolutePath()); + } + return rval; + } + + /** + * Create file object for layer file for reading + * + * must be synchronized externally + * + * @param id + * @param c + * @return a file object whose path isn't guaranteed to exist + * @throws OgcException + */ + private File getLayerFileRead(String id, Class c) throws OgcException { + return new File(getClassDirRead(c), encode(id)); + } + + /** + * Create file object for layer file for writing + * + * must be synchronized externally + * + * @param id + * @param c + * @param createPath + * if true, path to file will be created if nonexistent + * @return + * @throws OgcException + */ + private File getLayerFileWrite(String id, Class c, boolean createPath) + throws OgcException { + return new File(getClassDirWrite(c, createPath), encode(id)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerStore#getAll(java.lang.Class) + */ + @Override + public > List getAll( + Class c) throws OgcException { + ReentrantReadWriteLock lock = getLock(c); + ReadLock readLock = lock.readLock(); + readLock.lock(); + try { + File classDir = getClassDirRead(c); + if (!classDir.exists()) { + return new ArrayList(0); + } + File[] listFiles = classDir.listFiles(new FileFilter() { + @Override + public boolean accept(File f) { + return f.isFile(); + } + }); + List rval = new ArrayList(listFiles.length); + for (File f : listFiles) { + rval.add(deserialize(f, c)); + } + return rval; + } finally { + readLock.unlock(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerStore#createOrUpdate(com.raytheon + * .uf.edex.ogc.common.db.SimpleLayer) + */ + @Override + public void createOrUpdate(SimpleLayer l) + throws OgcException { + Class c = l.getClass(); + ReentrantReadWriteLock lock = getLock(c); + WriteLock writeLock = lock.writeLock(); + writeLock.lock(); + try { + serialize(l, getLayerFileWrite(l.getIdentifier(), c, true)); + } finally { + writeLock.unlock(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerStore#createOrUpdate(java.util + * .List) + */ + @Override + public void createOrUpdate( + List> layers) + throws OgcException { + Map, List>> map = new HashMap, List>>(); + for (SimpleLayer l : layers) { + List> list = map.get(l.getClass()); + if (list == null) { + list = new ArrayList>(); + map.put(l.getClass(), list); + } + list.add(l); + } + for (Entry, List>> e : map.entrySet()) { + Class c = e.getKey(); + ReentrantReadWriteLock lock = getLock(c); + WriteLock writeLock = lock.writeLock(); + writeLock.lock(); + try { + for (SimpleLayer l : e.getValue()) { + serialize(l, getLayerFileWrite(l.getIdentifier(), c, true)); + } + } finally { + writeLock.unlock(); + } + } + } + + /** + * Store layer + * + * @param l + * @param f + * @throws OgcException + */ + private void serialize(SimpleLayer l, File f) throws OgcException { + try { + serializer.serialize(l, new FileOutputStream(f)); + } catch (Exception e) { + throw new OgcException(Code.InternalServerError, e); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerStore#delete(java.lang.String, + * java.lang.Class) + */ + @Override + public void delete(String id, Class> c) + throws OgcException { + File layerFile = getLayerFileWrite(id, c, false); + if (!layerFile.exists()) { + return; + } + ReentrantReadWriteLock lock = getLock(c); + WriteLock writeLock = lock.writeLock(); + writeLock.lock(); + try { + if (layerFile.exists()) { + layerFile.delete(); + } + } finally { + writeLock.unlock(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerStore#deleteAll(java.lang.Class) + */ + @Override + public void deleteAll(Class> c) + throws OgcException { + ReentrantReadWriteLock lock = getLock(c); + WriteLock writeLock = lock.writeLock(); + writeLock.lock(); + try { + File classDir = getClassDirWrite(c, false); + if (!classDir.exists()) { + return; + } + for (File f : classDir.listFiles()) { + if (f.isFile()) { + f.delete(); + } + } + } finally { + writeLock.unlock(); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ICollectorAddon.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ICollectorAddon.java new file mode 100644 index 0000000000..c9eb501a84 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ICollectorAddon.java @@ -0,0 +1,60 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.Date; +import java.util.Set; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; + +/** + * Interface for extending layer collectors to perform additional tasks + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 17, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface ICollectorAddon, R extends PluginDataObject> { + + /** + * Called after record is added to layer. Both should be treated as + * read-only. + * + * @param layer + * @param record + */ + public void onCollect(final L layer, final R record); + + /** + * Called after group of records have been added to layers + */ + public void onFinish(); + + /** + * Called after collector has purged all data + */ + public void onPurgeAll(); + + /** + * Called after collector has purged expired data + * + * @param timesToKeep + */ + public void onPurgeExpired(Set timesToKeep); +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ILayerCache.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ILayerCache.java new file mode 100644 index 0000000000..8967f08cbb --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ILayerCache.java @@ -0,0 +1,48 @@ +/* +* The following software products were developed by Raytheon: +* +* ADE (AWIPS Development Environment) software +* CAVE (Common AWIPS Visualization Environment) software +* EDEX (Environmental Data Exchange) software +* uFrame™ (Universal Framework) software +* +* Copyright (c) 2010 Raytheon Co. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/org/documents/epl-v10.php +* +* +* Contractor Name: Raytheon Company +* Contractor Address: +* 6825 Pine Street, Suite 340 +* Mail Stop B8 +* Omaha, NE 68106 +* 402.291.0100 +* +* +* SOFTWARE HISTORY +* +* Date Ticket# Engineer Description +* ------------ ---------- ----------- -------------------------- +* Sep 11, 2012 bclement Initial creation +* +*/ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.List; + +import com.raytheon.uf.edex.ogc.common.OgcException; + +/** + * + * @author bclement + * @version 1.0 + */ +public interface ILayerCache> { + + public List getLayers() throws OgcException; + + public L getLayer(String name) throws OgcException; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ILayerStore.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ILayerStore.java new file mode 100644 index 0000000000..67015384fa --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/ILayerStore.java @@ -0,0 +1,93 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.List; + +import com.raytheon.uf.edex.ogc.common.OgcException; + +/** + * Storage interface for layers + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 4, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface ILayerStore { + + /** + * Retrieve layer from store + * + * @param id + * @param c + * @return null if layer is not in store + * @throws OgcException + */ + public > L get( + String id, Class c) throws OgcException; + + /** + * Retrieve all layers for class + * + * @param c + * @return + * @throws OgcException + */ + public > List getAll( + Class c) throws OgcException; + + /** + * Persist layer + * + * @param layer + * @throws OgcException + */ + public void createOrUpdate(SimpleLayer layer) + throws OgcException; + + /** + * Persist layers + * + * @param layers + * @throws OgcException + */ + public void createOrUpdate( + List> layers) + throws OgcException; + + /** + * Remove layer with id from store + * + * @param id + * @param c + * @throws OgcException + */ + public void delete(String id, Class> c) + throws OgcException; + + /** + * Delete all layers with class c from store + * + * @param c + * @throws OgcException + */ + public void deleteAll(Class> c) + throws OgcException; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerCollector.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerCollector.java index 0db22cf7e2..48f15b883d 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerCollector.java @@ -1,152 +1,139 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + */ package com.raytheon.uf.edex.ogc.common.db; +import java.lang.reflect.Constructor; import java.util.Calendar; import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Set; import org.apache.commons.lang.time.DateUtils; -import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfig; -import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfigurationManager; -import com.raytheon.uf.common.datadelivery.harvester.OGCAgent; -import com.raytheon.uf.common.datadelivery.registry.Coverage; -import com.raytheon.uf.common.datadelivery.registry.DataLevelType; -import com.raytheon.uf.common.datadelivery.registry.DataSet; -import com.raytheon.uf.common.datadelivery.registry.DataSetMetaData; -import com.raytheon.uf.common.datadelivery.registry.DataSetName; -import com.raytheon.uf.common.datadelivery.registry.DataType; -import com.raytheon.uf.common.datadelivery.registry.Levels; -import com.raytheon.uf.common.datadelivery.registry.Parameter; -import com.raytheon.uf.common.datadelivery.registry.Provider; -import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; -import com.raytheon.uf.common.datadelivery.registry.handlers.IDataSetHandler; -import com.raytheon.uf.common.datadelivery.registry.handlers.IDataSetMetaDataHandler; -import com.raytheon.uf.common.registry.handler.RegistryHandlerException; +import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; -/** - * - * Layer Collector - * - *
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * 08/09/2012   754       dhladky      initial creation, based on B Clements original
- * 04/22/2013   1746      dhladky      Removed DB dependency from WFS code
- * 
- * - * @author dhladky - * @version 1.0 - */ +public abstract class LayerCollector, R extends PluginDataObject> + implements ILayerCache { -public abstract class LayerCollector> { + protected Class recordClass; - private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(LayerCollector.class); + protected Class layerClass; - protected LayerTransformer transformer; - - protected HarvesterConfig config = null; - - protected OGCAgent agent = null; + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected Map parameters = null; + protected final ILayerStore store; - public LayerCollector(LayerTransformer transformer) { - setTransformer(transformer); - this.config = HarvesterConfigurationManager.getOGCConfiguration(); - setAgent((OGCAgent)config.getAgent()); - storeProvider(config.getProvider()); - } + protected CollectorAddonFactory addonFactory = new CollectorAddonFactory() { + @Override + public ICollectorAddon create() { + return new ICollectorAddon() { + @Override + public void onCollect(L layer, R record) { + } - public HarvesterConfig getConfig() { - return config; - } + @Override + public void onFinish() { + } - public void setConfig(HarvesterConfig config) { - this.config = config; - } + @Override + public void onPurgeAll() { + } - public void update(L old, L shiny) { - updateDates(old, shiny); - updateDims(old, shiny); - } + @Override + public void onPurgeExpired(Set timesToKeep) { + } - public void updateDates(L old, L shiny) { - Set shinyTimes = shiny.getTimes(); - Set oldTimes = old.getTimes(); - if (shinyTimes != null && shinyTimes != null) { - for (Date time : shinyTimes) { - oldTimes.add(time); - } + }; } + }; + + public LayerCollector(Class layerClass, Class recordClass, + ILayerStore store) { + this.recordClass = recordClass; + this.layerClass = layerClass; + this.store = store; } - public void updateDims(L old, L shiny) { - Set oldDims = old.getDimensions(); - Set shinyDims = shiny.getDimensions(); - if (oldDims != null) { - if (shinyDims != null) { - updateDimLists(oldDims, shinyDims); - } - } + /** + * Returns object for additional tasks at layer collection + * + * @return + */ + public ICollectorAddon getAddon() { + return addonFactory.create(); } - public Map getDimMap(Set dims) { - HashMap rval = new HashMap( - dims.size()); - for (DIMENSION sd : dims) { - rval.put(sd.getName(), sd); + protected L copy(final L orig) throws OgcException { + L rval; + try { + Constructor constructor = layerClass.getConstructor(layerClass); + rval = constructor.newInstance(orig); + } catch (Exception e) { + log.error("Unable to copy layer: " + layerClass, e); + throw new OgcException(Code.InternalServerError); } return rval; } - public void updateDimLists(Set oldDims, Set shinyDims) { - Map oldMap = getDimMap(oldDims); - Map shinyMap = getDimMap(shinyDims); - for (String name : shinyMap.keySet()) { - DIMENSION shinyDim = shinyMap.get(name); - DIMENSION oldDim = oldMap.get(name); - if (oldDim == null) { - oldDims.add(shinyDim); - } else { - updateDimValues(oldDim, shinyDim); - } + protected L newLayer() { + try { + return layerClass.newInstance(); + } catch (Exception e) { + log.error("Unable to instantiate class: " + layerClass, e); + throw new RuntimeException(e); } } - public void updateDimValues(DIMENSION oldDim, DIMENSION shinyDim) { - Set oldValues = oldDim.getValues(); - Set shinyValues = shinyDim.getValues(); - if (oldValues != null && shinyValues != null) { - for (String val : shinyValues) { - oldValues.add(val); + public void clearLayers(Class c) throws OgcException { + store.deleteAll(c); + } + + public void replaceTimes(L layer) throws OgcException { + L old = store.get(layer.getIdentifier(), layerClass); + if (old == null) { + store.createOrUpdate(layer); + } else { + Set times = old.getTimes(); + times.clear(); + Set newTimes = layer.getTimes(); + if (newTimes != null) { + times.addAll(newTimes); } + store.createOrUpdate(layer); + } + } + + public void updateLayer(L layer) throws OgcException { + L old = store.get(layer.getIdentifier(), layerClass); + if (old == null) { + store.createOrUpdate(layer); + } else { + old.update(layer); + store.createOrUpdate(layer); } } @@ -172,6 +159,15 @@ public abstract class LayerCollector getDataLevelTypes(Parameter cp) { - return cp.getLevelType(); - } - - protected abstract L newLayer(); - - protected abstract void setCoverage(L layer); - - protected abstract Coverage getCoverage(); - - public void setParameters(L layer) { - synchronized (layer) { - if (getParameters() == null || getParameters().isEmpty()) { - parameters = new HashMap(); - for (Parameter parm : agent.getLayer(layer.getName()) - .getParameters()) { - // place in map - parameters.put(parm.getName(), parm); - storeParameter(parm); - } - } - } - } - - public Map getParameters() { - return parameters; - } - - protected abstract void setDataSet(L layer); - - protected abstract DataSet getDataSet(); - - protected abstract void setDataSetMetaData(L layer); - - protected abstract DataSetMetaData getDataSetMetaData(); - - protected abstract DataType getDataType(); - - public abstract Levels getLevels(DataLevelType type, String collectionName); - - public LayerTransformer getTransformer() { - return transformer; - } - - public void setTransformer(LayerTransformer transformer) { - this.transformer = transformer; - } - - public OGCAgent getAgent() { - return agent; - } - - public void setAgent(OGCAgent agent) { - this.agent = agent; + public void setAddonFactory(CollectorAddonFactory addonFactory) { + this.addonFactory = addonFactory; } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerTransformer.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerTransformer.java index 6a96ed98bc..7e3e09faf4 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerTransformer.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerTransformer.java @@ -1,22 +1,26 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + */ package com.raytheon.uf.edex.ogc.common.db; import java.util.ArrayList; @@ -40,16 +44,13 @@ import org.geotools.geometry.jts.ReferencedEnvelope; import org.opengis.referencing.ReferenceIdentifier; import org.opengis.referencing.crs.CoordinateReferenceSystem; -import com.raytheon.uf.common.dataquery.db.QueryParam; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.edex.database.DataAccessLayerException; -import com.raytheon.uf.edex.database.dao.CoreDao; -import com.raytheon.uf.edex.database.dao.DaoConfig; -import com.raytheon.uf.edex.database.query.DatabaseQuery; import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; import com.raytheon.uf.edex.ogc.common.OgcDimension; +import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; import com.raytheon.uf.edex.ogc.common.OgcLayer; import com.raytheon.uf.edex.ogc.common.OgcStyle; @@ -66,7 +67,6 @@ import com.vividsolutions.jts.geom.Polygon; * Jun 13, 2011 bclement Initial creation * **/ - public class LayerTransformer> { protected static IUFStatusHandler log = UFStatus @@ -78,14 +78,15 @@ public class LayerTransformer lcache; + protected static String timeUnit = "ISO8601"; - protected Class layerClass; + public static final Pattern frontDot = Pattern + .compile("^(-?[0-9]*\\.?[0-9]+)(.*)$"); - public static final Pattern frontDot = Pattern - .compile("^(-?[0-9]*\\.?[0-9]+)(.*)$"); - public static final Pattern backDot = Pattern - .compile("^(-?[0-9]+\\.?[0-9]*)(.*)$"); + public static final Pattern backDot = Pattern + .compile("^(-?[0-9]+\\.?[0-9]*)(.*)$"); /** * Construct a LayerTransformer that uses a different layerClass and @@ -97,9 +98,9 @@ public class LayerTransformer layerClass) { + public LayerTransformer(String key, ILayerCache lcache) { this.key = key; - this.layerClass = layerClass; + this.lcache = lcache; } /** @@ -107,18 +108,8 @@ public class LayerTransformer params = Arrays.asList(new QueryParam(field, name)); - List res; - res = query(layerClass, params); - if (res == null || res.isEmpty()) { - return null; - } - if (res.size() > 1) { - log.warn("Multiple layers found with the same name, returning first"); - } - return layerClass.cast(res.get(0)); + public L find(String name) throws OgcException { + return lcache.getLayer(name); } /** @@ -127,32 +118,36 @@ public class LayerTransformer l = find(layer); - return getDimension(l, dimension); + public DIMENSION getDimension(String layer, String dimension) + throws OgcException { + L l = find(layer); + if (l == null) { + return null; + } + return l.getDimension(dimension); } - /** - * @param layer - * @param dimension - * @return null if layer/dimension not found - */ - public static > DIMENSION getDimension( - L layer, - String dimension) { - if (layer == null) { - return null; - } - DIMENSION rval = null; + /** + * Get all dimensions that start with prefix. Case insensitive. + * + * @param layer + * @param prefix + * @return empty list if layer/dimension not found + */ + public static > List getDimsByPrefix( + L layer, String prefix) { + List rval = new ArrayList(2); + if (layer == null) { + return rval; + } for (DIMENSION d : layer.getDimensions()) { - if (d.getName().equalsIgnoreCase(dimension)) { - rval = d; - break; - } - } - return rval; - } + String lower = d.getName().toLowerCase(); + if (lower.startsWith(prefix.toLowerCase())) { + rval.add(d); + } + } + return rval; + } /** * @param dim @@ -265,27 +260,28 @@ public class LayerTransformer(0); } - Set set = new TreeSet(); - set.addAll(times); - Iterator i = set.iterator(); - StringBuilder sb = new StringBuilder(); - List rval = new ArrayList(); - Date curr = i.next(); - while (curr != null) { - startRange(sb, curr); - curr = endRange(curr, i, sb); - if (curr != null) { - rval.add(sb.toString()); - sb = new StringBuilder(); - } + if ( times.size() % 2 != 0){ + String msg = "Odd number of times for layer " + layer.getName() + + ". Should be even to construct time ranges."; + log.warn(msg + " Dropping last time"); } - String last = sb.toString(); - if (!last.isEmpty()) { - rval.add(last); + + Iterator iter = times.iterator(); + int ranges = times.size() / 2; + List rval = new ArrayList(ranges); + for (int i = 0; i < ranges; ++i) { + Date start = iter.next(); + Date end = iter.next(); + rval.add(formatRange(start, end)); } + return rval; } + protected static String formatRange(Date start, Date end) { + return format(start) + '/' + format(end) + "/0"; + } + /** * End a range started by startRange() * @@ -354,7 +350,7 @@ public class LayerTransformer getAllTimes() { + public TreeSet getAllTimes() throws OgcException { TreeSet rval = new TreeSet(); List layers = getLayers(); for (L l : layers) { @@ -363,16 +359,17 @@ public class LayerTransformer getLayers() { - List rval = query(layerClass); - return rval; + public List getLayers() throws OgcException { + return lcache.getLayers(); } - public List getLayersAsOgc(TimeFormat tformat, StyleLookup lookup) { + public List getLayersAsOgc(TimeFormat tformat, StyleLookup lookup) + throws OgcException { return transform(getLayers(), tformat, lookup); } - public List getLayersAsOgc(StyleLookup lookup) { + public List getLayersAsOgc(StyleLookup lookup) + throws OgcException { return getLayersAsOgc(TimeFormat.LIST, lookup); } @@ -405,15 +402,9 @@ public class LayerTransformer List query(Class c) { - return query(c, null); - } - - protected List query(Class c, List params) { - try { - DatabaseQuery query = new DatabaseQuery(c); - if (params != null && !params.isEmpty()) { - for (QueryParam p : params) { - query.addQueryParam(p); - } - } - DaoConfig config = DaoConfig.forClass(layerClass); - CoreDao dao = new CoreDao(config); - @SuppressWarnings("unchecked") - final List retVal = (List) dao.queryByCriteria(query); - return retVal; - } catch (Exception e) { - log.error("Unable to query entity: " + c, e); - return new ArrayList(0); - } - } - - protected > List unwrap( - List holders) { - List rval = new ArrayList(holders.size()); - for (H holder : holders) { - rval.add(holder.getValue()); - } - return rval; - } - /** * @param layerName * @return null if layer name isn't found * @throws DataAccessLayerException */ - public Date getLatestTime(String layerName) throws DataAccessLayerException { + public Date getLatestTime(String layerName) throws OgcException { L simpleLayer = find(layerName); return getLatestTime(simpleLayer); } @@ -557,25 +520,11 @@ public class LayerTransformer layerClass) { - this.layerClass = layerClass; - } - - /** - * @return the layerClass - */ - public Class getLayerClass() { - return layerClass; - } - /** * @return + * @throws OgcException */ - public TreeSet getLatestTimes() { + public TreeSet getLatestTimes() throws OgcException { List layers = getLayers(); TreeSet rval = new TreeSet(); for (L l : layers) { @@ -585,4 +534,11 @@ public class LayerTransformer getLcache() { + return lcache; + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/PointDataLayer.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/PointDataLayer.java new file mode 100644 index 0000000000..4a878cdce4 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/PointDataLayer.java @@ -0,0 +1,138 @@ +/* +* The following software products were developed by Raytheon: +* +* ADE (AWIPS Development Environment) software +* CAVE (Common AWIPS Visualization Environment) software +* EDEX (Environmental Data Exchange) software +* uFrame™ (Universal Framework) software +* +* Copyright (c) 2010 Raytheon Co. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/org/documents/epl-v10.php +* +* +* Contractor Name: Raytheon Company +* Contractor Address: +* 6825 Pine Street, Suite 340 +* Mail Stop B8 +* Omaha, NE 68106 +* 402.291.0100 +* +* +* SOFTWARE HISTORY +* +* Date Ticket# Engineer Description +* ------------ ---------- ----------- -------------------------- +* Sep 6, 2012 bclement Initial creation +* +*/ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.edex.ogc.common.db.LayerTransformer.TimeFormat; + +/** + * + * @author bclement + * @version 1.0 + */ +@Entity +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@XmlAccessorType(XmlAccessType.NONE) +@DynamicSerialize +public abstract class PointDataLayer extends + SimpleLayer { + + private static final long serialVersionUID = 4301480632118555546L; + + public PointDataLayer() { + } + + public PointDataLayer(SimpleLayer other) { + super(other); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.SimpleLayer#getTimeEntries() + */ + @Override + public List getTimeEntries() { + return LayerTransformer.getTimes(this, TimeFormat.HOUR_RANGES); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.SimpleLayer#getDimensions() + */ + @Override + public Set getDimensions() { + return new TreeSet(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.SimpleLayer#getDefaultTimeEntry() + */ + @Override + public String getDefaultTimeEntry() { + return LayerTransformer.getTimeRange(getDefaultTime()); + } + + /** + * Create formatted time range string with range start at the latest time + * minus milliOffset and the range end at the latest time. + * + * @param milliOffset + * @return + */ + protected String getRangeSinceLatest( + long milliOffset) { + Date end = getTimes().last(); + long startTime = end.getTime() - milliOffset; + Date start = new Date(startTime); + String startStr = LayerTransformer.format(start); + String endStr = LayerTransformer.format(end); + return startStr + "/" + endStr; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.SimpleLayer#updateDates(com.raytheon + * .uf.edex.ogc.common.db.SimpleLayer) + */ + @Override + public void updateDates(SimpleLayer other) { + SortedSet memTimes = other.getTimes(); + if (memTimes == null || memTimes.isEmpty()) { + return; + } + SortedSet dbtimes = this.getTimes(); + SortedSet all = new TreeSet(memTimes); + all.addAll(dbtimes); + dbtimes.clear(); + dbtimes.add(all.first()); + dbtimes.add(all.last()); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/PurgeNotification.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/PurgeNotification.java new file mode 100644 index 0000000000..3af348e261 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/PurgeNotification.java @@ -0,0 +1,89 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.Date; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import com.raytheon.uf.common.dataplugin.PluginException; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.core.EDEXUtil; +import com.raytheon.uf.edex.core.EdexException; +import com.raytheon.uf.edex.database.dao.CoreDao; +import com.raytheon.uf.edex.database.plugin.PurgeResults; + +/** + * Basic purge notification that sends all kept times to notification topic + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 6, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class PurgeNotification { + + private final String pluginName; + + protected static final IUFStatusHandler statusHandler = UFStatus + .getHandler(CoreDao.class); + + /** + * @param pluginName + */ + public PurgeNotification(String pluginName) { + this.pluginName = pluginName; + } + + public void purgeAllData() throws PluginException { + try { + EDEXUtil.getMessageProducer().sendAsyncUri(getTopicName("all"), + null); + } catch (EdexException e) { + statusHandler.error("Problem sending purge all message for " + + pluginName, e); + } + } + + public void purgeExpiredData(PurgeResults res) throws PluginException { + try { + if (res.didPurge()) { + Map> timesKept = res.getTimesKept(); + Set keepers = new TreeSet(); + if (timesKept != null) { + for (String pk : timesKept.keySet()) { + keepers.addAll(timesKept.get(pk)); + } + } + EDEXUtil.getMessageProducer().sendAsyncUri( + getTopicName("expired"), keepers); + } + } catch (EdexException e) { + statusHandler.error("Problem sending purge expired message for " + + pluginName, e); + } + } + + private String getTopicName(String purgeType) { + return String.format("jms-generic:topic:Purge.%s.%s", purgeType, + this.pluginName); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SQLParamRestriction.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SQLParamRestriction.java new file mode 100644 index 0000000000..e201cb7817 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SQLParamRestriction.java @@ -0,0 +1,77 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.hibernate.Criteria; +import org.hibernate.HibernateException; +import org.hibernate.criterion.CriteriaQuery; +import org.hibernate.criterion.Criterion; +import org.hibernate.engine.TypedValue; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 20, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class SQLParamRestriction implements Criterion { + + private static final long serialVersionUID = -7987314731153087246L; + private final String sql; + + private static Pattern paramPattern = Pattern + .compile("\\{([a-zA-Z0-9_\\.]+)\\}"); + + public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { + + StringBuffer result = new StringBuffer(); + Matcher matcher = paramPattern.matcher(sql); + while (matcher.find()) { + String token = matcher.group(1); + String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, token); + if (columns.length > 0) { + matcher.appendReplacement(result, columns[0]); + } + } + matcher.appendTail(result); + return result.toString(); + + } + + public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { + return new TypedValue[0]; + } + + public String toString() { + return sql; + } + + protected SQLParamRestriction(String sql) { + this.sql = sql; + } + + public static Criterion restriction(String sql) { + return new SQLParamRestriction(sql); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleDimension.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleDimension.java index 30c14e91ac..616a1c52cf 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleDimension.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleDimension.java @@ -1,33 +1,36 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ - /** +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * * SOFTWARE HISTORY * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Nov 1, 2011 bclement Initial creation * - **/ - + */ package com.raytheon.uf.edex.ogc.common.db; +import java.io.Serializable; import java.util.Set; import java.util.TreeSet; @@ -55,11 +58,13 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * @author dhladky * @version 1.0 */ - @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize -public abstract class SimpleDimension implements Comparable, ISerializableObject { +public abstract class SimpleDimension implements Comparable, + Serializable, ISerializableObject { + + private static final long serialVersionUID = 4654482181227204619L; @XmlElement @DynamicSerializeElement @@ -69,6 +74,14 @@ public abstract class SimpleDimension implements Comparable, I @DynamicSerializeElement protected String units; + public SimpleDimension() { + } + + public SimpleDimension(SimpleDimension other) { + this.name = other.name; + this.units = other.units; + } + /** * @return live reference to values set, should not return null */ @@ -83,9 +96,6 @@ public abstract class SimpleDimension implements Comparable, I public abstract String getDefaultValue( SimpleLayer layer); - public SimpleDimension() { - } - /** * @param lowest * set true to return lowest value, otherwise highest is returned @@ -122,6 +132,20 @@ public abstract class SimpleDimension implements Comparable, I return val != null ? String.valueOf(val.intValue()) : null; } + /** + * @param lowest + * set true to return lowest value, otherwise highest is returned + * @return + */ + protected String getString(boolean lowest) { + Set values = this.getValues(); + if (values.isEmpty()) { + return null; + } + TreeSet sorted = new TreeSet(values); + return lowest ? sorted.first() : sorted.last(); + } + /** * @return the name */ @@ -152,7 +176,6 @@ public abstract class SimpleDimension implements Comparable, I this.units = units; } - @Override public int compareTo(SimpleDimension o) { return this.name.compareTo(o.name); @@ -182,4 +205,14 @@ public abstract class SimpleDimension implements Comparable, I return false; return true; } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "[name=" + name + ", values=" + getValues() + "]"; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleLayer.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleLayer.java index 6a48427f45..7c3ecbb791 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleLayer.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SimpleLayer.java @@ -1,41 +1,49 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Mar 29, 2011 bclement Initial creation + * + */ package com.raytheon.uf.edex.ogc.common.db; +import java.io.Serializable; import java.util.Date; +import java.util.HashMap; +import java.util.List; import java.util.Set; -import java.util.SortedSet; +import java.util.TreeSet; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.FetchType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.hibernate.annotations.Sort; -import org.hibernate.annotations.SortType; -import org.hibernate.annotations.Type; - +import com.raytheon.uf.common.dataplugin.persist.IPersistableDataObject; import com.raytheon.uf.common.serialization.adapters.GeometryAdapter; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @@ -46,17 +54,17 @@ import com.vividsolutions.jts.geom.Polygon; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Mar 29, 2011 bclement Initial creation - * Apr 22, 2013 1746 dhladky Removed DB dependency from WFS code - * Jul 16, 2013 2181 bsteffen Convert geometry types to use hibernate- - * spatial + * Mar 29, 2011 bclement Initial creation + * 04/22/2013 1746 dhladky Removed DB dependency from WFS code * **/ - @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize -public abstract class SimpleLayer { +public abstract class SimpleLayer implements + IPersistableDataObject, Serializable { + + private static final long serialVersionUID = -9102070476178937194L; @XmlElement @DynamicSerializeElement @@ -74,7 +82,6 @@ public abstract class SimpleLayer { @DynamicSerializeElement protected String targetCrsCode; - @Column @XmlElement @DynamicSerializeElement protected double targetMinx; @@ -91,16 +98,144 @@ public abstract class SimpleLayer { @DynamicSerializeElement protected double targetMaxy; - @Type(type = "org.hibernatespatial.GeometryUserType") @XmlJavaTypeAdapter(value = GeometryAdapter.class) @DynamicSerializeElement protected Polygon crs84Bounds; @XmlElement @DynamicSerializeElement - @Sort(type = SortType.NATURAL) - @ElementCollection(fetch = FetchType.EAGER) - protected SortedSet times; + protected TreeSet times; + + /** + * + */ + public SimpleLayer(TreeSet times) { + this.times = times; + } + + public SimpleLayer() { + this.times = new TreeSet(); + } + + public SimpleLayer(SimpleLayer other) { + this.crs84Bounds = (Polygon) other.crs84Bounds.clone(); + this.name = other.name; + this.nx = other.nx; + this.ny = other.ny; + this.targetCrsCode = other.targetCrsCode; + this.targetMaxx = other.targetMaxx; + this.targetMaxy = other.targetMaxy; + this.targetMinx = other.targetMinx; + this.targetMiny = other.targetMiny; + if (other.times != null) { + this.times = new TreeSet(other.times); + } else { + this.times = new TreeSet(); + } + } + + /** + * Merge layer values from other into this layer + * + * @param other + */ + public void update(SimpleLayer other) { + if (other == null) { + return; + } + updateDates(other); + updateDims(other); + } + + /** + * Merge time values from other into this layer + * + * @param other + */ + public void updateDates(SimpleLayer other) { + Set otherTimes = other.getTimes(); + if (otherTimes == null) { + return; + } + Set thisTimes = this.getTimes(); + if (thisTimes == null) { + setTimes(new TreeSet(otherTimes)); + } else { + for (Date time : otherTimes) { + thisTimes.add(time); + } + } + } + + /** + * Merge dimension values from other into this layer + * + * @param other + */ + public void updateDims(SimpleLayer other) { + Set otherDims = other.getDimensions(); + if (otherDims == null) { + return; + } + Set thisDims = this.getDimensions(); + if (thisDims != null) { + if (thisDims != null) { + updateDimLists(thisDims, otherDims); + } + } + } + + /** + * Merge dimension values from shinyDims into oldDims + * + * @param oldDims + * @param shinyDims + */ + protected void updateDimLists(Set oldDims, + Set shinyDims) { + HashMap oldMap = getDimMap(oldDims); + HashMap shinyMap = getDimMap(shinyDims); + for (String name : shinyMap.keySet()) { + DIMENSION shinyDim = shinyMap.get(name); + DIMENSION oldDim = oldMap.get(name); + if (oldDim == null) { + oldDims.add(shinyDim); + } else { + updateDimValues(oldDim, shinyDim); + } + } + } + + /** + * Create dimension lookup map keyed by dimension name + * + * @param dims + * @return + */ + protected HashMap getDimMap(Set dims) { + HashMap rval = new HashMap( + dims.size()); + for (DIMENSION sd : dims) { + rval.put(sd.getName(), sd); + } + return rval; + } + + /** + * Merge values from shinyDim into oldDim + * + * @param oldDim + * @param shinyDim + */ + protected void updateDimValues(DIMENSION oldDim, DIMENSION shinyDim) { + Set oldValues = oldDim.getValues(); + Set shinyValues = shinyDim.getValues(); + if (oldValues != null && shinyValues != null) { + for (String val : shinyValues) { + oldValues.add(val); + } + } + } /** * @return live reference to dimensions list, should not return null @@ -110,20 +245,48 @@ public abstract class SimpleLayer { /** * @return live reference to times set, should not return null */ - public SortedSet getTimes() { + public TreeSet getTimes() { return times; } - public void setTimes(SortedSet times) { + public void setTimes(TreeSet times) { this.times = times; } + /** + * @return list of formatted times for layer (could be ranges) + */ + public List getTimeEntries() { + return LayerTransformer.getTimes(this); + } + public Date getDefaultTime() { return this.getTimes().last(); } - @Override - public String toString() { + /** + * @param dimension + * @return null if dimension not found + */ + public DIMENSION getDimension(String dimension) { + DIMENSION rval = null; + for (DIMENSION d : this.getDimensions()) { + if (d.getName().equalsIgnoreCase(dimension)) { + rval = d; + break; + } + } + return rval; + } + + /** + * @return formatted time string (could be a range) + */ + public String getDefaultTimeEntry() { + return LayerTransformer.format(getDefaultTime()); + } + + public String toString() { return name == null ? super.toString() : name; } @@ -191,6 +354,11 @@ public abstract class SimpleLayer { this.targetMaxy = targetMaxy; } + @Override + public String getIdentifier() { + return name; + } + public Polygon getCrs84Bounds() { return crs84Bounds; } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SingleLayerCollector.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SingleLayerCollector.java new file mode 100644 index 0000000000..cbd18330a8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/SingleLayerCollector.java @@ -0,0 +1,279 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Sep 11, 2012 bclement Initial creation + * Aug 18, 2013 #2097 dhladky Updates for interfaces etc. + * + */ +package com.raytheon.uf.edex.ogc.common.db; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.geotools.geometry.jts.JTS; +import org.geotools.geometry.jts.ReferencedEnvelope; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.vividsolutions.jts.geom.Envelope; + +/** + * + * @author bclement + * @version 1.0 + */ +public abstract class SingleLayerCollector, R extends PluginDataObject> + extends LayerCollector { + + private L _layer; + + protected ReadWriteLock lock = new ReentrantReadWriteLock(); + + protected String layerName; + + /** + * @param transformer + */ + public SingleLayerCollector(Class layerClass, Class recordClass, + String layerName, ILayerStore store) { + super(layerClass, recordClass, store); + this.layerName = layerName; + } + + @SuppressWarnings("unchecked") + public void add(PluginDataObject... pdos) { + Lock write = lock.writeLock(); + write.lock(); + + try { + ICollectorAddon addon = getAddon(); + L layer = getLayer(); + for (PluginDataObject pdo : pdos) { + if (recordClass.equals(pdo.getClass())) { + R record = (R) pdo; + Calendar time = getTime(record); + replaceRange(layer, time); + addon.onCollect(layer, (R) pdo); + } + } + addon.onFinish(); + + } finally { + write.unlock(); + } + } + + private void replaceRange(L layer, Calendar time) { + Date floor = truncateToMinute(time.getTime()); + Date ceil = roundUpToMinute(time.getTime()); + SortedSet times = layer.getTimes(); + Date earliest; + Date latest; + if (times.isEmpty()) { + earliest = floor; + latest = ceil; + } else { + Date lfirst = times.first(); + Date llast = times.last(); + earliest = lfirst.before(floor) ? lfirst : floor; + latest = llast.after(ceil) ? llast : ceil; + } + times.clear(); + times.add(earliest); + times.add(latest); + } + + private L getLayer() { + if (_layer == null) { + try { + List res = store.getAll(layerClass); + if (!res.isEmpty()) { + _layer = res.get(0); + } + } catch (OgcException e) { + log.error("Problem reading layer from database", e); + } + if (_layer == null) { + _layer = newLayer(); + } + } + return _layer; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.LayerCollector#newLayer() + */ + @Override + protected L newLayer() { + L rval = super.newLayer(); + initLayer(rval); + return rval; + } + + protected void initLayer(L layer) { + layer.setName(layerName); + ReferencedEnvelope env = new ReferencedEnvelope(-180, 180, -90, 90, + MapUtil.LATLON_PROJECTION); + layer.setCrs84Bounds(JTS.toGeometry((Envelope) env)); + layer.setTargetCrsCode("CRS:84"); + layer.setTargetMaxx(env.getMaxX()); + layer.setTargetMaxy(env.getMaxY()); + layer.setTargetMinx(env.getMinX()); + layer.setTargetMiny(env.getMinY()); + } + + public void updateDB() { + Lock read = lock.readLock(); + read.lock(); + try { + L layer = getLayer(); + if (!layer.getTimes().isEmpty()) { + updateLayer(layer); + } + } catch (OgcException e) { + log.error("problem updating layer", e); + } + read.unlock(); + } + + protected abstract Calendar getTime(R record); + + public void purgeExpired(Set timesToKeep) { + Lock write = lock.writeLock(); + write.lock(); + try { + L layer = getLayer(); + SortedSet ltimes = layer.getTimes(); + ltimes.clear(); + if (!timesToKeep.isEmpty()) { + SortedSet incoming = new TreeSet(timesToKeep); + Date earliest = truncateToMinute(incoming.first()); + Date latest = roundUpToMinute(incoming.last()); + ltimes.add(earliest); + ltimes.add(latest); + } + try { + replaceTimes(layer); + } catch (OgcException e) { + log.error("problem purging expired layer times", e); + } + getAddon().onPurgeExpired(timesToKeep); + } finally { + write.unlock(); + } + } + + public void purgeAll() { + Lock write = lock.writeLock(); + write.lock(); + try { + L layer = getLayer(); + layer.getTimes().clear(); + try { + clearLayers(layerClass); + } catch (Exception e) { + log.error("problem purging layers", e); + } + } finally { + write.unlock(); + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.LayerCache#getLayers() + */ + @Override + public List getLayers() { + ArrayList rval = new ArrayList(1); + L copy = getCopy(); + if (copy != null) { + rval.add(copy); + } + return rval; + } + + private L getCopy() { + L rval = null; + Lock read = lock.readLock(); + read.lock(); + try { + L layer = getLayer(); + if (!layer.getTimes().isEmpty()) { + rval = copy(layer); + } + } finally { + read.unlock(); + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerCollector#copy(com.raytheon.uf + * .edex.ogc.common.db.SimpleLayer) + */ + @Override + protected L copy(L orig) { + L rval = newLayer(); + // assume that only times are different + rval.getTimes().addAll(orig.getTimes()); + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerCache#getLayer(java.lang.String) + */ + @Override + public L getLayer(String name) { + if (layerName.equals(name)) { + return getCopy(); + } else { + return null; + } + } + + @Override + public String getLayerName(R rec) { + return this.layerName; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/AbstractFeatureFactory.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/AbstractFeatureFactory.java deleted file mode 100644 index 54c19ce3e8..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/AbstractFeatureFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.raytheon.uf.edex.ogc.common.feature; - -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ - -import java.util.List; - -import org.opengis.feature.simple.SimpleFeature; - -import com.raytheon.uf.common.datadelivery.harvester.ConfigLayer; -import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfig; -import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfigurationManager; -import com.raytheon.uf.common.datadelivery.harvester.OGCAgent; -import com.raytheon.uf.common.dataplugin.PluginDataObject; - -/** - * - * Abstract Feature Factory - * - *
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * 04/22/2013   1746      dhladky      initial
- * 
- * - * @author dhladky - * @version 1.0 - */ - -public abstract class AbstractFeatureFactory implements FeatureFactory { - - public AbstractFeatureFactory() { - configureFeature(); - } - - public void configureFeature() { - getLayer(); - } - - protected ConfigLayer layer; - - @Override - public abstract List convert(PluginDataObject[] pdos); - - public abstract String getName(); - - /** - * Gets the ConfigLayer associated with this feature - * @return - */ - public ConfigLayer getLayer() { - - if (layer == null) { - OGCAgent agent = null; - HarvesterConfig config = HarvesterConfigurationManager - .getOGCConfiguration(); - if (config.getAgent() instanceof OGCAgent) { - agent = (OGCAgent) config.getAgent(); - if (agent != null) { - layer = agent.getLayer(getName()); - } - } - } - return layer; - } - -} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/GmlUtils.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/GmlUtils.java new file mode 100644 index 0000000000..acb45545bf --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/GmlUtils.java @@ -0,0 +1,155 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.feature; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.raytheon.uf.edex.ogc.common.InvalidVersionException; +import com.raytheon.uf.edex.ogc.common.Version; +import com.raytheon.uf.edex.ogc.common.http.MimeType; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 30, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class GmlUtils { + + public static final MimeType GML31_TYPE = new MimeType( + "application/gml+xml; version=3.1"); + + public static final MimeType GML32_TYPE = new MimeType( + "application/gml+xml; version=3.2"); + + public static final MimeType GML311_OLD_TYPE = new MimeType( + "text/xml; subtype=\"gml/3.1.1\""); + + public static final MimeType GML321_OLD_TYPE = new MimeType( + "text/xml; subtype=\"gml/3.2.1\""); + + public static final MimeType GML31_VND_TYPE = new MimeType( + "application/vnd.ogc.gml; version=3.1"); + + public static final MimeType GML32_VND_TYPE = new MimeType( + "application/vnd.ogc.gml; version=3.2"); + + protected static final Pattern subPattern = Pattern + .compile("^\\s*([a-zA-Z]+)/([0-9\\.]+).*$"); + + protected static final Pattern versionPattern = Pattern + .compile("^\\s*([0-9]+)\\.([0-9]+)\\.?([0-9]+)?.*$"); + + protected static final Map versionMap; + static { + versionMap = new HashMap(); + versionMap.put(new Version(3, 1, 0), GML31_TYPE); + versionMap.put(new Version(3, 2, 0), GML32_TYPE); + } + + /** + * @param type + * @return true if type is a form of gml + */ + public static boolean isGml(MimeType type){ + if ( "application".equalsIgnoreCase(type.getType())){ + if ("gml+xml".equalsIgnoreCase(type.getSubtype())) { + return true; + } + if ( "vnd.ogc.gml".equalsIgnoreCase(type.getSubtype())){ + return true; + } + } else if ("text".equalsIgnoreCase(type.getType()) + && "xml".equals(type.getSubtype())) { + String param = type.getParam("subtype"); + if (param != null && param.toLowerCase().startsWith("gml")) { + return true; + } + } + return false; + } + + /** + * @param type + * @return null if type isn't gml or version is not found + */ + public static String getGmlVersion(MimeType type) { + if (!isGml(type)) { + return null; + } + String param = type.getParam("version"); + if (param != null) { + return param; + } + param = type.getParam("subtype"); + if (param != null) { + Matcher m = subPattern.matcher(param); + if (m.matches()) { + return m.group(2); + } + } + return null; + } + + /** + * @param left + * @param right + * @return true if both are gml types with versions and those versions have + * the same major and minor versions + */ + public static boolean areCompatible(MimeType left, MimeType right){ + String leftVStr = getGmlVersion(left); + String rightVStr = getGmlVersion(right); + if ( leftVStr == null || rightVStr == null){ + return false; + } + try { + Version leftVersion = new Version(leftVStr); + Version rightVersion = new Version(rightVStr); + return leftVersion.equalsMajorMinor(rightVersion); + } catch (InvalidVersionException e) { + return false; + } + } + + /** + * Find the supported GML version that matches the arguments major and minor + * version + * + * @param type + * @return null if no match found + */ + public static MimeType getMatchingGmlVersion(MimeType type) { + String vstr = getGmlVersion(type); + if (vstr == null) { + return null; + } + try{ + Version version = new Version(vstr).majorMinorOnly(); + return versionMap.get(version); + } catch (InvalidVersionException e){ + return null; + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java index e5d9cde5a4..8b22163f04 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java @@ -31,6 +31,7 @@ package com.raytheon.uf.edex.ogc.common.feature; import java.io.ByteArrayOutputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.List; @@ -44,6 +45,7 @@ import com.raytheon.uf.common.json.geo.GeoJsonUtilSimpleImpl; import com.raytheon.uf.common.json.geo.MixedFeatureCollection; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; +import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * @@ -52,43 +54,61 @@ import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; */ public class JsonFeatureFormatter implements SimpleFeatureFormatter { - public static String mimeType = "application/json"; + public static MimeType mimeType = new MimeType("application/json"); protected GeoJsonUtil jsonUtil = new GeoJsonUtilSimpleImpl(); - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#format(java.util - * .List) - */ + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#format + * (java.util.List, java.io.OutputStream) + */ + @Override + public void format(List> features, OutputStream out) + throws Exception { + MixedFeatureCollection mixed = convert(features); + jsonUtil.serialize(mixed, out); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#format(java.util + * .List) + */ @Override public OgcResponse format(List> features) throws Exception { - List> colls = new ArrayList>( - features.size()); - for (List l : features) { - if (l != null && !l.isEmpty()) { - SimpleFeatureType t = l.get(0).getFeatureType(); - MemoryFeatureCollection c = new MemoryFeatureCollection(t); - c.addAll(l); - colls.add(c); - } - } - MixedFeatureCollection mixed = new MixedFeatureCollection(colls); + MixedFeatureCollection mixed = convert(features); ByteArrayOutputStream baos = new ByteArrayOutputStream(); jsonUtil.serialize(mixed, baos); return new OgcResponse(baos.toString(), mimeType, TYPE.TEXT); } + protected MixedFeatureCollection convert(List> features) { + List> colls = new ArrayList>( + features.size()); + for (List l : features) { + if (l != null && !l.isEmpty()) { + SimpleFeatureType t = l.get(0).getFeatureType(); + MemoryFeatureCollection c = new MemoryFeatureCollection(t); + c.addAll(l); + colls.add(c); + } + } + return new MixedFeatureCollection(colls); + } + /* * (non-Javadoc) * * @see com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#getMimeType() */ @Override - public String getMimeType() { + public MimeType getMimeType() { return mimeType; } @@ -100,8 +120,8 @@ public class JsonFeatureFormatter implements SimpleFeatureFormatter { * (java.lang.String) */ @Override - public boolean matchesFormat(String format) { - return mimeType.equalsIgnoreCase(format); + public boolean matchesFormat(MimeType format) { + return mimeType.equalsIgnoreParams(format); } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java index 458de0bcc9..ae50a9af7a 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java @@ -45,8 +45,6 @@ import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.geotools.data.DefaultTransaction; import org.geotools.data.FeatureSource; import org.geotools.data.FeatureStore; @@ -60,8 +58,11 @@ import org.opengis.feature.simple.SimpleFeatureType; import sun.misc.IOUtils; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; +import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * @@ -70,39 +71,58 @@ import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; */ public class ShpFeatureFormatter implements SimpleFeatureFormatter { - public static final String mimeType = "application/zip"; + public static final MimeType mimeType = new MimeType("application/zip"); - protected Log log = LogFactory.getLog(this.getClass()); + public static final MimeType zipType = new MimeType("shape-zip"); + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); protected byte[] buffer = new byte[1024 * 4]; - /* (non-Javadoc) - * @see com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#format(java.util.List) - */ + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#format + * (java.util.List, java.io.OutputStream) + */ + @Override + public void format(List> features, OutputStream out) + throws Exception { + FeatureCollection coll = convert(features); + if (coll == null) { + return; + } + File tmpDir = createTempDir(); + try { + writeShape(tmpDir, coll); + File zip = createZip(tmpDir); + readFile(zip, out); + } finally { + if (tmpDir != null && tmpDir.exists()) { + deleteDir(tmpDir); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#format + * (java.util.List) + */ @Override public OgcResponse format(List> features) throws Exception { - List> colls = new ArrayList>( - features.size()); - for (List l : features) { - if (l != null && !l.isEmpty()) { - SimpleFeatureType t = l.get(0).getFeatureType(); - MemoryFeatureCollection c = new MemoryFeatureCollection(t); - c.addAll(l); - colls.add(c); - } - } - // TODO handle multiple schemas - if (colls.size() > 1) { - log.error("Too many feature types sent to shapefile formatter"); - } - if (colls.isEmpty()) { - return new OgcResponse(new byte[0], mimeType, TYPE.BYTE); - } + FeatureCollection coll = convert(features); + if (coll == null) { + return new OgcResponse(new byte[0], mimeType, TYPE.BYTE); + } File tmpDir = createTempDir(); try { - writeShape(tmpDir, colls.get(0)); + writeShape(tmpDir, coll); File zip = createZip(tmpDir); byte[] bytes = readFile(zip); return new OgcResponse(bytes, mimeType, TYPE.BYTE); @@ -113,6 +133,28 @@ public class ShpFeatureFormatter implements SimpleFeatureFormatter { } } + protected FeatureCollection convert( + List> features) { + List> colls = new ArrayList>( + features.size()); + for (List l : features) { + if (l != null && !l.isEmpty()) { + SimpleFeatureType t = l.get(0).getFeatureType(); + MemoryFeatureCollection c = new MemoryFeatureCollection(t); + c.addAll(l); + colls.add(c); + } + } + // TODO handle multiple schemas + if (colls.size() > 1) { + log.error("Too many feature types sent to shapefile formatter"); + } + if (colls.isEmpty()) { + return null; + } + return colls.get(0); + } + protected File createZip(File dir) throws IOException { File rval = new File(dir, "res.zip"); ZipOutputStream out = null; @@ -177,6 +219,15 @@ public class ShpFeatureFormatter implements SimpleFeatureFormatter { protected byte[] readFile(File f) throws FileNotFoundException, IOException { return IOUtils.readFully(new FileInputStream(f), -1, true); } + + protected void readFile(File f, OutputStream out) throws IOException { + FileInputStream fin = new FileInputStream(f); + try { + copy(fin, out); + } finally { + fin.close(); + } + } protected void writeShape(File dir, FeatureCollection coll) @@ -215,7 +266,7 @@ public class ShpFeatureFormatter implements SimpleFeatureFormatter { * @see com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#getMimeType() */ @Override - public String getMimeType() { + public MimeType getMimeType() { return mimeType; } @@ -227,11 +278,11 @@ public class ShpFeatureFormatter implements SimpleFeatureFormatter { * (java.lang.String) */ @Override - public boolean matchesFormat(String format) { - if (mimeType.equalsIgnoreCase(format)) { + public boolean matchesFormat(MimeType format) { + if (mimeType.equalsIgnoreParams(format)) { return true; } - if (format.equalsIgnoreCase("shape-zip")) { + if (format.equalsIgnoreParams(zipType)) { return true; } return false; diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java index bc044581ae..4c14e4b54a 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java @@ -30,11 +30,13 @@ */ package com.raytheon.uf.edex.ogc.common.feature; +import java.io.OutputStream; import java.util.List; import org.opengis.feature.simple.SimpleFeature; import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * @@ -46,7 +48,10 @@ public interface SimpleFeatureFormatter { public OgcResponse format(List> features) throws Exception; - public String getMimeType(); + public void format(List> features, OutputStream out) + throws Exception; - public boolean matchesFormat(String format); + public MimeType getMimeType(); + + public boolean matchesFormat(MimeType format); } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/AbstractPdoFilter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/AbstractPdoFilter.java new file mode 100644 index 0000000000..d8c905798c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/AbstractPdoFilter.java @@ -0,0 +1,43 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.filter; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 14, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractPdoFilter { + + public abstract boolean matches(PluginDataObject pdo); + + public static AbstractPdoFilter noFilter() { + return new AbstractPdoFilter() { + + @Override + public boolean matches(PluginDataObject pdo) { + return true; + } + }; + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/ComparisonFilter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/ComparisonFilter.java new file mode 100644 index 0000000000..ed69ba0233 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/ComparisonFilter.java @@ -0,0 +1,237 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.filter; + +import java.lang.reflect.Field; +import java.math.BigDecimal; + +import org.apache.commons.lang.StringUtils; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.edex.ogc.common.util.ConvertService; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 14, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class ComparisonFilter extends AbstractPdoFilter { + + public static enum CompOp { + EQ, LT, LTE, GT, GTE, NEQ, NULL + }; + + protected String field; + + protected CompOp op; + + protected Object value; + + private volatile Field[] accessChain; + + private final Object accessMutex = new Object(); + + /** + * @param field + * @param op + * @param value + */ + public ComparisonFilter(String field, CompOp op, Object value) { + this.field = field; + this.op = op; + this.value = value; + } + + /** + * @param field + * @param op + * @param value + */ + public ComparisonFilter(String field, Object value) { + this(field, CompOp.EQ, value); + } + + /** + * + */ + private ComparisonFilter() { + } + + public static ComparisonFilter isNull(String field) { + ComparisonFilter rval = new ComparisonFilter(); + rval.field = field; + rval.op = CompOp.NULL; + return rval; + } + + @Override + public boolean matches(PluginDataObject pdo) { + if (accessChain == null) { + findField(pdo); + } + Object lhs = access(pdo); + if (lhs != null && value instanceof Number && lhs instanceof Number) { + return matchNumeric(lhs); + } + switch (op) { + case EQ: + return value.equals(lhs); + case NEQ: + return !value.equals(lhs); + case NULL: + return lhs == null; + default: + return true; + } + } + + private boolean matchNumeric(Object lhs) { + BigDecimal left = new BigDecimal(lhs.toString()); + BigDecimal right = new BigDecimal(value.toString()); + int diff = left.compareTo(right); + switch (op) { + case GT: + return diff > 0; + case EQ: + return diff == 0; + case GTE: + return diff >= 0; + case LT: + return diff < 0; + case LTE: + return diff <= 0; + case NEQ: + return diff != 0; + default: + // TODO a return value of true disregards filter, a return of false + // may be a better option + return true; + } + } + + private Object access(PluginDataObject pdo) throws IllegalArgumentException { + Object target = pdo; + for (Field f : accessChain) { + try { + if (target == null) { + return null; + } + target = f.get(target); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } + } + return target; + } + + private void findField(PluginDataObject pdo) { + try { + synchronized (accessMutex) { + if (accessChain == null) { + Class c = pdo.getClass(); + String[] fieldPath = StringUtils.split(field, '.'); + accessChain = ConvertService.get().getFields(c, fieldPath); + } + } + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + /** + * @return the field + */ + public String getField() { + return field; + } + + /** + * @return the op + */ + public CompOp getOp() { + return op; + } + + /** + * @return the value + */ + public Object getValue() { + return value; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + if (op.equals(CompOp.NULL)) { + return "[" + field + " is NULL]"; + } + return "[" + field + " " + op + " " + value + "]"; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((field == null) ? 0 : field.hashCode()); + result = prime * result + ((op == null) ? 0 : op.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ComparisonFilter other = (ComparisonFilter) obj; + if (field == null) { + if (other.field != null) + return false; + } else if (!field.equals(other.field)) + return false; + if (op != other.op) + return false; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/LogicFilter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/LogicFilter.java new file mode 100644 index 0000000000..d9a7b0b06f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/LogicFilter.java @@ -0,0 +1,175 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.filter; + +import java.util.Arrays; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 14, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class LogicFilter extends AbstractPdoFilter { + + public static enum LogicOp { + AND, OR, NOT + }; + + protected AbstractPdoFilter[] filters; + + protected LogicOp op; + + /** + * @param filters + * @param op + */ + public LogicFilter(LogicOp op, AbstractPdoFilter... filters) { + this.filters = filters; + this.op = op; + } + + public static LogicFilter or(AbstractPdoFilter... filters) { + return new LogicFilter(LogicOp.OR, filters); + } + + public static LogicFilter and(AbstractPdoFilter... filters) { + return new LogicFilter(LogicOp.AND, filters); + } + + public static LogicFilter not(AbstractPdoFilter filter) { + return new LogicFilter(LogicOp.NOT, filter); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.filter.AbstractFilterOp#matches(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + public boolean matches(PluginDataObject pdo) { + switch (op) { + case AND: + return and(pdo); + case OR: + return or(pdo); + case NOT: + return !filters[0].matches(pdo); + } + return false; + } + + private boolean and(PluginDataObject pdo) { + for (AbstractPdoFilter filter : filters) { + if (!filter.matches(pdo)) { + return false; + } + } + return true; + } + + private boolean or(PluginDataObject pdo) { + for (AbstractPdoFilter filter : filters) { + if (filter.matches(pdo)) { + return true; + } + } + return false; + } + + /** + * @return the filters + */ + public AbstractPdoFilter[] getFilters() { + return filters; + } + + /** + * @return the op + */ + public LogicOp getOp() { + return op; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + if (op.equals(LogicOp.NOT)) { + return "[ NOT " + filters[0].toString() + "]"; + } + StringBuilder builder = new StringBuilder(); + if (filters.length < 1) { + return "[]"; + } else { + builder.append("[").append(filters[0].toString()); + } + for (int i = 1; i < filters.length; ++i) { + AbstractPdoFilter filter = filters[i]; + builder.append(" " + op + " "); + builder.append(filter.toString()); + } + builder.append("]"); + return builder.toString(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(filters); + result = prime * result + ((op == null) ? 0 : op.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LogicFilter other = (LogicFilter) obj; + if (!Arrays.equals(filters, other.filters)) + return false; + if (op != other.op) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/SpatialFilter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/SpatialFilter.java new file mode 100644 index 0000000000..1123fb6f6a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/SpatialFilter.java @@ -0,0 +1,180 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.filter; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.geospatial.ISpatialEnabled; +import com.raytheon.uf.common.geospatial.ISpatialObject; +import com.vividsolutions.jts.geom.Geometry; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 14, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class SpatialFilter extends AbstractPdoFilter { + + public static enum SpatialOp { + EQUALS, CONTAINS, COVERS, COVEREDBY, CROSSES, DISJOINT, INTERSECTS, OVERLAPS, TOUCHES, WITHIN + }; + + protected Geometry geometry; + + protected SpatialOp op; + + /** + * @param geometry + * @param op + */ + public SpatialFilter(SpatialOp op, Geometry geometry) { + this.geometry = geometry; + this.op = op; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.filter.AbstractFilterOp#matches(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + public boolean matches(PluginDataObject pdo) { + if (geometry == null) { + return true; + } + if (pdo instanceof ISpatialEnabled) { + if (!matchSpatial(((ISpatialEnabled) pdo).getSpatialObject())) { + return false; + } + } else if (pdo instanceof ISpatialObject) { + if (!matchSpatial((ISpatialObject) pdo)) { + return false; + } + } + return true; + } + + private boolean matchSpatial(ISpatialObject spat) { + Geometry other = spat.getGeometry(); + boolean rval; + switch (op) { + case EQUALS: + rval = other.equals(this.geometry); + break; + case CONTAINS: + rval = other.contains(this.geometry); + break; + case COVERS: + rval = other.covers(this.geometry); + break; + case COVEREDBY: + rval = other.coveredBy(this.geometry); + break; + case CROSSES: + rval = other.crosses(this.geometry); + break; + case DISJOINT: + rval = other.disjoint(this.geometry); + break; + case INTERSECTS: + rval = other.intersects(this.geometry); + break; + case OVERLAPS: + rval = other.overlaps(this.geometry); + break; + case TOUCHES: + rval = other.touches(this.geometry); + break; + case WITHIN: + rval = other.within(this.geometry); + break; + default: + rval = true; + break; + } + return rval; + } + + /** + * @return the geometry + */ + public Geometry getGeometry() { + return geometry; + } + + /** + * @return the op + */ + public SpatialOp getOp() { + return op; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "[geometry " + op + " " + geometry + "]"; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((geometry == null) ? 0 : geometry.toText().hashCode()); + result = prime * result + ((op == null) ? 0 : op.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SpatialFilter other = (SpatialFilter) obj; + if (geometry == null) { + if (other.geometry != null) + return false; + } else if (!geometry.equals(other.geometry)) + return false; + if (op != other.op) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/TemporalFilter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/TemporalFilter.java new file mode 100644 index 0000000000..48ef4fb3d6 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/TemporalFilter.java @@ -0,0 +1,220 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.filter; + +import java.util.Date; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.TimeRange; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 14, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class TemporalFilter extends AbstractPdoFilter { + + public static enum TimeOp { + After, Before, Begins, BegunBy, TContains, During, TEquals, TOverlaps, Meets, OverlappedBy, MetBy, Ends, EndedBy + }; + + protected DataTime time; + + protected TimeOp op; + + /** + * @param time + * @param op + */ + public TemporalFilter(TimeOp op, DataTime time) { + this.time = time; + this.op = op; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.filter.AbstractFilterOp#matches(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + public boolean matches(PluginDataObject pdo) { + DataTime other = pdo.getDataTime(); + if (other == null) { + return false; + } + TimeRange otherRange = other.getValidPeriod(); + Date t1Start = otherRange.getStart(); + Date t1End = otherRange.getEnd(); + TimeRange range = time.getValidPeriod(); + Date t2Start = range.getStart(); + Date t2End = range.getEnd(); + switch (op) { + case After: + return t1Start.after(t2End); + case Before: + return t1End.before(t2Start); + case Begins: + if (isRange(time)) { + if (isRange(other)) { + return t1Start.equals(t2Start) && t1End.before(t2End); + } else { + return t1Start.equals(t2Start); + } + } + case BegunBy: + if (isRange(other)) { + if (isRange(time)) { + return t1Start.equals(t2Start) && t1End.after(t2End); + } else { + return t1Start.equals(t2Start); + } + } + case During: + if (isRange(time)) { + return t1Start.after(t2Start) && t1End.before(t2End); + } + case EndedBy: + if (isRange(other)) { + if (isRange(time)) { + return t1Start.before(t2Start) && t1End.equals(t2End); + } else { + return t1End.equals(t2End); + } + } + case Ends: + if (isRange(time)) { + if (isRange(other)) { + return t1Start.after(t2Start) && t1End.equals(t2End); + } else { + return t1End.equals(t2End); + } + } + case Meets: + if (isRange(other) && isRange(time)) { + return t1End.equals(t2Start); + } + case MetBy: + if (isRange(other) && isRange(time)) { + return t1Start.equals(t2End); + } + case OverlappedBy: + if (isRange(other) && isRange(time)) { + return t1Start.after(t2Start) && t1Start.before(t2End) + && t1End.after(t2End); + } + case TContains: + if (isRange(other)) { + if (isRange(time)) { + return t1Start.before(t2Start) && t2End.before(t1End); + } else { + return t1Start.before(t2Start) && t1End.after(t2End); + } + } + case TEquals: + if (!(isRange(other) ^ isRange(time))) { + return t1Start.equals(t2Start) && t1End.equals(t2End); + } + case TOverlaps: + if (isRange(other) && isRange(time)) { + return t1Start.before(t2Start) && t1End.after(t2Start) + && t1End.before(t2End); + } + } + + return false; + } + + public static boolean isRange(DataTime time) { + return time.getUtilityFlags().contains(DataTime.FLAG.PERIOD_USED); + } + + /** + * @return the time + */ + public DataTime getTime() { + return time; + } + + /** + * @return the op + */ + public TimeOp getOp() { + return op; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + String tstamp; + if (isRange(this.time)) { + tstamp = time.getValidPeriod().toString(); + } else { + tstamp = time.getRefTime().toString(); + } + return "[time " + op + " " + tstamp + "]"; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((op == null) ? 0 : op.hashCode()); + result = prime * result + ((time == null) ? 0 : time.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TemporalFilter other = (TemporalFilter) obj; + if (op != other.op) + return false; + if (time == null) { + if (other.time != null) + return false; + } else if (!time.equals(other.time)) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/VerticalFilter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/VerticalFilter.java new file mode 100644 index 0000000000..ef85d8dafd --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/filter/VerticalFilter.java @@ -0,0 +1,125 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.filter; + +import java.util.Map; + +import javax.measure.unit.Unit; + +import org.apache.commons.collections.map.LRUMap; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.edex.ogc.common.spatial.AltUtil; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalEnabled; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalSpatialFactory; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 23, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class VerticalFilter extends AbstractPdoFilter { + + public static enum VerticalOp { + ABOVE, BELOW, BETWEEN + }; + + private final VerticalOp op; + + private final VerticalCoordinate vert; + + @SuppressWarnings("unchecked") + private final Map, VerticalCoordinate> cache = new LRUMap(2); + + /** + * @param op + * @param alt + */ + public VerticalFilter(VerticalOp op, VerticalCoordinate vert) { + this.op = op; + this.vert = vert; + cache.put(vert.getUnits(), vert); + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.filter.AbstractPdoFilter#matches(com.raytheon.uf.common.dataplugin.PluginDataObject) + */ + @SuppressWarnings("unchecked") + @Override + public boolean matches(PluginDataObject pdo) { + VerticalEnabled enabled; + if (pdo instanceof VerticalEnabled) { + enabled = (VerticalEnabled) pdo; + } else if ( (enabled = (VerticalEnabled) VerticalSpatialFactory + .getEnabled(pdo.getClass()))!= null) { + } else { + return false; + } + VerticalCoordinate left = enabled.getVerticalCoordinate(pdo); + if (left == null) { + return false; + } + VerticalCoordinate right; + try { + right = getConverted(left.getUnits(), left.getRef()); + } catch (Exception e) { + // unable to convert + return false; + } + switch (op) { + case ABOVE: + return left.compareTo(right) > 0; + case BELOW: + return left.compareTo(right) < 0; + case BETWEEN: + return left.compareTo(right) == 0; + default: + return false; + } + } + + private VerticalCoordinate getConverted(Unit units, Reference ref) { + VerticalCoordinate rval = cache.get(units); + if (rval != null) { + return rval; + } + rval = AltUtil.convert(units, ref, vert); + cache.put(units, rval); + return rval; + } + + /** + * @return the op + */ + public VerticalOp getOp() { + return op; + } + + /** + * @return the vert + */ + public VerticalCoordinate getVert() { + return vert; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/EnvelopeConverter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/EnvelopeConverter.java new file mode 100644 index 0000000000..4cd3d82bee --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/EnvelopeConverter.java @@ -0,0 +1,268 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 26, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.ogc.common.gml3_1_1; + +import java.text.ParseException; +import java.util.Arrays; +import java.util.List; + +import net.opengis.gml.v_3_1_1.CoordType; +import net.opengis.gml.v_3_1_1.CoordinatesType; +import net.opengis.gml.v_3_1_1.DirectPositionType; +import net.opengis.gml.v_3_1_1.EnvelopeType; + +import org.apache.commons.lang.StringUtils; + +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.spatial.CoordinateUtil; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +/** + * Convert GML 3.1.1 envelopes to JTS envelopes + * + * @author bclement + * @version 1.0 + */ +public class EnvelopeConverter { + + /** + * Returns number of dimensions in envelope + * + * @param env + * @return + * @throws Exception + */ + public static int getDims(EnvelopeType env) throws OgcException { + if (env.isSetSrsDimension() && env.getSrsDimension().intValue() > 1) { + return env.getSrsDimension().intValue(); + } + if (env.isSetLowerCorner()) { + DirectPositionType lc = env.getLowerCorner(); + return lc.getValue().size(); + } + if (env.isSetCoord()) { + CoordType coord = env.getCoord().get(0); + int size = 0; + // this will be incorrect if dimensions aren't populated + // monotonically + size += coord.getX() != null ? 1 : 0; + size += coord.getY() != null ? 1 : 0; + size += coord.getZ() != null ? 1 : 0; + return size; + } + if (env.isSetCoordinates()) { + CoordinatesType coords = env.getCoordinates(); + return StringUtils.split(coords.getValue()).length; + } + if (env.isSetPos()) { + DirectPositionType pos = env.getPos().get(0); + return pos.getValue().size(); + } + throw new OgcException(Code.InvalidParameterValue, + "Unsupported envelope dimensions"); + } + + /** + * Convert GML envelope to JTS envelope + * + * @param env + * @return + * @throws Exception + */ + public Envelope convert(EnvelopeType env) throws OgcException { + Coordinate[] coords = getCoordinates(env); + return new Envelope(coords[0], coords[1]); + } + + /** + * Convert GML envelope to JTS coordinates. + * + * @param env + * @param dims + * @return + * @throws Exception + */ + public Coordinate[] getCoordinates(EnvelopeType env) + throws OgcException { + int dims = getDims(env); + if (env.isSetLowerCorner() && env.isSetUpperCorner()) { + return translate(env.getLowerCorner(), env.getUpperCorner(), dims); + } + if (env.isSetCoord()) { + return handleCoordList(env.getCoord(), dims); + } + if (env.isSetCoordinates()) { + return handleCoordinates(env.getCoordinates(), dims); + } + if (env.isSetPos()) { + return handlePosList(env.getPos(), dims); + } + throw new OgcException(Code.InvalidFormat, + "Unsupported envelope format"); + } + + /** + * Convert direct positions to JTS bounding box. Output will only include + * the number of dimensions specified in dims + * + * @param lower + * @param upper + * @param dims + * @return + * @throws Exception + */ + protected Coordinate[] translate(DirectPositionType lower, + DirectPositionType upper, int dims) throws OgcException { + List lowers = lower.getValue(); + List uppers = upper.getValue(); + if (lowers == null || uppers == null || lowers.size() < dims + || uppers.size() < dims) { + throw new OgcException(Code.InvalidFormat, + "Unsupported envelope format"); + } + Coordinate l; + Coordinate u; + if (dims == 2) { + l = new Coordinate(lowers.get(0), lowers.get(1)); + u = new Coordinate(uppers.get(0), uppers.get(1)); + } else if (dims == 3) { + l = new Coordinate(lowers.get(0), lowers.get(1), lowers.get(2)); + u = new Coordinate(uppers.get(0), uppers.get(1), uppers.get(2)); + } else { + throw new OgcException(Code.InvalidFormat, + "Unsupported envelope format"); + } + return new Coordinate[] { l, u }; + } + + /** + * Convert list of direct positions to JTS coordinates. Output will only + * include the number of dimensions specified in dims + * + * @param pos + * @param dims + * @return + * @throws Exception + */ + private Coordinate[] handlePosList(List pos, int dims) + throws OgcException { + return translate(pos.get(0), pos.get(1), dims); + } + + /** + * Convert list of coords to JTS coordinates. Output will only include the + * number of dimensions specified in dims + * + * @param coords + * @param dims + * @return + * @throws Exception + */ + protected Coordinate[] handleCoordList(List coords, int dims) + throws OgcException { + CoordType c0 = coords.get(0); + CoordType c1 = coords.get(1); + return translate(createPos(c0), createPos(c1), dims); + } + + /** + * Convert GML coordinates to JTS coordinates. Output will only include the + * number of dimensions specified in dims + * + * @param coordinates + * @param dims + * @return + * @throws Exception + */ + protected Coordinate[] handleCoordinates(CoordinatesType coordinates, + int dims) + throws OgcException { + try { + List coords = CoordinateUtil.parseCoordinates(coordinates + .getValue()); + return translate(createPos(coords.get(0)), + createPos(coords.get(1)), dims); + } catch (ParseException e) { + throw new OgcException(Code.InvalidFormat, + "Invalid coordinate string"); + } + } + + /** + * Create direct position type from double values in strings + * + * @param doubles + * @return + */ + protected DirectPositionType createPos(String[] doubles) { + Double[] rval = new Double[doubles.length]; + for (int i = 0; i < doubles.length; ++i) { + rval[i] = Double.parseDouble(doubles[i]); + } + return createPos(rval); + } + + /** + * Convert coordtype to direct position + * + * @param coord + * @return + * @throws Exception + */ + protected DirectPositionType createPos(CoordType coord) throws OgcException { + Double[] rval; + if (coord.isSetZ()) { + rval = new Double[] { coord.getX().doubleValue(), + coord.getY().doubleValue(), coord.getZ().doubleValue() }; + } else if (coord.isSetY()) { + rval = new Double[] { coord.getX().doubleValue(), + coord.getY().doubleValue() }; + } else { + rval = new Double[] { coord.getX().doubleValue() }; + } + return createPos(rval); + } + + /** + * Create direct position type from double values in strings + * + * @param doubles + * @return + */ + protected DirectPositionType createPos(Double... coords) { + DirectPositionType rval = new DirectPositionType(); + rval.setValue(Arrays.asList(coords)); + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/GeometryConverter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/GeometryConverter.java new file mode 100644 index 0000000000..ff26e0ca96 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/GeometryConverter.java @@ -0,0 +1,62 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 25, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.ogc.common.gml3_1_1; + +import net.opengis.gml.v_3_1_1.AbstractGeometryType; + +import org.geotools.geometry.jts.JTS; +import org.jvnet.jaxb2_commons.locator.DefaultRootObjectLocator; +import org.jvnet.ogc.gml.v_3_1_1.jts.ConversionFailedException; +import org.jvnet.ogc.gml.v_3_1_1.jts.GML311ToJTSGeometryConverter; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.ParseException; + +/** + * + * @author bclement + * @version 1.0 + */ +public class GeometryConverter { + + public Geometry convert(Envelope env) throws ParseException { + return JTS.toGeometry(env); + } + + public Geometry convert(AbstractGeometryType value) + throws ConversionFailedException { + GML311ToJTSGeometryConverter converter = new GML311ToJTSGeometryConverter(); + return converter.createGeometry(new DefaultRootObjectLocator(value), + value); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/GmlWktWriter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/GmlWktWriter.java new file mode 100644 index 0000000000..250e27be0f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_1_1/GmlWktWriter.java @@ -0,0 +1,401 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 25, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.ogc.common.gml3_1_1; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +import net.opengis.gml.v_3_1_1.AbstractCurveType; +import net.opengis.gml.v_3_1_1.AbstractGeometryType; +import net.opengis.gml.v_3_1_1.AbstractRingPropertyType; +import net.opengis.gml.v_3_1_1.AbstractRingType; +import net.opengis.gml.v_3_1_1.CoordType; +import net.opengis.gml.v_3_1_1.CurvePropertyType; +import net.opengis.gml.v_3_1_1.DirectPositionListType; +import net.opengis.gml.v_3_1_1.DirectPositionType; +import net.opengis.gml.v_3_1_1.LineStringPropertyType; +import net.opengis.gml.v_3_1_1.LineStringType; +import net.opengis.gml.v_3_1_1.LinearRingType; +import net.opengis.gml.v_3_1_1.MultiLineStringType; +import net.opengis.gml.v_3_1_1.MultiPointType; +import net.opengis.gml.v_3_1_1.MultiPolygonType; +import net.opengis.gml.v_3_1_1.PointArrayPropertyType; +import net.opengis.gml.v_3_1_1.PointPropertyType; +import net.opengis.gml.v_3_1_1.PointType; +import net.opengis.gml.v_3_1_1.PolygonPropertyType; +import net.opengis.gml.v_3_1_1.PolygonType; +import net.opengis.gml.v_3_1_1.RingType; + +/** + * + * @author bclement + * @version 1.0 + */ +public abstract class GmlWktWriter { + + protected static final Map, GmlWktWriter> geomMap; + static { + geomMap = new HashMap, GmlWktWriter>(); + geomMap.put(PolygonType.class, new Polygon()); + geomMap.put(MultiPolygonType.class, new MultiPolygon()); + geomMap.put(PointType.class, new Point()); + geomMap.put(MultiPointType.class, new MultiPoint()); + geomMap.put(LinearRingType.class, new LinearRing()); + geomMap.put(LineStringType.class, new LineString()); + geomMap.put(MultiLineStringType.class, new MultiLineString()); + } + + public abstract String write(AbstractGeometryType geom) throws Exception; + + public static String write(JAXBElement elem) + throws Exception { + GmlWktWriter writer = geomMap.get(elem.getDeclaredType()); + if (writer != null) { + return writer.write(elem.getValue()); + } else { + throw new Exception("Unsupported geometry type: " + + elem.getDeclaredType()); + } + } + + protected void addPolygon(PolygonType poly, StringBuilder sb) + throws Exception { + sb.append('('); + AbstractRingPropertyType value = poly.getExterior().getValue(); + AbstractRingType ring = value.getRing().getValue(); + addAbstractRing(ring, sb); + List> interior = poly + .getInterior(); + if (interior != null && !interior.isEmpty()) { + sb.append(','); + addInterior(interior, sb); + } + sb.append(')'); + } + + /** + * @param interior + * @param sb + * @throws Exception + */ + protected void addInterior( + List> interior, + StringBuilder sb) throws Exception { + Iterator> i = interior.iterator(); + sb.append('('); + addAbstractRing(i.next().getValue().getRing().getValue(), sb); + while (i.hasNext()) { + sb.append(','); + addAbstractRing(i.next().getValue().getRing().getValue(), sb); + } + } + + protected void addAbstractRing(AbstractRingType ring, StringBuilder sb) + throws Exception { + if (ring instanceof LinearRingType) { + addLinearRing((LinearRingType) ring, sb); + } else if (ring instanceof RingType) { + addRing((RingType) ring, sb); + } else { + throw new Exception("Unsupported ring type" + ring.getClass()); + } + } + + /** + * @param ring + * @param sb + * @throws Exception + */ + private void addRing(RingType ring, StringBuilder sb) throws Exception { + List curvProps = ring.getCurveMember(); + Iterator i = curvProps.iterator(); + AbstractCurveType curve = i.next().getCurve().getValue(); + if (curve instanceof LineStringType) { + addLineString((LineStringType) curve, sb); + } else { + throw new Exception("Unsupported curve type: " + curve.getClass()); + } + } + + /** + * @param ring + * @param sb + * @throws Exception + */ + private void addLinearRing(LinearRingType ring, StringBuilder sb) + throws Exception { + DirectPositionListType posList = ring.getPosList(); + List coord = ring.getCoord(); + List> elems = ring.getPosOrPointPropertyOrPointRep(); + addLine(posList, elems, coord, sb); + } + + protected void addLine(DirectPositionListType posList, + List> elems, List coord, StringBuilder sb) + throws Exception { + sb.append("("); + if (posList != null) { + addPosList(posList, sb); + } else if (elems != null) { + addMixedPos(elems, sb); + } else if (coord != null) { + addCoords(coord, sb); + } else { + throw new Exception("Unsupported LineString format"); + } + sb.append(")"); + } + + /** + * @param coord + * @param sb + */ + protected void addCoords(List coord, StringBuilder sb) { + Iterator i = coord.iterator(); + addPoint(convert(i.next()), sb); + while (i.hasNext()) { + sb.append(", "); + addPoint(convert(i.next()), sb); + } + } + + protected void addLineString(LineStringType lst, StringBuilder sb) + throws Exception { + DirectPositionListType posList = lst.getPosList(); + List> elems = lst.getPosOrPointPropertyOrPointRep(); + addLine(posList, elems, null, sb); + } + + protected void addMixedPos(List> elems, StringBuilder sb) + throws Exception { + Iterator> i = elems.iterator(); + while (i.hasNext()) { + JAXBElement elem = i.next(); + Object value = elem.getValue(); + List point = null; + if (value instanceof DirectPositionType) { + DirectPositionType pos = (DirectPositionType) value; + point = pos.getValue(); + } else if (value instanceof PointPropertyType) { + PointPropertyType pointProp = (PointPropertyType) value; + DirectPositionType pos = pointProp.getPoint().getPos(); + CoordType coord = pointProp.getPoint().getCoord(); + if (pos != null) { + point = pos.getValue(); + } else if (coord != null) { + point = convert(coord); + } + } + if (point == null) { + throw new Exception("Unsupported position type: " + + value.getClass()); + } + addPoint(point, sb); + if (i.hasNext()) { + sb.append(", "); + } + } + } + + public void addPointPropList(List pointProps, + StringBuilder sb) throws Exception { + Iterator i = pointProps.iterator(); + addPoint(i.next().getPoint(), sb); + while (i.hasNext()) { + sb.append(' '); + addPoint(i.next().getPoint(), sb); + } + } + + public void addPointList(List point, StringBuilder sb) + throws Exception { + Iterator i = point.iterator(); + addPoint(i.next(), sb); + while (i.hasNext()) { + sb.append(' '); + addPoint(i.next(), sb); + } + } + + protected void addPoint(PointType point, StringBuilder sb) throws Exception { + DirectPositionType pos = point.getPos(); + CoordType coord = point.getCoord(); + if (pos != null) { + addPoint(pos.getValue(), sb); + } else if (coord != null) { + addPoint(convert(coord), sb); + } else { + throw new Exception("Unsupported point format"); + } + } + + protected void addPoint(List point, StringBuilder sb) { + Iterator j = point.iterator(); + sb.append(j.next()); + while (j.hasNext()) { + sb.append(" "); + sb.append(j.next()); + } + } + + protected List convert(CoordType coord) { + ArrayList rval = new ArrayList(3); + rval.add(coord.getX().doubleValue()); + BigDecimal y = coord.getY(); + BigDecimal z = coord.getZ(); + if (y != null) { + rval.add(y.doubleValue()); + if (z != null) { + rval.add(z.doubleValue()); + } + } + return rval; + } + + protected void addPosList(DirectPositionListType poslist, StringBuilder sb) + throws Exception { + int dim = poslist.getSrsDimension().intValue(); + List value = poslist.getValue(); + if (dim < 2 || value.size() % dim != 0) { + throw new Exception("Invalid dimensions for position list"); + } + Iterator i = value.iterator(); + while (i.hasNext()) { + sb.append(i.next()); + for (int j = 0; j < dim; ++j) { + sb.append(" "); + sb.append(i.next()); + } + if (i.hasNext()) { + sb.append(", "); + } + } + } + + public static class LineString extends GmlWktWriter { + @Override + public String write(AbstractGeometryType geom) throws Exception { + LineStringType lst = (LineStringType) geom; + StringBuilder sb = new StringBuilder("LINESTRING "); + addLineString(lst, sb); + return sb.toString(); + } + } + + public static class MultiLineString extends GmlWktWriter { + @Override + public String write(AbstractGeometryType geom) throws Exception { + MultiLineStringType mlst = (MultiLineStringType) geom; + StringBuilder sb = new StringBuilder("MULTILINESTRING ("); + Iterator i = mlst.getLineStringMember() + .iterator(); + addLineString(i.next().getLineString(), sb); + while (i.hasNext()) { + sb.append(','); + addLineString(i.next().getLineString(), sb); + } + sb.append(')'); + return sb.toString(); + } + } + + public static class Point extends GmlWktWriter { + @Override + public String write(AbstractGeometryType geom) throws Exception { + PointType p = (PointType) geom; + StringBuilder sb = new StringBuilder("POINT ("); + addPoint(p, sb); + sb.append(')'); + return sb.toString(); + } + } + + public static class MultiPoint extends GmlWktWriter { + @Override + public String write(AbstractGeometryType geom) throws Exception { + MultiPointType mult = (MultiPointType) geom; + StringBuilder sb = new StringBuilder("MULTIPOINT ("); + List pointProps = mult.getPointMember(); + PointArrayPropertyType array = mult.getPointMembers(); + if (pointProps != null) { + addPointPropList(pointProps, sb); + } + if (array != null) { + addPointList(array.getPoint(), sb); + } + sb.append(')'); + return sb.toString(); + } + } + + public static class Polygon extends GmlWktWriter { + @Override + public String write(AbstractGeometryType geom) throws Exception { + PolygonType poly = (PolygonType) geom; + StringBuilder sb = new StringBuilder("POLYGON "); + addPolygon(poly, sb); + return sb.toString(); + } + } + + public static class MultiPolygon extends GmlWktWriter { + @Override + public String write(AbstractGeometryType geom) throws Exception { + MultiPolygonType poly = (MultiPolygonType) geom; + StringBuilder sb = new StringBuilder("MULTIPOLYGON ("); + List value = poly.getPolygonMember(); + Iterator i = value.iterator(); + addPolygon(i.next().getPolygon(), sb); + while (i.hasNext()) { + sb.append(','); + addPolygon(i.next().getPolygon(), sb); + } + sb.append(')'); + return sb.toString(); + } + } + + public static class LinearRing extends GmlWktWriter { + @Override + public String write(AbstractGeometryType geom) throws Exception { + LinearRingType ring = (LinearRingType) geom; + StringBuilder sb = new StringBuilder("LINEARRING "); + addAbstractRing(ring, sb); + return sb.toString(); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_2_1/EnvelopeConverter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_2_1/EnvelopeConverter.java new file mode 100644 index 0000000000..2fec8304d1 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_2_1/EnvelopeConverter.java @@ -0,0 +1,237 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 26, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.ogc.common.gml3_2_1; + +import java.text.ParseException; +import java.util.Arrays; +import java.util.List; + +import net.opengis.gml.v_3_1_1.CoordType; +import net.opengis.gml.v_3_2_1.CoordinatesType; +import net.opengis.gml.v_3_2_1.DirectPositionType; +import net.opengis.gml.v_3_2_1.EnvelopeType; + +import org.apache.commons.lang.StringUtils; + +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.spatial.CoordinateUtil; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +/** + * Converter for GML 3.2.1 envelopes to JTS envelopes + * + * @author bclement + * @version 1.0 + */ +public class EnvelopeConverter { + + /** + * Returns number of dimensions in envelope + * + * @param env + * @return + * @throws Exception + */ + public static int getDims(EnvelopeType env) throws OgcException { + if (env.isSetSrsDimension() && env.getSrsDimension().intValue() > 1) { + return env.getSrsDimension().intValue(); + } + if (env.isSetLowerCorner()) { + DirectPositionType lc = env.getLowerCorner(); + return lc.getValue().size(); + } + if (env.isSetCoordinates()) { + CoordinatesType coords = env.getCoordinates(); + return StringUtils.split(coords.getValue()).length; + } + if (env.isSetPos()) { + DirectPositionType pos = env.getPos().get(0); + return pos.getValue().size(); + } + throw new OgcException(Code.InvalidParameterValue, + "Unsupported envelope dimensions"); + } + + /** + * Convert GML envelope to JTS envelope + * + * @param env + * @return + * @throws Exception + */ + public Envelope convert(EnvelopeType env) throws OgcException { + Coordinate[] coords = getCoordinates(env); + return new Envelope(coords[0], coords[1]); + } + + /** + * Convert GML envelope to JTS coordinates. + * + * @param env + * @param dims + * @return + * @throws Exception + */ + public Coordinate[] getCoordinates(EnvelopeType env) throws OgcException { + int dims = getDims(env); + if (env.isSetLowerCorner() && env.isSetUpperCorner()) { + return translate(env.getLowerCorner(), env.getUpperCorner(), dims); + } + if (env.isSetCoordinates()) { + return handleCoordinates(env.getCoordinates(), dims); + } + if (env.isSetPos()) { + return handlePosList(env.getPos(), dims); + } + throw new OgcException(Code.InvalidFormat, + "Unsupported envelope format"); + } + + /** + * Convert direct positions to JTS bounding box. Output will only include + * the number of dimensions specified in dims + * + * @param lower + * @param upper + * @param dims + * @return + * @throws Exception + */ + protected Coordinate[] translate(DirectPositionType lower, + DirectPositionType upper, int dims) throws OgcException { + List lowers = lower.getValue(); + List uppers = upper.getValue(); + if (lowers == null || uppers == null || lowers.size() < dims + || uppers.size() < dims) { + throw new OgcException(Code.InvalidFormat, + "Unsupported envelope format"); + } + Coordinate l; + Coordinate u; + if (dims == 2) { + l = new Coordinate(lowers.get(0), lowers.get(1)); + u = new Coordinate(uppers.get(0), uppers.get(1)); + } else if (dims == 3) { + l = new Coordinate(lowers.get(0), lowers.get(1), lowers.get(2)); + u = new Coordinate(uppers.get(0), uppers.get(1), uppers.get(2)); + } else { + throw new OgcException(Code.InvalidFormat, + "Unsupported envelope format"); + } + return new Coordinate[] { l, u }; + } + + /** + * Convert list of direct positions to JTS coordinates. Output will only + * include the number of dimensions specified in dims + * + * @param pos + * @param dims + * @return + * @throws Exception + */ + private Coordinate[] handlePosList(List pos, int dims) + throws OgcException { + return translate(pos.get(0), pos.get(1), dims); + } + + /** + * Convert GML coordinates to JTS coordinates. Output will only include the + * number of dimensions specified in dims + * + * @param coordinates + * @param dims + * @return + * @throws Exception + */ + protected Coordinate[] handleCoordinates(CoordinatesType coordinates, + int dims) throws OgcException { + try { + List coords = CoordinateUtil.parseCoordinates(coordinates + .getValue()); + return translate(createPos(coords.get(0)), + createPos(coords.get(1)), dims); + } catch (ParseException e) { + throw new OgcException(Code.InvalidFormat, + "Invalid coordinate string"); + } + } + + /** + * Create direct position type from double values in strings + * + * @param doubles + * @return + */ + protected DirectPositionType createPos(String[] doubles) { + Double[] rval = new Double[doubles.length]; + for (int i = 0; i < doubles.length; ++i) { + rval[i] = Double.parseDouble(doubles[i]); + } + return createPos(rval); + } + + /** + * Convert coordtype to direct position + * + * @param coord + * @return + * @throws Exception + */ + protected DirectPositionType createPos(CoordType coord) throws OgcException { + Double[] rval; + if (coord.isSetZ()) { + rval = new Double[] { coord.getX().doubleValue(), + coord.getY().doubleValue(), coord.getZ().doubleValue() }; + } else if (coord.isSetY()) { + rval = new Double[] { coord.getX().doubleValue(), + coord.getY().doubleValue() }; + } else { + rval = new Double[] { coord.getX().doubleValue() }; + } + return createPos(rval); + } + + /** + * Create direct position type from double values in strings + * + * @param doubles + * @return + */ + protected DirectPositionType createPos(Double... coords) { + DirectPositionType rval = new DirectPositionType(); + rval.setValue(Arrays.asList(coords)); + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_2_1/GeometryConverter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_2_1/GeometryConverter.java new file mode 100644 index 0000000000..5b5a986356 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/gml3_2_1/GeometryConverter.java @@ -0,0 +1,909 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 25, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.ogc.common.gml3_2_1; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.gml.v_3_2_1.AbstractCurveType; +import net.opengis.gml.v_3_2_1.AbstractGeometricAggregateType; +import net.opengis.gml.v_3_2_1.AbstractGeometricPrimitiveType; +import net.opengis.gml.v_3_2_1.AbstractGeometryType; +import net.opengis.gml.v_3_2_1.AbstractRingPropertyType; +import net.opengis.gml.v_3_2_1.AbstractRingType; +import net.opengis.gml.v_3_2_1.CoordinatesType; +import net.opengis.gml.v_3_2_1.CurveArrayPropertyType; +import net.opengis.gml.v_3_2_1.CurvePropertyType; +import net.opengis.gml.v_3_2_1.DirectPositionListType; +import net.opengis.gml.v_3_2_1.DirectPositionType; +import net.opengis.gml.v_3_2_1.GeometryArrayPropertyType; +import net.opengis.gml.v_3_2_1.GeometryPropertyType; +import net.opengis.gml.v_3_2_1.LineStringType; +import net.opengis.gml.v_3_2_1.LinearRingType; +import net.opengis.gml.v_3_2_1.MultiCurveType; +import net.opengis.gml.v_3_2_1.MultiGeometryType; +import net.opengis.gml.v_3_2_1.MultiPointType; +import net.opengis.gml.v_3_2_1.ObjectFactory; +import net.opengis.gml.v_3_2_1.PointArrayPropertyType; +import net.opengis.gml.v_3_2_1.PointPropertyType; +import net.opengis.gml.v_3_2_1.PointType; +import net.opengis.gml.v_3_2_1.PolygonType; + +import org.geotools.geometry.jts.JTS; + +import com.vividsolutions.jts.geom.Coordinate; +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.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.ParseException; + +/** + * Converts between GML 3.2.1 and JTS geometries + * + * @author bclement + * @version 1.0 + */ +public class GeometryConverter { + + protected final GeometryFactory factory = new GeometryFactory(); + + protected final ObjectFactory gmlFactory = new ObjectFactory(); + + /** + * Supports geometry collection, polygon, point and linestring + * + * @param value + * @return + * @throws IllegalArgumentException + */ + public AbstractGeometryType convert(Geometry value) + throws IllegalArgumentException { + AbstractGeometryType rval; + if (value instanceof GeometryCollection) { + rval = convert((GeometryCollection) value); + } else if (value instanceof Polygon) { + rval = convert((Polygon) value); + } else if (value instanceof Point) { + rval = convert((Point) value); + } else if (value instanceof LineString) { + rval = convert((LineString) value); + } else { + throw new IllegalArgumentException("Unsupported geometry type: " + + value.getClass()); + } + return rval; + } + + /** + * Only supports multipolygon, multipoint and multilinestring + * + * @param value + * @return + * @throws IllegalArgumentException + */ + public AbstractGeometricAggregateType convert(GeometryCollection value) + throws IllegalArgumentException { + AbstractGeometricAggregateType rval; + if (value instanceof MultiPolygon) { + rval = convert((MultiPolygon) value); + } else if (value instanceof MultiPoint) { + rval = convert((MultiPoint) value); + } else if (value instanceof MultiLineString) { + rval = convert((MultiLineString) value); + } else { + throw new IllegalArgumentException("Unsupported geometry type: " + + value.getClass()); + } + return rval; + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + public MultiGeometryType convert(MultiPolygon value) + throws IllegalArgumentException { + MultiGeometryType rval = new MultiGeometryType(); + int count = value.getNumGeometries(); + List members = new ArrayList( + count); + for (int i = 0; i < count; ++i) { + GeometryPropertyType prop = new GeometryPropertyType(); + Polygon p = (Polygon) value.getGeometryN(i); + PolygonType ptype = convert(p); + prop.setAbstractGeometry(gmlFactory.createAbstractGeometry(ptype)); + members.add(prop); + } + rval.setGeometryMember(members); + return rval; + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + public MultiPointType convert(MultiPoint value) + throws IllegalArgumentException { + MultiPointType rval = new MultiPointType(); + int count = value.getNumGeometries(); + List members = new ArrayList( + count); + for (int i = 0; i < count; ++i) { + PointPropertyType prop = new PointPropertyType(); + Point p = (Point) value.getGeometryN(i); + PointType ptype = convert(p); + prop.setPoint(ptype); + members.add(prop); + } + rval.setPointMember(members); + return rval; + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + public MultiCurveType convert(MultiLineString value) + throws IllegalArgumentException { + MultiCurveType rval = new MultiCurveType(); + int count = value.getNumGeometries(); + List members = new ArrayList( + count); + for (int i = 0; i < count; ++i) { + CurvePropertyType prop = new CurvePropertyType(); + LineString ls = (LineString) value.getGeometryN(i); + LineStringType lstype = convert(ls); + prop.setAbstractCurve(gmlFactory.createAbstractCurve(lstype)); + } + rval.setCurveMember(members); + return rval; + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + public PolygonType convert(Polygon value) throws IllegalArgumentException { + PolygonType rval = new PolygonType(); + AbstractRingPropertyType ext = new AbstractRingPropertyType(); + LinearRingType ring = convertStringRing(value.getExteriorRing()); + ext.setAbstractRing(gmlFactory.createAbstractRing(ring)); + rval.setExterior(ext); + int holeCount = value.getNumInteriorRing(); + List holes = new ArrayList( + holeCount); + for (int i = 0; i < holeCount; ++i) { + AbstractRingPropertyType prop = new AbstractRingPropertyType(); + LineString hole = value.getInteriorRingN(i); + ring = convertStringRing(hole); + prop.setAbstractRing(gmlFactory.createAbstractRing(ring)); + } + rval.setInterior(holes); + return rval; + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + protected LinearRingType convertStringRing(LineString value) + throws IllegalArgumentException { + int dims = value.getDimension(); + Coordinate[] coords = value.getCoordinates(); + return ringFromCoords(dims, coords); + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + protected LinearRingType convert(LinearRing value) + throws IllegalArgumentException { + int dims = value.getDimension(); + Coordinate[] coords = value.getCoordinates(); + return ringFromCoords(dims, coords); + } + + /** + * @param dims + * number of dimensions in each coordinate + * @param coords + * @return + * @throws IllegalArgumentException + */ + protected LinearRingType ringFromCoords(int dims, Coordinate[] coords) + throws IllegalArgumentException { + LinearRingType rval = new LinearRingType(); + DirectPositionListType posList = posListFromCoords(dims, coords); + rval.setPosList(posList); + return rval; + } + + /** + * @param dims + * number of dimensions in each coordinate + * @param coords + * @return + * @throws IllegalArgumentException + */ + protected DirectPositionListType posListFromCoords(int dims, + Coordinate[] coords) throws IllegalArgumentException { + DirectPositionListType posList = new DirectPositionListType(); + if (dims < 2 && coords.length > 0) { + // check for uninitialized dims + Coordinate sample = coords[0]; + // 3 if sample.z is not NaN + // 2 if sample.z is NaN and sample.y is not NaN + dims = Double.isNaN(sample.z) ? 2 : 3; + } + posList.setCount(BigInteger.valueOf(coords.length)); + posList.setSrsDimension(BigInteger.valueOf(dims)); + List dubs; + if (dims == 2) { + dubs = convert2D(coords); + } else if (dims == 3) { + dubs = convert3D(coords); + } else { + throw new IllegalArgumentException( + "Unsupported number of dimensions: " + dims); + } + posList.setValue(dubs); + return posList; + } + + /** + * @param coords + * 2D coordinates + * @return + */ + protected List convert2D(Coordinate... coords) { + List rval = new ArrayList(coords.length * 2); + for (Coordinate c : coords) { + rval.add(c.x); + rval.add(c.y); + } + return rval; + } + + /** + * @param coords + * 3D coodinates + * @return + */ + protected List convert3D(Coordinate... coords) { + List rval = new ArrayList(coords.length * 3); + for (Coordinate c : coords) { + rval.add(c.x); + rval.add(c.y); + rval.add(c.z); + } + return rval; + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + public PointType convert(Point value) throws IllegalArgumentException { + PointType rval = new PointType(); + int dims = value.getDimension(); + DirectPositionType pos = posFromCoord(dims, value.getCoordinate()); + rval.setPos(pos); + return rval; + } + + /** + * @param dims + * number of dimensions in coordinate + * @param c + * @return + * @throws IllegalArgumentException + */ + protected DirectPositionType posFromCoord(int dims, Coordinate c) + throws IllegalArgumentException { + DirectPositionType rval = new DirectPositionType(); + if (dims == 0) { + // check for uninitialized dims + dims = Double.isNaN(c.z) ? 2 : 3; + } + if (dims == 2) { + rval.setValue(convert2D(c)); + } else if (dims == 3) { + rval.setValue(convert3D(c)); + } else { + throw new IllegalArgumentException( + "Unsupported number of dimensions: " + dims); + } + return rval; + } + + /** + * @param value + * @return + * @throws IllegalArgumentException + */ + public LineStringType convert(LineString value) + throws IllegalArgumentException { + LineStringType rval = new LineStringType(); + int dims = value.getDimension(); + Coordinate[] coords = value.getCoordinates(); + DirectPositionListType posList = posListFromCoords(dims, coords); + rval.setPosList(posList); + return rval; + } + + /** + * @param env + * @return + * @throws ParseException + */ + public Geometry convert(Envelope env) throws ParseException { + return JTS.toGeometry(env); + } + + /** + * @param value + * @return + * @throws Exception + */ + public Geometry convert(AbstractGeometryType value) throws Exception { + Geometry rval; + if (value instanceof AbstractGeometricAggregateType) { + rval = convert((AbstractGeometricAggregateType) value); + } else if (value instanceof AbstractGeometricPrimitiveType) { + rval = convert((AbstractGeometricPrimitiveType) value); + } else { + throw new Exception("Unsupported Geometry type: " + + value.getClass()); + } + return rval; + } + + /** + * Supports multipoint, multilinestring and multipolygon + * + * @param agg + * @return + * @throws Exception + */ + public GeometryCollection convert(AbstractGeometricAggregateType agg) + throws Exception { + GeometryCollection rval; + if (agg instanceof MultiGeometryType) { + rval = convert((MultiGeometryType) agg); + } else if (agg instanceof MultiPointType) { + rval = convert((MultiPointType) agg); + } else if (agg instanceof MultiCurveType) { + rval = convert((MultiCurveType) agg); + } else { + throw new Exception("Unsupported geometry aggregate type: " + + agg.getClass()); + } + return rval; + } + + /** + * Only supports multilinestring + * + * @param multiCurve + * @return + * @throws Exception + */ + public MultiLineString convert(MultiCurveType multiCurve) throws Exception { + List curves = new ArrayList(); + if (multiCurve.isSetCurveMember()) { + List members = multiCurve.getCurveMember(); + for (CurvePropertyType cpt : members) { + curves.add(cpt.getAbstractCurve().getValue()); + } + } + if (multiCurve.isSetCurveMembers()) { + CurveArrayPropertyType members = multiCurve.getCurveMembers(); + List> elems = members + .getAbstractCurve(); + for (JAXBElement e : elems) { + curves.add(e.getValue()); + } + } + LineString[] lineStrings = new LineString[curves.size()]; + Iterator iter = curves.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + AbstractCurveType curve = iter.next(); + if (!(curve instanceof LineStringType)) { + throw new Exception("Unsupported multicurve member type: " + + curve.getClass()); + } + lineStrings[i] = convert((LineStringType) curve); + } + return factory.createMultiLineString(lineStrings); + } + + /** + * + * @param multiPoint + * @return + * @throws Exception + */ + public MultiPoint convert(MultiPointType multiPoint) throws Exception { + List points = new ArrayList(); + if (multiPoint.isSetPointMember()) { + List members = multiPoint.getPointMember(); + for (PointPropertyType ppt : members) { + points.add(ppt.getPoint()); + } + } + if (multiPoint.isSetPointMembers()) { + PointArrayPropertyType members = multiPoint.getPointMembers(); + points.addAll(members.getPoint()); + } + Point[] rval = new Point[points.size()]; + Iterator iter = points.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + PointType ptype = iter.next(); + rval[i] = convert(ptype); + } + return factory.createMultiPoint(rval); + } + + /** + * Only supports multipolygon + * + * @param multiGeom + * @return + * @throws Exception + */ + public MultiPolygon convert(MultiGeometryType multiGeom) throws Exception { + List geoms = new ArrayList(); + if (multiGeom.isSetGeometryMember()) { + List members = multiGeom.getGeometryMember(); + for (GeometryPropertyType gpt : members) { + geoms.add(gpt.getAbstractGeometry().getValue()); + } + } + if (multiGeom.isSetGeometryMembers()) { + GeometryArrayPropertyType members = multiGeom.getGeometryMembers(); + List> elems = members + .getAbstractGeometry(); + for (JAXBElement e : elems) { + geoms.add(e.getValue()); + } + } + Polygon[] polys = new Polygon[geoms.size()]; + Iterator iter = geoms.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + AbstractGeometryType geom = iter.next(); + if (geom instanceof AbstractGeometricAggregateType) { + throw new Exception("Nested geometry aggregates not supported"); + } + if (!(geom instanceof PolygonType)) { + throw new Exception("Unsupported multi geometry type: " + + geom.getClass()); + } + PolygonType ptype = (PolygonType) geom; + polys[i] = convert(ptype); + } + return factory.createMultiPolygon(polys); + } + + /** + * Supports point, linestring and polygon + * + * @param primitive + * @return + * @throws Exception + */ + public Geometry convert(AbstractGeometricPrimitiveType primitive) + throws Exception { + Geometry rval; + if (primitive instanceof LineStringType) { + rval = convert((LineStringType) primitive); + } else if (primitive instanceof PolygonType) { + rval = convert((PolygonType) primitive); + } else if (primitive instanceof PointType) { + rval = convert((PointType) primitive); + } else { + throw new Exception("Unsupported Geometry type: " + + primitive.getClass()); + } + return rval; + } + + /** + * @param point + * @return + * @throws Exception + */ + public Point convert(PointType point) throws Exception { + Coordinate coord; + if (point.isSetCoordinates()) { + CoordinatesType ct = point.getCoordinates(); + coord = convert(ct)[0]; + } else if (point.isSetPos()) { + DirectPositionType pos = point.getPos(); + coord = convert(pos); + } else { + throw new Exception("Unable to find coordinate for point: " + point); + } + return factory.createPoint(coord); + } + + /** + * @param poly + * @return + * @throws Exception + */ + public Polygon convert(PolygonType poly) throws Exception { + AbstractRingPropertyType exterior = poly.getExterior(); + LinearRing shell = convert(exterior); + List interior = poly.getInterior(); + LinearRing[] holes = new LinearRing[interior.size()]; + Iterator iter = interior.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + holes[i] = convert(iter.next()); + } + return factory.createPolygon(shell, holes); + } + + /** + * @param ring + * @return + * @throws Exception + */ + public LinearRing convert(AbstractRingPropertyType ring) throws Exception { + JAXBElement abs = ring.getAbstractRing(); + AbstractRingType value = abs.getValue(); + if (value instanceof LinearRingType) { + return convert((LinearRingType) value); + } else { + throw new Exception("Unsupported ring type: " + ring.getClass()); + } + } + + /** + * @param ring + * @return + * @throws Exception + */ + public LinearRing convert(LinearRingType ring) throws Exception { + Coordinate[] coords; + if (ring.isSetCoordinates()) { + CoordinatesType ctype = ring.getCoordinates(); + coords = convert(ctype); + } else if (ring.isSetPosList()) { + DirectPositionListType posList = ring.getPosList(); + coords = convert(posList); + } else if (ring.isSetPosOrPointPropertyOrPointRep()) { + List> innerChoice = ring + .getPosOrPointPropertyOrPointRep(); + coords = convertPosOrPointChoice(innerChoice); + } else { + throw new Exception("Unable to find coordinates for ring: " + ring); + } + return factory.createLinearRing(coords); + } + + /** + * @param line + * @return + * @throws Exception + */ + public LineString convert(LineStringType line) throws Exception { + Coordinate[] coords; + if (line.isSetCoordinates()) { + CoordinatesType ctype = line.getCoordinates(); + coords = convert(ctype); + } else if (line.isSetPosList()) { + DirectPositionListType posList = line.getPosList(); + coords = convert(posList); + } else if (line.isSetPosOrPointPropertyOrPointRep()) { + List> innerChoice = line + .getPosOrPointPropertyOrPointRep(); + coords = convertPosOrPointChoice(innerChoice); + } else { + throw new Exception("Unable to find coordinates for line: " + line); + } + return factory.createLineString(coords); + } + + /** + * Converts list of Pos (DirectPositionType), PointPropertyType or PointType + * elements to list of coordinates + * + * @param list + * @return + * @throws Exception + */ + protected Coordinate[] convertPosOrPointChoice(List> list) + throws Exception { + Coordinate[] rval = new Coordinate[list.size()]; + Iterator> iter = list.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + JAXBElement elem = iter.next(); + Object obj = elem.getValue(); + if (obj instanceof DirectPositionType) { + DirectPositionType dpt = (DirectPositionType) obj; + rval[i] = convert(dpt); + } else if (obj instanceof PointPropertyType) { + PointPropertyType ppt = (PointPropertyType) obj; + rval[i] = convert(ppt); + } else if (obj instanceof PointType) { + rval[i] = convertToCoord((PointType) obj); + } + } + return rval; + } + + /** + * @param ppt + * @return + * @throws Exception + */ + protected Coordinate convert(PointPropertyType ppt) throws Exception { + PointType point = ppt.getPoint(); + return convertToCoord(point); + } + + /** + * @param point + * @return + * @throws Exception + */ + protected Coordinate convertToCoord(PointType point) throws Exception { + Coordinate rval; + if (point.isSetCoordinates()) { + CoordinatesType coordinates = point.getCoordinates(); + rval = convert(coordinates)[0]; + } else if (point.isSetPos()) { + DirectPositionType pos = point.getPos(); + rval = convert(pos); + } else { + throw new Exception("Unable to find coordinates for point: " + + point); + } + return rval; + } + + /** + * @param pos + * @return + */ + protected Coordinate convert(DirectPositionType pos) { + Coordinate rval; + int dims = 2; + if (pos.isSetSrsDimension()) { + dims = pos.getSrsDimension().intValue(); + } + List value = pos.getValue(); + double x = value.get(0); + double y = value.get(1); + if (dims == 2) { + rval = new Coordinate(x, y); + } else { + rval = new Coordinate(x, y, value.get(3)); + } + return rval; + } + + /** + * @param posList + * @return + * @throws Exception + */ + protected Coordinate[] convert(DirectPositionListType posList) + throws Exception { + int len; + int dims; + List doubles = posList.getValue(); + if (posList.isSetCount()) { + len = posList.getCount().intValue(); + dims = posList.getSrsDimension().intValue(); + } else { + // default 2D TODO should use outer geom SRS dim + dims = 2; + len = doubles.size() / dims; + } + if (dims < 2 || dims > 3) { + throw new Exception("Unsupported number of dimensions: " + dims); + } + if (dims * len != doubles.size()) { + throw new Exception("Invalid pos list"); + } + Coordinate[] rval = new Coordinate[len]; + Iterator iter = doubles.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + double x = iter.next(); + double y = iter.next(); + if (dims == 2) { + rval[i] = new Coordinate(x, y); + } else { + rval[i] = new Coordinate(x, y, iter.next()); + } + } + return rval; + } + + /** + * Ensure that a string only contains one character + * + * @param str + * string containing character + * @param isSet + * if false, returns fallback + * @param fallback + * default character for use if string is not set + * @return + * @throws Exception + * if string isn't 1 character long and is set + */ + protected Character ensureChar(String str, boolean isSet, Character fallback) + throws Exception { + if (!isSet) { + return fallback; + } + if (str.length() != 1) { + throw new Exception("Invalid character string length: " + str); + } + return str.charAt(0); + } + + /** + * states for coordinate conversion state machine + */ + protected static enum CoordState { + START, NUM, BETWEEN, OUTER, INNER + } + + /** + * @param ctype + * @return + * @throws Exception + */ + protected Coordinate[] convert(CoordinatesType ctype) throws Exception { + String value = ctype.getValue(); + Character innerSeparator = ensureChar(ctype.getCs(), ctype.isSetCs(), + ','); + Character outerSeparator = ensureChar(ctype.getTs(), ctype.isSetTs(), + ' '); + String decimal = "."; + if (ctype.isSetDecimal()) { + decimal = ctype.getDecimal(); + if (!decimal.equals(".")) { + value = value.replace(decimal, "."); + } + } + + int len = value.length(); + StringBuilder sb = new StringBuilder(); + CoordState state = CoordState.START; + ArrayList nums = new ArrayList(3); + List coords = new ArrayList(); + for (int i = 0; i < len; ++i) { + char c = value.charAt(i); + switch (state) { + case START: + if (isNumber(c)) { + state = CoordState.NUM; + sb.append(c); + } + break; + case NUM: + if (isNumber(c)) { + sb.append(c); + } else { + if (innerSeparator.equals(c)) { + state = CoordState.INNER; + } else if (outerSeparator.equals(c)) { + state = CoordState.OUTER; + } else { + state = CoordState.BETWEEN; + } + nums.add(Double.parseDouble(sb.toString())); + sb = new StringBuilder(); + } + break; + case BETWEEN: + if (isNumber(c)) { + throw new Exception("Invalid coordinates string: " + value); + } else if (innerSeparator.equals(c)) { + state = CoordState.INNER; + } else if (outerSeparator.equals(c)) { + state = CoordState.OUTER; + } + break; + case OUTER: + if (isNumber(c)) { + sb.append(c); + state = CoordState.NUM; + coords.add(convert(nums)); + } else if (innerSeparator.equals(c)) { + state = CoordState.INNER; + } + break; + case INNER: + if (isNumber(c)) { + sb.append(c); + state = CoordState.NUM; + } + break; + } + } + if (state.equals(CoordState.NUM)) { + nums.add(Double.parseDouble(sb.toString())); + } + coords.add(convert(nums)); + return coords.toArray(new Coordinate[coords.size()]); + } + + /** + * @param c + * @return true if c is a valid character used in representing a number + */ + protected boolean isNumber(Character c) { + return Character.isDigit(c); + } + + /** + * @param nums + * @return + * @throws Exception + */ + protected Coordinate convert(List nums) throws Exception { + Coordinate rval; + if (nums.size() == 2) { + rval = new Coordinate(nums.get(0), nums.get(1)); + } else if (nums.size() == 3) { + rval = new Coordinate(nums.get(0), nums.get(1), nums.get(2)); + } else { + throw new Exception("Unsupported dimension length: " + nums.size()); + } + nums.clear(); + return rval; + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/EndpointInfo.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/EndpointInfo.java new file mode 100644 index 0000000000..0241d94788 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/EndpointInfo.java @@ -0,0 +1,155 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.http; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 26, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class EndpointInfo { + + protected String protocol; + + protected String host; + + protected int port; + + protected String path; + + protected String encoding; + + protected boolean postOnly = true; + + /** + * @param protocol + * @param host + * @param port + * @param path + */ + public EndpointInfo(String protocol, String host, int port, String path) { + this.protocol = protocol; + this.host = host; + this.port = port; + this.path = path; + } + + /** + * @param host + * @param port + * @param path + */ + public EndpointInfo(String host, int port, String path) { + this("http", host, port, path); + } + + /** + * @return the protocol + */ + public String getProtocol() { + return protocol; + } + + /** + * @param protocol + * the protocol to set + */ + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + /** + * @return the host + */ + public String getHost() { + return host; + } + + /** + * @param host + * the host to set + */ + public void setHost(String host) { + this.host = host; + } + + /** + * @return the port + */ + public int getPort() { + return port; + } + + /** + * @param port + * the port to set + */ + public void setPort(int port) { + this.port = port; + } + + /** + * @return the path + */ + public String getPath() { + return path; + } + + /** + * @param path + * the path to set + */ + public void setPath(String path) { + this.path = path; + } + + /** + * @return the encoding + */ + public String getEncoding() { + return encoding; + } + + /** + * @param encoding + * the encoding to set + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * @return the postOnly + */ + public boolean isPostOnly() { + return postOnly; + } + + /** + * @param postOnly + * the postOnly to set + */ + public void setPostOnly(boolean postOnly) { + this.postOnly = postOnly; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/IOgcHttpPooler.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/IOgcHttpPooler.java new file mode 100644 index 0000000000..6680f68b34 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/IOgcHttpPooler.java @@ -0,0 +1,37 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.http; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 31, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public interface IOgcHttpPooler { + + public Object borrowObject(Object key); + + public void returnObject(Object key, Object borrowed); + + public void drain(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/MimeType.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/MimeType.java new file mode 100644 index 0000000000..6e8a03b6a2 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/MimeType.java @@ -0,0 +1,210 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.http; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; + +/** + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 29, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class MimeType { + + protected String type; + + protected String subtype; + + protected Map parameters; + + private static final String TOKEN_CLASS = "[^ \\t\\(\\)\\\\\\/@,;:<>\\[\\]\\?=\"]"; + + private static final Pattern TYPE_PATTERN = Pattern.compile("^\\s*(" + + TOKEN_CLASS + "+)/?(" + TOKEN_CLASS + "+)?.*$"); + + private static final Pattern PARAM_PATTERN = Pattern.compile(";\\s*(" + + TOKEN_CLASS + "+)=(" + TOKEN_CLASS + "+|\"\\S+\")"); + + public MimeType(String mime){ + Matcher m = TYPE_PATTERN.matcher(mime); + if (m.matches()) { + this.type = m.group(1).toLowerCase(); + int typeEnd; + this.subtype = m.group(2); + if (this.subtype != null) { + typeEnd = m.end(2); + this.subtype = this.subtype.toLowerCase(); + } else { + typeEnd = m.end(1); + } + String params = mime.substring(typeEnd); + this.parameters = getParameters(params); + } else { + throw new IllegalArgumentException("Invalid mime type string: " + + mime); + } + } + + private static Map getParameters(String paramStr) { + Matcher m = PARAM_PATTERN.matcher(paramStr); + Map rval = new LinkedHashMap(); + while (m.find()) { + String param = m.group(1).toLowerCase(); + String value = StringUtils.strip(m.group(2), "\""); + rval.put(param, value); + } + return Collections.unmodifiableMap(rval); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((parameters == null) ? 0 : parameters.hashCode()); + result = prime * result + ((subtype == null) ? 0 : subtype.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MimeType other = (MimeType) obj; + if (parameters == null) { + if (other.parameters != null) + return false; + } else { + if (other.parameters == null) { + return false; + } + if (parameters.size() != other.parameters.size()) { + return false; + } + for (String s : parameters.keySet()) { + String val = parameters.get(s); + if (!val.equalsIgnoreCase(other.parameters.get(s))) { + return false; + } + } + } + if (subtype == null) { + if (other.subtype != null) + return false; + } else if (!subtype.equalsIgnoreCase(other.subtype)) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equalsIgnoreCase(other.type)) + return false; + return true; + } + + public boolean equalsIgnoreParams(MimeType other) { + if (other == null) { + return false; + } + if (subtype == null) { + if (other.subtype != null) + return false; + } else if (!subtype.equalsIgnoreCase(other.subtype)) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equalsIgnoreCase(other.type)) + return false; + return true; + } + + /** + * @param paramName + * @return null if parameter is not found + */ + public String getParam(String paramName) { + return parameters.get(paramName.toLowerCase()); + } + + public int getNumParams() { + return parameters.size(); + } + + @Override + public String toString(){ + StringBuilder sb = new StringBuilder(toStringWithoutParams()); + for ( String key : this.parameters.keySet()){ + sb.append("; ").append(key); + sb.append("="); + String value = this.parameters.get(key); + if (value.matches("^" + TOKEN_CLASS + "+$")) { + sb.append(value); + } else { + sb.append("\"").append(value).append("\""); + } + } + return sb.toString(); + } + + public String toStringWithoutParams() { + StringBuilder sb = new StringBuilder(); + sb.append(this.type).append("/"); + sb.append(this.subtype); + return sb.toString(); + } + + /** + * @return the type + */ + public String getType() { + return type; + } + + + /** + * @return the subtype + */ + public String getSubtype() { + return subtype; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpEndpoint.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpEndpoint.java index 2514c8adeb..ecf5d32704 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpEndpoint.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpEndpoint.java @@ -29,6 +29,9 @@ import javax.servlet.http.HttpServletResponse; import org.apache.camel.Exchange; import org.apache.camel.Processor; +import com.raytheon.uf.edex.ogc.common.stats.OgcStatsRecorder; +import com.raytheon.uf.edex.ogc.common.stats.StatsRecorderFinder; + /** * TODO - Class comment here * @@ -45,25 +48,35 @@ import org.apache.camel.Processor; * @version 1 */ public class OgcHttpEndpoint implements Processor { + + public static final String HEADER_AC_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; + + public static final String HEADER_AC_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; + + public static final String HEADER_AC_EXPOSE_HEADERS = "Access-Control-Expose-Headers"; - protected OgcHttpPool pool; + protected IOgcHttpPooler pool; /** * */ - public OgcHttpEndpoint(OgcHttpPool pool) { + public OgcHttpEndpoint(IOgcHttpPooler pool) { this.pool = pool; } @Override public void process(Exchange ex) throws Exception { + long start = System.nanoTime(); + Map headers = ex.getIn().getHeaders(); HttpServletResponse response = ex.getIn().getBody( HttpServletResponse.class); HttpServletRequest httpRequest = ex.getIn().getBody( HttpServletRequest.class); + + setCorsHeaders(headers, response); long id = Thread.currentThread().getId(); OgcHttpHandler handler = (OgcHttpHandler) pool.borrowObject(id); @@ -73,7 +86,28 @@ public class OgcHttpEndpoint implements Processor { ogcReq.setInputStream(ex.getIn().getBody(InputStream.class)); } handler.handle(ogcReq); + + // TODO get service from request somehow?? remove time and duration + // calculation from critical path + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "OGCRest", true); + pool.returnObject(id, handler); } + /** + * Set the CORS headers allowing access from alternate origins. + * @param headers + * @param response + */ + protected void setCorsHeaders(Map headers, HttpServletResponse response) { + String allowedOrigins = "*"; + + response.setHeader(HEADER_AC_ALLOW_ORIGIN, allowedOrigins); + + response.setHeader(HEADER_AC_ALLOW_CREDENTIALS, "false"); + + response.setHeader(HEADER_AC_EXPOSE_HEADERS,""); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java index 1df4fe2987..9c9a5a32e6 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java @@ -27,18 +27,254 @@ */ package com.raytheon.uf.edex.ogc.common.http; +import java.io.InputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.commons.collections.map.CaseInsensitiveMap; +import org.apache.commons.lang.StringUtils; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; +import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; /** * @author bclement * */ -public interface OgcHttpHandler { +public abstract class OgcHttpHandler { - public static final String USER_HEADER = "username"; + public static final String USER_HEADER = "username"; - public static final String ROLES_HEADER = "roles"; + public static final String ROLES_HEADER = "roles"; - public static final String EXCEP_FORMAT_HEADER = "exceptions"; + public static final String EXCEP_FORMAT_HEADER = "exceptions"; + + public static final String VERSION_HEADER = "version"; + + public static final String ACCEPT_VERSIONS_HEADER = "acceptversions"; + + public abstract void handle(OgcHttpRequest request); + + private IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + public static MimeType getMimeType(Map map, String key) + throws OgcException { + String str = getString(map, key); + if (str == null || str.isEmpty()) { + return null; + } + try { + return new MimeType(str); + } catch (IllegalArgumentException e) { + throw new OgcException(Code.InvalidParameterValue, e); + } + } + + public static String getString(Map map, String key) + throws OgcException { + Object obj = map.get(key); + String rval = null; + if (obj != null) { + if (obj instanceof String) { + rval = (String) obj; + } else if (obj instanceof String[]) { + // they may have multiple values for the entry + String[] arr = (String[]) obj; + rval = arr[0]; + for (int i = 1; i < arr.length; ++i) { + if (!rval.equalsIgnoreCase(arr[i])) { + throw new OgcException(Code.InvalidParameterValue, + "Multiple values for parameter: " + key); + } + } + } else if (obj instanceof Collection) { + Collection col = (Collection) obj; + Iterator i = col.iterator(); + rval = i.next().toString(); + while (i.hasNext()) { + if (!rval.equalsIgnoreCase(i.next().toString())) { + throw new OgcException(Code.InvalidParameterValue, + "Multiple values for parameter: " + key); + } + } + } + } + return rval; + } + + public static String getVersionInHeader(Map headerMap) + throws OgcException { + return getString(headerMap, VERSION_HEADER); + } + + public static String[] getAcceptVersionInHeader( + Map headerMap) throws OgcException { + return getStringArr(headerMap, ACCEPT_VERSIONS_HEADER); + } + + /** + * @param in + * @return null if not found + * @throws XMLStreamException + */ + public static String[] getAttributeArrInRoot(InputStream in, String attrib) + throws XMLStreamException { + String vstr = getAttributeInRoot(in, attrib); + if (vstr == null) { + return null; + } + return StringUtils.split(vstr, ','); + } + + /** + * @param in + * @param attrib + * @return null if not found + * @throws XMLStreamException + */ + public static String getAttributeInRoot(InputStream in, String attrib) + throws XMLStreamException { + XMLStreamReader reader = XMLInputFactory.newInstance() + .createXMLStreamReader(in); + while (reader.next() != XMLStreamReader.START_ELEMENT) { + } + return getAttributeValue(reader, attrib); + } + + /** + * @param reader + * @param attrib + * @return null if attribute not found + */ + protected static String getAttributeValue(XMLStreamReader reader, + String attrib) { + int count = reader.getAttributeCount(); + for (int i = 0; i < count; ++i) { + String local = reader.getAttributeLocalName(i); + if (local.equalsIgnoreCase(attrib)) { + String ns = reader.getAttributeNamespace(i); + return reader.getAttributeValue(ns, local); + } + } + return null; + } + + public static String[] getStringArr(Map map, String key) { + Object obj = map.get(key); + String[] rval = null; + if (obj != null) { + if (obj instanceof String[]) { + rval = (String[]) obj; + } else if (obj instanceof String) { + rval = ((String) obj).split(",", -1); + } else if (obj instanceof Collection) { + Collection col = (Collection) obj; + rval = new String[col.size()]; + Iterator iter = col.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + rval[i] = iter.next().toString(); + } + } + } + return rval; + } + + public static Integer getInt(Map map, String key) + throws OgcException { + Object obj = map.get(key); + Integer rval = null; + if (obj != null) { + if (obj instanceof Integer) { + rval = (Integer) obj; + } else { + // try to decode string + rval = getInt(getString(map, key)); + } + } + return rval; + } + + public static Integer getInt(String str) { + Integer rval = null; + try { + rval = Integer.parseInt(str); + } catch (Exception e) { + // leave rval as null + } + return rval; + } + + public static Boolean getBool(Map map, String key) + throws OgcException { + Object obj = map.get(key); + Boolean rval = null; + if (obj != null) { + if (obj instanceof Boolean) { + rval = (Boolean) obj; + } else { + // decode as string + rval = getBool(getString(map, key)); + } + } + return rval; + } + + public static Boolean getBool(String str) { + Boolean rval = null; + try { + rval = Boolean.parseBoolean(str); + } catch (Exception e) { + // leave rval as null + } + return rval; + } + + protected OgcResponse handleError(OgcException e, MimeType exceptionFormat) { + log.error("Error handler not configured for http handler: " + + this.getClass()); + String rval = "\n"; + rval += "\n"; + rval += "" + e.getMessage() + + "\n"; + rval += "\n"; + return new OgcResponse(rval, OgcResponse.TEXT_XML_MIME, TYPE.TEXT); + } + + protected void sendResponse(IOgcHttpResponse httpRes, OgcResponse response) + throws Exception { + try { + OgcResponseOutput.output(response, httpRes); + } catch (OgcException e) { + OgcResponse error = handleError(e, null); + OgcResponseOutput.output(error, httpRes); + } + } + + @SuppressWarnings("unchecked") + protected static Map getDimensions( + Map headers) { + Map rval = new CaseInsensitiveMap(); + for (String key : headers.keySet()) { + if (key.toLowerCase().startsWith("dim_")) { + String dim = key.substring(4); + rval.put(dim, (String) headers.get(key)); + } + } + return rval; + } - public void handle(OgcHttpRequest request); } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpPool.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpPool.java index 70ba45658f..bddeb2fa99 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpPool.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpPool.java @@ -27,19 +27,21 @@ */ package com.raytheon.uf.edex.ogc.common.http; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.commons.pool.KeyedPoolableObjectFactory; import org.apache.commons.pool.impl.GenericKeyedObjectPool; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + /** * @author bclement * */ -public class OgcHttpPool extends GenericKeyedObjectPool { +public class OgcHttpPool extends GenericKeyedObjectPool implements + IOgcHttpPooler { /** The logger */ - private transient Log logger = LogFactory.getLog(getClass()); + private transient IUFStatusHandler log = UFStatus.getHandler(getClass()); public OgcHttpPool(KeyedPoolableObjectFactory ogcFactory) { super(ogcFactory); @@ -51,7 +53,7 @@ public class OgcHttpPool extends GenericKeyedObjectPool { try { retVal = super.borrowObject(key); } catch (IllegalStateException e) { - logger.error( + log.error( "Unable to borrow Ogc HTTP instance from pool for key: " + key, e); throw new RuntimeException(e); @@ -63,7 +65,7 @@ public class OgcHttpPool extends GenericKeyedObjectPool { if (retVal == null) { // it still didn't work, blow up - logger.error( + log.error( "Unable to borrow Ogc HTTP instance from pool for key: " + key, e); throw new RuntimeException(e); @@ -79,7 +81,7 @@ public class OgcHttpPool extends GenericKeyedObjectPool { super.returnObject(key, borrowed); } } catch (Exception e) { - logger.error("Unable to return Ogc HTTP instance to pool for key: " + log.error("Unable to return Ogc HTTP instance to pool for key: " + key, e); } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/SingleHttpPool.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/SingleHttpPool.java new file mode 100644 index 0000000000..3d8be73c93 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/SingleHttpPool.java @@ -0,0 +1,64 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.http; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 31, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class SingleHttpPool implements IOgcHttpPooler { + + private final OgcHttpHandler handler; + + /** + * @param handler + */ + public SingleHttpPool(OgcHttpHandler handler) { + this.handler = handler; + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.http.OgcHttpPooler#borrowObject(java.lang.Object) + */ + @Override + public OgcHttpHandler borrowObject(Object key) { + return handler; + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.http.OgcHttpPooler#returnObject(java.lang.Object, java.lang.Object) + */ + @Override + public void returnObject(Object key, Object borrowed) { + // nothing to do + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.http.OgcHttpPooler#drain() + */ + @Override + public void drain() { + // nothing to do + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/jaxb/OgcJaxbManager.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/jaxb/OgcJaxbManager.java index 9241e27c47..7a5f374452 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/jaxb/OgcJaxbManager.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/jaxb/OgcJaxbManager.java @@ -1,24 +1,21 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. * * * SOFTWARE HISTORY @@ -26,7 +23,7 @@ * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Mar 30, 2011 bclement Initial creation - * May 30, 2013 753 dhladky updated + * Aug 18, 2013 #2097 dhladky extended JAXBManager * */ package com.raytheon.uf.edex.ogc.common.jaxb; @@ -36,19 +33,28 @@ import java.io.FileReader; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; +import java.util.HashMap; import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.sun.xml.bind.api.JAXBRIContext; import com.sun.xml.bind.marshaller.NamespacePrefixMapper; /** @@ -57,96 +63,129 @@ import com.sun.xml.bind.marshaller.NamespacePrefixMapper; * @author bclement * @version 1.0 */ -public class OgcJaxbManager { +public class OgcJaxbManager extends JAXBManager { - protected JAXBContext jaxbContext = null; + private final JAXBContext jaxbContext; - protected int QUEUE_SIZE = 10; + protected static final int QUEUE_SIZE = 10; - protected Queue unmarshallers = new ConcurrentLinkedQueue(); + protected volatile int unmarshallersCreated = 0; - protected Queue marshallers = new ConcurrentLinkedQueue(); + protected volatile int marshallersCreated = 0; - protected int unmarshallersCreated = 0; + protected final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected int marshallersCreated = 0; + private volatile NamespacePrefixMapper mapper; - protected Log log = LogFactory.getLog(this.getClass()); + protected final ReadWriteLock prefixLock = new ReentrantReadWriteLock(); - protected Map prefixMap = null; + protected static final String JAXB_NAMESPACE_MAPPER = "com.sun.xml.bind.namespacePrefixMapper"; - private NamespacePrefixMapper mapper; - - protected static final String JAXB_NAMESPACE_MAPPER = "com.sun.xml.bind.namespacePrefixMapper"; - - public OgcJaxbManager(Class[] classes) throws JAXBException { - jaxbContext = JAXBContext.newInstance(classes); + public OgcJaxbManager(Class[] classes) throws JAXBException { + jaxbContext = JAXBContext.newInstance(classes, getJaxbConfig()); } - protected Unmarshaller getUnmarshaller() throws JAXBException { - Unmarshaller m = unmarshallers.poll(); - if (m == null) { - if (unmarshallersCreated < QUEUE_SIZE) { - m = jaxbContext.createUnmarshaller(); - ++unmarshallersCreated; - } else { - int tries = 0; - do { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - // ignore - } - m = unmarshallers.poll(); - tries++; - if (tries >= 20) { - log.debug("Unable to get jaxb unmarshaller from pool after " - + tries + " tries. Growing pool size."); - m = jaxbContext.createUnmarshaller(); - ++unmarshallersCreated; - } - } while (m == null); - } + private static Map getJaxbConfig() throws JAXBException { + Map jaxbConfig = new HashMap(); + TransientAnnotationReader reader = new TransientAnnotationReader(); + try { + reader.addTransientField(Throwable.class + .getDeclaredField("stackTrace")); + reader.addTransientMethod(Throwable.class + .getDeclaredMethod("getStackTrace")); + } catch (Exception e) { + throw new JAXBException("Unable to add transient members", e); } + jaxbConfig.put(JAXBRIContext.ANNOTATION_READER, reader); + return jaxbConfig; + } - return m; - } + protected Unmarshaller getUnmarshaller() throws JAXBException { + Unmarshaller m = unmarshallers.poll(); + if (m == null) { + if (unmarshallersCreated < QUEUE_SIZE) { + synchronized (unmarshallers) { + m = jaxbContext.createUnmarshaller(); + ++unmarshallersCreated; + } + } else { + int tries = 0; + do { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + // ignore + } + m = unmarshallers.poll(); + tries++; + if (tries >= 20) { + log.debug("Unable to get jaxb unmarshaller from pool after " + + tries + " tries. Growing pool size."); + synchronized (unmarshallers) { + m = jaxbContext.createUnmarshaller(); + ++unmarshallersCreated; + } + } + } while (m == null); + } + } + return m; + } - protected Marshaller getMarshaller() throws JAXBException { - Marshaller m = marshallers.poll(); - if (m == null) { - if (marshallersCreated < QUEUE_SIZE) { - m = jaxbContext.createMarshaller(); - ++marshallersCreated; - } else { - int tries = 0; - do { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - // ignore - } - m = marshallers.poll(); - tries++; - if (tries >= 20) { - log.debug("Unable to get jaxb marshaller from pool after " - + tries + " tries. Growing pool size."); - m = jaxbContext.createMarshaller(); - ++marshallersCreated; - } - } while (m == null); - } - } + protected Marshaller getMarshaller() throws JAXBException { + Marshaller m = marshallers.poll(); + if (m == null) { + if (marshallersCreated < QUEUE_SIZE) { + synchronized (marshallers) { + m = jaxbContext.createMarshaller(); + ++marshallersCreated; + } + } else { + int tries = 0; + do { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + // ignore + } + m = marshallers.poll(); + tries++; + if (tries >= 20) { + log.debug("Unable to get jaxb marshaller from pool after " + + tries + " tries. Growing pool size."); + synchronized (marshallers) { + m = jaxbContext.createMarshaller(); + ++marshallersCreated; + } + } + } while (m == null); + } + } + return m; + } - return m; - } + public Object unmarshal(String xml) throws JAXBException { + Unmarshaller msh = null; + try { + msh = getUnmarshaller(); + StringReader reader = new StringReader(xml); + Object obj = msh.unmarshal(reader); + if (obj instanceof JAXBElement) { + obj = ((JAXBElement) obj).getValue(); + } + return obj; + } finally { + if (msh != null) { + unmarshallers.add(msh); + } + } + } - public Object unmarshal(String xml) throws JAXBException { + public Object unmarshal(Node node) throws JAXBException { Unmarshaller msh = null; try { msh = getUnmarshaller(); - StringReader reader = new StringReader(xml); - Object obj = msh.unmarshal(reader); + Object obj = msh.unmarshal(node); if (obj instanceof JAXBElement) { obj = ((JAXBElement) obj).getValue(); } @@ -174,72 +213,97 @@ public class OgcJaxbManager { } } - public Object unmarshal(InputStream xml) throws JAXBException { - Unmarshaller msh = null; - try { - msh = getUnmarshaller(); - Object obj = msh.unmarshal(xml); - if (obj instanceof JAXBElement) { - obj = ((JAXBElement) obj).getValue(); - } - return obj; - } finally { - if (msh != null) { - unmarshallers.add(msh); - } - } + public Object unmarshal(InputStream xml) throws JAXBException { + Unmarshaller msh = null; + try { + msh = getUnmarshaller(); + Object obj = msh.unmarshal(xml); + if (obj instanceof JAXBElement) { + obj = ((JAXBElement) obj).getValue(); + } + return obj; + } finally { + if (msh != null) { + unmarshallers.add(msh); + } + } + } + + public String marshal(Object obj) throws JAXBException { + return marshal(obj, true); + } + + public String marshal(Object obj, boolean formatted) throws JAXBException { + return marshal(obj, null, formatted, false); + } + + public String marshal(Object obj, boolean formatted, boolean fragment) + throws JAXBException { + return marshal(obj, null, formatted, fragment); } - public String marshal(Object obj) throws JAXBException { - return marshal(obj, true); - } - - public String marshal(Object obj, boolean formatted) throws JAXBException { - return marshal(obj, null, formatted); - } - - public void marshal(Object obj, OutputStream out, String schemaLocation, - boolean formatted) throws JAXBException { + public Node marshalToNode(Object obj) throws JAXBException, + ParserConfigurationException { Marshaller msh = getMarshaller(); try { - - msh.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatted); - if (mapper != null) { - msh.setProperty(JAXB_NAMESPACE_MAPPER, mapper); - } - if (schemaLocation != null && !schemaLocation.isEmpty()) { - msh.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation); - } - msh.marshal(obj, out); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + msh.marshal(obj, doc); + return doc.getFirstChild(); } finally { marshallers.add(msh); } } - public String marshal(Object obj, String schemaLocation, boolean formatted) - throws JAXBException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - marshal(obj, out, schemaLocation, formatted); - return out.toString(); - } + public void marshal(Object obj, OutputStream out, String schemaLocation, + boolean formatted, boolean fragment) throws JAXBException { + Marshaller msh = getMarshaller(); + try { - public Map getPrefixMap() { - return prefixMap; - } + msh.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatted); + msh.setProperty(Marshaller.JAXB_FRAGMENT, fragment); + if (mapper != null) { + Lock read = prefixLock.readLock(); + read.lock(); + try { + msh.setProperty(JAXB_NAMESPACE_MAPPER, mapper); + } finally { + read.unlock(); + } + } + if (schemaLocation != null && !schemaLocation.isEmpty()) { + msh.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation); + } + msh.marshal(obj, out); + } finally { + marshallers.add(msh); + } + } - public void setPrefixMap(final Map prefixMap) { - this.prefixMap = prefixMap; - this.mapper = new NamespacePrefixMapper() { - @Override - public String getPreferredPrefix(String namespaceUri, - String suggestion, boolean requirePrefix) { - return prefixMap.get(namespaceUri); - } - }; - } + public String marshal(Object obj, String schemaLocation, boolean formatted, + boolean fragment) + throws JAXBException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + marshal(obj, out, schemaLocation, formatted, fragment); + return out.toString(); + } - public JAXBContext getJaxbContext() { - return jaxbContext; - } + public void setPrefixMap(final Map prefixMap) { + Lock write = prefixLock.writeLock(); + write.lock(); + try { + this.mapper = new NamespacePrefixMapper() { + @Override + public String getPreferredPrefix(String namespaceUri, + String suggestion, boolean requirePrefix) { + return prefixMap.get(namespaceUri); + } + }; + } finally { + write.unlock(); + } + } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/jaxb/TransientAnnotationReader.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/jaxb/TransientAnnotationReader.java new file mode 100644 index 0000000000..041129c0f8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/jaxb/TransientAnnotationReader.java @@ -0,0 +1,309 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.jaxb; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import javax.xml.bind.annotation.XmlTransient; + +import com.sun.xml.bind.v2.model.annotation.AbstractInlineAnnotationReaderImpl; +import com.sun.xml.bind.v2.model.annotation.Locatable; +import com.sun.xml.bind.v2.model.annotation.RuntimeAnnotationReader; +import com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 11, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +@SuppressWarnings("rawtypes") +public class TransientAnnotationReader extends + AbstractInlineAnnotationReaderImpl + implements + RuntimeAnnotationReader { + + private static class XmlTransientProxyHandler implements InvocationHandler { + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + if (args == null || args.length == 0) { + if (method.getName().equals("annotationType")) { + return XmlTransient.class; + } + if (method.getName().equals("toString")) { + return "XmlTransient"; + } + } + String msg = "@XmlTransient doesn't support method: " + + method.getName(); + throw new UnsupportedOperationException(msg); + } + + private static XmlTransient create() { + ClassLoader loader = XmlTransientProxyHandler.class + .getClassLoader(); + Class[] interfaces = new Class[] { XmlTransient.class }; + XmlTransientProxyHandler handler = new XmlTransientProxyHandler(); + return (XmlTransient) Proxy.newProxyInstance(loader, interfaces, + handler); + } + } + + private static final Annotation XML_TRANSIENT_ANNOTATION = XmlTransientProxyHandler + .create(); + + private static final Annotation[] XML_TRANSIENT_ANNOTATION_ONLY = { XML_TRANSIENT_ANNOTATION }; + + private final RuntimeAnnotationReader delegate = new RuntimeInlineAnnotationReader(); + + private final Set> transientClasses = Collections + .newSetFromMap(new ConcurrentHashMap, Boolean>()); + + private final Set transientFields = Collections + .newSetFromMap(new ConcurrentHashMap()); + + private final Set transientMethods = Collections + .newSetFromMap(new ConcurrentHashMap()); + + /** + * + */ + public TransientAnnotationReader() { + } + + public void addTransientClass(Class c) { + transientClasses.add(c); + } + + public void addTransientField(Field f) { + transientFields.add(f); + } + + public void addTransientMethod(Method m) { + transientMethods.add(m); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getAllFieldAnnotations + * (java.lang.Object, com.sun.xml.bind.v2.model.annotation.Locatable) + */ + @Override + public Annotation[] getAllFieldAnnotations(Field f, Locatable srcPos) { + if (transientFields.contains(f)) { + return XML_TRANSIENT_ANNOTATION_ONLY; + } + return delegate.getAllFieldAnnotations(f, srcPos); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getAllMethodAnnotations + * (java.lang.Object, com.sun.xml.bind.v2.model.annotation.Locatable) + */ + @Override + public Annotation[] getAllMethodAnnotations(Method m, Locatable srcPos) { + if (transientMethods.contains(m)) { + return XML_TRANSIENT_ANNOTATION_ONLY; + } + return delegate.getAllMethodAnnotations(m, srcPos); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getClassAnnotation + * (java.lang.Class, java.lang.Object, + * com.sun.xml.bind.v2.model.annotation.Locatable) + */ + @SuppressWarnings("unchecked") + @Override + public A getClassAnnotation(Class type, Class c, + Locatable srcPos) { + if (transientClasses.contains(c)) { + return (A) XML_TRANSIENT_ANNOTATION; + } + return delegate.getClassAnnotation(type, c, srcPos); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getClassArrayValue + * (java.lang.annotation.Annotation, java.lang.String) + */ + @Override + public Type[] getClassArrayValue(Annotation a, String name) { + return delegate.getClassArrayValue(a, name); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getClassValue(java + * .lang.annotation.Annotation, java.lang.String) + */ + @Override + public Type getClassValue(Annotation a, String name) { + return delegate.getClassValue(a, name); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getFieldAnnotation + * (java.lang.Class, java.lang.Object, + * com.sun.xml.bind.v2.model.annotation.Locatable) + */ + @SuppressWarnings("unchecked") + @Override + public A getFieldAnnotation(Class type, Field f, + Locatable srcPos) { + if (XmlTransient.class.isAssignableFrom(type) + && transientFields.contains(f)) { + return (A) XML_TRANSIENT_ANNOTATION; + } + return delegate.getFieldAnnotation(type, f, srcPos); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getMethodAnnotation + * (java.lang.Class, java.lang.Object, + * com.sun.xml.bind.v2.model.annotation.Locatable) + */ + @SuppressWarnings("unchecked") + @Override + public A getMethodAnnotation(Class type, + Method m, Locatable srcPos) { + if (XmlTransient.class.isAssignableFrom(type) + && transientMethods.contains(m)) { + return (A) XML_TRANSIENT_ANNOTATION; + } + return delegate.getMethodAnnotation(type, m, srcPos); + } + + /* + * (non-Javadoc) + * + * @see com.sun.xml.bind.v2.model.annotation.AnnotationReader# + * getMethodParameterAnnotation(java.lang.Class, java.lang.Object, int, + * com.sun.xml.bind.v2.model.annotation.Locatable) + */ + @Override + public A getMethodParameterAnnotation(Class type, + Method m, int index, Locatable srcPos) { + return delegate.getMethodParameterAnnotation(type, m, index, srcPos); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#getPackageAnnotation + * (java.lang.Class, java.lang.Object, + * com.sun.xml.bind.v2.model.annotation.Locatable) + */ + @Override + public A getPackageAnnotation(Class type, + Class c, Locatable srcPos) { + return delegate.getPackageAnnotation(type, c, srcPos); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#hasClassAnnotation + * (java.lang.Object, java.lang.Class) + */ + @Override + public boolean hasClassAnnotation(Class c, Class type) { + if (transientClasses.contains(c)) { + return true; + } + return delegate.hasClassAnnotation(c, type); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#hasFieldAnnotation + * (java.lang.Class, java.lang.Object) + */ + @Override + public boolean hasFieldAnnotation(Class type, Field f) { + if (XmlTransient.class.isAssignableFrom(type) + && transientFields.contains(f)) { + return true; + } + return delegate.hasFieldAnnotation(type, f); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AnnotationReader#hasMethodAnnotation + * (java.lang.Class, java.lang.Object) + */ + @Override + public boolean hasMethodAnnotation(Class type, + Method m) { + if (XmlTransient.class.isAssignableFrom(type) + && transientMethods.contains(m)) { + return true; + } + return delegate.hasMethodAnnotation(type, m); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.xml.bind.v2.model.annotation.AbstractInlineAnnotationReaderImpl + * #fullName(java.lang.Object) + */ + @Override + protected String fullName(Method m) { + return m.getDeclaringClass().getName() + '#' + m.getName(); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/level/LevelDimUtil.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/level/LevelDimUtil.java new file mode 100644 index 0000000000..40d61b7e3b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/level/LevelDimUtil.java @@ -0,0 +1,105 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.level; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.raytheon.uf.common.dataplugin.level.Level; +import com.raytheon.uf.common.dataplugin.level.MasterLevel; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 18, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class LevelDimUtil { + + public static final String LEVEL_DIM_PREFIX = "LEVEL_"; + + public static final Pattern levelPattern = Pattern + .compile("^(-?[0-9]*\\.?[0-9]+)(_(-?[0-9]*\\.?[0-9]+))?(.*)?$"); + + /** + * @param dimName + * @param value + * @param defaultUnits + * @return null if not parsed + * @throws OgcException + */ + public static Level parseLevel(String dimName, String value, + String defaultUnits) throws OgcException { + String name = dimName.substring(LEVEL_DIM_PREFIX.length()); + Matcher m = levelPattern.matcher(value); + if (!m.matches()) { + return null; + } + Level rval = new Level(); + MasterLevel master = new MasterLevel(name); + rval.setMasterLevel(master); + rval.setLevelonevalue(parseWithDefault(m.group(1), Level.INVALID_VALUE)); + rval.setLeveltwovalue(parseWithDefault(m.group(3), Level.INVALID_VALUE)); + String units = m.group(4) == null || m.group(4).isEmpty() ? defaultUnits + : m.group(4); + if (units != null) { + master.setUnitString(units); + } else { + master.setUnitString(defaultUnits); + } + return rval; + } + + /** + * @param input + * @param defaultVal + * @return default if input is null/empty + * @throws OgcException + */ + private static double parseWithDefault(String input, double defaultVal) + throws OgcException { + if (input == null || input.isEmpty()) { + return defaultVal; + } + try { + return Double.parseDouble(input); + } catch (Exception e) { + throw new OgcException(Code.InvalidParameterValue, + "Invalid level value: " + input, e); + } + } + + /** + * Return formatted level value + * + * @param level + * @return + */ + public static String formatLevelValue(Level level) { + String rval = level.getLevelOneValueAsString(); + if (level.isLevelTwoValid()) { + rval += "_" + level.getLevelTwoValueAsString(); + } + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/IOgcHttpResponse.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/IOgcHttpResponse.java new file mode 100644 index 0000000000..42071d844d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/IOgcHttpResponse.java @@ -0,0 +1,55 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.output; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 7, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface IOgcHttpResponse { + + /** + * This can only be called once + * + * @return + * @throws IOException + */ + public OutputStream getOutputStream() throws IOException; + + /** + * @param status + */ + public void setStatus(int status); + + /** + * @param type + */ + public void setContentType(String type); + + /** + * @param encoding + */ + public void setCharacterEncoding(String encoding); +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/OgcResponseOutput.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/OgcResponseOutput.java index b76c4bb48c..2c261cde11 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/OgcResponseOutput.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/OgcResponseOutput.java @@ -31,19 +31,21 @@ package com.raytheon.uf.edex.ogc.common.output; import java.awt.image.RenderedImage; -import java.io.PrintWriter; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.nio.ByteBuffer; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; -import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcException.Code; import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.OgcResponse.ErrorType; /** * @@ -52,7 +54,7 @@ import com.raytheon.uf.edex.ogc.common.OgcResponse; */ public class OgcResponseOutput { - public static void output(OgcResponse response, HttpServletResponse httpRes) + public static void output(OgcResponse response, IOgcHttpResponse httpRes) throws Exception { switch (response.getType()) { case TEXT: @@ -71,56 +73,78 @@ public class OgcResponseOutput { } - protected static void checkError(OgcResponse response, - HttpServletResponse httpRes) { - int code = HttpServletResponse.SC_OK; - switch (response.getError()) { - case INT_ERR: - code = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - break; - case BAD_REQ: - code = HttpServletResponse.SC_BAD_REQUEST; - break; - case NOT_IMPLEMENTED: - code = HttpServletResponse.SC_NOT_IMPLEMENTED; - break; - } + protected static void checkError(OgcResponse response, + IOgcHttpResponse httpRes) { + int code = getErrorCode(response.getError()); httpRes.setStatus(code); } - public static void sendText(OgcResponse response, - HttpServletResponse httpRes) throws Exception { - httpRes.setContentType(response.getMimetype()); - checkError(response, httpRes); - Object obj = response.getBody(); - ServletOutputStream out = null; - PrintWriter writer = null; - try { - if (obj instanceof byte[]) { - // UTF8 bytes - httpRes.setCharacterEncoding("UTF-8"); - out = httpRes.getOutputStream(); - out.write((byte[]) obj); - } else { - writer = httpRes.getWriter(); - writer.write(obj.toString()); - } - } catch (Exception e) { - httpRes.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - throw e; - } finally { - if (out != null) { - out.close(); - } - if (writer != null) { - writer.close(); - } - } + public static int getErrorCode(ErrorType error) { + int code; + switch (error) { + case INT_ERR: + code = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + break; + case BAD_REQ: + code = HttpServletResponse.SC_BAD_REQUEST; + break; + case NOT_IMPLEMENTED: + code = HttpServletResponse.SC_NOT_IMPLEMENTED; + break; + case NONE: + code = HttpServletResponse.SC_OK; + break; + default: + throw new IllegalArgumentException("Unsupported error type: " + + error); + } + return code; + } + + public static void sendText(OgcResponse response, IOgcHttpResponse httpRes) + throws Exception { + OutputStream out = httpRes.getOutputStream(); + sendText(response, httpRes, out); } - public static void sendImage(OgcResponse response, - HttpServletResponse httpRes) throws Exception { - String mimetype = response.getMimetype(); + /** + * Send text when output stream has already be retrieved. Closes output + * stream. + * + * @param response + * @param httpRes + * @param out + * @throws Exception + */ + public static void sendText(OgcResponse response, IOgcHttpResponse httpRes, + OutputStream out) throws Exception { + httpRes.setContentType(response.getMimetype().toString()); + checkError(response, httpRes); + Object obj = response.getBody(); + try { + if (obj instanceof byte[]) { + // UTF8 bytes + httpRes.setCharacterEncoding("UTF-8"); + out.write((byte[]) obj); + out.flush(); + } else { + Writer writer = new OutputStreamWriter(out); + writer.write(obj.toString()); + writer.flush(); + } + } catch (Exception e) { + httpRes.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + throw e; + } finally { + if (out != null) { + out.close(); + } + } + } + + public static void sendImage(OgcResponse response, IOgcHttpResponse httpRes) + throws Exception { + String mimetype = response.getMimetype().toString(); checkError(response, httpRes); httpRes.setContentType(mimetype); ImageOutputStream out = null; @@ -146,8 +170,8 @@ public class OgcResponseOutput { } public static void sendByteArray(OgcResponse response, - HttpServletResponse httpRes) throws Exception { - httpRes.setContentType(response.getMimetype()); + IOgcHttpResponse httpRes) throws Exception { + httpRes.setContentType(response.getMimetype().toString()); checkError(response, httpRes); Object obj = response.getBody(); byte[] arr; @@ -158,10 +182,11 @@ public class OgcResponseOutput { } else { throw new Exception("Unsupported class: " + obj.getClass()); } - ServletOutputStream out = null; + OutputStream out = null; try { out = httpRes.getOutputStream(); out.write(arr); + out.flush(); } catch (Exception e) { httpRes.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); throw e; diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/ServletOgcResponse.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/ServletOgcResponse.java new file mode 100644 index 0000000000..9b8f94f879 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/ServletOgcResponse.java @@ -0,0 +1,75 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.output; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.servlet.http.HttpServletResponse; + +/** + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 7, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class ServletOgcResponse implements IOgcHttpResponse { + + private final HttpServletResponse response; + + /** + * + */ + public ServletOgcResponse(HttpServletResponse response) { + this.response = response; + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#getOutputStream() + */ + @Override + public OutputStream getOutputStream() throws IOException { + return response.getOutputStream(); + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#setStatus(int) + */ + @Override + public void setStatus(int status) { + response.setStatus(status); + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#setContentType(java.lang.String) + */ + @Override + public void setContentType(String type) { + response.setContentType(type); + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#setCharacterEncoding(java.lang.String) + */ + @Override + public void setCharacterEncoding(String encoding) { + response.setCharacterEncoding(encoding); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/StoredHttpResponse.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/StoredHttpResponse.java new file mode 100644 index 0000000000..1398eae705 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/output/StoredHttpResponse.java @@ -0,0 +1,108 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.output; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.servlet.http.HttpServletResponse; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 7, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class StoredHttpResponse implements IOgcHttpResponse { + + private ByteArrayOutputStream baos; + + private int status = HttpServletResponse.SC_OK; + + private String contentType; + + private String characterEncoding; + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#getOutputStream() + */ + @Override + public OutputStream getOutputStream() throws IOException { + baos = new ByteArrayOutputStream(); + return baos; + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#setStatus(int) + */ + @Override + public void setStatus(int status) { + this.status = status; + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#setContentType(java.lang.String) + */ + @Override + public void setContentType(String type) { + this.contentType = type; + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.output.OgcHttpResponse#setCharacterEncoding(java.lang.String) + */ + @Override + public void setCharacterEncoding(String encoding) { + this.characterEncoding = encoding; + } + + /** + * @return the status + */ + public int getStatus() { + return status; + } + + /** + * @return the contentType + */ + public String getContentType() { + return contentType; + } + + /** + * @return the characterEncoding + */ + public String getCharacterEncoding() { + return characterEncoding; + } + + /** + * @return empty byte array if {@link StoredHttpResponse#getOutputStream()} + * hasn't been called + */ + public byte[] getBody() { + if (baos == null) { + return new byte[0]; + } + return baos.toByteArray(); + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/AbstractOwsService.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/AbstractOwsService.java new file mode 100644 index 0000000000..a1361dee5d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/AbstractOwsService.java @@ -0,0 +1,64 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.soap; + +import java.util.Arrays; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.ws.WebServiceContext; +import javax.xml.ws.handler.MessageContext; + +import net.opengis.ows.v_1_1_0.ExceptionReport; +import net.opengis.ows.v_1_1_0.ExceptionType; + +import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 31, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractOwsService { + + protected abstract WebServiceContext getContext(); + + protected EndpointInfo getInfo() { + MessageContext mc = getContext().getMessageContext(); + HttpServletRequest req = (HttpServletRequest) mc + .get(MessageContext.SERVLET_REQUEST); + EndpointInfo rval = new EndpointInfo(req.getServerName(), + req.getServerPort(), req.getPathInfo()); + rval.setEncoding("SOAP"); + return rval; + } + + protected ServiceExceptionReport getReport(String code, String message, + String version) { + ExceptionReport report = new ExceptionReport(); + report.setVersion(version); + ExceptionType et = new ExceptionType(); + et.setExceptionCode(code); + et.setExceptionText(Arrays.asList(message)); + report.setException(Arrays.asList(et)); + return new ServiceExceptionReport(message, report); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/CustomWsdlInterceptor.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/CustomWsdlInterceptor.java new file mode 100644 index 0000000000..43c46e6da7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/CustomWsdlInterceptor.java @@ -0,0 +1,134 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.soap; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; + +import org.apache.cxf.common.util.StringUtils; +import org.apache.cxf.helpers.IOUtils; +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.message.Message; +import org.apache.cxf.message.MessageImpl; +import org.apache.cxf.phase.AbstractPhaseInterceptor; +import org.apache.cxf.phase.Phase; +import org.apache.cxf.transport.Conduit; +import org.apache.cxf.transport.http.UrlUtilities; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + +/** + * WSDL reader + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 28, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CustomWsdlInterceptor extends AbstractPhaseInterceptor { + + private String wsdl; + + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(CustomWsdlInterceptor.class); + + /** + * @param phase + * @throws IOException + */ + public CustomWsdlInterceptor(String wsdlLocation) throws IOException { + super(Phase.READ); + ClassLoader loader = this.getClass().getClassLoader(); + InputStream in = loader.getResourceAsStream(wsdlLocation); + this.wsdl = IOUtils.readStringFromStream(in); + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.cxf.interceptor.Interceptor#handleMessage(org.apache.cxf.message + * .Message) + */ + @Override + public void handleMessage(Message msg) throws Fault { + String method = (String) msg.get(Message.HTTP_REQUEST_METHOD); + String query = (String) msg.get(Message.QUERY_STRING); + if (!"GET".equals(method) || StringUtils.isEmpty(query)) { + return; + } + String baseUrl = (String) msg.get(Message.REQUEST_URL); + String host = getHostName(baseUrl); + + synchronized (msg.getExchange().getEndpoint()) { + Map args = UrlUtilities.parseQueryString(query); + if (args.containsKey("wsdl")) { + + OutputStream os = null; + + try { + + Conduit c = msg.getExchange().getDestination() + .getBackChannel(msg, null, null); + + Message mout = new MessageImpl(); + mout.setExchange(msg.getExchange()); + msg.getExchange().setOutMessage(mout); + mout.put(Message.CONTENT_TYPE, "text/xml"); + c.prepare(mout); + os = mout.getContent(OutputStream.class); + OutputStreamWriter writer = new OutputStreamWriter(os); + writer.write(process(host)); + writer.close(); + msg.getInterceptorChain().abort(); + } catch (IOException e) { + throw new Fault(e); + } finally { + if (os != null) { + try { + os.close(); + } catch (Exception e) { + statusHandler.error("Unable to close CXF stream.", e); + } + } + msg.getExchange().setOutMessage(null); + } + } + } + } + + private String getHostName(String url) throws Fault { + try { + return new URL(url).getHost(); + } catch (MalformedURLException e) { + throw new Fault(e); + } + } + + private String process(String host) { + // TODO more robust processing + return wsdl.replaceAll("0\\.0\\.0\\.0", host); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/JaxWsConfigServerFactoryBean.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/JaxWsConfigServerFactoryBean.java new file mode 100644 index 0000000000..d313983716 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/JaxWsConfigServerFactoryBean.java @@ -0,0 +1,95 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.soap; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.cxf.jaxb.JAXBDataBinding; +import org.apache.cxf.jaxws.JaxWsServerFactoryBean; + +import com.sun.xml.bind.api.JAXBRIContext; +import com.sun.xml.bind.v2.model.annotation.RuntimeAnnotationReader; + +/** + * allows jaxb context of server to be configured + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 21, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class JaxWsConfigServerFactoryBean extends JaxWsServerFactoryBean { + + public void setClasses(Class[] classes) { + JAXBDataBinding dataBinding = (JAXBDataBinding) getServiceFactory() + .getDataBinding(); + Class[] old = dataBinding.getExtraClass(); + if (old != null && old.length > 0) { + Set> all = new HashSet>(); + all.addAll(Arrays.asList(old)); + all.addAll(Arrays.asList(classes)); + classes = all.toArray(new Class[all.size()]); + } + dataBinding.setExtraClass(classes); + getServiceFactory().setDataBinding(dataBinding); + } + + public void setAnnotationReader(RuntimeAnnotationReader reader) { + setContextProperty(JAXBRIContext.ANNOTATION_READER, reader); + } + + public void setMtomEnabled(boolean enabled) { + JAXBDataBinding dataBinding = (JAXBDataBinding) getServiceFactory() + .getDataBinding(); + dataBinding.setMtomEnabled(enabled); + getServiceFactory().setDataBinding(dataBinding); + Map old = getProperties(); + Map props = new HashMap(); + if (old != null) { + props.putAll(old); + } + props.put("mtom-enabled", enabled); + this.setProperties(props); + } + + public void setContextProperty(String property, Object value) { + JAXBDataBinding dataBinding = (JAXBDataBinding) getServiceFactory() + .getDataBinding(); + Map old = dataBinding.getContextProperties(); + Map props = new HashMap(); + if (old != null) { + props.putAll(old); + } + props.put(property, value); + dataBinding.setContextProperties(props); + getServiceFactory().setDataBinding(dataBinding); + } + + public void setNamespaceMap(Map map) { + JAXBDataBinding dataBinding = (JAXBDataBinding) getServiceFactory() + .getDataBinding(); + dataBinding.setNamespaceMap(map); + getServiceFactory().setDataBinding(dataBinding); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/ServiceExceptionReport.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/ServiceExceptionReport.java new file mode 100644 index 0000000000..97ef97ef5e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/soap/ServiceExceptionReport.java @@ -0,0 +1,66 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + +package com.raytheon.uf.edex.ogc.common.soap; + +import javax.xml.ws.WebFault; + +import net.opengis.ows.v_1_1_0.ExceptionReport; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.1.6 in JDK 6 + * Generated source version: 2.1 + * + */ +@WebFault(name = "ExceptionReport", targetNamespace = "http://www.opengis.net/ows/1.1") +public class ServiceExceptionReport + extends Exception +{ + + private static final long serialVersionUID = 6719686901014342367L; + /** + * Java type that goes as soapenv:Fault detail element. + * + */ + private ExceptionReport faultInfo; + + /** + * + * @param message + * @param faultInfo + */ + public ServiceExceptionReport(String message, ExceptionReport faultInfo) { + super(message); + this.faultInfo = faultInfo; + } + + /** + * + * @param message + * @param faultInfo + * @param cause + */ + public ServiceExceptionReport(String message, ExceptionReport faultInfo, Throwable cause) { + super(message, cause); + this.faultInfo = faultInfo; + } + + /** + * + * @return + * returns fault bean: net.opengis.ows._1.ExceptionReport + */ + public ExceptionReport getFaultInfo() { + return faultInfo; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/AltUtil.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/AltUtil.java new file mode 100644 index 0000000000..f27779a1f0 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/AltUtil.java @@ -0,0 +1,157 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import javax.measure.converter.ConversionException; +import javax.measure.unit.SI; +import javax.measure.unit.Unit; + +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 4, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class AltUtil { + + private static final double T0 = 288.0; + + private static final double gamma = 0.0065; + + private static final double p0 = 1013.2; + + private static final double c1 = 5.256; + + private static final double c2 = 14600.0; + + private static final double z11 = 11000.0; + + private static final double p11 = 226.0971; + + private static final double Flag = 1e37; + + private static final double Flg = 1.0E10; + + /** + * Convert Millibars (hPa) to Meters + * + * @param p + * @return + */ + public static double mbToMeters(double p) { + double rval; + if (p > Flg || p < 1.0) { + rval=Flag; + }else if (p > p11){ + rval = ((T0 - T0 * Math.pow(p / p0, 1 / c1)) / gamma); + }else{ + rval = (c2 * Math.log10(p11 / p) + z11); + } + return rval; + } + + /** + * Convert Meters to Millibars (hPa) + * + * @param m + * @return + */ + public static double metersToMb(double m) { + double rval; + if (m > Flg) { + rval = Flag; + } else if (m < z11) { + rval = p0 * Math.pow(((T0 - gamma * m) / T0), c1); + } else { + rval = p11 * Math.pow(10.0, ((z11 - m) / c2)); + } + return rval; + } + + /** + * Convert value from srcUnits to targetUnits + * + * @param targetUnits + * @param srcUnits + * @param value + * @return + * @throws ConversionException + */ + public static double convert(Unit targetUnits, Unit srcUnits, + double value) throws ConversionException { + if (targetUnits == null || srcUnits == null) { + return value; + } + if (targetUnits.equals(srcUnits)) { + return value; + } + if (targetUnits.isCompatible(srcUnits)) { + return srcUnits.getConverterTo(targetUnits).convert(value); + } + if (srcUnits.isCompatible(SI.PASCAL) + && targetUnits.isCompatible(SI.METER)) { + double inPa = srcUnits.getConverterTo(SI.PASCAL).convert(value); + double inM = mbToMeters(inPa / 100); + return SI.METER.getConverterTo(targetUnits).convert(inM); + } else if (srcUnits.isCompatible(SI.METER) + && targetUnits.isCompatible(SI.PASCAL)) { + double inM = srcUnits.getConverterTo(SI.METER).convert(value); + double inPa = metersToMb(inM) * 100; + return SI.PASCAL.getConverterTo(targetUnits).convert(inPa); + } else { + throw new ConversionException("Unable to find converter between " + + srcUnits + + " and " + targetUnits); + } + } + + /** + * Converts a vertical coordinate to the target units and reference point + * + * @param targetUnits + * @param targetRef + * @param vert + * @return + * @throws ConversionException + */ + public static VerticalCoordinate convert(Unit targetUnits, + Reference targetRef, VerticalCoordinate vert) + throws ConversionException { + if (targetUnits == null) { + return vert; + } + // FIXME handle reference + Unit srcUnits = vert.getUnits(); + if (targetUnits.equals(srcUnits)) { + return vert; + } + if (!vert.isRange()) { + return new VerticalCoordinate(convert(targetUnits, srcUnits, + vert.getValue()), targetUnits, targetRef); + } else { + return new VerticalCoordinate(convert(targetUnits, srcUnits, + vert.getMin()), convert(targetUnits, srcUnits, + vert.getMax()), targetUnits, targetRef); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/BoundingBoxUtil.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/BoundingBoxUtil.java new file mode 100644 index 0000000000..f6e8fc2297 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/BoundingBoxUtil.java @@ -0,0 +1,482 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; + +import javax.measure.unit.SI; +import javax.measure.unit.Unit; + +import net.opengis.gml.v_3_1_1.EnvelopeType; +import net.opengis.ows.v_1_1_0.BoundingBoxType; + +import org.geotools.geometry.DirectPosition2D; +import org.geotools.geometry.GeneralDirectPosition; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultCompoundCRS; +import org.opengis.geometry.DirectPosition; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.crs.GeographicCRS; +import org.opengis.referencing.crs.SingleCRS; +import org.opengis.referencing.cs.CoordinateSystem; +import org.opengis.referencing.cs.CoordinateSystemAxis; + +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.gml3_1_1.EnvelopeConverter; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; +import com.vividsolutions.jts.geom.Coordinate; + +/** + * Utilities for Bounding box parsing + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 16, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class BoundingBoxUtil { + + /** + * Split 3D envelope into composite parts + * + * @param env + * @return + * @throws OgcException + */ + public static Composite3DBoundingBox separate3DEnvelope(EnvelopeType env) + throws OgcException { + if (EnvelopeConverter.getDims(env) != 3) { + throw new OgcException(Code.InvalidParameterValue, + "3D bounding box requires 3 dimensions"); + } + if (!env.isSetSrsName()) { + throw new OgcException(Code.MissingParameterValue, + "Missing SRS name in bounding box"); + } + Coordinate[] coords = new EnvelopeConverter().getCoordinates(env); + GeneralDirectPosition min = new GeneralDirectPosition(new double[] { + coords[0].x, coords[0].y, coords[0].z }); + GeneralDirectPosition max = new GeneralDirectPosition(new double[] { + coords[1].x, coords[1].y, coords[1].z }); + + return separate3DEnvelope(min, max, env.getSrsName()); + } + + /** + * Split 3D envelope into composite parts + * + * @param env + * @return + * @throws OgcException + */ + public static Composite3DBoundingBox separate3DEnvelope( + net.opengis.gml.v_3_2_1.EnvelopeType env) throws OgcException { + if (com.raytheon.uf.edex.ogc.common.gml3_2_1.EnvelopeConverter + .getDims(env) != 3) { + throw new OgcException(Code.InvalidParameterValue, + "3D bounding box requires 3 dimensions"); + } + if (!env.isSetSrsName()) { + throw new OgcException(Code.MissingParameterValue, + "Missing SRS name in bounding box"); + } + Coordinate[] coords = new com.raytheon.uf.edex.ogc.common.gml3_2_1.EnvelopeConverter() + .getCoordinates(env); + GeneralDirectPosition min = new GeneralDirectPosition(new double[] { + coords[0].x, coords[0].y, coords[0].z }); + GeneralDirectPosition max = new GeneralDirectPosition(new double[] { + coords[1].x, coords[1].y, coords[1].z }); + + return separate3DEnvelope(min, max, env.getSrsName()); + } + + /** + * Split 3D envelope into composite parts + * + * @param bbox3d + * @return + * @throws OgcException + */ + public static Composite3DBoundingBox separate3DEnvelope( + BoundingBoxType bbox3d) throws OgcException { + List lc = bbox3d.getLowerCorner(); + List uc = bbox3d.getUpperCorner(); + if (lc.size() != 3 || uc.size() != 3) { + throw new OgcException(Code.InvalidParameterValue, + "3D bounding box requires 3 dimensions"); + } + DirectPosition min = convert(lc); + DirectPosition max = convert(uc); + if (!bbox3d.isSetCrs()) { + throw new OgcException(Code.MissingParameterValue, + "Missing SRS name in bounding box"); + } + return separate3DEnvelope(min, max, bbox3d.getCrs()); + } + + /** + * Convert list of doubles to a direct position + * + * @param coordinate + * @return + */ + public static DirectPosition convert(List coordinate) { + GeneralDirectPosition rval = new GeneralDirectPosition( + coordinate.size()); + Iterator iter = coordinate.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + rval.setOrdinate(i, iter.next()); + } + return rval; + } + + /** + * Split a 3d bounding box into composite parts + * + * @param min3d + * lower corner + * @param max3d + * upper corner + * @param crsName + * @return + * @throws OgcException + */ + public static Composite3DBoundingBox separate3DEnvelope( + DirectPosition min3d, DirectPosition max3d, String crsName) + throws OgcException { + check3dBounds(min3d, max3d); + Matcher m = CrsLookup.EXTENDED_3D_CRS_PATTERN.matcher(crsName); + String horizCrs; + Unit units; + Reference ref = Reference.UNKNOWN; + if (!m.matches()) { + String norm = CrsLookup.normalize(crsName); + if (!"epsg:4979".equalsIgnoreCase(norm)) { + return separate3DEnvelope(min3d, max3d, getCrs(crsName)); + } + horizCrs = "EPSG:4326"; + units = SI.METER; + ref = Reference.ABOVE_MSL; + } else { + horizCrs = m.group(1); + units = Unit.valueOf(m.group(2)); + if (m.group(4) != null) { + ref = Reference.fromAbbreviation(m.group(4).toUpperCase()); + } else { + // check if unit string matches reference level + ref = Reference.fromAbbreviation(m.group(2).toUpperCase()); + } + } + // TODO this assumes that Z is always the 3rd axis + DirectPosition2D min2d = new DirectPosition2D(min3d.getOrdinate(0), + min3d.getOrdinate(1)); + DirectPosition2D max2d = new DirectPosition2D(max3d.getOrdinate(0), + max3d.getOrdinate(1)); + ReferencedEnvelope horiz = convert2D(min2d, max2d, horizCrs); + VerticalCoordinate vert = new VerticalCoordinate(min3d.getOrdinate(2), + max3d.getOrdinate(2), units, ref); + return new Composite3DBoundingBox(horiz, vert); + } + + /** + * Split a 3d bounding box into composite parts + * + * @param min3d + * lower corner + * @param max3d + * upper corner + * @param crs3d + * @return + * @throws OgcException + */ + public static Composite3DBoundingBox separate3DEnvelope( + DirectPosition min3d, DirectPosition max3d, + CoordinateReferenceSystem crs3d) throws OgcException { + if (crs3d.getCoordinateSystem().getDimension() != 3) { + throw new OgcException(Code.InvalidCRS, "Expected 3D CRS"); + } + check3dBounds(min3d, max3d); + SingleCRS crs2d = CRS.getHorizontalCRS(crs3d); + DirectPosition2D min2d = new DirectPosition2D(); + DirectPosition2D max2d = new DirectPosition2D(); + double maxVert = 0; + double minVert = 0; + CoordinateSystem cs3d = crs3d.getCoordinateSystem(); + CoordinateSystem cs2d = crs2d.getCoordinateSystem(); + CoordinateSystemAxis vertAxis = null; + for (int i = 0; i < cs3d.getDimension(); ++i) { + CoordinateSystemAxis axis3d = cs3d.getAxis(i); + int j = 0; + for (; j < cs2d.getDimension(); ++j) { + CoordinateSystemAxis axis2d = cs2d.getAxis(j); + if (CRS.equalsIgnoreMetadata(axis3d, axis2d)) { + min2d.setOrdinate(j, min3d.getOrdinate(i)); + max2d.setOrdinate(j, max3d.getOrdinate(i)); + break; + } + } + if (j == cs2d.getDimension()) { + // axis didn't match 2d axis, assume vert axis + vertAxis = axis3d; + minVert = min3d.getOrdinate(i); + maxVert = max3d.getOrdinate(i); + } + } + ReferencedEnvelope ref; + // test 3d crs since authority info gets stripped + if (CrsLookup.isEpsgGeoCrs(crs3d)) { + // EPSG uses lat/lon, we use lon/lat + ref = new ReferencedEnvelope(min2d.y, max2d.y, min2d.x, max2d.x, + crs2d); + } else { + ref = new ReferencedEnvelope(min2d.x, max2d.x, + min2d.y, max2d.y, crs2d); + } + checkGeoBounds(ref); + VerticalCoordinate vert = new VerticalCoordinate(minVert, maxVert, + vertAxis.getUnit(), getReference(vertAxis)); + return new Composite3DBoundingBox(ref, vert); + } + + /** + * Ensure that if the envelope is lat/lon, it is in bounds + * + * @param env + * @throws OgcException + * if out of bounds + */ + private static void checkGeoBounds(ReferencedEnvelope env) + throws OgcException { + if (env.getCoordinateReferenceSystem() instanceof GeographicCRS) { + if (env.getMinX() < -180 || env.getMaxX() > 180 + || env.getMinY() < -90 || env.getMaxY() > 90) { + throw new OgcException(Code.InvalidParameterValue, + "Geo bounds not in range. Check axis order"); + } + } + } + + /** + * Ensure that the bounds are of the correct dimension and order + * + * @param min2d + * @param max2d + * @throws OgcException + */ + private static void check2dBounds(DirectPosition min2d, DirectPosition max2d) + throws OgcException { + checkBounds(min2d, max2d, 2); + } + + /** + * Ensure that the bounds are of the correct dimension and order + * + * @param min3d + * @param max3d + * @throws OgcException + */ + private static void check3dBounds(DirectPosition min3d, DirectPosition max3d) + throws OgcException { + checkBounds(min3d, max3d, 3); + } + + /** + * Ensure that the bounds are of the correct dimension and order + * + * @param min + * @param max + * @param dims + * @throws OgcException + */ + private static void checkBounds(DirectPosition min, DirectPosition max, + int dims) throws OgcException { + if (min.getDimension() != dims || max.getDimension() != dims) { + String msg = String.format( + "%dD bounding box must have %d dimensions", dims, dims); + throw new OgcException(Code.InvalidParameterValue, msg); + } + for (int i = 0; i < dims; ++i) { + if (min.getOrdinate(i) > max.getOrdinate(i)) { + throw new OgcException(Code.InvalidParameterValue, + "Minimum coordinate cannot be larger than maximum coordinate"); + } + } + } + + /** + * Convert a 2d bounding box with crs to a referenced envelope + * + * @param min2d + * @param max2d + * @param crsName + * @return + * @throws OgcException + */ + public static ReferencedEnvelope convert2D(DirectPosition min2d, + DirectPosition max2d, String crsName) throws OgcException { + CoordinateReferenceSystem crs = getCrs(crsName); + if (crs instanceof DefaultCompoundCRS) { + throw new OgcException(Code.InvalidCRS, + "Cannot use 3D CRS with 2D bounds"); + } + check2dBounds(min2d, max2d); + double minx; + double miny; + double maxx; + double maxy; + if (CrsLookup.isEpsgGeoCrs(crs)) { + // EPSG uses lat/lon, we use lon/lat + minx = min2d.getOrdinate(1); + maxx = max2d.getOrdinate(1); + miny = min2d.getOrdinate(0); + maxy = max2d.getOrdinate(0); + } else { + minx = min2d.getOrdinate(0); + maxx = max2d.getOrdinate(0); + miny = min2d.getOrdinate(1); + maxy = max2d.getOrdinate(1); + } + ReferencedEnvelope rval = new ReferencedEnvelope(minx, maxx, miny, + maxy, crs); + checkGeoBounds(rval); + return rval; + } + + /** + * Convert 2d jaxb envelope to JTS envelope + * + * @param env + * @return + * @throws OgcException + */ + public static ReferencedEnvelope convert2D(EnvelopeType env) + throws OgcException { + if (EnvelopeConverter.getDims(env) != 2) { + throw new OgcException(Code.InvalidParameterValue, + "2D bounding box must have 2 dimensions"); + } + if (!env.isSetSrsName()) { + throw new OgcException(Code.MissingParameterValue, + "Missing SRS name in bounding box"); + } + Coordinate[] coords = new EnvelopeConverter().getCoordinates(env); + DirectPosition2D min = new DirectPosition2D(coords[0].x, coords[0].y); + DirectPosition2D max = new DirectPosition2D(coords[1].x, coords[1].y); + return convert2D(min, max, env.getSrsName()); + } + + /** + * Convert 2d jaxb envelope to JTS envelope + * + * @param env + * @return + * @throws OgcException + */ + public static ReferencedEnvelope convert2D( + net.opengis.gml.v_3_2_1.EnvelopeType env) throws OgcException { + if (com.raytheon.uf.edex.ogc.common.gml3_2_1.EnvelopeConverter + .getDims(env) != 2) { + throw new OgcException(Code.InvalidParameterValue, + "2D bounding box must have 2 dimensions"); + } + if (!env.isSetSrsName()) { + throw new OgcException(Code.MissingParameterValue, + "Missing SRS name in bounding box"); + } + Coordinate[] coords = new com.raytheon.uf.edex.ogc.common.gml3_2_1.EnvelopeConverter() + .getCoordinates(env); + DirectPosition2D min = new DirectPosition2D(coords[0].x, coords[0].y); + DirectPosition2D max = new DirectPosition2D(coords[1].x, coords[1].y); + return convert2D(min, max, env.getSrsName()); + } + + /** + * Convert 2d jaxb bounding box to JTS envelope + * + * @param bbox2d + * @return + * @throws OgcException + */ + public static ReferencedEnvelope convert2D(BoundingBoxType bbox2d) + throws OgcException { + List lc = bbox2d.getLowerCorner(); + List uc = bbox2d.getUpperCorner(); + if (lc.size() != 2 || uc.size() != 2) { + throw new OgcException(Code.InvalidParameterValue, + "2D bounding box must have 2 dimensions"); + } + if (!bbox2d.isSetCrs()) { + throw new OgcException(Code.MissingParameterValue, + "Missing SRS name in bounding box"); + } + DirectPosition min = convert(lc); + DirectPosition max = convert(uc); + return convert2D(min, max, bbox2d.getCrs()); + } + + /** + * Determine altitude reference of vertical axis + * + * @param verticalAxis + * @return + * @throws OgcException + */ + public static VerticalCoordinate.Reference getReference( + CoordinateSystemAxis verticalAxis) throws OgcException { + String code = verticalAxis.getName().getCode().toLowerCase(); + if ( code.contains("ellipsoid")){ + return VerticalCoordinate.Reference.ABOVE_ELLIPSOID; + } else if (code.contains("gravity") || code.contains("geoid")) { + return VerticalCoordinate.Reference.ABOVE_MSL; + } else if (code.contains("barometric")) { + return VerticalCoordinate.Reference.PRESSURE_LEVEL; + } else if(code.contains("flight")){ + return VerticalCoordinate.Reference.FLIGHT_LEVEL; + } else if (code.contains("ground")){ + return VerticalCoordinate.Reference.ABOVE_GROUND; + } + throw new OgcException(Code.InvalidCRS, "Unable to parse vertical CRS"); + } + + + /** + * Parse CRS String to object + * + * @param srs + * @return + * @throws OgcException + */ + public static CoordinateReferenceSystem getCrs(String srs) + throws OgcException { + try { + CoordinateReferenceSystem rval = CrsLookup.lookup(srs); + if (rval == null) { + throw new Exception(); + } + return rval; + } catch (Exception e) { + throw new OgcException(Code.InvalidParameterValue, "Unknown SRS: " + + srs); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/Composite3DBoundingBox.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/Composite3DBoundingBox.java new file mode 100644 index 0000000000..4ba0018560 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/Composite3DBoundingBox.java @@ -0,0 +1,112 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import org.geotools.geometry.jts.ReferencedEnvelope; + + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 16, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class Composite3DBoundingBox { + + private final ReferencedEnvelope horizontal; + + private final String native2DCrsUrn; + + private final VerticalCoordinate vertical; + + /** + * @param horizontal + */ + public Composite3DBoundingBox(ReferencedEnvelope horizontal) { + this(horizontal, null, null); + } + + /** + * @param horizontal + * @param native2DCrsUrn + */ + public Composite3DBoundingBox(ReferencedEnvelope horizontal, + String native2DCrsUrn) { + this(horizontal, native2DCrsUrn, null); + } + + /** + * @param horizontal + * @param vertical + */ + public Composite3DBoundingBox(ReferencedEnvelope horizontal, + VerticalCoordinate vertical) { + this(horizontal, null, vertical); + } + + + /** + * @param horizontal + * @param native2DCrsUrn + * @param vertical + */ + public Composite3DBoundingBox(ReferencedEnvelope horizontal, + String native2DCrsUrn, VerticalCoordinate vertical) { + this.horizontal = horizontal; + this.native2DCrsUrn = native2DCrsUrn; + this.vertical = vertical; + } + + /** + * @return the horizontal bbox + */ + public ReferencedEnvelope getHorizontal() { + return horizontal; + } + + /** + * @return the vertical + */ + public VerticalCoordinate getVertical() { + return vertical; + } + + /** + * @return the native2DCrsUrn + */ + public String getNative2DCrsUrn() { + return native2DCrsUrn; + } + + /** + * @return true if bounding box has vertical component + */ + public boolean hasVertical() { + return vertical != null; + } + + /** + * @return true if horizontal CRS has a native URN + */ + public boolean hasNative2DCrs() { + return native2DCrsUrn != null; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/CoordinateUtil.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/CoordinateUtil.java new file mode 100644 index 0000000000..10a520c481 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/CoordinateUtil.java @@ -0,0 +1,80 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 16, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoordinateUtil { + + private static final Pattern COORD_PATTERN = Pattern.compile( + "[-+]?[0-9]*\\.?[0-9]+(\\s*,\\s*[-+]?[0-9]*\\.?[0-9]+)*", + Pattern.MULTILINE); + + /** + * Parses a formatted string that has space separated coordinates where the + * coordinate values are comma separated. e.g (1,2 3,4) + * + * @param str + * @return + * @throws ParseException + */ + public static List parseCoordinates(String str) + throws ParseException { + List rval = new ArrayList(); + Matcher m = COORD_PATTERN.matcher(str); + if (!m.find()) { + throw new ParseException("Invalid coordinates string: " + str, 0); + } + String[] values = StringUtils.split(m.group(0), ", \t\n"); + int dims = values.length; + do { + values = StringUtils.split(m.group(0), ", \t\n"); + if (values.length != dims) { + throw new ParseException("Inconsistent dimension count: " + + m.group(0), m.start(0)); + } + Double[] nums = new Double[dims]; + for (int i = 0; i < dims; ++i) { + try { + nums[i] = Double.parseDouble(values[i]); + } catch (Exception e) { + throw new ParseException( + "Unable to parse coordinate value: " + values[i], + m.start(0)); + } + } + rval.add(nums); + } while (m.find()); + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/CrsLookup.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/CrsLookup.java index 98d2d27408..7fc12e5cc4 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/CrsLookup.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/CrsLookup.java @@ -30,13 +30,29 @@ */ package com.raytheon.uf.edex.ogc.common.spatial; +import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.measure.quantity.Quantity; +import javax.measure.unit.Unit; + import org.apache.commons.collections.map.LRUMap; +import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultCompoundCRS; +import org.geotools.referencing.crs.DefaultVerticalCRS; +import org.geotools.referencing.cs.DefaultCoordinateSystemAxis; +import org.geotools.referencing.cs.DefaultVerticalCS; +import org.geotools.referencing.datum.DefaultVerticalDatum; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; +import org.opengis.referencing.ReferenceIdentifier; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.crs.GeographicCRS; +import org.opengis.referencing.cs.AxisDirection; + +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; /** * TODO Add Description @@ -75,25 +91,101 @@ public class CrsLookup { protected static final Pattern OGC_CODE_PATTERN = Pattern .compile("^([a-zA-Z]+)([0-9]+)$"); + public static final Pattern EXTENDED_3D_CRS_PATTERN = Pattern.compile( + "(urn.*)_plus_z_in_([^_]+)(_([^_]+))?", Pattern.CASE_INSENSITIVE); + + /** + * Lookup coordinate reference system object from OGC URN or Code + * + * @param crs + * @return + * @throws NoSuchAuthorityCodeException + * @throws FactoryException + * @throws OgcException + */ public static CoordinateReferenceSystem lookup(String crs) - throws NoSuchAuthorityCodeException, FactoryException { + throws NoSuchAuthorityCodeException, FactoryException, OgcException { if (crs == null) { return null; } - crs = normalize(crs); - CoordinateReferenceSystem rval; - synchronized (cache) { - rval = (CoordinateReferenceSystem) cache.get(crs); - if (rval == null) { - rval = decodeCrs(crs); - if (rval != null) { - cache.put(crs, rval); - } - } - } - return rval; + Matcher m = EXTENDED_3D_CRS_PATTERN.matcher(crs); + if (m.matches()) { + return decodeExtended3D(m); + } + return lookupFromCache(crs); } + /** + * Parse extended CRS string that has matched + * {@link CrsLookup#EXTENDED_3D_CRS_PATTERN} + * + * @param m + * @return + * @throws NoSuchAuthorityCodeException + * @throws FactoryException + * @throws OgcException + */ + protected static CoordinateReferenceSystem decodeExtended3D(Matcher m) + throws NoSuchAuthorityCodeException, FactoryException, OgcException { + String base2dName = m.group(1); + CoordinateReferenceSystem base2d = lookupFromCache(base2dName); + Unit units = Unit.valueOf(m.group(2)); + Reference ref = Reference.UNKNOWN; + if (m.group(4) != null) { + ref = Reference.fromAbbreviation(m.group(4).toUpperCase()); + } else { + // check if unit string matches reference level + ref = Reference.fromAbbreviation(m.group(2).toUpperCase()); + } + AxisDirection dir = ref.equals(Reference.PRESSURE_LEVEL) ? AxisDirection.DOWN + : AxisDirection.UP; + DefaultCoordinateSystemAxis axis = new DefaultCoordinateSystemAxis( + ref.longName, dir, units); + DefaultVerticalCS cs = new DefaultVerticalCS(axis); + DefaultVerticalDatum datum = new DefaultVerticalDatum(ref.longName, + DefaultVerticalDatum + .getVerticalDatumTypeFromLegacyCode(ref.datumType)); + DefaultVerticalCRS vertCrs = new DefaultVerticalCRS(ref.longName, + datum, cs); + return new DefaultCompoundCRS(m.group(0), base2d, vertCrs); + } + + /** + * Lookup coordinate reference system object from OGC URN or Code + * + * @param crs + * @return + * @throws NoSuchAuthorityCodeException + * @throws FactoryException + * @throws OgcException + */ + protected static CoordinateReferenceSystem lookupFromCache(String crs) + throws NoSuchAuthorityCodeException, FactoryException, OgcException { + if (crs.startsWith(NativeCrsAuthority.NATIVE_CRS_PREFIX)) { + return NativeCrsFactory.lookup(crs); + } + crs = normalize(crs); + CoordinateReferenceSystem rval; + synchronized (cache) { + rval = (CoordinateReferenceSystem) cache.get(crs); + if (rval == null) { + rval = decodeCrs(crs); + if (rval != null) { + cache.put(crs, rval); + } + } + } + return rval; + } + + /** + * Lookup coordinate reference system object from Code + * + * @param crs + * @return + * @throws NoSuchAuthorityCodeException + * @throws FactoryException + */ protected static CoordinateReferenceSystem decodeCrs(String crs) throws NoSuchAuthorityCodeException, FactoryException { if (crs.equalsIgnoreCase("epsg:900913") @@ -103,6 +195,12 @@ public class CrsLookup { return CRS.decode(crs, true); } + /** + * Construct google crs, caches result. Can be called multiple times. + * + * @return + * @throws FactoryException + */ protected static CoordinateReferenceSystem getGoogleCrs() throws FactoryException { if (googleCrs == null) { @@ -111,7 +209,16 @@ public class CrsLookup { return googleCrs; } - protected static String normalize(String crs) { + /** + * Normalize OGC URNs and Codes to be code in the following format + *
+     * [auth]:[code]
+     * 
+ * + * @param crs + * @return + */ + protected static String normalize(String crs) { String[] parts = crs.split(":"); String rval; if (parts.length == 2) { @@ -130,6 +237,63 @@ public class CrsLookup { return rval.toLowerCase(); } + /** + * Construct an Extended OGC CRS URN from the composite bounds + * + * @param bbox + * @return + */ + public static String createCrsURN(Composite3DBoundingBox bbox) { + ReferencedEnvelope horiz = bbox.getHorizontal(); + String rval; + if (bbox.hasNative2DCrs()) { + rval = bbox.getNative2DCrsUrn(); + } else { + rval = createCrsURN(horiz.getCoordinateReferenceSystem()); + } + if (bbox.hasVertical()) { + VerticalCoordinate vert = bbox.getVertical(); + StringBuilder sb = new StringBuilder(rval); + sb.append("_plus_Z_in_"); + sb.append(vert.getUnits().toString()); + Reference ref = vert.getRef(); + if (!ref.equals(Reference.UNKNOWN)) { + sb.append("_").append(ref.abbreviation); + } + rval = sb.toString(); + } + return rval; + } + + /** + * Create an OGC CRS URN from the crs object + * + * @param crs + * @return + */ + protected static String createCrsURN(CoordinateReferenceSystem crs) { + ReferenceIdentifier id = crs.getIdentifiers().iterator().next(); + return String.format("urn:ogc:def:crs:%s::%s", id.getCodeSpace(), + id.getCode()); + } + + /** + * Return true if urn matches Extended CRS pattern + * + * @param urn + * @return + */ + public static boolean isExtended3dCRS(String urn) { + return EXTENDED_3D_CRS_PATTERN.matcher(urn).matches(); + } + + /** + * Construct a crs code from authority and code + * + * @param authority + * @param code + * @return + */ protected static String constructCode(String authority, String code) { if (!authority.equalsIgnoreCase("epsg") && !authority.equalsIgnoreCase("crs")) { @@ -140,4 +304,18 @@ public class CrsLookup { return authority + ":" + code; } + /** + * @param crs + * @return true if crs has EPSG as the authority and is a geographic crs + */ + public static boolean isEpsgGeoCrs(CoordinateReferenceSystem crs) { + try { + String auth = crs.getName().getCodeSpace(); + return "epsg".equalsIgnoreCase(auth) + && crs instanceof GeographicCRS; + } catch (NullPointerException e) { + return false; + } + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/NativeCrsAuthority.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/NativeCrsAuthority.java new file mode 100644 index 0000000000..31d94de135 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/NativeCrsAuthority.java @@ -0,0 +1,42 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.plugin.dataset.urn.URNLookup; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 6, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface NativeCrsAuthority { + + public static final String NATIVE_CRS_PREFIX = URNLookup.WXSRV_URN_PREFIX + + "crs:"; + + public CoordinateReferenceSystem lookup(String URN) throws OgcException; + + public String getId(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/NativeCrsFactory.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/NativeCrsFactory.java new file mode 100644 index 0000000000..917c808844 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/NativeCrsFactory.java @@ -0,0 +1,105 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections.map.LRUMap; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.springframework.context.ApplicationContext; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.core.EDEXUtil; +import com.raytheon.uf.edex.ogc.common.OgcException; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 6, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class NativeCrsFactory { + + @SuppressWarnings("unchecked") + private static final Map cache = Collections + .synchronizedMap(new LRUMap(5)); + + private static Map auths = null; + + private static final IUFStatusHandler log = UFStatus + .getHandler(NativeCrsAuthority.class); + + static { + new Thread(new Runnable() { + @Override + public void run() { + while (!EDEXUtil.isRunning()) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + } + } + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx + .getBeanNamesForType(NativeCrsAuthority.class); + auths = new HashMap(beans.length); + for (String bean : beans) { + NativeCrsAuthority nca = (NativeCrsAuthority) ctx + .getBean(bean); + auths.put(nca.getId(), nca); + } + } + }).run(); + } + + /** + * Lookup native CRS using URN + * + * @param urn + * @return null if not found + * @throws OgcException + */ + public static CoordinateReferenceSystem lookup(String urn) + throws OgcException { + CoordinateReferenceSystem rval = cache.get(urn); + if (rval != null) { + return rval; + } + if (auths == null) { + log.error("Attempted to lookup CRS before initialized", + new Exception()); + return null; + } + + for (Entry e : auths.entrySet()) { + NativeCrsAuthority auth = e.getValue(); + rval = auth.lookup(urn); + if (rval != null) { + cache.put(urn, rval); + return rval; + } + } + return null; + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/RecordUtil.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/RecordUtil.java index 5bcfe79fa1..b60636af62 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/RecordUtil.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/RecordUtil.java @@ -153,11 +153,11 @@ public class RecordUtil { nativeEnvelope, envelope); } - protected static DataReprojector getDataReprojector(IDataStore dataStore) { + public static DataReprojector getDataReprojector(IDataStore dataStore) { return new DataReprojector(dataStore); } - protected static ReferencedEnvelope getNativeEnvelope(ISpatialObject spatial) + public static ReferencedEnvelope getNativeEnvelope(ISpatialObject spatial) throws FactoryException { CoordinateReferenceSystem crs = spatial.getCrs(); Geometry geom = spatial.getGeometry(); diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalCoordinate.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalCoordinate.java new file mode 100644 index 0000000000..0e909dcf69 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalCoordinate.java @@ -0,0 +1,205 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.measure.quantity.Length; +import javax.measure.unit.NonSI; +import javax.measure.unit.SI; +import javax.measure.unit.Unit; +import javax.measure.unit.UnitFormat; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 23, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class VerticalCoordinate implements Comparable { + + public static final Unit FLIGHT_LEVEL_UNIT = SI.HECTO(NonSI.FOOT); + + static { + UnitFormat.getInstance().alias(FLIGHT_LEVEL_UNIT, "FL"); + UnitFormat.getInstance().label(FLIGHT_LEVEL_UNIT, "FL"); + } + + public static enum Reference { + ABOVE_GROUND("AGL", 2000, "height above ground"), ABOVE_MSL("AMSL", + 2005, "gravity-related height"), ABOVE_ELLIPSOID("AEH", 2002, + "ellipsoidal height"), PRESSURE_LEVEL("PL", 2003, + "barometric altitude"), FLIGHT_LEVEL("FL", 2003, "flight level"), UNKNOWN( + "", 2000, "unkown"); + + private static final Map ABB_MAP; + + static { + Map map = new HashMap( + Reference.values().length); + for (Reference r : Reference.values()) { + map.put(r.abbreviation, r); + } + ABB_MAP = Collections.unmodifiableMap(map); + } + + public static Reference fromAbbreviation(String abb) { + Reference rval = ABB_MAP.get(abb); + if ( rval == null){ + rval = Reference.UNKNOWN; + } + return rval; + } + + public final String abbreviation; + + public final int datumType; + + public final String longName; + + private Reference(String abb, int datum, String longName) { + this.abbreviation = abb; + this.datumType = datum; + this.longName = longName; + } + }; + + private final double min; + + private final double max; + + private final Unit units; + + private final Reference ref; + + private final boolean range; + + private VerticalCoordinate(double min, double max, Unit units, + Reference ref, boolean isRange) { + this.min = min; + this.max = max; + this.units = units; + this.ref = ref; + this.range = isRange; + } + + public VerticalCoordinate(double min, double max, Unit units, + Reference ref) { + this(min, max, units, ref, true); + } + + public VerticalCoordinate(double min, double max, Unit units) { + this(min, max, units, Reference.ABOVE_MSL); + } + + public VerticalCoordinate(double value, Unit units, Reference ref) { + this(value, value, units, ref, false); + } + + public VerticalCoordinate(double value, Unit units) { + this(value, units, Reference.ABOVE_MSL); + } + + public double getValue() { + return min; + } + + /** + * @return the min + */ + public double getMin() { + return min; + } + + /** + * @return the max + */ + public double getMax() { + return max; + } + + /** + * @return the units + */ + public Unit getUnits() { + return units; + } + + /** + * @return the ref + */ + public Reference getRef() { + return ref; + } + + /** + * @return the range + */ + public boolean isRange() { + return range; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(VerticalCoordinate o) { + if (o == null) { + return 1; + } + byte state = 0x00; + if (this.range) { + state |= 0x01; + } + if (o.range) { + state |= 0x02; + } + switch (state) { + case 0: + // both single value + return Double.compare(this.min, o.min); + case 1:// this range, other single + case 3:// both range + if (this.min > o.max) { + return 1; + } + if (this.max < o.min) { + return -1; + } + return 0; + case 2: + // this single, other range + if (this.min > o.max) { + return 1; + } + if (this.min < o.min) { + return -1; + } + return 0; + } + + return 0; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalEnabled.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalEnabled.java new file mode 100644 index 0000000000..e69f98e54a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalEnabled.java @@ -0,0 +1,41 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +/** + * Adapter for vertical spatial information + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 23, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface VerticalEnabled { + + /** + * @param obj + * @return null if object has no vertical information + */ + public VerticalCoordinate getVerticalCoordinate(T obj); + + /** + * @return class supported by enabler + */ + public Class getSupportedClass(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalSpatialFactory.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalSpatialFactory.java new file mode 100644 index 0000000000..f37a002326 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/spatial/VerticalSpatialFactory.java @@ -0,0 +1,92 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.spatial; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.context.ApplicationContext; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.core.EDEXUtil; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 29, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class VerticalSpatialFactory { + + private static Map, VerticalEnabled> REGISTRY = null; + + private static final IUFStatusHandler log = UFStatus + .getHandler(VerticalSpatialFactory.class); + + private static final class Init implements Runnable { + @Override + public void run() { + while (!EDEXUtil.isRunning()) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + } + } + try { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx.getBeanNamesForType(VerticalEnabled.class); + HashMap, VerticalEnabled> map = new HashMap, VerticalEnabled>( + beans.length); + for (String bean : beans) { + VerticalEnabled ve = (VerticalEnabled) ctx + .getBean(bean); + map.put(ve.getSupportedClass(), ve); + } + REGISTRY = Collections.unmodifiableMap(map); + } catch (Throwable e) { + log.error("Unable to init " + VerticalSpatialFactory.class, e); + } + } + } + + static { + new Thread(new Init()).start(); + } + + /** + * @param c + * @return null if factory isn't initialized or no vertical enabled found + * for c + */ + @SuppressWarnings("unchecked") + public static VerticalEnabled getEnabled(Class c) { + if (REGISTRY == null) { + return null; + } + return (VerticalEnabled) REGISTRY.get(c); + } + + public static boolean isInitialized() { + return REGISTRY != null; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/NoopStatsRecorder.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/NoopStatsRecorder.java new file mode 100644 index 0000000000..aca0ad60e7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/NoopStatsRecorder.java @@ -0,0 +1,79 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.stats; + + +/** + * Lightweight placeholder stats object, does not record stats + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 25, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class NoopStatsRecorder implements OgcStatsRecorder { + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.OgcStatsRecorder#recordRequest(long, + * long, java.lang.String, boolean) + */ + @Override + public void recordRequest(long time, long duration, String service, + boolean success) { + // do nothing + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.OgcStatsRecorder#getMinRequestTime(java + * .lang.String) + */ + @Override + public long getMinRequestTime(String service) { + return 0; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.OgcStatsRecorder#getMaxRequestTime(java + * .lang.String) + */ + @Override + public long getMaxRequestTime(String service) { + return 0; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.OgcStatsRecorder#getAvgRequestTime(java + * .lang.String) + */ + @Override + public long getAvgRequestTime(String service) { + return 0; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/OgcStatsRecorder.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/OgcStatsRecorder.java new file mode 100644 index 0000000000..ce5929ab28 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/OgcStatsRecorder.java @@ -0,0 +1,72 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.stats; + + + +/** + * interface for recording ogc service stats + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 25, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface OgcStatsRecorder { + + /** + * Records the request that was made with some basic raw information about + * it. + * + * @param time + * time of observation in milliseconds + * @param duration + * duration of request in nanoseconds + * @param service + * Id for service + * @param success + * indicates if the request being timed was successful + */ + public void recordRequest(long time, long duration, String service, + boolean success); + + /** + * Retrieve statistic about service + * + * @param service + * @return + */ + public long getMinRequestTime(String service); + + /** + * Retrieve statistic about service + * + * @param service + * @return + */ + public long getMaxRequestTime(String service); + + /** + * Retrieve statistic about service + * + * @param service + * @return + */ + public long getAvgRequestTime(String service); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/StatsRecorderFinder.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/StatsRecorderFinder.java new file mode 100644 index 0000000000..abfaa08a35 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/stats/StatsRecorderFinder.java @@ -0,0 +1,62 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.stats; + +import org.springframework.context.ApplicationContext; + +import com.raytheon.uf.edex.core.EDEXUtil; + +/** + * Retrieves stats recorder for system + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 25, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class StatsRecorderFinder { + + private static volatile OgcStatsRecorder recorder = null; + + private static final Object recorderMutex = new Object(); + + /** + * Find stats recorder, defaults to no-op service if none found + * + * @return + */ + public static OgcStatsRecorder find() { + if (recorder == null) { + synchronized (recorderMutex) { + if (recorder == null) { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx + .getBeanNamesForType(OgcStatsRecorder.class); + if (beans.length == 0) { + recorder = new NoopStatsRecorder(); + } else { + recorder = (OgcStatsRecorder) ctx.getBean(beans[0]); + } + } + } + } + + return recorder; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/time/ForecastTimeUtil.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/time/ForecastTimeUtil.java index 4d63c18461..0a2c629bfc 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/time/ForecastTimeUtil.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/time/ForecastTimeUtil.java @@ -43,9 +43,8 @@ import java.util.regex.Pattern; import javax.xml.bind.DatatypeConverter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcException.Code; @@ -67,7 +66,23 @@ public class ForecastTimeUtil { protected Pattern fcstPattern = Pattern .compile("^([0-9]+)([sSmMhHdD]?).*$"); - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + public static final byte NONE = 0x00; + + public static final byte VALID = 0x01; + + public static final byte FCST = 0x02; + + public static final byte FCST_VALID = 0x03; + + public static final byte REF = 0x04; + + public static final byte REF_VALID = 0x05; + + public static final byte REF_FCST = 0x06; + + public static final byte REF_FCST_VALID = 0x07; /** * Gets a list of datatimes for specified layer. If dimensions has values @@ -79,10 +94,11 @@ public class ForecastTimeUtil { * @return * @throws WmsException */ - public SortedSet getDataTimes(SimpleLayer layer, - Map dimensions) throws OgcException { - return getDataTimes(layer, (String) null, dimensions); - } + public SortedSet getDataTimes( + SimpleLayer layer, + Map dimensions) throws OgcException { + return getDataTimes(layer, (String) null, dimensions); + } /** * Gets a list of datatimes for specified layer. If dimensions has values @@ -96,38 +112,92 @@ public class ForecastTimeUtil { * @return * @throws WmsException */ - public SortedSet getDataTimes(SimpleLayer layer, String time, + public SortedSet getDataTimes( + SimpleLayer layer, String time, Map dimensions) throws OgcException { - Calendar validTime = getValidTime(layer, time); - return getDataTimes(layer, validTime, dimensions); - } - - public SortedSet getDataTimes(SimpleLayer layer, Date time, - Map dimensions) throws OgcException { - Calendar validTime; - if (time == null) { - validTime = getValidTime(layer, null); - } else { - validTime = Calendar.getInstance(TimeZone.getTimeZone("GMT")); - validTime.setTime(time); + Calendar validTime = null; + if (time != null) { + validTime = getValidTime(layer, time); } return getDataTimes(layer, validTime, dimensions); } - protected SortedSet getDataTimes(SimpleLayer layer, - Calendar time, - Map dimensions) throws OgcException { - String refStr = dimensions.get(refKey); - String fcstStr = dimensions.get(fcstKey); + public SortedSet getDataTimes( + SimpleLayer layer, Date time, + Map dimensions) throws OgcException { + Calendar validTime = null; + if (time != null) { + validTime = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + validTime.setTime(time); + } + return getDataTimes(layer, validTime, dimensions); + } + + protected SortedSet getDataTimes( + SimpleLayer layer, Calendar time, + Map dimensions) throws OgcException { + String refStr = dimensions.get(refKey); + String fcstStr = dimensions.get(fcstKey); SortedSet rval = new TreeSet(); - if (fcstStr != null && refStr != null) { - rval.add(getDataTime(refStr, fcstStr, time)); - } else if (fcstStr != null) { - rval.add(getDataTimeFcst(fcstStr, time)); - } else if (refStr != null) { - rval.add(getDataTimeRef(refStr, time)); - } else { + byte state = getState(time, refStr, fcstStr); + switch (state) { + case NONE: + time = getValidTime(layer, null); + case VALID: rval = getCandidates(layer, time); + break; + case REF_FCST_VALID: + rval.add(getDataTime(refStr, fcstStr, time)); + break; + case FCST_VALID: + rval.add(getDataTimeFcst(fcstStr, time)); + break; + case REF_VALID: + rval.add(getDataTimeRef(refStr, time)); + break; + case REF: + rval.add(getDataTimeRef(refStr, layer)); + break; + case FCST: + rval.add(getDataTimeFcst(fcstStr, layer)); + break; + case REF_FCST: + rval.add(getDataTime(refStr, fcstStr, null)); + break; + } + return rval; + } + + /** + * @param fcstStr + * @param layer + * @return + * @throws OgcException + */ + protected DataTime getDataTimeFcst(String fcstStr, + SimpleLayer layer) + throws OgcException { + int fcst = parseForcast(fcstStr); + SimpleDimension refDim = layer.getDimension(refKey); + Set refTimes = refDim.getValues(); + SortedSet refEpochTimes = new TreeSet(); + for (String ref : refTimes) { + Date d = parseTimeString(ref).getTime(); + refEpochTimes.add(d.getTime()); + } + SortedSet validTimes = layer.getTimes(); + DataTime rval = null; + for (Date valid : validTimes) { + long ref = valid.getTime() - (fcst * 1000); + Date refTime = new Date(ref); + if (refEpochTimes.contains(refTime.getTime())) { + rval = new DataTime(refTime, fcst); + break; + } + } + if (rval == null) { + throw new OgcException(Code.InvalidDimensionValue, + "No valid times match forecast offset: " + fcstStr); } return rval; } @@ -140,11 +210,12 @@ public class ForecastTimeUtil { * @return * @throws WmsException */ - protected SimpleDimension getDimension(SimpleLayer layer, String dimension) - throws OgcException { - SimpleDimension dim; + protected SimpleDimension getDimension( + SimpleLayer layer, String dimension) + throws OgcException { + SimpleDimension dim; try { - dim = LayerTransformer.getDimension(layer, dimension); + dim = layer.getDimension(dimension); if (dim == null) { // UNLIKELY: must have been the dimension log.error("layer: " + layer + " missing dimension: " @@ -172,8 +243,9 @@ public class ForecastTimeUtil { * @return * @throws WmsException */ - protected SortedSet getCandidates(SimpleLayer layer, - Calendar validTime) throws OgcException { + protected SortedSet getCandidates( + SimpleLayer layer, Calendar validTime) + throws OgcException { SimpleDimension refDim = getDimension(layer, refKey); SimpleDimension fcstDim = getDimension(layer, fcstKey); TreeSet fcsts = LayerTransformer.getDimValuesAsDouble(fcstDim); @@ -245,6 +317,36 @@ public class ForecastTimeUtil { return new DataTime(ref, (int) (diff / 1000)); } + /** + * Creates datatime using only refTime + * + * @param refStr + * @return valid datatime with lowest forecast offset + * @throws WmsException + */ + protected DataTime getDataTimeRef(String refStr, + SimpleLayer layer) throws OgcException { + Calendar ref = parseTimeStr(refStr, refKey); + SimpleDimension fcstDim = layer.getDimension(fcstKey); + TreeSet offsets = LayerTransformer.getDimValuesAsDouble(fcstDim); + SortedSet validTimes = layer.getTimes(); + DataTime rval = null; + for ( Double offset : offsets){ + int fcstTime = ( offset.intValue() * 1000); + long refPlusOffset = ref.getTimeInMillis() + fcstTime ; + Date d = new Date(refPlusOffset); + if ( validTimes.contains(d)){ + rval = new DataTime(ref, offset.intValue()); + break; + } + } + if (rval == null) { + throw new OgcException(Code.InvalidDimensionValue, + "No valid times match refTime: " + ref); + } + return rval; + } + /** * Parses time string with error handling. * @@ -329,11 +431,13 @@ public class ForecastTimeUtil { Calendar validTime) throws OgcException { Calendar ref = parseTimeStr(refStr, refKey); int fcst = parseForcast(fcstStr); - long diff = validTime.getTimeInMillis() - ref.getTimeInMillis(); - if (diff != (fcst * 1000)) { - String msg = String.format("%s and time must differ by %s", refKey, - fcstKey); - throw new OgcException(Code.InvalidDimensionValue, msg); + if (validTime != null) { + long diff = validTime.getTimeInMillis() - ref.getTimeInMillis(); + if (diff != (fcst * 1000)) { + String msg = String.format("%s and time must differ by %s", + refKey, fcstKey); + throw new OgcException(Code.InvalidDimensionValue, msg); + } } return new DataTime(ref, fcst); } @@ -347,8 +451,9 @@ public class ForecastTimeUtil { * @return * @throws WmsException */ - protected Calendar getValidTime(SimpleLayer layer, String time) - throws OgcException { + protected Calendar getValidTime( + SimpleLayer layer, String time) + throws OgcException { Calendar rval; if (time == null) { try { @@ -368,4 +473,19 @@ public class ForecastTimeUtil { } return rval; } + + protected static byte getState(Calendar validTime, String refTime, + String fcstOffset) { + byte rval = 0; + if (refTime != null) { + rval |= 0x04; + } + if (fcstOffset != null) { + rval |= 0x02; + } + if (validTime != null) { + rval |= 0x01; + } + return rval; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/AddonPropsPostProcessor.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/AddonPropsPostProcessor.java new file mode 100644 index 0000000000..29eadb7279 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/AddonPropsPostProcessor.java @@ -0,0 +1,79 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.util; + +import java.util.Map; +import java.util.Map.Entry; + +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * Allows setting of additional properties on beans defined in other spring + * files + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 19, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class AddonPropsPostProcessor implements BeanPostProcessor { + + private final Map> propsMap; + + /** + * @param propsMap + * a mapping of bean names to properties maps. For example: + * + *
+	 *            { "myBean" :
+	 *            	{ "myProp" : "value" }
+	 *            }
+	 * 
+ */ + public AddonPropsPostProcessor(Map> propsMap) { + this.propsMap = propsMap; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) + */ + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + Map props = propsMap.get(beanName); + if (props != null) { + BeanWrapperImpl wrapper = new BeanWrapperImpl(bean); + for (Entry e : props.entrySet()) { + wrapper.setPropertyValue(e.getKey(), e.getValue()); + } + } + return bean; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/ConvertService.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/ConvertService.java new file mode 100644 index 0000000000..37050f60bf --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/ConvertService.java @@ -0,0 +1,68 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.util; + +import org.springframework.context.ApplicationContext; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.core.EDEXUtil; + +/** + * Service to get convert utility + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 16, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class ConvertService { + + private static volatile Converter cache = null; + + private static final Object cacheMutex = new Object(); + + private static final IUFStatusHandler status = UFStatus + .getHandler(ConvertService.class); + + /** + * @return registered converter + */ + public static Converter get() { + if (cache == null) { + synchronized (cacheMutex) { + if (cache == null) { + try { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx + .getBeanNamesForType(Converter.class); + if (beans == null || beans.length < 1) { + return new DefaultConverter(); + } + cache = (Converter) ctx.getBean(beans[0]); + } catch (Exception e) { + status.error("problem getting service from spring", e); + return new DefaultConverter(); + } + } + } + } + return cache; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/Converter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/Converter.java new file mode 100644 index 0000000000..9dcf9926a1 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/Converter.java @@ -0,0 +1,45 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.util; + +import java.lang.reflect.Field; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 16, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface Converter { + + public Object convertObject(String value, Class desiredClass); + + public String toString(Object obj); + + public Object convertAsType(String value, Class entity, String fieldName) + throws SecurityException, NoSuchFieldException; + + public Object convertAsType(String value, Class entity, + String[] fieldPath) throws SecurityException, NoSuchFieldException; + + public Field[] getFields(Class entity, String[] fieldPath) + throws SecurityException, NoSuchFieldException; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/DefaultConverter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/DefaultConverter.java new file mode 100644 index 0000000000..5ed74f74f8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/DefaultConverter.java @@ -0,0 +1,96 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.util; + +import java.lang.reflect.Field; + +import com.raytheon.uf.common.util.ConvertUtil; + +/** + * Converter that uses convertUtil + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 16, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class DefaultConverter implements Converter { + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.util.Converter#convertObject(java.lang + * .String, java.lang.Class) + */ + @Override + public Object convertObject(String value, Class desiredClass) { + return ConvertUtil.convertObject(value, desiredClass); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.util.Converter#toString(java.lang.Object) + */ + @Override + public String toString(Object obj) { + return ConvertUtil.toString(obj); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.util.Converter#convertAsType(java.lang + * .String, java.lang.Class, java.lang.String) + */ + @Override + public Object convertAsType(String value, Class entity, String fieldName) + throws SecurityException, NoSuchFieldException { + return ConvertUtil.convertAsType(value, entity, fieldName); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.util.Converter#convertAsType(java.lang + * .String, java.lang.Class, java.lang.String[]) + */ + @Override + public Object convertAsType(String value, Class entity, + String[] fieldPath) throws SecurityException, NoSuchFieldException { + return ConvertUtil.convertAsType(value, entity, fieldPath); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.util.Converter#getFields(java.lang.Class, + * java.lang.String[]) + */ + @Override + public Field[] getFields(Class entity, String[] fieldPath) + throws SecurityException, NoSuchFieldException { + return ConvertUtil.getFields(entity, fieldPath); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PatchConverter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PatchConverter.java new file mode 100644 index 0000000000..3bb3caa43f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PatchConverter.java @@ -0,0 +1,65 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.util; + +import java.util.Calendar; +import java.util.Date; + +import javax.xml.bind.DatatypeConverter; + +/** + * Workaround for race condition for multiple versions of bean utils. Sometimes + * the custom data and calendar converters don't get registered correctly + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 16, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class PatchConverter extends DefaultConverter { + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.util.DefaultConverter#convertObject(java + * .lang.String, java.lang.Class) + */ + @Override + public Object convertObject(String value, Class desiredClass) { + if (desiredClass.equals(Calendar.class)) { + try { + // see if string is in ISO 8601 + return DatatypeConverter.parseDateTime(value); + } catch (Exception e) { + // let convertUtils try + } + } + if (desiredClass.equals(Date.class)) { + try { + // see if string is in ISO 8601 + return DatatypeConverter.parseDateTime(value).getTime(); + } catch (Exception e) { + // let convertUtils try + } + } + return super.convertObject(value, desiredClass); + } + + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PluginFilterProcessor.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PluginFilterProcessor.java new file mode 100644 index 0000000000..603cf01bac --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PluginFilterProcessor.java @@ -0,0 +1,107 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.Processor; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + +/** + * Allows for dynamic filtering of plugin data objects in a route + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 26, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class PluginFilterProcessor implements Processor { + + private final List filters = new ArrayList(); + + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + private final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + /* (non-Javadoc) + * @see org.apache.camel.Processor#process(org.apache.camel.Exchange) + */ + @Override + public void process(Exchange exchange) throws Exception { + Message in = exchange.getIn(); + PluginDataObject[] body = null; + try { + body = in.getBody(PluginDataObject[].class); + } catch (Exception e) { + log.error("Unable to get data objects as array", e); + } + if (body == null) { + return; + } + ReadLock read = lock.readLock(); + read.lock(); + try { + for (PluginIngestFilter filter : filters) { + body = filter.filter(body); + } + } finally { + read.unlock(); + } + in.setBody(body); + } + + /** + * Add all filters to filter list, can be called multiple times + * + * @param filters + */ + public void setFilters(List filters) { + WriteLock write = lock.writeLock(); + write.lock(); + try { + this.filters.addAll(filters); + } finally { + write.unlock(); + } + } + + /** + * Add single filter to filter list, can be called multiple times + * + * @param filter + */ + public void setFilter(PluginIngestFilter filter) { + WriteLock write = lock.writeLock(); + write.lock(); + try { + this.filters.add(filter); + } finally { + write.unlock(); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PluginIngestFilter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PluginIngestFilter.java new file mode 100644 index 0000000000..815e6dd0ad --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/util/PluginIngestFilter.java @@ -0,0 +1,34 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.ogc.common.util; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; + +/** + * Interface for filtering data objects + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 26, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface PluginIngestFilter { + + public PluginDataObject[] filter(PluginDataObject[] pdos); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/.classpath b/edexOsgi/com.raytheon.uf.edex.ogc.registry/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/.project b/edexOsgi/com.raytheon.uf.edex.ogc.registry/.project new file mode 100644 index 0000000000..db92268aef --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.edex.ogc.registry + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.edex.ogc.registry/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.ogc.registry/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..e2b31f837f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Ogc Registry +Bundle-SymbolicName: com.raytheon.uf.edex.ogc.registry +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: com.raytheon.uf.edex.ogc.common;bundle-version="1.0.0", + com.raytheon.uf.common.datadelivery.harvester;bundle-version="1.0.0", + com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", + org.geotools;bundle-version="2.6.4", + com.raytheon.uf.common.status;bundle-version="1.12.1174", + com.raytheon.uf.common.time;bundle-version="1.12.1174", + com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174", + org.apache.commons.lang;bundle-version="2.3.0", + com.raytheon.uf.common.registry.ebxml;bundle-version="1.0.0", + com.raytheon.uf.common.datadelivery.retrieval;bundle-version="1.0.0", + com.raytheon.uf.common.geospatial;bundle-version="1.12.1174", + com.raytheon.uf.edex.wfs;bundle-version="1.0.0" +Export-Package: com.raytheon.uf.edex.ogc.registry diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/build.properties b/edexOsgi/com.raytheon.uf.edex.ogc.registry/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryCollectorAddon.java b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryCollectorAddon.java new file mode 100644 index 0000000000..ba9b554e36 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryCollectorAddon.java @@ -0,0 +1,287 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.ogc.registry; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfig; +import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfigurationManager; +import com.raytheon.uf.common.datadelivery.harvester.OGCAgent; +import com.raytheon.uf.common.datadelivery.registry.Coverage; +import com.raytheon.uf.common.datadelivery.registry.DataLevelType; +import com.raytheon.uf.common.datadelivery.registry.DataSet; +import com.raytheon.uf.common.datadelivery.registry.DataSetMetaData; +import com.raytheon.uf.common.datadelivery.registry.DataSetName; +import com.raytheon.uf.common.datadelivery.registry.DataType; +import com.raytheon.uf.common.datadelivery.registry.Levels; +import com.raytheon.uf.common.datadelivery.registry.Parameter; +import com.raytheon.uf.common.datadelivery.registry.Provider; +import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; +import com.raytheon.uf.common.datadelivery.registry.handlers.IDataSetHandler; +import com.raytheon.uf.common.datadelivery.registry.handlers.IDataSetMetaDataHandler; +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.registry.handler.RegistryHandlerException; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.edex.ogc.common.db.ICollectorAddon; +import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 23, 2013            bclement     Initial creation
+ * Aug 08, 2013            dhladky      Made operational
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class RegistryCollectorAddon, R extends PluginDataObject> + implements ICollectorAddon { + + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(RegistryCollectorAddon.class); + + protected HarvesterConfig config = null; + + protected OGCAgent agent = null; + + protected Map parameters = null; + + /** + * + */ + public RegistryCollectorAddon() { + this.config = HarvesterConfigurationManager.getOGCConfiguration(); + setAgent((OGCAgent) config.getAgent()); + storeProvider(config.getProvider()); + } + + public HarvesterConfig getConfig() { + return config; + } + + public void setConfig(HarvesterConfig config) { + this.config = config; + } + + /** + * Find the DPA config + * + * @return + */ + public HarvesterConfig getConfiguration() { + return config; + } + + /** + * Stroe Data objects + * + * @param metaDatas + * @param dataSet + */ + public void storeMetaData(final DataSetMetaData metaData) { + + IDataSetMetaDataHandler handler = DataDeliveryHandlers + .getDataSetMetaDataHandler(); + + final String description = metaData.getDataSetDescription(); + statusHandler.info("Attempting store of DataSetMetaData[" + description + + "]"); + + try { + handler.update(metaData); + statusHandler.info("DataSetMetaData [" + description + + "] successfully stored in Registry"); + } catch (RegistryHandlerException e) { + statusHandler.handle(Priority.PROBLEM, "DataSetMetaData [" + + description + "] failed to store in Registry"); + + } + } + + /** + * + * @param dataSetToStore + */ + protected void storeDataSetName(DataSet dataSetToStore) { + + DataSetName dsn = new DataSetName(); + // Set the RegistryObject Id keys for this Object + // using the values from the DataSetMetaData Object. + dsn.setProviderName(dataSetToStore.getProviderName()); + dsn.setDataSetType(dataSetToStore.getDataSetType()); + dsn.setDataSetName(dataSetToStore.getDataSetName()); + + // Now add the parameter Objects so we can associate + // the DataSetName with parameters.. + dsn.setParameters(dataSetToStore.getParameters()); + + try { + DataDeliveryHandlers.getDataSetNameHandler().update(dsn); + statusHandler.info("DataSetName object store complete, dataset [" + + dsn.getDataSetName() + "]"); + } catch (RegistryHandlerException e) { + statusHandler.handle(Priority.PROBLEM, + "DataSetName object store failed:", e); + } + } + + /** + * @param dataSet + */ + protected void storeDataSet(final DataSet dataSet) { + + DataSet dataSetToStore = getDataSetToStore(dataSet); + final String dataSetName = dataSetToStore.getDataSetName(); + IDataSetHandler handler = DataDeliveryHandlers.getDataSetHandler(); + + try { + handler.update(dataSetToStore); + statusHandler.info("Dataset [" + dataSetName + + "] successfully stored in Registry"); + storeDataSetName(dataSet); + + } catch (RegistryHandlerException e) { + statusHandler.handle(Priority.PROBLEM, "Dataset [" + dataSetName + + "] failed to store in Registry"); + } + } + + /** + * Make sure our provider is contained in the Registry + * + * @param provider + */ + protected void storeProvider(final Provider provider) { + + try { + DataDeliveryHandlers.getProviderHandler().update(provider); + } catch (RegistryHandlerException e) { + statusHandler.handle(Priority.PROBLEM, + "Provider [" + provider.getName() + + "] failed to store in Registry"); + } + } + + /** + * Checks for a {@link DataSet} already existing with the same name in the + * Registry. If so, then combine the objects. + * + * @param dataSet + * the dataSet + * @return the dataSet instance that should be stored to the registry + */ + protected DataSet getDataSetToStore(DataSet dataSet) { + try { + DataSet result = DataDeliveryHandlers.getDataSetHandler() + .getByNameAndProvider(dataSet.getDataSetName(), + dataSet.getProviderName()); + if (result != null) { + dataSet.combine(result); + } + } catch (RegistryHandlerException e) { + statusHandler.handle(Priority.PROBLEM, + "Unable to retrieve dataset.", e); + } + return dataSet; + } + + /** + * Store a parameter object to the registry. If necessary, also store the + * ParameterLevel Objects needed to successfully store the Parameter Object. + * + * @param parameter + * The Parameter Object to store. + */ + protected void storeParameter(Parameter parameter) { + + try { + DataDeliveryHandlers.getParameterHandler().update(parameter); + } catch (RegistryHandlerException e) { + statusHandler.handle(Priority.PROBLEM, + "Failed to store parameter [" + parameter.getName() + "]"); + } + } + + /** + * Get me my level types for this param + * + * @param cp + * @return + */ + public List getDataLevelTypes(Parameter cp) { + return cp.getLevelType(); + } + + protected abstract void setCoverage(L layer); + + protected abstract Coverage getCoverage(); + + public void setParameters(L layer) { + synchronized (layer) { + if (getParameters() == null || getParameters().isEmpty()) { + parameters = new HashMap(); + for (Parameter parm : agent.getLayer(layer.getName()) + .getParameters()) { + // place in map + parameters.put(parm.getName(), parm); + storeParameter(parm); + } + } + } + } + + public Map getParameters() { + return parameters; + } + + protected abstract void setDataSet(L layer); + + protected abstract DataSet getDataSet(); + + protected abstract void setDataSetMetaData(L layer); + + protected abstract DataSetMetaData getDataSetMetaData(); + + protected abstract DataType getDataType(); + + public abstract Levels getLevels(DataLevelType type, String collectionName); + + public OGCAgent getAgent() { + return agent; + } + + public void setAgent(OGCAgent agent) { + this.agent = agent; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryCollectorAddonProvider.java b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryCollectorAddonProvider.java new file mode 100644 index 0000000000..1880c4c4f2 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryCollectorAddonProvider.java @@ -0,0 +1,68 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.ogc.registry; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.edex.ogc.common.db.ICollectorAddon; +import com.raytheon.uf.edex.ogc.common.db.CollectorAddonFactory; +import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; + +/** + * Provides access to a single CollectorAddon instance through the factory + * interface + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 23, 2013            bclement     Initial creation
+ * Aug 18, 2013  #2097     dhladky      Adapted to AWIPS
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class RegistryCollectorAddonProvider, R extends PluginDataObject> + implements CollectorAddonFactory { + + private final ICollectorAddon addon; + + /** + * @param addon + */ + public RegistryCollectorAddonProvider(ICollectorAddon addon) { + this.addon = addon; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.CollectorAddonFactory#create() + */ + @Override + public ICollectorAddon create() { + return addon; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryFeatureTypeModifier.java b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryFeatureTypeModifier.java new file mode 100644 index 0000000000..82c807e628 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/RegistryFeatureTypeModifier.java @@ -0,0 +1,150 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.ogc.registry; + +import java.util.List; + +import com.raytheon.uf.common.datadelivery.harvester.ConfigLayer; +import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfig; +import com.raytheon.uf.common.datadelivery.harvester.OGCAgent; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.reg.IFeatureTypeModifier; + +/** + * Restricts feature crs and bounds by registry metadata + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 26, 2013            bclement     Initial creation
+ * Aug 18, 2013  #2097     dhladky      Adapted to AWIPS
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class RegistryFeatureTypeModifier implements IFeatureTypeModifier { + + protected HarvesterConfig config = null; + + protected ConfigLayer layer = null; + + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(RegistryFeatureTypeModifier.class); + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.FeatureTypeModifier#modify(java.util.List) + */ + @Override + public List modify(List list) { + for (WfsFeatureType ft : list) { + modify(ft); + } + return list; + } + + public void modify(WfsFeatureType ft) { + String name = ft.getName().getName(); + OgcGeoBoundingBox boundingBox = getBoundingBox(name); + if (boundingBox != null) { + ft.setBbox(boundingBox); + } + String crs = getCRS(name); + if (crs != null) { + ft.setDefaultSRS(crs); + } + } + + /** + * Get the configuration for the layer (feature) + * + * @param name + * @return + */ + public ConfigLayer getConfigLayer(String name) { + ConfigLayer layer = null; + if (config.getAgent() != null) { + if (config.getAgent() instanceof OGCAgent) { + layer = ((OGCAgent) config.getAgent()).getLayer(name); + } + } + return layer; + } + + /** + * Gets the configured bounded box + * + * @param layer + * @return + */ + public OgcGeoBoundingBox getBoundingBox(String name) { + OgcGeoBoundingBox bbox = null; + + try { + ConfigLayer layer = getConfigLayer(name); + double upperLeftLon = layer.getMinx(); + double lowerRightLon = layer.getMaxx(); + double upperLeftLat = layer.getMaxy(); + double lowerRightLat = layer.getMiny(); + bbox = new OgcGeoBoundingBox(lowerRightLon, upperLeftLon, + upperLeftLat, lowerRightLat); + + } catch (Exception e) { + statusHandler.handle(Priority.ERROR, + "Couldn't create Bounding Box for feature: " + name + + ", Using default", e); + } + + return bbox; + } + + /** + * Override this if you want a different CRS from you config + * + * @param name + * @return + */ + public String getCRS(String name) { + String crs = null; + + try { + ConfigLayer layer = getConfigLayer(name); + crs = layer.getCrs(); + } catch (Exception e) { + statusHandler.handle(Priority.ERROR, + "Couldn't retrieve CRS for feature: " + name + + ", Using default", e); + } + + return crs; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/WCSLayerCollector.java b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/WcsRegistryCollectorAddon.java similarity index 65% rename from edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/WCSLayerCollector.java rename to edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/WcsRegistryCollectorAddon.java index ebf24e8513..fe40bb57fb 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/WCSLayerCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/WcsRegistryCollectorAddon.java @@ -17,12 +17,13 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.edex.ogc.common.db; +package com.raytheon.uf.edex.ogc.registry; import java.util.Collection; -import java.util.HashMap; +import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Set; import com.raytheon.uf.common.datadelivery.registry.Coverage; import com.raytheon.uf.common.datadelivery.registry.DataLevelType; @@ -36,48 +37,43 @@ import com.raytheon.uf.common.datadelivery.retrieval.util.LookupManager; import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; import com.raytheon.uf.edex.ogc.common.interfaces.IWCSMetaData; /** - * - * WCS Layer Collector + * WCS Registry layer collector * *
+ * 
  * SOFTWARE HISTORY
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * 08/09/2012   754       dhladky      Modified from a class written by Brian Clements
- * 04/01/2013   1746      dhladky      Updated for MADIS configuration
+ * Jul 25, 2013            bclement     Initial creation
+ * Aug 18, 2013  #2097     dhladky      Adapted to AWIPS
+ * 
  * 
* - * @author dhladky + * @author bclement * @version 1.0 */ - -public abstract class WCSLayerCollector, R extends PluginDataObject> - extends DefaultLayerCollector implements - IWCSMetaData { +public class WcsRegistryCollectorAddon, R extends PluginDataObject> + extends RegistryCollectorAddon implements IWCSMetaData { private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(WCSLayerCollector.class); - - protected GriddedDataSet gds = null; - - protected GriddedDataSetMetaData gdsmd = null; - - protected Time time = null; - + .getHandler(WcsRegistryCollectorAddon.class); - public WCSLayerCollector(LayerTransformer transformer, - Class layerClass, Class recordClass) { - super(transformer, layerClass, recordClass); - } + protected GriddedDataSet gds = null; + + protected GriddedDataSetMetaData gdsmd = null; + + protected Time time = null; @Override protected void setCoverage(L layer) { - //TODO: NOt yet implemented + // TODO: NOt yet implemented } - @Override protected Coverage getCoverage() { @@ -94,36 +90,32 @@ public abstract class WCSLayerCollector coll) { - Map layermap = new HashMap(coll.size()); - for (R pdo : coll) { - if (recordClass.equals(pdo.getClass())) { - R rec = recordClass.cast(pdo); - String name = getLayerName(rec); - L layer = layermap.get(name); - if (layer == null) { - layer = newLayer(); - layer.setName(name); - if (initializeLayer(layer, rec)) { - layermap.put(name, layer); - } else { - continue; - } - } - addToTimes(layer, rec); - addToDims(layer, rec); - statusHandler.info("Adding layer " + layer.getName()); - } - } - - sendMetaData(layermap, coll); + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.CollectorAddon#onCollect(com.raytheon + * .uf.edex.ogc.common.db.SimpleLayer, + * com.raytheon.uf.common.dataplugin.PluginDataObject) + */ + @Override + public void onCollect(L layer, R record) { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.CollectorAddon#onFinish() + */ + @Override + public void onFinish() { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.CollectorAddon#onPurgeAll() + */ + @Override + public void onPurgeAll() { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.CollectorAddon#onPurgeExpired(java + * .util.Set) + */ + @Override + public void onPurgeExpired(Set timesToKeep) { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.interfaces.IWCSMetaData#sendMetaData( + * java.util.Map, java.util.Collection) + */ + @Override + public void sendMetaData(Map layermap, Collection coll) { + // TODO Auto-generated method stub + } } diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/WFSLayerCollector.java b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/WfsRegistryCollectorAddon.java similarity index 51% rename from edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/WFSLayerCollector.java rename to edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/WfsRegistryCollectorAddon.java index 73ec8ee25c..1505f4850b 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/WFSLayerCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.registry/src/com/raytheon/uf/edex/ogc/registry/WfsRegistryCollectorAddon.java @@ -1,5 +1,3 @@ -package com.raytheon.uf.edex.ogc.common.db; - /** * This software was developed and / or modified by Raytheon Company, * pursuant to Contract DG133W-05-CQ-1067 with the US Government. @@ -19,14 +17,19 @@ package com.raytheon.uf.edex.ogc.common.db; * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ +package com.raytheon.uf.edex.ogc.registry; +import java.lang.reflect.Constructor; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Set; import java.util.TimeZone; +import java.util.TreeSet; +import org.geotools.geometry.jts.JTS; import org.geotools.geometry.jts.ReferencedEnvelope; import com.raytheon.uf.common.datadelivery.harvester.ConfigLayer; @@ -40,38 +43,42 @@ import com.raytheon.uf.common.datadelivery.registry.PointTime; import com.raytheon.uf.common.datadelivery.registry.Time; import com.raytheon.uf.common.datadelivery.registry.WFSPointDataSet; import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.geospatial.MapUtil; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.util.ImmutableDate; +import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; import com.raytheon.uf.edex.ogc.common.interfaces.IWFSMetaData; import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; /** - * - * WFS Layer Collector + * Collector addon for WFS collectors with a single layer that adds time + * information to registry * *
+ * 
  * SOFTWARE HISTORY
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * 08/09/2012   754       dhladky      initial creation
- * 04/01/2013   1746      dhladky      Updated for MADIS implementation
- * 05/29/2013   753       dhladky      Updated Point Data Datasets
+ * Jul 23, 2013            bclement     Initial creation
+ * Aug 08, 2013 2097       dhladky      Made operational
+ * 
  * 
* - * @author dhladky + * @author bclement * @version 1.0 */ +public class WfsRegistryCollectorAddon, R extends PluginDataObject> + extends RegistryCollectorAddon implements IWFSMetaData { -public abstract class WFSLayerCollector, R extends PluginDataObject> - extends DefaultLayerCollector implements - IWFSMetaData { + protected final IUFStatusHandler statusHandler = UFStatus.getHandler(this + .getClass()); - private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(WFSLayerCollector.class); - - protected WFSPointDataSet wpds = wpds = new WFSPointDataSet(); + protected WFSPointDataSet wpds = new WFSPointDataSet(); protected PointDataSetMetaData pdsmd = new PointDataSetMetaData(); @@ -79,14 +86,132 @@ public abstract class WFSLayerCollector lclass = layer.getClass(); + try { + Constructor constructor = lclass.getConstructor(lclass); + return (L) constructor.newInstance(layer); + } catch (Exception e) { + statusHandler.error("Unable to clone layer", e); + return (L) new SimpleLayer((SimpleLayer) layer) { + private static final long serialVersionUID = -7014438001156256263L; + + @Override + public Set getDimensions() { + return new TreeSet(); + } + }; + } + } + + /** + * @param layer + */ + protected void initializeLayer(L layer) { + synchronized (layer) { + // create the main point data set + layer.setName(layerName); + setDataSet(layer); + Coordinate lowerRight = getCoverage().getLowerRight(); + Coordinate upperLeft = getCoverage().getUpperLeft(); + ReferencedEnvelope env = new ReferencedEnvelope(upperLeft.x, + lowerRight.x, lowerRight.y, upperLeft.y, + MapUtil.LATLON_PROJECTION); + layer.setCrs84Bounds(JTS.toGeometry((Envelope) env)); + ConfigLayer configLayer = getAgent().getLayer(layer.getName()); + layer.setTargetCrsCode(configLayer.getCrs()); + layer.setTargetMaxx(configLayer.getMaxx()); + layer.setTargetMaxy(configLayer.getMaxy()); + layer.setTargetMinx(configLayer.getMinx()); + layer.setTargetMiny(configLayer.getMiny()); + layer.setTimes(new TreeSet()); + // install main dataset name on registry + + storeDataSet(getDataSet()); + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.CollectorAddon#onFinish() + */ + @Override + public void onFinish() { - public WFSLayerCollector(LayerTransformer transformer, - Class layerClass, Class recordClass) { - super(transformer, layerClass, recordClass); - this.layer = newLayer(); } @Override @@ -112,12 +237,15 @@ public abstract class WFSLayerCollector timesToKeep) { + // TODO Auto-generated method stub + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.classpath b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.project b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.project new file mode 100644 index 0000000000..ba7a96dbda --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.edex.plugin.dataset.urn + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..781580a7fe --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Tue Apr 02 10:27:06 CDT 2013 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..534dbdaad6 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Dataset-URN +Bundle-SymbolicName: com.raytheon.uf.edex.plugin.dataset.urn +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: org.springframework;bundle-version="2.5.6", + com.raytheon.uf.edex.core;bundle-version="1.12.1174", + org.apache.commons.lang;bundle-version="2.3.0", + com.raytheon.uf.common.status;bundle-version="1.12.1174" +Export-Package: com.raytheon.uf.edex.plugin.dataset.urn diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/build.properties b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/build.properties new file mode 100644 index 0000000000..ea64e28012 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + res/,\ + bin/ diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/res/spring/wxsrv-dataset-urn.xml b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/res/spring/wxsrv-dataset-urn.xml new file mode 100644 index 0000000000..ffc9251453 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/res/spring/wxsrv-dataset-urn.xml @@ -0,0 +1,17 @@ + + + + + file:///${edex.home}/data/utility/edex_static/base/wxsrv/namedata/ncep_to_cf_mapping.csv + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/CFNameLookup.java b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/CFNameLookup.java new file mode 100644 index 0000000000..7475866751 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/CFNameLookup.java @@ -0,0 +1,165 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + +package com.raytheon.uf.edex.plugin.dataset.urn; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + +/** + * Singleton to facilitate the lookup of the CF Standard name from a shortened + * name such as those in GRIB processing. Also maintains a mapping of the CF names + * to ontology individuals to facilitate dynamic ontology updates and individual + * creation. + * @author behemmi + * + */ +public class CFNameLookup { + + private static CFNameLookup instance; + + private IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + private Map ncepToCFMapping; + + protected Map cfToNcepMapping; + private Map cfToOntologyRelationMapping; + private Map cfToOntologyClassMapping; + + private CFNameLookup(CFNameResource resource) { + ncepToCFMapping = new HashMap(); + cfToOntologyRelationMapping = new HashMap(); + cfToOntologyClassMapping = new HashMap(); + cfToNcepMapping = new HashMap(); + + try { + if (resource.getConfigFileResource() != null) { + InputStream configStream = resource.getConfigFileResource().getInputStream(); + BufferedReader in = new BufferedReader(new InputStreamReader(configStream)); + String line = null; + + while((line = in.readLine()) != null) { + if(line.startsWith("#") || line.length() == 0) { + //comment, ignore + continue; + } + + //limit splitting to 2 to account for multiple tabs and trim for map insert + String[] parts = line.split("\t", 2); + if(parts != null && parts.length > 1) { + + //check for an Ontology relation after the CF Name + String[] ontRelParts = parts[1].trim().split("\t", 2); + if(ontRelParts != null && ontRelParts.length > 1) { + + //check for an Ontology class after the Ontoogy relation + String[] ontClassParts = ontRelParts[1].trim().split("\t", 2); + if(ontClassParts != null && ontClassParts.length > 1) { + //this line has everything, populate all the HashMaps + cfToOntologyClassMapping.put(ontRelParts[0].trim(), ontClassParts[1].trim()); + cfToOntologyRelationMapping.put(ontRelParts[0].trim(), ontClassParts[0].trim()); + ncepToCFMapping.put(parts[0].toUpperCase().trim(), ontRelParts[0].trim()); + cfToNcepMapping.put(ontRelParts[0].trim(), + parts[0].toUpperCase().trim()); + } else { + //only entries up the relation are present + cfToOntologyRelationMapping.put(ontRelParts[0].trim(), ontRelParts[1].trim()); + ncepToCFMapping.put(parts[0].toUpperCase().trim(), ontRelParts[0].trim()); + cfToNcepMapping.put(ontRelParts[0].trim(), + parts[0].toUpperCase().trim()); + log.warn("CF Name " + + ontRelParts[0].trim() + + " not mapped to Ontology Class in Config"); + } + } else { + //only the cf and ncep entries are on this line + ncepToCFMapping.put(parts[0].toUpperCase().trim(), parts[1].trim()); + cfToNcepMapping.put(parts[1].trim(), parts[0] + .toUpperCase().trim()); + log.warn("CF Name " + parts[1].trim() + + " not mapped to Ontology Info in Config"); + } + } else { + log.warn("NCEP Name " + parts[0] + + " not mapped to CF Name in Config"); + } + } + } else { + throw new IOException("Config File Resource null"); + } + } catch (IOException e) { + log.error("Configured mapping to CF Names not available", e); + } + instance = this; + } + + public static CFNameLookup getInstance(){ + //expecting instantiation from spring so no 'new' call here + //like in the normal singleton pattern + return instance; + } + + /** + * Returns the CF Name if available, defaults to the ncep name otherwise + * + * @param ncepName + * @return + */ + public String getCFFromNCEP(String ncepName) { + String cfName = ncepName; + if(ncepToCFMapping.containsKey(ncepName.toUpperCase())) { + cfName = ncepToCFMapping.get(ncepName.toUpperCase()); + } + return cfName; + } + + /** + * Returns the NCEP name if available, defaults to the cf name otherwise + * + * @param cfName + * @return + */ + public String getNCEPFromCF(String cfName) { + String ncepName = cfName; + if (cfToNcepMapping.containsKey(cfName)) { + ncepName = cfToNcepMapping.get(cfName).toUpperCase(); + } + + return ncepName; + } + + /** + * Looks up the associated ontology axiom for a given CF Name, returns null + * if no entities are associated + * @param cfName + * @return + */ + public String getOntologyRelationFromCF(String cfName) { + return cfToOntologyRelationMapping.get(cfName); + } + + /** + * Looks up the associated ontology class for a given CF Name, returns null + * if no entities are associated + * @param cfName + * @return + */ + public String getOntologyclassFromCF(String cfName) { + return cfToOntologyClassMapping.get(cfName); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/CFNameResource.java b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/CFNameResource.java new file mode 100644 index 0000000000..5882fa421b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/CFNameResource.java @@ -0,0 +1,31 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + +package com.raytheon.uf.edex.plugin.dataset.urn; + +import org.springframework.core.io.Resource; + +public class CFNameResource { + + /** + * Spring resource for properties file, this is preferred over a filepath + * string + */ + protected Resource configFileResource = null; + + public Resource getConfigFileResource() { + return configFileResource; + } + + public void setConfigFileResource(Resource configFileResource) { + this.configFileResource = configFileResource; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/URNLookup.java b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/URNLookup.java new file mode 100644 index 0000000000..5bada70675 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/src/com/raytheon/uf/edex/plugin/dataset/urn/URNLookup.java @@ -0,0 +1,156 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.dataset.urn; + + +/** + * Lookup URNs. + * + * @author ekladstrup + * @version 1.0 + */ +public class URNLookup { + + public static final String WXSRV_URN_PREFIX = "urn:x-wxsrv:"; + + public static final String MODEL_URN_PREFIX = WXSRV_URN_PREFIX + "Dataset"; + + // From ucar.edu WXCM primer + public static final String FDC_AIRCRAFT_REPORT = "urn:fdc:icao:procedure:AircraftReport"; + + // From ucar.edu WXCM primer + public static final String ICAO_CODE_PREFIX = "urn:icao:code:weatherStation"; + + private static enum State { + START, ONE_SLASH, MULT_SLASH, ONE_COLON + } + + /** + * Convert EDEX internal ID to external URN + * + * Single slashes are replaced by single colons. Any additional slashes + * immediately following are converted into URN escape sequences. 'foo/bar' + * -> 'foo:bar', 'foo//bar' -> 'foo:%2fbar'. Any colons in the local string + * are escaped with another colon. 'foo:bar/baz' -> 'foo::bar:baz'. Other + * non-URN characters are escaped using URN escape formatting. + * + * Dataset URN prefix is attached. + * + * @param local + * dataURI based ID + * @return + */ + public static String localToUrn(String local) { + State s = State.START; + StringBuilder sb = new StringBuilder(MODEL_URN_PREFIX).append(':'); + for (int i = 0; i < local.length(); ++i) { + char curr = local.charAt(i); + switch (curr) { + case '/': + if (s.equals(State.START)) { + s = State.ONE_SLASH; + sb.append(':'); + } else if (s.equals(State.ONE_SLASH)) { + s = State.MULT_SLASH; + sb.append("%2f"); + } else if (s.equals(State.MULT_SLASH)) { + sb.append("%2f"); + } + break; + case ':': + sb.append("::"); + s = State.START; + break; + case '%': + case '?': + case '#': + case ' ': + sb.append(String.format("%%%02x", (short) curr)); + s = State.START; + break; + default: + sb.append(curr); + s = State.START; + } + } + return sb.toString(); + } + + /** + * Convert external URN to internal EDEX ID + * + * URN escaped characters are converted to ASCII. Single colons are + * converted to slashes. Colon pairs are converted to single colons. + * + * Dataset URN prefix is assumed to be on input. + * + * @param urn + * @return dataURI based ID + */ + public static String urnToLocal(String urn) { + // add 1 since the last ":" is not included in the length + String unique = urn.substring(MODEL_URN_PREFIX.length() + 1); + State s = State.START; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < unique.length(); ++i) { + char curr = unique.charAt(i); + char next; + switch (curr) { + case ':': + if (s.equals(State.START)) { + s = State.ONE_COLON; + continue; + } else { + sb.append(':'); + s = State.START; + continue; + } + case '%': + next = (char) Short.parseShort(unique.substring(i + 1, i + 3), + 16); + i += 2; + break; + default: + next = curr; + break; + } + if (s.equals(State.ONE_COLON)) { + sb.append('/'); + s = State.START; + } + sb.append(next); + } + return sb.toString(); + } + + public static String getAircraftReportURN() { + return FDC_AIRCRAFT_REPORT; + } + + public static String icaoToUrn(String station) { + return ICAO_CODE_PREFIX + ":" + station; + } + + /** + * Slice the icao urn and return the local part + * + * @param urn + * @return Blank string or local part if prefix is the proper icao prefix, + * null if the prefix does not match expectations + */ + public static String urnToIcao(String urn) { + if (urn.startsWith(ICAO_CODE_PREFIX)) { + // add 1 since the last ":" is not included in the length + return urn.substring(ICAO_CODE_PREFIX.length() + 1); + } else { + return null; + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/utility/edex_static/base/wxsrv/namedata/ncep_to_cf_mapping.csv b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/utility/edex_static/base/wxsrv/namedata/ncep_to_cf_mapping.csv new file mode 100644 index 0000000000..9a30f8e7bf --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.dataset.urn/utility/edex_static/base/wxsrv/namedata/ncep_to_cf_mapping.csv @@ -0,0 +1,278 @@ +#This file contains a user editable mapping of names that would be seen as part of data ingest to +#more standardized CF (NetCDF Climate and Forecast) names. The first list is taken directly from +#the NetCDF Climate and Forecast (CF) Metadata Convention website and the entries that follow +#are as needed additions based on what is being seen in data. The third column is a listing +#of ontology names that map to the cf names. This allows for updates and additions to both +#the ontology and the CF list while maintaining the codes ability to generate ontology individuals. +#note that the third column is case sensitive. + +#all values from http://cf-pcmdi.llnl.gov/documents/cf-standard-names/ncep-grib-code-cf-standard-name-mapping +#NCEP #CF Name #Ontology Axiom IRI #Ontology Class IRI +PRES air_pressure http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +PRMSL air_pressure_at_sea_level http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +PTEND tendency_of_air_pressure http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +ICAHT standard_atmosphere_reference_height +GP geopotential http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +HGT geopotential_height http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +DIST altitude +HSTDV height_standard_deviation +TOZNE equivalent_thickness_at_stp_of_atmosphere_o3_content +TMP air_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +VTMP virtual_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +POT air_potential_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +EPOT pseudo_equivalent_potential_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +T MAX max_air_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +T MIN min_air_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +DPT dew_point_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +DEPR dew_point_depression http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +LAPR air_temperature_lapse_rate http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +VIS visibility_in_air +RDSP1 radar_spectra_1 +RDSP2 radar_spectra_2 +RDSP3 radar_spectra_3 +PLI parcel_lifted_index +TMP A air_temperature_anomaly http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +PRESA air_pressure_anomaly http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +GP A geopotential_height_anomaly http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +WVSP1 wave_spectra_1 +WVSP2 wave_spectra_2 +WVSP3 wave_spectra_3 +WDIR wind_from_direction http://wxsrv/ontology/weather.owl#hasWindDirection http://wxsrv/ontology/weather.owl#WindDirection +WIND wind_speed http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +U GRD eastward_wind http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +V GRD northward_wind http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +STRM atmosphere_horizontal_streamfunction +V POT atmosphere_horizontal_velocity_potential http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +MNTSF montgomery_stream_function +SGCVV vertical_air_velocity_expressed_as_tendency_of_sigma http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +V VEL vertical_air_velocity_expressed_as_tendency_of_pressure http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +DZDT upward_air_velocity http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +ABS V atmosphere_absolute_vorticity http://wxsrv/ontology/weather.owl#hasWindShear http://wxsrv/ontology/weather.owl#WindShear +ABS D atmosphere_absolute_divergence +REL V atmosphere_relative_vorticity http://wxsrv/ontology/weather.owl#hasWindShear http://wxsrv/ontology/weather.owl#WindShear +REL D divergence_of_wind http://wxsrv/ontology/weather.owl#hasWindShear http://wxsrv/ontology/weather.owl#WindShear +VUCSH eastward_wind_shear http://wxsrv/ontology/weather.owl#hasWindShear http://wxsrv/ontology/weather.owl#WindShear +VVCSH northward_wind_shear http://wxsrv/ontology/weather.owl#hasWindShear http://wxsrv/ontology/weather.owl#WindShear +DIR C direction_of_sea_water_velocity http://wxsrv/ontology/weather.owl#hasSeaWaterDirection http://wxsrv/ontology/weather.owl#SeaWaterDirection +SP C sea_water_speed http://wxsrv/ontology/weather.owl#hasSeaWaterSpeed http://wxsrv/ontology/weather.owl#SeaWaterSpeed +UOGRD eastward_sea_water_velocity http://wxsrv/ontology/weather.owl#hasSeaWaterSpeed http://wxsrv/ontology/weather.owl#SeaWaterSpeed +VOGRD northward_sea_water_velocity http://wxsrv/ontology/weather.owl#hasSeaWaterSpeed http://wxsrv/ontology/weather.owl#SeaWaterSpeed +SPF H specific_humidity +R H relative_humidity http://wxsrv/ontology/weather.owl#hasRelativeHumidity http://wxsrv/ontology/weather.owl#RelativeHumidity +MIXR humidity_mixing_ratio +P WAT atmosphere_water_vapour_content +VAPP water_vapour_pressure +SAT D water_vapour_saturation_deficit +EVP water_evaporation_amount +C ICE atmosphere_cloud_ice_content +PRATE precipitation_flux +TSTM thunderstorm_probability +A PCP precipitation_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +NCPCP large_scale_precipitation_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +ACPCP convective_precipitation_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +SRWEQ snowfall_flux +WEASD surface_snow_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +SNO D surface_snow_thickness http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +MIXHT ocean_mixed_layer_thickness +TTHDP transient_thermocline_depth +MTHD main_thermocline_depth +MTHA main_thermocline_anomoly +T CDC cloud_area_fraction http://wxsrv/ontology/weather.owl#hasCloudAreaFraction http://wxsrv/ontology/weather.owl#CloudAreaFraction +CDCON convective_cloud_area_fraction http://wxsrv/ontology/weather.owl#hasCloudAreaFraction http://wxsrv/ontology/weather.owl#CloudAreaFraction +L CDC low_cloud_area_fraction http://wxsrv/ontology/weather.owl#hasCloudAreaFraction http://wxsrv/ontology/weather.owl#CloudAreaFraction +M CDC medium_cloud_area_fraction http://wxsrv/ontology/weather.owl#hasCloudAreaFraction http://wxsrv/ontology/weather.owl#CloudAreaFraction +H CDC high_cloud_area_fraction http://wxsrv/ontology/weather.owl#hasCloudAreaFraction http://wxsrv/ontology/weather.owl#CloudAreaFraction +C WAT atmosphere_cloud_condensed_water_content +BLI best_lifted_index +SNO C convective_snowfall_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +SNO L large_scale_snowfall_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +WTMP sea_water_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +LAND land_area_fraction http://wxsrv/ontology/weather.owl#hasLandAreaFraction http://wxsrv/ontology/weather.owl#LandAreaFraction +DSL M sea_surface_height_above_sea_level +SFC R surface_roughness_length +ALBDO surface_albedo +TSOIL soil_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +SOIL soil_moisture_content +VEG vegetation_area_fraction +SALTY sea_water_salinity +DEN density +WATR surface_runoff_amount +ICE C sea_ice_area_fraction +ICETK sea_ice_thickness +DICED direction_of_sea_ice_velocity http://wxsrv/ontology/weather.owl#hasSeaWaterDirection http://wxsrv/ontology/weather.owl#SeaWaterDirection +SICED sea_ice_speed http://wxsrv/ontology/weather.owl#hasSeaWaterSpeed http://wxsrv/ontology/weather.owl#SeaWaterSpeed +U ICE sea_ice_eastward_velocity http://wxsrv/ontology/weather.owl#hasSeaWaterSpeed http://wxsrv/ontology/weather.owl#SeaWaterSpeed +V ICE sea_ice_northward_velocity http://wxsrv/ontology/weather.owl#hasSeaWaterSpeed http://wxsrv/ontology/weather.owl#SeaWaterSpeed +ICE G tendency_of_sea_ice_thickness_due_to_thermodynamics +ICE D divergence_of_sea_ice_velocity http://wxsrv/ontology/weather.owl#hasSeaWaterSpeed http://wxsrv/ontology/weather.owl#SeaWaterSpeed +SNO M surface_snow_melt_amount +HTSGW significant_height_of_wind_and_swell_waves +WVDIR direction_of_wind_wave_velocity +WVHGT significant_height_of_wind_waves +WVPER wind_wave_period +SWDIR direction_of_swell_wave_velocity +SWELL significant_height_of_swell_waves +SWPER swell_wave_period +DIRPW primary_wave_direction +PERPW primary_wave_mean_period +DIRSW secondary_wave_direction +PERSW secondary_wave_mean_period +NSWRS surface_net_upward_shortwave_flux +NLWRS surface_net_upward_longwave_flux +NSWRT toa_net_upward_shortwave_flux +NLWRT toa_net_upward_longwave_flux +LWAVR net_upward_longwave_flux_in_air +SWAVR net_upward_shortwave_flux_in_air +G RAD surface_downwelling_shortwave_flux +BRTMP brightness_temperature +LWRAD wave_number_radiance +SWRAD wave_length_radiance +LHTFL surface_upward_latent_heat_flux +SHTFL surface_upward_sensible_heat_flux +BLYDP boundary_layer_dissipation +U FLX downward_eastward_momentum_flux_in_air +V FLX downward_northward_momentum_flux_in_air +WMIXE wind_mixing_energy_flux_into_ocean +IMG image_data +MSLSA standard_atmospheric_reduction_mean_sea_level_pressure +MSLMA maps_system_reduction_mean_sea_level_pressure +MSLET nam_model_reduction_mean_sea_level_pressure +LFTX surface_lifted_index +4LFTX best_four_layer_lifted_index +KX k_index +SX sweat_index +MCONV horizontal_moisture_divergence +VW SH wind_speed_shear +TSLSA standard_atmospheric_reduction_three_hour pressure_tendency +BVF2 brunt_vaisala_frequency +PVMW density_weighted_potontial_vorticity +CRAIN categorical_rain +CFRZR categorical_freezing_rain +CICEP categorical_ice_pellets +CSNOW categorical_snow +SOILW volumetric_soil_moisture_content +PEVPR potential_evaporation_rate +CWORK cloud_work_function +UGWD gravity_wave_stress_zonal_flux +VGWD gravity_wave_stress_meridonial_flux +PV potential_vorticity +COVMZ meridonail_zonal_wind_covariance +COVTZ temperature_zonal_wind_covariance +COVTM temperature_meridonail_wind_covariance +CLWMR cloud_mixing_ratio +O3MR ozone_mixing_ratio +GFLUX ground_heat_flux +CIN convective_inhibition +CAPE atmosphere_specific_convective_available_potential_energy +TKE turbulent_kinetic_energy +CONDP surface_parcel_condensation_pressure +CSUSF clear_sky_upward_solar_flux +CSDSF clear_sky_downward_solar_flux +CSULF clear_sky_upward_long_wave_flux +CSDLF clear_sky_downward_long_wave_flux +CFNSF cloud_forcing_net_solar_flux +CFNLF cloud_forcing_net_long_wave_flux +VBDSF visible_beam_downward_solar_flux +VDDSF visible_diffuse_downward_solar_flux +NBDSF near_ir_beam_downward_solar_flux +NDDSF near_ir_diffuse_downward_solar_flux +MFLX momentum_flux +LMH mass_point_model_surface +LMV velocity_point_model_surface +MLYNO model_layer_number +NLAT latitude +ELON east_longitude +LPSX log_pressure_x_gradient +LPSY log_pressure_y_gradient +HGTX height_x_gradient +HGTY height_y_gradient +VPTMP virtual_potential_temperature +HLCY storm_relative_helicity +PROB probability_from_ensemble +PROBN climate_normalized_probability_from_ensemble +POP probability_of_precipitation +CPOFP percent_of_frozen_precipitation +CPOZP probability_of_freezing_precipitation +USTM u_component_of_storm_motion +VSTM v_component_of_storm_motion +ICWAT ice_free_water_surface +DSWRF downward_short_wave_rad_flux +DLWRF downward_long_wave_rad_flux +UVI untra_violet_index +MSTAV moisture_availability +SFEXC exchange_coefficient +MIXLY surface_mixed_layers +USWRF upward_short_wave_rad_flux +ULWRF upward_long_wave_rad_flux +CDLYR amound_of_non_convective_cloud +CPRAT convective_precipitation_rate +TTDIA temperature_tendency_by_all_physics +TTRAD temperature_tendency_by_all_radiation +TTPHY temperature_tendency_by_nonradiation_physics +PREIX precipitation_index +TSD1D std_dev_irt_over_1x1_deg_area +NLGSP natural_log_of_surface_pressure +HPBL planetary_boundary_layer_height +5WAVH 5_wave_geopotential_height +CNWAT plant_canopy_surface_water +BMIXL blackadars_mixing_length_scale +AMIXL asymptotic_mixing_length_scale +PEVAP potential_evaporation +SNOHF snow_phase_change_heat_flux +MFLUX convective_cloud_mass_flux +DTRF downward_total_radiation_flux +UTRF upward_total_radiation_flux +BGRUN baseflow_groundwater_runoff +SSRUN storm_surface_runoff +03TOT total_ozone +SNOWC snow_cover +SNOWT snow_temperature +LRGHR large_scale_condensate_heat_rate +CNVHR deep_convective_heating_rate +CNVMR deep_convective_moistening_rate +SHAHR shallow_convective_heating_rate +SHAMR shallow_convectine_moistening_rate +VDFHR vertical_diffusion_heating_rate +VDFUA vertical_diffusion_zonal_acceleration +VDFVA vertical_diffusion_meridonal_acceleration +VDFMR vertical_diffusion_moistening_rate +SWHR solar_radiative_heating_rate +LWHR long_wave_radiative_heating_rate +CD drag_coefficient +FRICV friction_velocity +RI richardson_number +HLCY storm_relative_helicity + +#other mapping added based on what was seen in data +GH geopotential_height http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +T temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +RH relative_humidity http://wxsrv/ontology/weather.owl#hasRelativeHumidity http://wxsrv/ontology/weather.owl#RelativeHumidity +UW horizontal_wind_vector http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +VW vertical_wind_vector http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +ICIP icing_probability http://wxsrv/ontology/weather.owl#hasIcingProbability http://wxsrv/ontology/weather.owl#IcingProbability +PVV pressure_vertical_velocity + +#eta218 xml short name entries that do not already exist in the cf mapping +HELI helicity_sigma +TCC cloud_area_fraction http://wxsrv/ontology/weather.owl#hasCloudAreaFraction http://wxsrv/ontology/weather.owl#CloudAreaFraction +TP precipitation_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +STATICCORIOLIS coriolis_parameter +MNT min_air_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +MXT max_air_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +P air_pressure http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +T air_temperature http://wxsrv/ontology/weather.owl#hasTemperature http://wxsrv/ontology/weather.owl#Temperature +STATICSPACING grid_spacing +WD wind_from_direction http://wxsrv/ontology/weather.owl#hasWindDirection http://wxsrv/ontology/weather.owl#WindDirection +WS wind_speed http://wxsrv/ontology/weather.owl#hasWindSpeed http://wxsrv/ontology/weather.owl#WindSpeed +PLI parcel_lifted_index +PMSL air_pressure_at_sea_level http://wxsrv/ontology/weather.owl#hasBarometricPressure http://wxsrv/ontology/weather.owl#BarometricPressure +EMSP eta_mean_sea_level_pressure +CP convective_precipitation_amount http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +PW precipitable_water +STATICTOPO tolography +SLI surface_lifted_index +AV atmosphere_absolute_vorticity http://wxsrv/ontology/weather.owl#hasWindShear http://wxsrv/ontology/weather.owl#WindShear +REFC composite_radar_reflectivity +REFD derived_radar_reflectivity +SND surface_snow_thickness http://wxsrv/ontology/weather.owl#hasPrecipitationAmount http://wxsrv/ontology/weather.owl#PrecipitationAmount +THP thunderstorm_probability diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/META-INF/MANIFEST.MF index 55c3886d9a..306792c801 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/META-INF/MANIFEST.MF @@ -10,6 +10,7 @@ Require-Bundle: org.springframework;bundle-version="2.5.6", com.raytheon.uf.edex.ogc.common;bundle-version="1.0.0", javax.persistence;bundle-version="1.0.0", org.apache.commons.lang;bundle-version="2.3.0", + com.raytheon.uf.common.dataplugin.grib;bundle-version="1.12.1174", com.raytheon.uf.edex.database;bundle-version="1.0.0", com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174", org.hibernate;bundle-version="1.0.0", @@ -20,13 +21,18 @@ Require-Bundle: org.springframework;bundle-version="2.5.6", com.raytheon.uf.edex.core;bundle-version="1.12.1174", com.raytheon.uf.common.dataplugin.level;bundle-version="1.12.1174", com.raytheon.uf.common.status;bundle-version="1.12.1174", - com.raytheon.uf.common.gridcoverage;bundle-version="1.0.0", + org.apache.camel;bundle-version="1.0.0", + com.raytheon.uf.common.datastorage;bundle-version="1.12.1174", + javax.measure;bundle-version="1.0.0", + org.apache.commons.collections;bundle-version="3.2.0", + com.raytheon.uf.edex.plugin.dataset.urn;bundle-version="1.0.0", + ucar.nc2;bundle-version="1.0.0", + com.raytheon.uf.edex.plugin.unitconverter;bundle-version="1.0.0", com.raytheon.uf.common.spatial;bundle-version="1.0.0", - com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", - com.raytheon.uf.common.datadelivery.harvester;bundle-version="1.0.0", + com.raytheon.uf.common.gridcoverage;bundle-version="1.0.0", com.raytheon.uf.common.dataplugin.grid;bundle-version="1.0.0", - com.raytheon.uf.common.dataplugin.grib;bundle-version="1.12.1174" + com.raytheon.uf.common.parameter;bundle-version="1.0.0", + com.raytheon.uf.edex.plugin.grid;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: com.raytheon.uf.edex.plugin.grib.ogc -Import-Package: org.apache.commons.logging diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-decode-ogc.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-decode-ogc.xml new file mode 100644 index 0000000000..70566f39fc --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-decode-ogc.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + grid + + + + + + + ${header.CamelSplitSize} == 1 + + + + + + + + + + + + + + + java.lang.Throwable + + + + + + + + + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-dpa-ingest.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-dpa-ingest.xml deleted file mode 100644 index f93ae9911f..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-dpa-ingest.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - grib - - - - - - - - - grib - - - - - - - - - - - - - - - - - java.lang.Throwable - - - - - - - - - - - - - - - - diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-ogc-routes.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-ogc-routes.xml new file mode 100644 index 0000000000..5031190744 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-ogc-routes.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-ogc.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-ogc.xml index b2cdb3b48d..e95fa7c1e9 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-ogc.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/res/spring/grib-ogc.xml @@ -1,36 +1,42 @@ - - - + + + - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribDimension.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribDimension.java index 076444ac48..ece41ef2a8 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribDimension.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribDimension.java @@ -1,110 +1,88 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + package com.raytheon.uf.edex.plugin.grib.ogc; -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ - +import java.util.Collection; import java.util.HashMap; import java.util.Set; import java.util.SortedSet; +import java.util.TreeMap; import java.util.TreeSet; -import javax.persistence.ElementCollection; -import javax.persistence.FetchType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.apache.commons.lang.StringUtils; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.level.LevelDimUtil; import com.raytheon.uf.edex.ogc.common.time.ForecastTimeUtil; -/** - * - * Grib Dimension - * - *
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * 04/22/2013   1746       dhladky      Modified from a class written by Brian Clements
- * 
- * - * @author dhladky - * @version 1.0 - */ - - @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class GribDimension extends SimpleDimension { - public static final String REFTIME_DIM = "REFTIME"; + private static final long serialVersionUID = 1232298678216203380L; + + public static final String REFTIME_DIM = "REFTIME"; public static final String FORECAST_OFFSET_DIM = "FORECAST_OFFSET"; - public static final String LEVEL1_DIM = "LEVEL1"; + public static final String PARAM_DIM = "PARAMETER"; - public static final String LEVEL2_DIM = "LEVEL2"; + private transient DataTime defaultTime = null; - public static final String PERTURB_DIM = "PERTURBATION_NUM"; + protected transient IUFStatusHandler log = UFStatus.getHandler(this + .getClass()); - public static final String ENSEMBLE_DIM = "ENSEMBLE_TYPE"; + @XmlElement + @DynamicSerializeElement + protected Set values; - public static final String VERSION_DIM = "VERSION"; + public GribDimension() { + } - private transient DataTime defaultTime = null; + public GribDimension(String name, String units) { + this.name = name; + this.units = units; + this.values = new TreeSet(); + } - protected transient Log log = LogFactory.getLog(this.getClass()); + /** + * @param otherDim + */ + public GribDimension(GribDimension other) { + super(other); + this.values = new TreeSet(other.values); + } - @XmlElement - @DynamicSerializeElement - @ElementCollection(fetch = FetchType.EAGER) - protected Set values; + public void setValues(Set values) { + this.values = values; + } - public GribDimension() { - } - - public GribDimension(String name, String units) { - this.name = name; - this.units = units; - this.values = new TreeSet(); - } - - public void setValues(Set values) { - this.values = values; - } - - @Override - public Set getValues() { - return values; - } + @Override + public Set getValues() { + return values; + } /* * (non-Javadoc) @@ -112,7 +90,7 @@ public class GribDimension extends SimpleDimension { * @see com.raytheon.uf.edex.ogc.common.db.SimpleDimension#getDefaultValue() */ @Override - public String getDefaultValue(SimpleLayer layer) { + public String getDefaultValue(SimpleLayer layer) { String rval = null; if (GribDimension.REFTIME_DIM.equals(name)) { DataTime time = getDefaultTime(layer); @@ -120,35 +98,53 @@ public class GribDimension extends SimpleDimension { } else if (GribDimension.FORECAST_OFFSET_DIM.equals(name)) { DataTime time = getDefaultTime(layer); rval = time.getFcstTime() + "S"; - } else if (GribDimension.LEVEL1_DIM.equals(name)) { - rval = getDouble(true); - } else if (GribDimension.LEVEL2_DIM.equals(name)) { - rval = getDouble(true); - } else if (GribDimension.PERTURB_DIM.equals(name)) { - rval = getInt(true); - } else if (GribDimension.ENSEMBLE_DIM.equals(name)) { - rval = getInt(true); - } else if (GribDimension.VERSION_DIM.equals(name)) { - rval = getInt(true); - } - return rval; - } + } else if (name.startsWith(LevelDimUtil.LEVEL_DIM_PREFIX)) { + rval = getLevel(true); + } else { + rval = getString(true); + } + return rval; + } + + private String getLevel(boolean lowest) { + TreeMap sorted = new TreeMap(); + if (this.getValues().isEmpty()) { + return null; + } + for (String val : this.getValues()) { + String level1 = StringUtils.split(val, '_')[0]; + sorted.put(Double.parseDouble(level1), val); + } + Double key = lowest ? sorted.firstKey() : sorted.lastKey(); + return sorted.get(key); + } - protected DataTime getDefaultTime( - SimpleLayer layer) { - if (defaultTime == null){ - try { - SortedSet times = new ForecastTimeUtil() - .getDataTimes(layer, layer.getDefaultTime(), - new HashMap(0)); - defaultTime = times.last(); - } catch (OgcException e) { - log.error("Problem getting default times", e); - return new DataTime(layer.getDefaultTime()); - } - } - return defaultTime; - } + protected DataTime getDefaultTime(SimpleLayer layer) { + if (defaultTime == null){ + try { + SortedSet times = new ForecastTimeUtil() + .getDataTimes(layer, layer.getDefaultTime(), + new HashMap(0)); + defaultTime = times.last(); + } catch (OgcException e) { + log.error("Problem getting default times", e); + return new DataTime(layer.getDefaultTime()); + } + } + return defaultTime; + } + /** + * Copy contents of from into to + * + * @param to + * @param from + */ + public static void copy(Collection to, + Collection from) { + for (GribDimension d : from) { + to.add(new GribDimension(d)); + } + } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayer.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayer.java index 0bb652e65c..9f00d89748 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayer.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayer.java @@ -1,28 +1,16 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + package com.raytheon.uf.edex.plugin.grib.ogc; -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ - import java.util.Date; -import java.util.Set; -import java.util.SortedSet; import java.util.TreeSet; import javax.xml.bind.annotation.XmlAccessType; @@ -33,56 +21,160 @@ import javax.xml.bind.annotation.XmlRootElement; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; -/** - * - * GribLayer - * - *
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * 04/01/2013   1746       dhladky      Initial creation
- * 
- * - * @author dhladky - * @version 1.0 - */ - @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize -public class GribLayer extends SimpleLayer { +public abstract class GribLayer extends SimpleLayer { - @XmlElement - @DynamicSerializeElement - protected Set dimensions; + private static final long serialVersionUID = 6934503885157257766L; + + @XmlElement + @DynamicSerializeElement + protected String coverageName; + + @XmlElement + @DynamicSerializeElement + protected String crsWkt; + + @XmlElement + @DynamicSerializeElement + protected double nativeMinX; + + @XmlElement + @DynamicSerializeElement + protected double nativeMinY; + + @XmlElement + @DynamicSerializeElement + protected double nativeMaxX; + + @XmlElement + @DynamicSerializeElement + protected double nativeMaxY; + + @XmlElement + @DynamicSerializeElement + protected boolean vertical = true; public GribLayer() { - this(new TreeSet(), new TreeSet()); } - public GribLayer(TreeSet times, Set dimensions) { - this.times = times; - this.dimensions = dimensions; - } + public GribLayer(GribLayer other) { + super(other); + this.times = new TreeSet(other.getTimes()); + this.coverageName = other.getCoverageName(); + this.crsWkt = other.getCrsWkt(); + this.nativeMaxX = other.nativeMaxX; + this.nativeMaxY = other.nativeMaxY; + this.nativeMinX = other.nativeMinX; + this.nativeMinY = other.nativeMinY; + this.vertical = other.vertical; + } - public void setTimes(TreeSet times) { - this.times = times; - } + /** + * @return the coverageName + */ + public String getCoverageName() { + return coverageName; + } - public void setDimensions(Set dimensions) { - this.dimensions = dimensions; - } + /** + * @param coverageName + * the coverageName to set + */ + public void setCoverageName(String coverageName) { + this.coverageName = coverageName; + } - @Override - public Set getDimensions() { - return dimensions; - } + /** + * @return the crsWkt + */ + public String getCrsWkt() { + return crsWkt; + } - @Override - public SortedSet getTimes() { - return times; - } + /** + * @param crsWkt + * the crsWkt to set + */ + public void setCrsWkt(String crsWkt) { + this.crsWkt = crsWkt; + } + + /** + * @return the nativeMinX + */ + public double getNativeMinX() { + return nativeMinX; + } + + /** + * @param nativeMinX + * the nativeMinX to set + */ + public void setNativeMinX(double nativeMinX) { + this.nativeMinX = nativeMinX; + } + + /** + * @return the nativeMinY + */ + public double getNativeMinY() { + return nativeMinY; + } + + /** + * @param nativeMinY + * the nativeMinY to set + */ + public void setNativeMinY(double nativeMinY) { + this.nativeMinY = nativeMinY; + } + + /** + * @return the nativeMaxX + */ + public double getNativeMaxX() { + return nativeMaxX; + } + + /** + * @param nativeMaxX + * the nativeMaxX to set + */ + public void setNativeMaxX(double nativeMaxX) { + this.nativeMaxX = nativeMaxX; + } + + /** + * @return the nativeMaxY + */ + public double getNativeMaxY() { + return nativeMaxY; + } + + /** + * @param nativeMaxY + * the nativeMaxY to set + */ + public void setNativeMaxY(double nativeMaxY) { + this.nativeMaxY = nativeMaxY; + } + + /** + * @return the vertical + */ + public boolean isVertical() { + return vertical; + } + + /** + * @param vertical + * the vertical to set + */ + public void setVertical(boolean vertical) { + this.vertical = vertical; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayerCollector.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayerCollector.java index 341288d344..2e6192d920 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayerCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribLayerCollector.java @@ -1,32 +1,21 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + package com.raytheon.uf.edex.plugin.grib.ogc; -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ - -import java.util.Collection; -import java.util.Date; -import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; +import javax.measure.unit.SI; +import javax.measure.unit.Unit; + import org.geotools.geometry.jts.JTS; import org.geotools.geometry.jts.ReferencedEnvelope; import org.opengis.geometry.MismatchedDimensionException; @@ -34,52 +23,35 @@ import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; -import com.raytheon.uf.common.dataplugin.PluginDataObject; -import com.raytheon.uf.common.dataplugin.grib.GribModel; -import com.raytheon.uf.common.dataplugin.grib.GribRecord; +import com.raytheon.uf.common.dataplugin.grid.GridInfoRecord; +import com.raytheon.uf.common.dataplugin.grid.GridRecord; import com.raytheon.uf.common.dataplugin.level.Level; +import com.raytheon.uf.common.dataplugin.level.MasterLevel; import com.raytheon.uf.common.geospatial.MapUtil; import com.raytheon.uf.common.gridcoverage.GridCoverage; -import com.raytheon.uf.common.status.IUFStatusHandler; -import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.parameter.Parameter; import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.edex.ogc.common.OgcLayer; +import com.raytheon.uf.edex.ogc.common.db.DefaultLayerCollector; +import com.raytheon.uf.edex.ogc.common.db.ILayerStore; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; -import com.raytheon.uf.edex.ogc.common.db.WCSLayerCollector; +import com.raytheon.uf.edex.ogc.common.level.LevelDimUtil; +import com.raytheon.uf.edex.ogc.common.spatial.AltUtil; import com.vividsolutions.jts.geom.Envelope; -/** - * - * Grib Layer Collector - * - *
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * 08/09/2012   754       dhladky      Modified from a class written by Brian Clements
- * 
- * - * @author dhladky - * @version 1.0 - */ - -@SuppressWarnings({ "deprecation" }) public class GribLayerCollector extends - WCSLayerCollector { + DefaultLayerCollector { - private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(GribLayerCollector.class); - - public GribLayerCollector( - LayerTransformer transformer) { - super(transformer, GribLayer.class, GribRecord.class); + public GribLayerCollector(ILayerStore store) { + super(GridCompositeLayer.class, GridRecord.class, store); } @Override - protected void addToDims(GribLayer layer, GribRecord rec) { + protected void addToDims(GridCompositeLayer layer, GridRecord rec) { DataTime dt = rec.getDataTime(); - GribModel modelInfo = rec.getModelInfo(); - Level level = modelInfo.getLevel(); + GridInfoRecord info = rec.getInfo(); + Level level = info.getLevel(); Set dims = layer.getDimensions(); for (SimpleDimension d : dims) { String name = d.getName(); @@ -88,67 +60,101 @@ public class GribLayerCollector extends values.add(LayerTransformer.format(dt.getRefTime())); } else if (GribDimension.FORECAST_OFFSET_DIM.equals(name)) { values.add(dt.getFcstTime() + "S"); - } else if (GribDimension.LEVEL1_DIM.equals(name)) { - values.add(level.getLevelOneValueAsString()); - } else if (GribDimension.LEVEL2_DIM.equals(name)) { - values.add(level.getLevelTwoValueAsString()); - } else if (GribDimension.PERTURB_DIM.equals(name)) { - values.add(String.valueOf(modelInfo.getPerturbationNumber())); - } else if (GribDimension.ENSEMBLE_DIM.equals(name)) { - values.add(String.valueOf(modelInfo.getTypeEnsemble())); - } else if (GribDimension.VERSION_DIM.equals(name)) { - values.add(String.valueOf(rec.getGridVersion())); + } else if (name.startsWith(LevelDimUtil.LEVEL_DIM_PREFIX)) { + values.add(LevelDimUtil.formatLevelValue(level)); + } else if (GribDimension.PARAM_DIM.equals(name)) { + values.add(getParameter(rec)); } else { - statusHandler.warn("Unkown grib dimension: " + name); + log.warn("Unkown grib dimension: " + name); } } } - @Override - protected void addToTimes(GribLayer layer, GribRecord rec) { - Set times = layer.getTimes(); - times.add(rec.getDataTime().getValidTime().getTime()); + /** + * Get parameter string from record + * + * @param rec + * @return + */ + private String getParameter(GridRecord rec) { + String fieldName = rec.getInfo().getParameter().getAbbreviation(); + return GribRecordFinder.dbToOgcParameter(fieldName); } @Override - protected boolean initializeLayer(GribLayer layer, GribRecord rec) { - GribModel model = rec.getModelInfo(); - GridCoverage cov = model.getLocation(); - if (cov == null) { - statusHandler.warn("Recieved record without coverage!"); + protected void addToTimes(GridCompositeLayer layer, GridRecord rec) { + String parameter = getParameter(rec); + layer.addTime(parameter, rec.getDataTime().getValidTime().getTime()); + } + + @Override + protected boolean initializeLayer(GridCompositeLayer layer, GridRecord rec) { + GridInfoRecord info = rec.getInfo(); + Level level = info.getLevel(); + Parameter parameter = info.getParameter(); + if (parameter.getAbbreviation().startsWith("static")) { return false; } + Unit unit = level.getMasterLevel().getUnit(); + if (unit == null) { + layer.setVertical(false); + } + try { + AltUtil.convert(SI.METER, unit, 1); + } catch (Exception e) { + layer.setVertical(false); + } + GridCoverage cov = info.getLocation(); + if (cov == null) { + log.warn("Recieved record without coverage!"); + return false; + } + layer.setCoverageName(cov.getName()); + String crsWkt = cov.getCrsWKT(); + if (crsWkt == null) { + crsWkt = cov.getCrs().toWKT(); + } + layer.setCrsWkt(crsWkt); layer.setNx(cov.getNx()); layer.setNy(cov.getNy()); layer.setTargetCrsCode("CRS:84"); try { - Envelope env = getProperBounds(cov); + Envelope env = getProperBounds(layer, cov, info); layer.setTargetMinx(env.getMinX()); layer.setTargetMiny(env.getMinY()); layer.setTargetMaxx(env.getMaxX()); layer.setTargetMaxy(env.getMaxY()); layer.setCrs84Bounds(JTS.toGeometry(env)); } catch (Exception e) { - statusHandler.error("Unable to get crs84 bounds", e); + log.error("Unable to get crs84 bounds", e); return false; } - layer.setTimes(new TreeSet()); - String levelUnit = rec.getModelInfo().getLevelUnit(); + String levelUnit = level.getMasterLevel().getUnitString(); + MasterLevel master = level.getMasterLevel(); TreeSet dims = new TreeSet(); dims.add(new GribDimension(GribDimension.REFTIME_DIM, "ISO8601")); dims.add(new GribDimension(GribDimension.FORECAST_OFFSET_DIM, "ISO8601")); - dims.add(new GribDimension(GribDimension.LEVEL1_DIM, levelUnit)); - dims.add(new GribDimension(GribDimension.LEVEL2_DIM, levelUnit)); - dims.add(new GribDimension(GribDimension.PERTURB_DIM, null)); - dims.add(new GribDimension(GribDimension.ENSEMBLE_DIM, null)); - dims.add(new GribDimension(GribDimension.VERSION_DIM, null)); - layer.setDimensions(dims); + String levelName = LevelDimUtil.LEVEL_DIM_PREFIX + master.getName(); + dims.add(new GribDimension(levelName, levelUnit)); + dims.add(new GribDimension(GribDimension.PARAM_DIM, parameter.getUnit() + .toString())); + layer.addDimensions(getParameter(rec), dims); return true; } - protected ReferencedEnvelope getProperBounds(GridCoverage cov) - throws FactoryException, MismatchedDimensionException, - TransformException { + protected ReferencedEnvelope getProperBounds(GribLayer layer, + GridCoverage cov, GridInfoRecord info) throws FactoryException, + MismatchedDimensionException, TransformException { + String dataset = info.getDatasetId(); + // the gemglobal and gfs global grids are already in a crs:84 + // projection, + // so there is no transformation needed. + if (dataset.equals("GEMGlobal") || dataset.equals("GFS230") + || dataset.equals("GlobalWave")) { + return new ReferencedEnvelope(-180.0, 180.0, -90.0, 90.0, + cov.getCrs()); + } + // the polygon is not projected properly, must get native bounds and // reproject into crs:84 CoordinateReferenceSystem nativeCrs = cov.getCrs(); @@ -157,64 +163,59 @@ public class GribLayerCollector extends .getEnvelopeInternal(); ReferencedEnvelope nativeEnv = new ReferencedEnvelope(env.getMinX(), env.getMaxX(), env.getMinY(), env.getMaxY(), nativeCrs); - return nativeEnv.transform(MapUtil.LATLON_PROJECTION, true); + layer.setNativeMinX(env.getMinX()); + layer.setNativeMinY(env.getMinY()); + layer.setNativeMaxX(env.getMaxX()); + layer.setNativeMaxY(env.getMaxY()); + ReferencedEnvelope crs84Env = nativeEnv.transform( + MapUtil.LATLON_PROJECTION, true); + // This is to fix when non-polar coverages cross poles or opposite + // meridian + // This will completely break polar coverages + double minx = crs84Env.getMinX(); + double miny = crs84Env.getMinY(); + double maxx = crs84Env.getMaxX(); + double maxy = crs84Env.getMaxY(); + if (maxx > 180 || minx < -180) { + // coverage crosses opposite meridian, advertise all the way around + minx = -180; + maxx = 180; + } + if (maxy > 90) { + // coverage crosses north pole, truncate + maxy = 90; + } + if (miny < -90) { + // coverage crosses south pole, truncate + miny = -90; + } + return new ReferencedEnvelope(minx, maxx, miny, maxy, + crs84Env.getCoordinateReferenceSystem()); } @Override - protected String getLayerName(GribRecord rec) { - GribModel modelInfo = rec.getModelInfo(); - String modelName = modelInfo.getModelName(); - String parameter = modelInfo.getParameterAbbreviation(); - String level = modelInfo.getLevel().getMasterLevel().getName(); - return modelName + "/" + parameter + "/" + level; + public String getLayerName(GridRecord rec) { + return createLayerName(rec); } - @Override - public void sendMetaData(Map layermap, - Collection coll) { - - for (Entry entry : layermap.entrySet()) { - GribLayer layer = entry.getValue(); - - // for (GribDimension) - - // GriddedDataSetMetaData gdsmd = new GriddedDataSetMetaData(); - // GriddedCoverage griddedCoverage = new GriddedCoverage(); - // GridCoverage gridCoverage = - layer.toString(); - - } - - for (PluginDataObject pdo : coll) { - GribRecord gr = (GribRecord) pdo; - gr.toString(); - } - + public static String createLayerName(GridRecord rec) { + GridInfoRecord info = rec.getInfo(); + GridCoverage cov = info.getLocation(); + String levelName = info.getLevel().getMasterLevel().getName(); + return info.getDatasetId() + OgcLayer.keySeparator + cov.getName() + + OgcLayer.keySeparator + levelName; } - /** - * Get's the correct gridCoverage + + /* + * (non-Javadoc) * - * @return - * - * protected GridCoverage getGridCoverage() { - * - * GridCoverage gridCoverage = null; - * - * if (getProvider().getProjection().getName() - * .equals(LatLonGridCoverage.PROJECTION_TYPE)) { gridCoverage = new - * LatLonGridCoverage(); } else if - * (getProvider().getProjection().getName() - * .equals(LambertConformalGridCoverage.PROJECTION_TYPE)) { - * gridCoverage = new LambertConformalGridCoverage(); } else if - * (getProvider().getProjection().getName() - * .equals(MercatorGridCoverage.PROJECTION_TYPE)) { gridCoverage = - * new MercatorGridCoverage(); } else if - * (getProvider().getProjection().getName() - * .equals(PolarStereoGridCoverage.PROJECTION_TYPE)) { gridCoverage - * = new PolarStereoGridCoverage(); } - * - * return gridCoverage; - * - * } + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerCollector#copy(com.raytheon.uf + * .edex.ogc.common.db.SimpleLayer) */ + @Override + protected GridCompositeLayer copy(GridCompositeLayer orig) { + return new GridCompositeLayer(orig); + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribNativeCrsAuthority.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribNativeCrsAuthority.java new file mode 100644 index 0000000000..3a3903993a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribNativeCrsAuthority.java @@ -0,0 +1,108 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import java.util.List; + +import org.opengis.parameter.ParameterValueGroup; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.crs.ProjectedCRS; +import org.opengis.referencing.operation.Projection; + +import com.raytheon.uf.common.gridcoverage.GridCoverage; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.database.DataAccessLayerException; +import com.raytheon.uf.edex.database.dao.CoreDao; +import com.raytheon.uf.edex.database.dao.DaoConfig; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.spatial.NativeCrsAuthority; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 6, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GribNativeCrsAuthority implements NativeCrsAuthority { + + public static final String ID = "grib"; + + private final CoreDao covDao = new CoreDao( + DaoConfig.forClass(GridCoverage.class)); + + private final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.spatial.NativeCrsAuthority#lookup(java.lang.String) + */ + @Override + public CoordinateReferenceSystem lookup(String urn) throws OgcException { + if ( urn == null){ + return null; + } + String local = urn.substring(NATIVE_CRS_PREFIX.length()); + String[] parts = local.split(":"); + try { + List res = covDao.queryBySingleCriteria("name", parts[0]); + if (res == null || res.isEmpty()) { + return null; + } + GridCoverage cov = (GridCoverage) res.get(0); + return cov.getCrs(); + } catch (DataAccessLayerException e) { + log.error("Unable to lookup coverage", e); + throw new OgcException(Code.InternalServerError, e); + } + } + + /** + * @param cov + * @return Native CRS URN for coverage + */ + public static String createURN(GridCoverage cov) { + String name = cov.getName(); + // TODO assumption that all native grid systems are projected + ProjectedCRS crs = (ProjectedCRS) cov.getCrs(); + return createURN(name, crs); + } + + /** + * @param coverageName + * @param crs + * @return Native CRS URN for coverage + */ + public static String createURN(String coverageName, ProjectedCRS crs) { + Projection conv = crs.getConversionFromBase(); + ParameterValueGroup params = conv.getParameterValues(); + String projName = params.getDescriptor().getName().getCode(); + return NATIVE_CRS_PREFIX + coverageName + ":" + projName; + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.spatial.NativeCrsAuthority#getId() + */ + @Override + public String getId() { + return ID; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribRecordFinder.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribRecordFinder.java index 989a7b7884..f3c48a120a 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribRecordFinder.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribRecordFinder.java @@ -1,234 +1,413 @@ /* -* The following software products were developed by Raytheon: -* -* ADE (AWIPS Development Environment) software -* CAVE (Common AWIPS Visualization Environment) software -* EDEX (Environmental Data Exchange) software -* uFrame™ (Universal Framework) software -* -* Copyright (c) 2010 Raytheon Co. -* All rights reserved. This program and the accompanying materials -* are made available under the terms of the Eclipse Public License v1.0 -* which accompanies this distribution, and is available at -* http://www.eclipse.org/org/documents/epl-v10.php -* -* -* Contractor Name: Raytheon Company -* Contractor Address: -* 6825 Pine Street, Suite 340 -* Mail Stop B8 -* Omaha, NE 68106 -* 402.291.0100 -* -* -* SOFTWARE HISTORY -* -* Date Ticket# Engineer Description -* ------------ ---------- ----------- -------------------------- -* Feb 21, 2012 bclement Initial creation -* -*/ + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Feb 21, 2012 bclement Initial creation + * + */ package com.raytheon.uf.edex.plugin.grib.ogc; +import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; import java.util.SortedSet; -import java.util.regex.Matcher; import org.hibernate.Criteria; import org.hibernate.SessionFactory; import org.hibernate.classic.Session; +import org.hibernate.criterion.Conjunction; +import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Disjunction; import org.hibernate.criterion.Restrictions; -import com.raytheon.uf.common.dataplugin.grib.GribRecord; +import com.raytheon.uf.common.dataplugin.grid.GridInfoRecord; +import com.raytheon.uf.common.dataplugin.grid.GridRecord; +import com.raytheon.uf.common.dataplugin.level.Level; import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.edex.database.DataAccessLayerException; import com.raytheon.uf.edex.database.plugin.PluginDao; import com.raytheon.uf.edex.database.plugin.PluginFactory; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.OgcLayer; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; -import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.level.LevelDimUtil; import com.raytheon.uf.edex.ogc.common.time.ForecastTimeUtil; +import com.raytheon.uf.edex.plugin.dataset.urn.CFNameLookup; /** - * + * * @author bclement - * @version 1.0 + * @version 1.0 */ public class GribRecordFinder { - protected static String level1Key = "level1"; + public static final String INFO_ALIAS = "info_alias"; - protected static String level2Key = "level2"; + public static final String LEVEL_ALIAS = "level_alias"; - protected static String pertKey = "perturbation_num"; + public static final String MASTER_LEVEL_ALIAS = "master_level_alias"; - protected static String eTypeKey = "ensemble_type"; + public static final String COV_ALIAS = "cov_alias"; - protected static String versKey = "version"; + public static final String INFO = "info"; - public static class Level { - public Double value; + public static final String LEVEL = "info_alias.level"; - public String units; - } + public static final String LEVLE_ONE = LEVEL_ALIAS + ".levelonevalue"; - public static List find(LayerTransformer transformer, - String key, String layerName, Date time, - Map dimensions) - throws OgcException { - SimpleLayer l = getLayer(transformer, layerName); - SortedSet times = new ForecastTimeUtil().getDataTimes(l, - time, dimensions); - return findInternal(l, transformer, key, layerName, times, dimensions); - } + public static final String LEVLE_TWO = LEVEL_ALIAS + ".leveltwovalue"; - public static List find(LayerTransformer transformer, - String key, String layerName, String time, - Map dimensions) throws OgcException { - SimpleLayer l = getLayer(transformer, layerName); - SortedSet times = new ForecastTimeUtil().getDataTimes(l, - time, dimensions); - return findInternal(l, transformer, key, layerName, times, dimensions); - } + public static final String MASTER_LEVEL = LEVEL_ALIAS + ".masterLevel"; - protected static List findInternal(SimpleLayer l, - LayerTransformer transformer, String key, String layerName, - SortedSet times, Map dimensions) - throws OgcException { - String level1 = getLevel(dimensions, level1Key, l); - String level2 = getLevel(dimensions, level2Key, l); - String ensemble = getIntDim(dimensions, eTypeKey, l); - String pert = getIntDim(dimensions, pertKey, l); - String version = getIntDim(dimensions, versKey, l); - // TODO ensure consistency in which level gets returned - // TODO add support for more dimensions - return query(key, layerName, times, level1, level2, ensemble, pert, - version); - } + public static final String LEVEL_UNIT = MASTER_LEVEL_ALIAS + ".unitString"; - public static SimpleLayer getLayer(LayerTransformer transformer, - String layerName) throws OgcException { - SimpleLayer rval; - try { - rval = transformer.find(layerName); - } catch (DataAccessLayerException e) { - throw new OgcException(Code.InternalServerError, e); - } - if (rval == null) { - throw new OgcException(Code.LayerNotDefined); - } - return rval; - } + public static final String LEVEL_NAME = MASTER_LEVEL_ALIAS + ".name"; - protected static String getIntDim(Map dimensions, - String key, SimpleLayer layer) throws OgcException { - String str = dimensions.get(key); - String rval; - if (str != null) { - try { - Integer i = Integer.parseInt(str); - rval = i.toString(); - } catch (Exception e) { - throw new OgcException(Code.InvalidDimensionValue, key - + " must be a bare integer"); - } - } else { - SimpleDimension dim = LayerTransformer.getDimension(layer, key); - rval = dim.getDefaultValue(layer); - } - return rval; - } + public static final String DS_NAME = INFO_ALIAS + ".datasetId"; - /** - * @param dimensions - * @param key - * @param l - * @return null if level value not in dimensions and not in layer - */ - protected static String getLevel(Map dimensions, - String key, SimpleLayer layer) { - String dimKey = new String(key).toLowerCase(); - String level = dimensions.get(dimKey); - String rval; - if (level != null) { - Level l = parseLevel(level); - rval = l.value.toString(); - } else { - SimpleDimension dim = LayerTransformer.getDimension(layer, key); - rval = dim.getDefaultValue(layer); - } - return rval; - } + public static final String COVERAGE = INFO_ALIAS + ".location"; - @SuppressWarnings("unchecked") - protected static List query(String key, String layer, - SortedSet times, String level1, String level2, - String eType, String pert, String version) throws OgcException { - Session sess = null; - try { - PluginDao dao = PluginFactory.getInstance().getPluginDao(key); - SessionFactory sessFact = dao.getSessionFactory(); - sess = sessFact.openSession(); - Criteria criteria = sess.createCriteria(GribRecord.class); - criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); - Disjunction or = Restrictions.disjunction(); - for (DataTime dt : times) { - String uri = getDataUri(key, layer, dt, level1, level2, eType, - pert, - version); - or.add(Restrictions.like("dataURI", uri)); - } - criteria.add(or); - List res = (List) criteria.list(); - return res; - } catch (Exception e) { - throw new OgcException(Code.InternalServerError); - } finally { - if (sess != null) { - sess.close(); - } - } - } + public static final String COVERAGE_NAME = COV_ALIAS + ".name"; - protected static String getDataUri(String key, String layer, DataTime dt, - String level1, String level2, String eType, String pert, - String version) { - // this is based how the layer name is built in the layers table - // FIXME this is hackish - StringBuilder sb = new StringBuilder("/").append(key); - sb.append('/').append(dt.toString()).append("%/"); - sb.append(layer).append('/').append(level1); - sb.append('/').append(level2).append('/'); - sb.append((eType == null ? "null" : eType)).append('/'); - sb.append((pert == null ? "null" : pert)).append('/'); - sb.append((version == null ? "null" : version)); - return sb.toString().replaceAll(" ", "_"); - } + public static final String PARAM = INFO_ALIAS + ".parameter"; - protected static Level parseLevel(String level) { - if (level == null) { - return null; - } - Level rval = new Level(); - Matcher m = LayerTransformer.frontDot.matcher(level); - if (m.matches()) { - rval.value = Double.parseDouble(m.group(1)); - rval.units = m.group(2); - } else { - m = LayerTransformer.backDot.matcher(level); - if (m.matches()) { - rval.value = Double.parseDouble(m.group(1)); - rval.units = m.group(2); - } else { - rval = null; - } - } - return rval; - } + public static final String PARAM_ALIAS = "param_alias"; + public static final String PARAM_ABBV = PARAM_ALIAS + ".abbreviation"; + + public static final String REF_TIME = "dataTime.refTime"; + + public static final String FCST_TIME = "dataTime.fcstTime"; + + public static class Comp implements Comparator { + /* + * (non-Javadoc) + * + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + @Override + public int compare(GridRecord left, GridRecord right) { + Date rightRef = right.getDataTime().getRefTime(); + Date leftRef = left.getDataTime().getRefTime(); + int rval = rightRef.compareTo(leftRef); + if (rval == 0) { + GridInfoRecord leftInfo = left.getInfo(); + GridInfoRecord rightInfo = right.getInfo(); + // FIXME this doesn't take units into account + Level leftLevel = leftInfo.getLevel(); + Level rightLevel = rightInfo.getLevel(); + rval = (int) (leftLevel.getLevelonevalue() - rightLevel + .getLevelonevalue()); + if (rval == 0) { + if (leftInfo.getEnsembleId() != null) { + if (rightInfo.getEnsembleId() != null) { + rval = leftInfo.getEnsembleId().compareTo( + rightInfo.getEnsembleId()); + } else { + rval = 1; + } + } else { + if (rightInfo.getEnsembleId() != null) { + rval = -1; + } else { + rval = 0; + } + } + } + } + return rval; + } + } + + public static List findWms( + LayerTransformer transformer, + String key, String layerName, Date time, + Map dimensions) throws OgcException { + GridParamLayer l = getLayer(transformer, layerName); + SortedSet times = new ForecastTimeUtil().getDataTimes(l, + time, dimensions); + return findInternal(l, transformer, key, times, dimensions, + parseWmsId(layerName)); + } + + public static List findWms( + LayerTransformer transformer, + String key, String layerName, String time, + Map dimensions) throws OgcException { + GridParamLayer l = getLayer(transformer, layerName); + SortedSet times = new ForecastTimeUtil().getDataTimes(l, + time, dimensions); + return findInternal(l, transformer, key, times, dimensions, + parseWmsId(layerName)); + } + + protected static List findInternal(GridParamLayer l, + LayerTransformer transformer, + String key, SortedSet times, + Map dimensions, Criterion idCrit) + throws OgcException { + Criterion levelCrit = getLevel(dimensions, l); + String param = ogcToDbParameter(l.getParameter()); + // TODO ensure consistency in which level gets returned + // TODO add support for more dimensions + return query(key, times, param, idCrit, levelCrit); + } + + public static GridParamLayer getLayer( + LayerTransformer transformer, + String layerName) throws OgcException { + GridParamLayer rval; + try { + rval = transformer.find(layerName); + } catch (OgcException e) { + throw new OgcException(Code.InternalServerError, e); + } + if (rval == null) { + throw new OgcException(Code.LayerNotDefined); + } + return rval; + } + + protected static String getIntDim(Map dimensions, + String key, GribLayer layer) throws OgcException { + String rval = getDim(dimensions, key, layer); + if (rval != null) { + try { + Integer i = Integer.parseInt(rval); + rval = i.toString(); + } catch (Exception e) { + throw new OgcException(Code.InvalidDimensionValue, key + + " must be a bare integer"); + } + } + return rval; + } + + protected static String getDim(Map dimensions, String key, + GribLayer layer) { + String rval = dimensions.get(key); + if (rval == null) { + SimpleDimension dim = layer.getDimension(key); + rval = dim.getDefaultValue(layer); + } + return rval; + } + + /** + * @param dimensions + * @param l + * @return null if level value not in dimensions and not in layer + * @throws OgcException + */ + protected static Criterion getLevel(Map dimensions, + GribLayer layer) throws OgcException { + String dimName = null; + // find level dimension in request + for (String dim : dimensions.keySet()) { + String lower = dim.toLowerCase(); + if (lower.startsWith(LevelDimUtil.LEVEL_DIM_PREFIX.toLowerCase())) { + dimName = dim; + break; + } + } + SimpleDimension dim; + String value; + if (dimName == null) { + return null; + } else { + dim = layer.getDimension(dimName); + if (dim == null) { + return null; + } + value = dimensions.get(dimName); + } + // undo any case changes + dimName = dim.getName(); + return parseLevel(dimName, value, dim.getUnits()); + } + + @SuppressWarnings("unchecked") + protected static List query(String key, + SortedSet times, String param, Criterion idCrit, + Criterion levelCrit) throws OgcException { + Session sess = null; + try { + PluginDao dao = PluginFactory.getInstance().getPluginDao(key); + SessionFactory sessFact = dao.getSessionFactory(); + sess = sessFact.openSession(); + Criteria criteria = sess.createCriteria(GridRecord.class); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + Disjunction or = Restrictions.disjunction(); + Criterion paramCrit = Restrictions.eq(PARAM_ABBV, param); + for (DataTime dt : times) { + Conjunction and = Restrictions.conjunction(); + and.add(idCrit).add(paramCrit); + if (levelCrit != null) { + and.add(levelCrit); + } + and.add(getTimeCrit(dt)); + or.add(and); + } + criteria.add(or); + modCriteria(criteria); + List res = (List) criteria.list(); + return res; + } catch (Exception e) { + throw new OgcException(Code.InternalServerError); + } finally { + if (sess != null) { + sess.close(); + } + } + } + + /** + * @param dt + * @return + */ + private static Criterion getTimeCrit(DataTime dt) { + return Restrictions.and(Restrictions.eq(FCST_TIME, dt.getFcstTime()), + Restrictions.eq(REF_TIME, dt.getRefTime())); + } + + /** + * @param dimName + * @param value + * @param defaultUnits + * @return + * @throws OgcException + */ + public static Criterion parseLevel(String dimName, String value, + String defaultUnits) throws OgcException { + Level level = LevelDimUtil.parseLevel(dimName, value, defaultUnits); + if (level == null) { + return Restrictions.eq(LEVEL_NAME, + dimName.substring(LevelDimUtil.LEVEL_DIM_PREFIX.length())); + } + Criterion nameEq = Restrictions.eq(LEVEL_NAME, level.getMasterLevel() + .getName()); + Conjunction and = Restrictions.conjunction(); + and.add(nameEq); + and.add(Restrictions.eq(LEVLE_ONE, level.getLevelonevalue())); + and.add(Restrictions.eq(LEVLE_TWO, level.getLeveltwovalue())); + + String units = level.getMasterLevel().getUnitString(); + if (units != null) { + and.add(Restrictions.eq(LEVEL_UNIT, units)); + } else { + and.add(Restrictions.isNull(LEVEL_UNIT)); + } + + return and; + } + + /** + * @param id + * @return + * @throws OgcException + */ + public static Criterion parseWcsId(String id) throws OgcException { + String[] parts = id.split(OgcLayer.keySeparator); + String model; + String coverage; + String level; + if (parts.length < 3) { + throw new OgcException(Code.InvalidFormat, "Invalid id format"); + } else { + level = parts[2]; + coverage = parts[1]; + model = parts[0]; + } + Conjunction and = Restrictions.conjunction(); + and.add(Restrictions.eq(DS_NAME, model)); + and.add(Restrictions.eq(COVERAGE_NAME, coverage)); + and.add(Restrictions.eq(LEVEL_NAME, level)); + return and; + } + + /** + * @param id + * @return + * @throws OgcException + */ + public static Criterion parseWmsId(String id) throws OgcException { + String[] parts = id.split(OgcLayer.keySeparator); + String model; + String coverage; + String level; + String param; + if (parts.length < 4) { + throw new OgcException(Code.InvalidFormat, "Invalid id format"); + } else { + level = parts[3]; + coverage = parts[1]; + model = parts[0]; + param = ogcToDbParameter(parts[2]); + } + Conjunction and = Restrictions.conjunction(); + and.add(Restrictions.eq(DS_NAME, model)); + and.add(Restrictions.eq(COVERAGE_NAME, coverage)); + and.add(Restrictions.eq(LEVEL_NAME, level)); + and.add(Restrictions.eq(PARAM_ABBV, param)); + return and; + } + + /** + * Add grid aliases to criteria + * + * @param criteria + * @return + */ + public static Criteria modCriteria(Criteria criteria) { + criteria = criteria.createAlias(INFO, INFO_ALIAS); + criteria = criteria.createAlias(PARAM, PARAM_ALIAS); + criteria = criteria.createAlias(LEVEL, LEVEL_ALIAS); + criteria = criteria.createAlias(MASTER_LEVEL, MASTER_LEVEL_ALIAS); + return criteria.createAlias(COVERAGE, COV_ALIAS); + } + + /** + * Convert OGC parameter name to name stored in database + * + * @param parameter + * @return + */ + public static String ogcToDbParameter(String parameter) { + return CFNameLookup.getInstance().getNCEPFromCF(parameter); + } + + /** + * Convert parameter name stored in database to OGC name + * + * @param parameter + * @return + */ + public static String dbToOgcParameter(String parameter) { + return CFNameLookup.getInstance().getCFFromNCEP(parameter); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWcsSource.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWcsSource.java index 22877fede7..7481f2f667 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWcsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWcsSource.java @@ -31,21 +31,45 @@ package com.raytheon.uf.edex.plugin.grib.ogc; import java.util.ArrayList; -import java.util.Date; +import java.util.Calendar; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Matcher; + +import javax.measure.unit.Unit; +import javax.xml.bind.DatatypeConverter; + +import org.apache.commons.collections.map.LRUMap; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.referencing.CRS; +import org.hibernate.Criteria; +import org.hibernate.criterion.Conjunction; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.Disjunction; +import org.hibernate.criterion.Restrictions; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.crs.ProjectedCRS; -import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.PluginProperties; -import com.raytheon.uf.common.dataplugin.grib.GribRecord; +import com.raytheon.uf.common.dataplugin.grid.GridRecord; +import com.raytheon.uf.common.dataplugin.level.MasterLevel; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; -import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; -import com.raytheon.uf.edex.plugin.grib.ogc.GribRecordFinder; +import com.raytheon.uf.edex.ogc.common.level.LevelDimUtil; +import com.raytheon.uf.edex.ogc.common.spatial.AltUtil; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; +import com.raytheon.uf.edex.plugin.unitconverter.UnitLookup; import com.raytheon.uf.edex.wcs.WcsException; import com.raytheon.uf.edex.wcs.WcsException.Code; import com.raytheon.uf.edex.wcs.reg.CoverageTransform; @@ -60,15 +84,20 @@ import com.raytheon.uf.edex.wcs.reg.RangeField; * @author jelkins * @version 1.0 */ -public class GribWcsSource extends DefaultWcsSource { +public class GribWcsSource extends + DefaultWcsSource { - private CoverageTransform _cTransform; + private CoverageTransform _cTransform; - /** - * @param props - * @param layerTable - */ - public GribWcsSource(PluginProperties props, LayerTransformer transformer) { + private static final String PARAM_KEY = GribDimension.PARAM_DIM; + + /** + * @param props + * @param layerTable + */ + public GribWcsSource(PluginProperties props, + LayerTransformer transformer, + GribLayerCollector collector) { super(props, transformer); } @@ -78,103 +107,364 @@ public class GribWcsSource extends DefaultWcsSource { * @see com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getCoverageTransform() */ @Override - protected CoverageTransform getCoverageTransform() { + public CoverageTransform getCoverageTransform() { if (_cTransform == null) { - _cTransform = new CoverageTransform(transformer.getKey()) { - + _cTransform = new CoverageTransform( + transformer.getKey()) { @Override - protected List getRangeFields(SimpleLayer layer) { - Set dims = layer.getDimensions(); - List rval = new ArrayList( - dims.size()); - for (SimpleDimension dim : dims) { - rval.add(convert(dim)); + protected List getRangeFields(GribLayer layer) { + List rval = new ArrayList(); + SimpleDimension params = layer + .getDimension(GribDimension.PARAM_DIM); + for (String name : params.getValues()) { + rval.add(new RangeField(name, null)); } + SimpleDimension refDim = layer + .getDimension(GribDimension.REFTIME_DIM); + rval.add(convert(refDim)); return rval; } - protected RangeField convert(SimpleDimension dim) { - String name = dim.getName(); - Set fromVals = dim.getValues(); - String units = dim.getUnits(); - RangeField rf = new RangeField(name, null); - List axis = new ArrayList(1); - if ( units == null ){ - // use dim name as axis label - units = name; - } - axis.add(new RangeAxis(units, fromVals)); - rf.setAxis(axis); - return rf; - } + protected RangeField convert(SimpleDimension dim) { + String name = dim.getName(); + Set fromVals = dim.getValues(); + String units = dim.getUnits(); + RangeField rf = new RangeField(name, null); + List axis = new ArrayList(1); + if (units == null) { + // use dim name as axis label + units = name; + } + axis.add(new RangeAxis(units, fromVals)); + rf.setAxis(axis); + return rf; + } + + @SuppressWarnings("unchecked") + private final Map> cache = Collections + .synchronizedMap(new LRUMap(3)); + + private Unit getUnit(String str) { + Unit rval = cache.get(str); + if (rval == null) { + rval = Unit.valueOf(str); + cache.put(str, rval); + } + return rval; + } + + @Override + protected VerticalCoordinate getVertical(GribLayer layer) + throws WcsException { + if (!layer.isVertical()) { + return null; + } + List levels = LayerTransformer + .getDimsByPrefix(layer, + LevelDimUtil.LEVEL_DIM_PREFIX); + if (levels.isEmpty()) { + log.error("attempted to get vertical component of empty layer"); + throw new WcsException(Code.InternalServerError); + } + // TODO get sample that represents majority + SimpleDimension sample = levels.get(0); + Unit targetUnits = getUnit(sample.getUnits()); + String levelName = sample.getName().substring( + LevelDimUtil.LEVEL_DIM_PREFIX.length()); + Reference targetRef = VerticalLevelLookup + .getReference(levelName); + double min = Double.POSITIVE_INFINITY; + double max = Double.NEGATIVE_INFINITY; + for (SimpleDimension l : levels) { + String unitStr = l.getUnits(); + Unit unit = cache.get(unitStr); + if (unit == null) { + unit = Unit.valueOf(unitStr); + cache.put(unitStr, unit); + } + levelName = sample.getName().substring( + LevelDimUtil.LEVEL_DIM_PREFIX.length()); + Reference ref = VerticalLevelLookup + .getReference(levelName); + for ( String val : l.getValues()){ + VerticalCoordinate vert = parseLevelValue(val, + unit, ref); + VerticalCoordinate convert = AltUtil.convert( + targetUnits, targetRef, vert); + min = Math.min(min, convert.getMin()); + max = Math.max(max, convert.getMax()); + } + } + return new VerticalCoordinate(min, max, targetUnits, + targetRef); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.CoverageTransform#getBboxes( + * com.raytheon.uf.edex.ogc.common.db.SimpleLayer) + */ + @Override + protected List getBboxes(GribLayer layer) + throws WcsException { + List rval = new ArrayList( + 2); + VerticalCoordinate vert = getVertical(layer); + ReferencedEnvelope crs84Horiz = getHorizontal(layer); + rval.add(new Composite3DBoundingBox(crs84Horiz, vert)); + try { + GribLayer griblayer = (GribLayer) layer; + CoordinateReferenceSystem crs = CRS.parseWKT(griblayer + .getCrsWkt()); + ReferencedEnvelope nativeHoriz = new ReferencedEnvelope( + griblayer.getNativeMinX(), + griblayer.getNativeMaxX(), + griblayer.getNativeMinY(), + griblayer.getNativeMaxY(), crs); + String native2DCrsUrn = GribNativeCrsAuthority + .createURN(griblayer.getCoverageName(), + (ProjectedCRS) crs); + rval.add(new Composite3DBoundingBox(nativeHoriz, + native2DCrsUrn, vert)); + } catch (FactoryException e) { + log.error("Unable to determine native BBOX", e); + } + return rval; + } + }; } return _cTransform; } - @Override - protected PluginDataObject getRecord(String identifier, DataTime time, - List rangeFields) throws WcsException { - List res; - try { - Map dimensions = parseRange(rangeFields); - Date d = (time == null ? null : time.getRefTime()); - res = GribRecordFinder.find(transformer, transformer.getKey(), - identifier, d, dimensions); - } catch (OgcException e) { - WcsException err = new WcsException(e); - if (err.getCode().equals(Code.InternalServerError)) { - log.error("Problem getting grib layer: " + identifier); - } - throw err; - } - if (res.isEmpty()) { - throw new WcsException(Code.LayerNotDefined, - "No layer matching all specified dimensions found"); - } - if (res.size() > 1) { - throw new WcsException(Code.InternalServerError, - "Too many matches for criteria"); - } - return res.get(0); - } + private void addToMap(Map> map, String key, String item) { + Set list = map.get(key); + if (list == null) { + list = new TreeSet(); + map.put(key, list); + } + list.add(item); + } - /** - * @param rangeFields - * @return - */ - private Map parseRange(List fields) { - if (fields == null) { - return new HashMap(0); - } - Map rval = new HashMap(fields.size()); - for (RangeField rf : fields) { - String key = rf.getIdentifier().toLowerCase(); - if (rf.getAxis() == null) { - continue; - } - for (RangeAxis ra : rf.getAxis()) { - Set keys = ra.getKeys(); - if (keys != null && !keys.isEmpty()) { - // default to use the first value found - // TODO should throw and error if multiple range values are - // provided - rval.put(key, keys.iterator().next()); - break; - } - } - } - return rval; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#parseFields(java.util.List) + */ + @Override + protected Map> parseFields(List fields) + throws WcsException { + if (fields == null) { + return new HashMap>(0); + } + Map> rval = new HashMap>( + fields.size()); + for (RangeField rf : fields) { + String key = rf.getIdentifier().toLowerCase(); + if (rf.getAxis() == null || rf.getAxis().isEmpty()) { + addToMap(rval, PARAM_KEY, rf.getIdentifier()); + continue; + } + for (RangeAxis ra : rf.getAxis()) { + Set keys = ra.getKeys(); + if (keys != null && !keys.isEmpty()) { + rval.put(key, keys); + break; + } + } + } + return rval; + } + + /** + * @param val + * @return + * @throws WcsException + */ + private VerticalCoordinate parseLevelValue(String val, Unit unit, + Reference ref) throws WcsException { + Matcher m = LevelDimUtil.levelPattern.matcher(val); + if (m.matches()) { + double val1 = Double.parseDouble(m.group(1)); + if (m.group(3) == null) { + return new VerticalCoordinate(val1, unit, ref); + } else { + double val2 = Double.parseDouble(m.group(3)); + return new VerticalCoordinate(val1, val2, unit, ref); + } + } + throw new WcsException(Code.InvalidParameterValue, + "Invalid level field value: " + val); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getScalarField() + */ + @Override + protected String getScalarField() { + return GribRecordFinder.PARAM_ABBV; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getFilterClause(java.lang + * .String, com.raytheon.uf.common.time.DataTime, java.util.Map) + */ + @Override + protected Conjunction getFilterClause(String id, DataTime time, + Map> fields) throws WcsException { + Conjunction and = Restrictions.conjunction(); + try { + and.add(GribRecordFinder.parseWcsId(id)); + } catch (OgcException e) { + throw new WcsException(e); + } + for (Entry> e : fields.entrySet()) { + if (e.getKey().equalsIgnoreCase(GribDimension.REFTIME_DIM)) { + Set values = e.getValue(); + if (values == null || values.isEmpty()) { + continue; + } + if (values.size() == 1) { + Calendar cal = DatatypeConverter.parseDateTime(values + .iterator().next()); + and.add(Restrictions.eq(GribRecordFinder.REF_TIME, + cal.getTime())); + continue; + } + Disjunction or = Restrictions.disjunction(); + Iterator iter = values.iterator(); + while (iter.hasNext()) { + String val = iter.next(); + Calendar cal = DatatypeConverter.parseDateTime(val); + or.add(Restrictions.eq(GribRecordFinder.REF_TIME, + cal.getTime())); + } + and.add(or); + } + } + addIfNotNull(and, parseTime(time)); + and.add(Restrictions.not(Restrictions.like(GribRecordFinder.PARAM_ABBV, + "static%"))); + return and; + } + + /** + * Add criteria to conjunction if not null + * + * @param and + * @param crit + */ + private void addIfNotNull(Conjunction and, Criterion crit) { + if (crit != null) { + and.add(crit); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getScalarValue(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + protected String getScalarValue(GridRecord record) throws WcsException { + return GribRecordFinder.dbToOgcParameter(new GridFieldAdapter() + .getCoverageField(record)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getAltitude(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + protected VerticalCoordinate getAltitude(GridRecord record) + throws WcsException { + return new GridVerticalEnabler().getVerticalCoordinate(record); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getScalarUnit(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + protected Unit getScalarUnit(GridRecord record) { + return record.getInfo().getParameter().getUnit(); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#isUpPositive(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + protected boolean isUpPositive(GridRecord record) { + MasterLevel masterLevel = record.getInfo().getLevel() + .getMasterLevel(); + return !"DEC".equalsIgnoreCase(masterLevel.getType()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#modCriteria(org.hibernate + * .Criteria) + */ + @Override + protected Criteria modCriteria(Criteria criteria) { + return GribRecordFinder.modCriteria(criteria); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getScalarKey() + */ + @Override + protected String getScalarKey() { + return PARAM_KEY; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getUcarUnit(com.raytheon + * .uf.common.dataplugin.PluginDataObject) + */ + @Override + protected ucar.units.Unit getUcarUnit(GridRecord record) { + Unit parameterUnitObject = record.getInfo().getParameter().getUnit(); + return UnitLookup.getInstance().getUcarFromJsr(parameterUnitObject); + } /* * (non-Javadoc) * - * @see com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getNullPadValue() + * @see + * com.raytheon.uf.edex.wcs.reg.DefaultWcsSource#getScalarCrit(java.lang + * .String) */ @Override - protected Object getNullPadValue() { - return new Byte((byte) 0); + protected Criterion getScalarCrit(String value) { + return super.getScalarCrit(GribRecordFinder.ogcToDbParameter(value)); } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWmsSource.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWmsSource.java index 446b7aae38..b46242152d 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWmsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GribWmsSource.java @@ -30,86 +30,87 @@ */ package com.raytheon.uf.edex.plugin.grib.ogc; +import java.util.Collections; import java.util.List; import java.util.Map; import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.PluginException; import com.raytheon.uf.common.dataplugin.PluginProperties; -import com.raytheon.uf.common.dataplugin.grib.GribRecord; +import com.raytheon.uf.common.dataplugin.grid.GridRecord; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; -import com.raytheon.uf.edex.plugin.grib.ogc.GribRecordFinder; import com.raytheon.uf.edex.wms.WmsException; import com.raytheon.uf.edex.wms.WmsException.Code; import com.raytheon.uf.edex.wms.reg.DefaultWmsSource; import com.raytheon.uf.edex.wms.styling.ColormapStyleProvider; -import com.raytheon.uf.edex.wms.styling.CoverageStyleProvider; +import com.raytheon.uf.edex.wms.styling.ICoverageStyleProvider; /** * * @author jelkins * @version 1.0 */ -public class GribWmsSource extends DefaultWmsSource { +public class GribWmsSource extends + DefaultWmsSource { - protected ColormapStyleProvider styler = new ColormapStyleProvider( - "grib_style_library.xml", "Grid/Default"); + protected ColormapStyleProvider styler = new ColormapStyleProvider( + "grib_style_library.xml", "Grid/Default"); - public GribWmsSource(PluginProperties props, LayerTransformer transformer) - throws PluginException { - super(props, props.getPluginName(), transformer); - } + public GribWmsSource(PluginProperties props, + LayerTransformer transformer) + throws PluginException { + super(props, props.getPluginName(), transformer); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.reg.DefaultWmsSource#getRecord(java.lang.String, - * java.lang.String, java.lang.String, java.util.Map) - */ - @Override - protected PluginDataObject getRecord(String layer, String time, - String elevation, Map dimensions, - Map levelUnits) throws WmsException { - LayerTransformer transformer; - List res; - try { - transformer = getTransformer(); - res = GribRecordFinder.find(transformer, key, layer, time, - dimensions); - } catch (OgcException e) { - WmsException err = new WmsException(e); - if (err.getCode().equals(Code.InternalServerError)) { - log.error("Problem getting grib layer: " + layer); - } - throw err; - } catch (PluginException e) { - log.error("Unable to get transformer for grib", e); - throw new WmsException(Code.InternalServerError); - } - if (res.isEmpty()) { - throw new WmsException(Code.LayerNotDefined, - "No layer matching all specified dimensions found"); - } - if (res.size() > 1) { - throw new WmsException(Code.InternalServerError, - "Too many matches for criteria"); - } - return res.get(0); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.reg.DefaultWmsSource#getRecord(java.lang.String, + * java.lang.String, java.lang.String, java.util.Map) + */ + @Override + protected PluginDataObject getRecord(String layer, String time, + String elevation, Map dimensions, + Map levelUnits) throws WmsException { + LayerTransformer transformer; + List res; + try { + transformer = getTransformer(); + res = GribRecordFinder.findWms(transformer, key, layer, time, + dimensions); + } catch (OgcException e) { + WmsException err = new WmsException(e); + if (err.getCode().equals(Code.InternalServerError)) { + log.error("Problem getting grib layer: " + layer); + } + throw err; + } catch (PluginException e) { + log.error("Unable to get transformer for grib", e); + throw new WmsException(Code.InternalServerError); + } + if (res.isEmpty()) { + throw new WmsException(Code.LayerNotDefined, + "No layer matching all specified dimensions found"); + } + if (res.size() > 1) { + Collections.sort(res, new GribRecordFinder.Comp()); + } + return res.get(0); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.reg.DefaultWmsSource#getStyleProvider(java.lang - * .String) - */ - @Override - protected CoverageStyleProvider getStyleProvider(String layer) - throws WmsException { - return styler; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.reg.DefaultWmsSource#getStyleProvider(java.lang + * .String) + */ + @Override + protected ICoverageStyleProvider getStyleProvider(String layer) + throws WmsException { + return styler; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridCompositeLayer.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridCompositeLayer.java new file mode 100644 index 0000000000..4a00fefb9e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridCompositeLayer.java @@ -0,0 +1,217 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; + +import javax.xml.bind.annotation.XmlElement; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; + +/** + * Grid layer that sorts dimensions by parameter + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 27, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GridCompositeLayer extends GribLayer { + + private static final long serialVersionUID = 6178813246077412635L; + + @XmlElement + @DynamicSerializeElement + protected HashMap> dimensions = new HashMap>(); + + @XmlElement + @DynamicSerializeElement + protected HashMap> timeMap = new HashMap>(); + + /** + * + */ + public GridCompositeLayer() { + super(); + } + + /** + * @param other + */ + public GridCompositeLayer(GridCompositeLayer other) { + super(other); + this.dimensions = new HashMap>( + other.dimensions.size()); + for (Entry> e : other.dimensions + .entrySet()) { + TreeSet set = new TreeSet(); + GribDimension.copy(set, e.getValue()); + this.dimensions.put(e.getKey(), set); + } + this.timeMap = new HashMap>(other.timeMap.size()); + for (Entry> e : other.timeMap.entrySet()) { + this.timeMap.put(e.getKey(), new TreeSet(e.getValue())); + } + } + + @Override + public Set getDimensions() { + TreeSet rval = new TreeSet(); + for (Entry> e : dimensions.entrySet()) { + rval.addAll(e.getValue()); + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.SimpleLayer#getTimes() + */ + @Override + public TreeSet getTimes() { + TreeSet rval = new TreeSet(); + for (Entry> e : timeMap.entrySet()) { + rval.addAll(e.getValue()); + } + return rval; + } + + /** + * Add time for parameter + * + * @param parameter + * @param time + */ + public void addTime(String parameter, Date time) { + TreeSet set = timeMap.get(parameter); + if (set == null) { + set = new TreeSet(); + timeMap.put(parameter, set); + } + set.add(time); + } + + /** + * @param parameter + * @return empty list if parameter has no times + */ + public TreeSet getTimes(String parameter) { + TreeSet treeSet = timeMap.get(parameter); + if (treeSet == null) { + return new TreeSet(); + } else { + return new TreeSet(treeSet); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.SimpleLayer#updateDates(com.raytheon + * .uf.edex.ogc.common.db.SimpleLayer) + */ + @Override + public void updateDates(SimpleLayer other) { + if (!(other instanceof GridCompositeLayer)) { + return; + } + GridCompositeLayer shiny = (GridCompositeLayer) other; + for (Entry> e : shiny.timeMap.entrySet()) { + TreeSet thisSet = this.timeMap.get(e.getKey()); + if (thisSet == null) { + this.timeMap.put(e.getKey(), new TreeSet(e.getValue())); + } else { + thisSet.addAll(e.getValue()); + } + } + } + + /** + * @param parameter + * @return empty set if no dimensions for parameter + */ + public TreeSet getDimensions(String parameter) { + TreeSet rval = dimensions.get(parameter); + if (rval == null) { + return new TreeSet(); + } + return rval; + } + + /** + * @param parameter + * @param dims + */ + public void addDimensions(String parameter, TreeSet dims) { + dimensions.put(parameter, dims); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.SimpleLayer#updateDims(com.raytheon + * .uf.edex.ogc.common.db.SimpleLayer) + */ + @Override + public void updateDims(SimpleLayer other) { + if (!(other instanceof GridCompositeLayer)) { + return; + } + GridCompositeLayer shiny = (GridCompositeLayer) other; + for (String key : shiny.dimensions.keySet()) { + TreeSet otherDims = shiny.dimensions.get(key); + TreeSet thisDims = dimensions.get(key); + if (thisDims == null) { + thisDims = new TreeSet(); + GribDimension.copy(thisDims, otherDims); + dimensions.put(key, thisDims); + } else { + updateDimLists(thisDims, otherDims); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.SimpleLayer#getDimension(java.lang + * .String) + */ + @Override + public GribDimension getDimension(String dimension) { + // TODO slow + return getDimMap(getDimensions()).get(dimension); + } + + /** + * @return set of parameter names for composite layer + */ + public Set getParameters() { + return dimensions.keySet(); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridFieldAdapter.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridFieldAdapter.java new file mode 100644 index 0000000000..0fda29377b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridFieldAdapter.java @@ -0,0 +1,55 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import com.raytheon.uf.common.dataplugin.grid.GridRecord; +import com.raytheon.uf.edex.wcs.reg.IFieldAdapted; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 5, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GridFieldAdapter implements IFieldAdapted { + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.FieldAdapted#getCoverageField(java.lang. + * Object) + */ + @Override + public String getCoverageField(GridRecord record) { + return record.getInfo().getParameter().getAbbreviation(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.reg.FieldAdapted#getSupportedClass() + */ + @Override + public Class getSupportedClass() { + return GridRecord.class; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridNotifyDao.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridNotifyDao.java new file mode 100644 index 0000000000..bf0fa4ceb3 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridNotifyDao.java @@ -0,0 +1,76 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import com.raytheon.uf.common.dataplugin.PluginException; +import com.raytheon.uf.common.dataplugin.grid.GridConstants; +import com.raytheon.uf.edex.database.plugin.PurgeResults; +import com.raytheon.uf.edex.ogc.common.db.PurgeNotification; +import com.raytheon.uf.edex.plugin.grid.dao.GridDao; + +/** + * Dao with purge notification for grid + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 6, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GridNotifyDao extends GridDao { + + private final PurgeNotification notify; + + /** + * @throws PluginException + */ + public GridNotifyDao() throws PluginException { + this(GridConstants.GRID); + } + + /** + * @param pluginName + * @throws PluginException + */ + public GridNotifyDao(String pluginName) throws PluginException { + super(pluginName); + this.notify = new PurgeNotification(pluginName); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.plugin.grid.dao.GridDao#purgeExpiredData() + */ + @Override + public void purgeExpiredData() throws PluginException { + PurgeResults res = super.purgeExpiredDataWithResults(); + notify.purgeExpiredData(res); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.plugin.grid.dao.GridDao#purgeAllData() + */ + @Override + public void purgeAllData() throws PluginException { + super.purgeAllData(); + notify.purgeAllData(); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridParamLayer.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridParamLayer.java new file mode 100644 index 0000000000..4ab1bb8292 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridParamLayer.java @@ -0,0 +1,116 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import java.util.Date; +import java.util.Set; +import java.util.TreeSet; + +import javax.xml.bind.annotation.XmlElement; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; + +/** + * Grid layer that has dimensions for a single parameter + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 27, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GridParamLayer extends GribLayer { + + private static final long serialVersionUID = -5614814725742630980L; + + @XmlElement + @DynamicSerializeElement + protected TreeSet dimensions; + + @XmlElement + @DynamicSerializeElement + protected String parameter; + + /** + * + */ + public GridParamLayer() { + super(); + dimensions = new TreeSet(); + } + + /** + * @param other + */ + public GridParamLayer(GridParamLayer other) { + super(other); + this.parameter = other.parameter; + this.dimensions = new TreeSet(); + GribDimension.copy(this.dimensions, other.dimensions); + } + + /** + * @param other + */ + public GridParamLayer(String parameter, GridCompositeLayer other) { + super(other); + this.parameter = parameter; + this.times = new TreeSet(other.getTimes(parameter)); + TreeSet otherDims = other.getDimensions(parameter); + this.dimensions = new TreeSet(); + for (GribDimension dim : otherDims) { + if (dim.getName().equalsIgnoreCase(GribDimension.PARAM_DIM)) { + continue; + } + this.dimensions.add(new GribDimension(dim)); + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.plugin.grib.ogc.GribLayer#getDimensions() + */ + @Override + public Set getDimensions() { + return dimensions; + } + + /** + * @return the parameter + */ + public String getParameter() { + return parameter; + } + + /** + * @param parameter + * the parameter to set + */ + public void setParameter(String parameter) { + this.parameter = parameter; + } + + /** + * @param dimensions + * the dimensions to set + */ + public void setDimensions(TreeSet dimensions) { + this.dimensions = dimensions; + } + +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridVerticalEnabler.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridVerticalEnabler.java new file mode 100644 index 0000000000..526e6fc509 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridVerticalEnabler.java @@ -0,0 +1,89 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import javax.measure.unit.SI; + +import com.raytheon.uf.common.dataplugin.grid.GridRecord; +import com.raytheon.uf.common.dataplugin.level.Level; +import com.raytheon.uf.common.dataplugin.level.MasterLevel; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalEnabled; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 30, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GridVerticalEnabler implements VerticalEnabled { + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.spatial.VerticalEnabled#getVerticalCoordinate + * (java.lang.Object) + */ + @Override + public VerticalCoordinate getVerticalCoordinate(GridRecord rec) { + if (rec.getInfo() == null) { + return null; + } + Level level = rec.getInfo().getLevel(); + if (level == null) { + return null; + } + double l1 = level.getLevelonevalue(); + double l2 = level.getLeveltwovalue(); + MasterLevel master = level.getMasterLevel(); + VerticalCoordinate.Reference ref; + if (master.getUnit() == null) { + ref = Reference.UNKNOWN; + } else if (SI.PASCAL.isCompatible(master.getUnit())) { + ref = Reference.PRESSURE_LEVEL; + } else if ("FHAG".equalsIgnoreCase(master.getName())) { + ref = Reference.ABOVE_GROUND; + } else if (SI.METER.isCompatible(master.getUnit())) { + ref = Reference.ABOVE_MSL; + } else { + ref = Reference.UNKNOWN; + } + if (l2 == Level.INVALID_VALUE) { + return new VerticalCoordinate(l1, master.getUnit(), ref); + } else { + return new VerticalCoordinate(l1, l2, master.getUnit(), ref); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.spatial.VerticalEnabled#getSupportedClass + * () + */ + @Override + public Class getSupportedClass() { + return GridRecord.class; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridWmsLayerCache.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridWmsLayerCache.java new file mode 100644 index 0000000000..65cbb48e72 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/GridWmsLayerCache.java @@ -0,0 +1,117 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; + +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcLayer; +import com.raytheon.uf.edex.ogc.common.db.ILayerCache; + +/** + * Layer cache adapter to split composite levels into parameter levels + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 26, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GridWmsLayerCache implements ILayerCache { + + private final ILayerCache cache; + + /** + * @param cache + */ + public GridWmsLayerCache(ILayerCache cache) { + this.cache = cache; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.db.LayerCache#getLayers() + */ + @Override + public List getLayers() throws OgcException { + List origLayers = cache.getLayers(); + List rval = new ArrayList(origLayers.size()); + for (GridCompositeLayer orig : origLayers) { + String[] parts = StringUtils.split(orig.getName(), + OgcLayer.keySeparator); + for (String param : orig.getParameters()) { + rval.add(getParamLayer(orig, parts, param)); + } + } + return rval; + } + + /** + * @param orig + * @param name + * @param param + * @return + */ + private GridParamLayer getParamLayer(GridCompositeLayer orig, String name, + String param) { + GridParamLayer paramLayer = new GridParamLayer(param, orig); + paramLayer.setName(name); + return paramLayer; + } + + /** + * @param orig + * @param parts + * @param param + * @return + */ + private GribLayer getParamLayer(GridCompositeLayer orig, String[] parts, + String param) { + LinkedList partList = new LinkedList( + Arrays.asList(parts)); + partList.add(parts.length - 1, param); + return getParamLayer(orig, + StringUtils.join(partList, OgcLayer.keySeparator), param); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.LayerCache#getLayer(java.lang.String) + */ + @Override + public GribLayer getLayer(String name) throws OgcException { + String[] parts = StringUtils.split(name, + OgcLayer.keySeparator); + LinkedList partList = new LinkedList( + Arrays.asList(parts)); + String param = partList.remove(parts.length - 2); + GridCompositeLayer layer = cache.getLayer(StringUtils.join(partList, + OgcLayer.keySeparator)); + if (layer == null) { + return null; + } + return getParamLayer(layer, name, param); + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/VerticalLevelLookup.java b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/VerticalLevelLookup.java new file mode 100644 index 0000000000..7ae5b7657e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/src/com/raytheon/uf/edex/plugin/grib/ogc/VerticalLevelLookup.java @@ -0,0 +1,45 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.grib.ogc; + +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate.Reference; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 26, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class VerticalLevelLookup { + + public static Reference getReference(String masterLevel) { + if ("FH".equalsIgnoreCase(masterLevel)) { + return Reference.ABOVE_MSL; + } + if ("MB".equalsIgnoreCase(masterLevel)) { + return Reference.PRESSURE_LEVEL; + } + if ("FHAG".equalsIgnoreCase(masterLevel)) { + return Reference.ABOVE_GROUND; + } + return Reference.UNKNOWN; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/utility/common_static/base/styleRuleLib/grib_style_library.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/utility/common_static/base/styleRuleLib/grib_style_library.xml new file mode 100644 index 0000000000..b30a8c89eb --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.grib.ogc/utility/common_static/base/styleRuleLib/grib_style_library.xml @@ -0,0 +1,241 @@ + + + + + .*/DpT/SFC.* + + 90 + -60 + + Grid/gridded data + + + + .*/DpT/MB.* + + 1050 + 500 + + + 308.15 + 278.15 + 213.15 + 213.15 + + Grid/gridded data + + + + .*/DpT/MB.* + + 500 + 250 + + + 278.15 + 233.15 + 213.15 + 173.15 + + Grid/gridded data + + + + .*/WGS/SFC.* + + 36.0111111 + 0 + + Grid/gridded data + + + + .*/T/SFC.* + + + 319.261111 + + 233.15 + + Grid/gridded data + + + + .*/T/MB.* + + 1050 + 500 + + + 318.15 + 233.15 + + + Grid/gridded data + + 10 + + + + + .*/AV/[^/]*.* + + + 0.00030 + -0.00005 + + Grid/gridded data + + + + .*/BLI/[^/]*.* + + + 15 + -15 + + Grid/gridded data + + + + .*/CAPE/SFC.* + + 5000 + 0 + + Grid/gridded data + + + + .*/TCC/SFC.* + + + + + Grid/gridded data + + 25 50 75 + + + + + .*/WS/MB.* + + 1050 + 850 + + + 75 + 0 + + Grid/gridded data + + 10 + + + + + .*/WS/MB.* + + 850 + 200 + + + 0 + 0 + 200 + 75 + + Grid/gridded data + + 20 + + + + + .*/WS/SFC.* + + 75 + 0 + + Grid/gridded data + + 10 + + + + + .*/HTSGW/SFC.* + + 20 + 0 + + Grid/gridded data + + 5 + + + + + .*/ICIP/.* + + 1 + 0 + + Grid/gridded data + + 0.1 + + + + + .*/ICI/.* + + 5 + 0 + + Grid/icing_severity + + 1 + + + + + .*/SLDP/.* + + 1 + 0 + + Grid/icing_sld + + 0.25 + + + + + .*/TPFI/.* + + 1 + 0 + + Grid/aviation_turbulence_index + + 0.25 + + + + + .* + Grid/gridded data + + 255 + 0 + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/META-INF/MANIFEST.MF index a04de5a63c..b9727d78f1 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/META-INF/MANIFEST.MF @@ -19,11 +19,11 @@ Require-Bundle: com.raytheon.uf.edex.ogc.common;bundle-version="1.0.0", com.raytheon.uf.common.util;bundle-version="1.12.1174", com.raytheon.uf.edex.database;bundle-version="1.0.0", ogc.tools.gml;bundle-version="1.0.2", - com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", - com.raytheon.uf.common.datadelivery.harvester;bundle-version="1.0.0", com.raytheon.uf.common.geospatial;bundle-version="1.12.1174", com.raytheon.uf.common.pointdata;bundle-version="1.12.1174", com.raytheon.uf.edex.wms;bundle-version="1.0.0", - com.raytheon.uf.common.time;bundle-version="1.12.1174" + com.raytheon.uf.common.time;bundle-version="1.12.1174", + com.raytheon.uf.edex.pointdata;bundle-version="1.12.1174", + com.raytheon.uf.common.datastorage;bundle-version="1.12.1174" Export-Package: com.raytheon.uf.edex.plugin.madis.ogc, com.raytheon.uf.edex.plugin.madis.ogc.feature diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-ogc-routes.xml b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-ogc-routes.xml new file mode 100644 index 0000000000..86c6e62518 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-ogc-routes.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-ogc.xml b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-ogc.xml index acb655af84..59d651d72c 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-ogc.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-ogc.xml @@ -1,31 +1,25 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + - + @@ -33,7 +27,7 @@ - + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisDimension.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisDimension.java index 008f355208..ec2bf223be 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisDimension.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisDimension.java @@ -45,9 +45,11 @@ import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; public class MadisDimension extends SimpleDimension { - /** - * {@inheritDoc} - */ + private static final long serialVersionUID = -2255916443759465372L; + + /** + * {@inheritDoc} + */ @Override public Set getValues() { return new HashSet(); diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisFeatureFactory.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisFeatureFactory.java index ed913545b3..4a01d2f377 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisFeatureFactory.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisFeatureFactory.java @@ -33,7 +33,7 @@ import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.madis.MadisRecord; import com.raytheon.uf.common.geospatial.MapUtil; import com.raytheon.uf.common.util.CollectionUtil; -import com.raytheon.uf.edex.ogc.common.feature.AbstractFeatureFactory; +import com.raytheon.uf.edex.ogc.common.feature.FeatureFactory; import com.raytheon.uf.edex.plugin.madis.MadisPointDataTransform; import com.vividsolutions.jts.geom.Point; @@ -52,7 +52,7 @@ import com.vividsolutions.jts.geom.Point; * @version 1.0 */ -public class MadisFeatureFactory extends AbstractFeatureFactory { +public class MadisFeatureFactory implements FeatureFactory { private static final String LOCATION_KEY = "location"; @@ -207,7 +207,6 @@ public class MadisFeatureFactory extends AbstractFeatureFactory { } - @Override public String getName() { return name; } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayer.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayer.java index 098f51e80e..c60803a061 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayer.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayer.java @@ -50,9 +50,25 @@ import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; @DynamicSerialize public class MadisLayer extends SimpleLayer { - @Override + private static final long serialVersionUID = 1L; + + @Override public Set getDimensions() { return new TreeSet(); } + /** + * + */ + public MadisLayer() { + super(); + } + + /** + * @param other + */ + public MadisLayer(SimpleLayer other) { + super(other); + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayerCollector.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayerCollector.java index 9c8a1b8339..fcb7ad08ac 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayerCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisLayerCollector.java @@ -20,26 +20,12 @@ package com.raytheon.uf.edex.plugin.madis.ogc; * further licensing information. **/ -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.Calendar; +import java.util.TimeZone; -import org.geotools.geometry.jts.JTS; -import org.geotools.geometry.jts.ReferencedEnvelope; - -import com.raytheon.uf.common.datadelivery.harvester.ConfigLayer; -import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.madis.MadisRecord; -import com.raytheon.uf.common.geospatial.MapUtil; -import com.raytheon.uf.common.status.IUFStatusHandler; -import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; -import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; -import com.raytheon.uf.edex.ogc.common.db.WFSLayerCollector; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; +import com.raytheon.uf.edex.ogc.common.db.ILayerStore; +import com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector; /** * @@ -56,135 +42,27 @@ import com.vividsolutions.jts.geom.Envelope; * @version 1.0 */ -public class MadisLayerCollector extends WFSLayerCollector { +public class MadisLayerCollector extends + SingleLayerCollector { private static final String MADIS_LAYER_NAME = "madis"; - private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(MadisLayerCollector.class); - - private final int roundCutoff = 45; - - private volatile boolean alreadyInitialized; - - public MadisLayerCollector( - LayerTransformer transformer) { - super(transformer, MadisLayer.class, MadisRecord.class); - initializeLayer(layer, new MadisRecord()); + public MadisLayerCollector(ILayerStore store) { + super(MadisLayer.class, MadisRecord.class, MADIS_LAYER_NAME, store); } - @Override - public void addAll(Collection coll) { - for (MadisRecord rec : coll) { - addToTimes(layer, rec); - addToDims(layer, rec); - } - } - - private Date getTime(MadisRecord record) { - Date timeObs = record.getTimeObs(); - return roundToHour(timeObs, roundCutoff); - } - - /** - * {@inheritDoc} + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector#getTime(com.raytheon + * .uf.common.dataplugin.PluginDataObject) */ @Override - protected void addToTimes(MadisLayer layer, MadisRecord record) { - synchronized (layer) { - if (record != null) { - SortedSet times = layer.getTimes(); - times.add(getTime(record)); - statusHandler.handle(Priority.DEBUG, "Adding madis layer: " - + record.toString()); - } - } - } - - /** - * Filter geographically - */ - public PluginDataObject[] geoFilter(PluginDataObject[] pdos) { - - Collection withInGeoConstraint = new ArrayList(); - PluginDataObject[] pdor = null; - - synchronized (layer) { - - for (PluginDataObject record : pdos) { - - MadisRecord rec = (MadisRecord) record; - - if (rec != null) { - - Envelope e = getCoverage().getEnvelope(); - - if (rec.getLocation() != null) { - - Coordinate c = rec.getLocation().getLocation() - .getCoordinate(); - - if (c != null) { - - if (e.contains(c)) { - withInGeoConstraint.add(rec); - } else { - statusHandler.handle(Priority.DEBUG, - "Madis record discarded: outside of range: " - + rec.getLatitude() + " " - + rec.getLongitude()); - } - } - } - } - } - } - - if (!withInGeoConstraint.isEmpty()) { - int size = withInGeoConstraint.size(); - pdor = withInGeoConstraint.toArray(new PluginDataObject[size]); - } - - return pdor; - } - - /** - * {@inheritDoc} - */ - @Override - protected boolean initializeLayer(MadisLayer layer, MadisRecord rec) { - if (!alreadyInitialized) { - synchronized (layer) { - layer.setName(MADIS_LAYER_NAME); - // create the main point data set - setDataSet(layer); - ConfigLayer configLayer = getAgent().getLayer(layer.getName()); - Coordinate lowerRight = getCoverage().getLowerRight(); - Coordinate upperLeft = getCoverage().getUpperLeft(); - ReferencedEnvelope env = new ReferencedEnvelope(upperLeft.x, - lowerRight.x, lowerRight.y, upperLeft.y, - MapUtil.LATLON_PROJECTION); - layer.setCrs84Bounds(JTS.toGeometry((Envelope) env)); - layer.setTargetCrsCode(configLayer.getCrs()); - layer.setTargetMaxx(env.getMaxX()); - layer.setTargetMaxy(env.getMaxY()); - layer.setTargetMinx(env.getMinX()); - layer.setTargetMiny(env.getMinY()); - layer.setTimes(new TreeSet()); - // install main dataset name on registry - storeDataSet(getDataSet()); - } - alreadyInitialized = true; - } - return true; - } - - /** - * {@inheritDoc} - */ - @Override - protected String getLayerName(MadisRecord rec) { - return MADIS_LAYER_NAME; + protected Calendar getTime(MadisRecord record) { + Calendar rval = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + rval.setTime(record.getTimeObs()); + return rval; } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisNotifyDao.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisNotifyDao.java new file mode 100644 index 0000000000..0037371783 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisNotifyDao.java @@ -0,0 +1,96 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.madis.ogc; + +import com.raytheon.uf.common.dataplugin.PluginException; +import com.raytheon.uf.common.dataplugin.madis.MadisRecord; +import com.raytheon.uf.edex.database.plugin.PurgeResults; +import com.raytheon.uf.edex.ogc.common.db.PurgeNotification; +import com.raytheon.uf.edex.pointdata.PointDataPluginDao; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 29, 2013            dhladky     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class MadisNotifyDao extends PointDataPluginDao { + + + private final PurgeNotification notify; + + /** + * @throws PluginException + */ + public MadisNotifyDao() throws PluginException { + this("madis"); + } + + /** + * @param pluginName + * @throws PluginException + */ + public MadisNotifyDao(String pluginName) throws PluginException { + super(pluginName); + notify = new PurgeNotification(pluginName); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.database.plugin.PluginDao#purgeAllData() + */ + @Override + public void purgeAllData() throws PluginException { + super.purgeAllData(); + notify.purgeAllData(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.database.plugin.PluginDao#purgeExpiredData() + */ + @Override + public void purgeExpiredData() throws PluginException { + PurgeResults res = super.purgeExpiredDataWithResults(); + notify.purgeExpiredData(res); + } + + @Override + public String[] getKeysRequiredForFileName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public MadisRecord newObject() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getPointDataFileName(MadisRecord p) { + // TODO Auto-generated method stub + return null; + } + +} + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisTranslator.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisTranslator.java index c07181ef68..9c4ba21460 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisTranslator.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisTranslator.java @@ -1,18 +1,15 @@ package com.raytheon.uf.edex.plugin.madis.ogc; import java.util.ArrayList; -import java.util.List; import javax.xml.bind.JAXBElement; -import net.opengis.gml.v_3_1_1.AbstractFeatureType; - import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.madis.MadisRecord; import com.raytheon.uf.edex.plugin.madis.MadisPointDataTransform; import com.raytheon.uf.edex.plugin.madis.ogc.feature.Madis; import com.raytheon.uf.edex.plugin.madis.ogc.feature.MadisObjectFactory; -import com.raytheon.uf.edex.wfs.reg.WfsTranslator; +import com.raytheon.uf.edex.wfs.reg.IPdoGmlTranslator; /** * @@ -30,23 +27,23 @@ import com.raytheon.uf.edex.wfs.reg.WfsTranslator; * @author dhladky * @version 1.0 */ -public class MadisTranslator implements WfsTranslator { - - +public class MadisTranslator implements IPdoGmlTranslator { + + public static final String GML_VERSION = "3.1.1"; + public MadisTranslator() { } @Override - public List> translate( - PluginDataObject[] pdos) { - ArrayList> rval = new ArrayList>( + public ArrayList> translate(PluginDataObject[] pdos) { + ArrayList> rval = new ArrayList>( pdos.length); MadisPointDataTransform.populatePointDataFields(pdos); - + for (PluginDataObject pdo : pdos) { - rval.add(translate(pdo)); + rval.add(translate(pdo)); } return rval; } @@ -57,7 +54,17 @@ public class MadisTranslator implements WfsTranslator { */ public JAXBElement translate(PluginDataObject pdo) { - return new MadisObjectFactory().create(new Madis((MadisRecord)pdo)); + return new MadisObjectFactory().create(new Madis((MadisRecord) pdo)); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.PdoGmlTranslator#getVersion() + */ + @Override + public String getVersion() { + return GML_VERSION; } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWfsSource.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWfsSource.java index 3f767e64e6..3ee9ed9eb4 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWfsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWfsSource.java @@ -6,16 +6,18 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.PluginProperties; import com.raytheon.uf.common.dataplugin.madis.MadisRecord; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.edex.ogc.common.feature.FeatureFactory; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector; import com.raytheon.uf.edex.plugin.madis.ogc.feature.Madis; import com.raytheon.uf.edex.plugin.madis.ogc.feature.MadisObjectFactory; import com.raytheon.uf.edex.wfs.WfsFeatureType; -import com.raytheon.uf.edex.wfs.reg.DefaultWfsSource; -import com.raytheon.uf.edex.wfs.reg.WfsTranslator; +import com.raytheon.uf.edex.wfs.reg.IPdoGmlTranslator; +import com.raytheon.uf.edex.wfs.reg.PluginWfsSource; import com.raytheon.uf.edex.wfs.request.QualifiedName; /** @@ -34,11 +36,10 @@ import com.raytheon.uf.edex.wfs.request.QualifiedName; * @version 1.0 */ -public class MadisWfsSource extends DefaultWfsSource { - +public class MadisWfsSource extends PluginWfsSource { private static final String schemaloc = "META-INF/schema/madis.xsd"; - + private WfsFeatureType feature; private static String schemaXml = null; @@ -51,37 +52,34 @@ public class MadisWfsSource extends DefaultWfsSource { private static final IUFStatusHandler statusHandler = UFStatus .getHandler(MadisWfsSource.class); - - private static final Map fieldMap; - + + private static final Map fieldMap; + static { Map map = new HashMap(); map.put("obsLocation.location", spatialKey); + map.put("timeObs", "dataTime.refTime"); map.put("obsLocation.stationId", "location.stationId"); map.put("obsLocation.elevation", "location.elevation"); fieldMap = Collections.unmodifiableMap(map); } - public MadisWfsSource(PluginProperties props) { - super(props, KEY_NAME, new MadisTranslator(), new MadisFeatureFactory()); + public MadisWfsSource(PluginProperties props, IPdoGmlTranslator translator, + SingleLayerCollector, PluginDataObject> collector) { + super(props, KEY_NAME, Arrays.asList(translator), + new MadisFeatureFactory(), collector); feature = new WfsFeatureType(new QualifiedName(MADIS_NS, key, key), - key, getCRS(KEY_NAME), getBoundingBox(KEY_NAME)); + key, defaultCRS, fullBbox); } @Override public Map getFieldMap() { + return fieldMap; } - - public MadisWfsSource(PluginProperties props, String key, - WfsTranslator translator, FeatureFactory featFactory) { - super(props, key, translator, featFactory); - } - - @Override - public List listFeatureTypes() { + public List getFeatureTypes() { return Arrays.asList(feature); } @@ -97,7 +95,7 @@ public class MadisWfsSource extends DefaultWfsSource { rval = schemaXml; } catch (Exception e) { statusHandler.error("Problem reading madis schema", e); - rval = "Internal Error"; + rval = "Internal Error"; } return rval; } @@ -117,4 +115,22 @@ public class MadisWfsSource extends DefaultWfsSource { return new Class[] { Madis.class, MadisObjectFactory.class }; } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsSource#getFeatureVerticalField(com.raytheon + * .uf.edex.wfs.request.QualifiedName) + */ + @Override + public String getFeatureVerticalField(QualifiedName feature) { + // surface obs don't have vertical fields + return null; + } + + @Override + public String getFeatureIdField(QualifiedName feature) { + return "id"; + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWmsSource.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWmsSource.java index 37a363a66e..67b90ab95e 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWmsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/src/com/raytheon/uf/edex/plugin/madis/ogc/MadisWmsSource.java @@ -1,5 +1,24 @@ package com.raytheon.uf.edex.plugin.madis.ogc; +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.raytheon.uf.common.dataplugin.PluginProperties; @@ -9,7 +28,25 @@ import com.raytheon.uf.edex.wms.WmsException; import com.raytheon.uf.edex.wms.reg.PointDataWmsSource; import com.raytheon.uf.edex.wms.styling.FeatureStyleProvider; -public class MadisWmsSource extends PointDataWmsSource { +/** + * MADIS WMS Source + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Aug 18, 2013 2097       dhladky     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class MadisWmsSource extends + PointDataWmsSource { private static final String geometryField = "location.location"; @@ -23,10 +60,10 @@ public class MadisWmsSource extends PointDataWmsSource { * @param styles * @throws Exception */ - public MadisWmsSource(PluginProperties props, LayerTransformer transformer) + public MadisWmsSource(PluginProperties props, + LayerTransformer transformer) throws Exception { - super(props, "madis", transformer, - new MadisFeatureFactory()); + super(props, "madis", transformer, new MadisFeatureFactory()); } /* @@ -38,7 +75,7 @@ public class MadisWmsSource extends PointDataWmsSource { */ @Override protected String getGeometryField(String layer) { - // metar has only one layer + // madis has only one layer return geometryField; } @@ -50,7 +87,6 @@ public class MadisWmsSource extends PointDataWmsSource { */ @Override protected CoordinateReferenceSystem getCRS(String layer) { - return MapUtil.LATLON_PROJECTION; } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.classpath b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.project b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.project new file mode 100644 index 0000000000..d617859663 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.edex.plugin.madis.registry + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..e68d4d2905 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Madis Registry +Bundle-SymbolicName: com.raytheon.uf.edex.plugin.madis.registry +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: com.raytheon.uf.common.dataplugin.madis;bundle-version="1.0.0", + com.raytheon.uf.edex.plugin.madis;bundle-version="1.0.0", + com.raytheon.uf.edex.plugin.madis.ogc;bundle-version="1.0.0", + com.raytheon.uf.edex.ogc.registry;bundle-version="1.0.0", + com.raytheon.edex.common;bundle-version="1.12.1174", + com.raytheon.uf.edex.ogc.common;bundle-version="1.0.0", + com.raytheon.uf.edex.wfs;bundle-version="1.0.0", + com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", + com.raytheon.uf.common.pointdata;bundle-version="1.12.1174", + com.raytheon.uf.common.status;bundle-version="1.12.1174", + com.raytheon.uf.common.datadelivery.harvester;bundle-version="1.0.0" +Export-Package: com.raytheon.uf.edex.plugin.madis.registry diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/build.properties b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/build.properties new file mode 100644 index 0000000000..5791d48d5f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + res/ diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-dpa-ingest.xml b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/res/spring/madis-ogc-registry.xml similarity index 74% rename from edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-dpa-ingest.xml rename to edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/res/spring/madis-ogc-registry.xml index 85744e3d0c..5d8906c6c6 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis.ogc/res/spring/madis-dpa-ingest.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/res/spring/madis-ogc-registry.xml @@ -48,14 +48,48 @@
- - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -103,7 +137,7 @@ - + @@ -117,18 +151,18 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/src/com/raytheon/uf/edex/plugin/madis/registry/MadisRegistryCollectorAddon.java b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/src/com/raytheon/uf/edex/plugin/madis/registry/MadisRegistryCollectorAddon.java new file mode 100644 index 0000000000..844981d0e0 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis.registry/src/com/raytheon/uf/edex/plugin/madis/registry/MadisRegistryCollectorAddon.java @@ -0,0 +1,136 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.plugin.madis.registry; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.dataplugin.madis.MadisRecord; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.edex.ogc.common.db.LayerCollector; +import com.raytheon.uf.edex.ogc.common.util.PluginIngestFilter; +import com.raytheon.uf.edex.ogc.registry.WfsRegistryCollectorAddon; +import com.raytheon.uf.edex.plugin.madis.ogc.MadisDimension; +import com.raytheon.uf.edex.plugin.madis.ogc.MadisLayer; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +/** + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 24, 2013            bclement     Initial creation
+ * Aug 18, 2013 #2097      dhladky      Restored original functionality before renaming of this class
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class MadisRegistryCollectorAddon extends + WfsRegistryCollectorAddon + implements PluginIngestFilter { + + /** + * @param layerName + */ + public MadisRegistryCollectorAddon(String layerName) { + super(layerName); + this._layer = new MadisLayer(); + initializeLayer(_layer); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.registry.WfsRegistryCollectorAddon#getTime(com + * .raytheon.uf.common.dataplugin.PluginDataObject) + */ + @Override + protected Date getTime(MadisRecord record) { + Date time = record.getTimeObs(); + return LayerCollector.roundToHour(time, roundCutoff); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.registry.WfsRegistryCollectorAddon#copy(com. + * raytheon.uf.edex.ogc.common.db.SimpleLayer) + */ + @Override + protected MadisLayer copy(MadisLayer layer) { + return new MadisLayer(layer); + } + + /** + * Filter geographically + */ + public PluginDataObject[] filter(PluginDataObject[] pdos) { + + Collection withInGeoConstraint = new ArrayList(); + PluginDataObject[] pdor = null; + + for (PluginDataObject record : pdos) { + + MadisRecord rec = (MadisRecord) record; + + if (rec != null) { + + Envelope e = getCoverage().getEnvelope(); + + if (rec.getLocation() != null) { + + Coordinate c = rec.getLocation().getLocation() + .getCoordinate(); + + if (c != null) { + + if (e.contains(c)) { + withInGeoConstraint.add(rec); + } else { + statusHandler.handle( + Priority.DEBUG, + "Madis record discarded: outside of range: " + + rec.getLatitude() + " " + + rec.getLongitude()); + } + } + } + } + } + + if (!withInGeoConstraint.isEmpty()) { + int size = withInGeoConstraint.size(); + pdor = withInGeoConstraint.toArray(new PluginDataObject[size]); + } + + return pdor; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/pointdata/madisdb.xml b/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/pointdata/madisdb.xml index 9a059910fe..5c5deb4e35 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/pointdata/madisdb.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/pointdata/madisdb.xml @@ -24,5 +24,5 @@ - + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/spring/madis-common.xml b/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/spring/madis-common.xml index 04a215cb25..18a2bfd826 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/spring/madis-common.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.madis/res/spring/madis-common.xml @@ -9,6 +9,7 @@ + - - - - + + - + @@ -65,11 +63,6 @@ - - - - - \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/res/spring/obs-ogc-routes.xml b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/res/spring/obs-ogc-routes.xml new file mode 100644 index 0000000000..22b4dd3a02 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/res/spring/obs-ogc-routes.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/res/spring/obs-ogc.xml b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/res/spring/obs-ogc.xml index 6bc134cdf5..17c19ce684 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/res/spring/obs-ogc.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/res/spring/obs-ogc.xml @@ -1,31 +1,25 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + - + @@ -33,7 +27,7 @@ - + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarFeatureFactory.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarFeatureFactory.java index 1d2373ea96..1d4d52e631 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarFeatureFactory.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarFeatureFactory.java @@ -54,7 +54,7 @@ import com.raytheon.uf.common.dataplugin.obs.metar.util.SkyCover; import com.raytheon.uf.common.dataplugin.obs.metar.util.WeatherCondition; import com.raytheon.uf.common.geospatial.MapUtil; import com.raytheon.uf.common.util.CollectionUtil; -import com.raytheon.uf.edex.ogc.common.feature.AbstractFeatureFactory; +import com.raytheon.uf.edex.ogc.common.feature.FeatureFactory; import com.vividsolutions.jts.geom.Point; /** @@ -62,7 +62,7 @@ import com.vividsolutions.jts.geom.Point; * @author bclement * @version 1.0 */ -public class MetarFeatureFactory extends AbstractFeatureFactory { +public class MetarFeatureFactory implements FeatureFactory { private static final String TEMP_KEY = MetarPointDataTransform.TEMPERATURE; @@ -244,9 +244,4 @@ public class MetarFeatureFactory extends AbstractFeatureFactory { return rval; } - @Override - public String getName() { - return name; - } - } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayer.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayer.java index 2606c051ec..13b4ead127 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayer.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayer.java @@ -28,7 +28,8 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; -import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.db.DefaultPointDataDimension; +import com.raytheon.uf.edex.ogc.common.db.PointDataLayer; /** * @@ -48,11 +49,26 @@ import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize -public class MetarLayer extends SimpleLayer { +public class MetarLayer extends PointDataLayer { + + private static final long serialVersionUID = 7334386034469721056L; + + /** + * + */ + public MetarLayer() { + } + + /** + * @param layer + */ + public MetarLayer(MetarLayer layer) { + super(layer); + } @Override - public Set getDimensions() { - return new TreeSet(); + public Set getDimensions() { + return new TreeSet(); } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayerCollector.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayerCollector.java index 88fa08d417..61a7f364e1 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayerCollector.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarLayerCollector.java @@ -20,26 +20,12 @@ package com.raytheon.uf.edex.plugin.obs.ogc.metar; * further licensing information. **/ -import java.util.ArrayList; import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.SortedSet; -import java.util.TreeSet; -import org.geotools.geometry.jts.JTS; -import org.geotools.geometry.jts.ReferencedEnvelope; - -import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.obs.metar.MetarRecord; -import com.raytheon.uf.common.geospatial.MapUtil; -import com.raytheon.uf.common.status.IUFStatusHandler; -import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; -import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; -import com.raytheon.uf.edex.ogc.common.db.WFSLayerCollector; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; +import com.raytheon.uf.edex.ogc.common.db.DefaultPointDataDimension; +import com.raytheon.uf.edex.ogc.common.db.ILayerStore; +import com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector; /** * @@ -57,144 +43,26 @@ import com.vividsolutions.jts.geom.Envelope; * @version 1.0 */ -public class MetarLayerCollector extends - WFSLayerCollector { +public class MetarLayerCollector + extends + SingleLayerCollector { private static final String METAR_LAYER_NAME = "metar"; - private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(MetarLayerCollector.class); - - private final boolean truncate = true; - - private final int roundCutoff = 45; - - private volatile boolean alreadyInitialized; - - public MetarLayerCollector( - LayerTransformer transformer) { - super(transformer, MetarLayer.class, MetarRecord.class); - initializeLayer(layer, new MetarRecord()); + public MetarLayerCollector(ILayerStore store) { + super(MetarLayer.class, MetarRecord.class, METAR_LAYER_NAME, store); } - @Override - public void addAll(Collection coll) { - for (MetarRecord rec : coll) { - addToTimes(layer, rec); - addToDims(layer, rec); - } - } - - private Calendar getTime(MetarRecord record) { - Calendar timeObs = record.getTimeObs(); - if (truncate) { - return truncateToHour(timeObs); - } else { - return roundToHour(timeObs, roundCutoff); - } - } - - /** - * {@inheritDoc} + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector#getTime(com.raytheon + * .uf.common.dataplugin.PluginDataObject) */ @Override - protected void addToTimes(MetarLayer layer, MetarRecord record) { - synchronized (layer) { - if (record != null) { - SortedSet times = layer.getTimes(); - times.add(getTime(record).getTime()); - statusHandler.handle(Priority.DEBUG, "Adding metar layer: " - + record.toString()); - } - - } + protected Calendar getTime(MetarRecord record) { + return record.getTimeObs(); } - /** - * {@inheritDoc} - */ - @Override - protected boolean initializeLayer(MetarLayer layer, MetarRecord rec) { - if (!alreadyInitialized) { - synchronized (layer) { - layer.setName(METAR_LAYER_NAME); - // create the main point data set - setDataSet(layer); - Coordinate lowerRight = getCoverage().getLowerRight(); - Coordinate upperLeft = getCoverage().getUpperLeft(); - ReferencedEnvelope env = new ReferencedEnvelope(upperLeft.x, - lowerRight.x, lowerRight.y, upperLeft.y, - MapUtil.LATLON_PROJECTION); - layer.setCrs84Bounds(JTS.toGeometry((Envelope) env)); - layer.setTargetCrsCode("CRS:84"); - layer.setTargetMaxx(env.getMaxX()); - layer.setTargetMaxy(env.getMaxY()); - layer.setTargetMinx(env.getMinX()); - layer.setTargetMiny(env.getMinY()); - layer.setTimes(new TreeSet()); - // install main dataset name on registry - storeDataSet(getDataSet()); - } - alreadyInitialized = true; - } - return true; - } - - /** - * {@inheritDoc} - */ - @Override - protected String getLayerName(MetarRecord rec) { - return METAR_LAYER_NAME; - } - - /** - * Filter geographically - */ - - public PluginDataObject[] geoFilter(PluginDataObject[] pdos) { - - Collection withInGeoConstraint = new ArrayList(); - PluginDataObject[] pdor = null; - - synchronized (layer) { - - for (PluginDataObject record : pdos) { - - MetarRecord rec = (MetarRecord) record; - - if (rec != null) { - - Envelope e = getCoverage().getEnvelope(); - - if (rec.getLocation() != null) { - - Coordinate c = rec.getLocation().getLocation() - .getCoordinate(); - - if (c != null) { - - if (e.contains(c)) { - withInGeoConstraint.add(rec); - } else { - statusHandler.handle( - Priority.DEBUG, - "Madis record discarded: outside of range: " - + rec.getLatitude() + " " - + rec.getLongitude()); - } - } - } - } - } - } - - if (!withInGeoConstraint.isEmpty()) { - int size = withInGeoConstraint.size(); - pdor = withInGeoConstraint.toArray(new PluginDataObject[size]); - } - - return pdor; - } - } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarNotifyDao.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarNotifyDao.java new file mode 100644 index 0000000000..46b8cf3fc2 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarNotifyDao.java @@ -0,0 +1,76 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.obs.ogc.metar; + +import com.raytheon.edex.plugin.obs.ObsDao; +import com.raytheon.uf.common.dataplugin.PluginException; +import com.raytheon.uf.edex.database.plugin.PurgeResults; +import com.raytheon.uf.edex.ogc.common.db.PurgeNotification; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 29, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class MetarNotifyDao extends ObsDao { + + + private final PurgeNotification notify; + + /** + * @throws PluginException + */ + public MetarNotifyDao() throws PluginException { + this("obs"); + } + + /** + * @param pluginName + * @throws PluginException + */ + public MetarNotifyDao(String pluginName) throws PluginException { + super(pluginName); + notify = new PurgeNotification(pluginName); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.database.plugin.PluginDao#purgeAllData() + */ + @Override + public void purgeAllData() throws PluginException { + super.purgeAllData(); + notify.purgeAllData(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.database.plugin.PluginDao#purgeExpiredData() + */ + @Override + public void purgeExpiredData() throws PluginException { + PurgeResults res = super.purgeExpiredDataWithResults(); + notify.purgeExpiredData(res); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarTranslator.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarTranslator.java index a3514099d2..21a82c893e 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarTranslator.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarTranslator.java @@ -34,13 +34,11 @@ import java.util.ArrayList; import javax.xml.bind.JAXBElement; -import net.opengis.gml.v_3_1_1.AbstractFeatureType; - import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.obs.metar.MetarRecord; import com.raytheon.uf.edex.plugin.obs.ogc.metar.feature.Metar; import com.raytheon.uf.edex.plugin.obs.ogc.metar.feature.MetarObjectFactory; -import com.raytheon.uf.edex.wfs.reg.WfsTranslator; +import com.raytheon.uf.edex.wfs.reg.IPdoGmlTranslator; /** * @@ -58,31 +56,42 @@ import com.raytheon.uf.edex.wfs.reg.WfsTranslator; * @version 1.0 */ -public class MetarTranslator implements WfsTranslator { +public class MetarTranslator implements IPdoGmlTranslator { - public MetarTranslator() { - - } + public static final String GML_VERSION = "3.1.1"; - @Override - public ArrayList> translate( - PluginDataObject[] pdos) { - ArrayList> rval = new ArrayList>( - pdos.length); - for (PluginDataObject pdo : pdos) { - rval.add(translate(pdo)); - } - return rval; - } + public MetarTranslator() { - /** - * @param pdo - * @return - */ - public JAXBElement translate(PluginDataObject pdo) { - MetarRecord record = (MetarRecord) pdo; - Metar to = new Metar(record); - return new MetarObjectFactory().create(to); - } + } + + @Override + public ArrayList> translate(PluginDataObject[] pdos) { + ArrayList> rval = new ArrayList>( + pdos.length); + for (PluginDataObject pdo : pdos) { + rval.add(translate(pdo)); + } + return rval; + } + + /** + * @param pdo + * @return + */ + public JAXBElement translate(PluginDataObject pdo) { + MetarRecord record = (MetarRecord) pdo; + Metar to = new Metar(record); + return new MetarObjectFactory().create(to); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.PdoGmlTranslator#getVersion() + */ + @Override + public String getVersion() { + return GML_VERSION; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWfsSource.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWfsSource.java index ebf55368db..53c3b5d757 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWfsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWfsSource.java @@ -37,14 +37,18 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.PluginProperties; import com.raytheon.uf.common.dataplugin.obs.metar.MetarRecord; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector; import com.raytheon.uf.edex.plugin.obs.ogc.metar.feature.Metar; import com.raytheon.uf.edex.plugin.obs.ogc.metar.feature.MetarObjectFactory; import com.raytheon.uf.edex.wfs.WfsFeatureType; -import com.raytheon.uf.edex.wfs.reg.DefaultWfsSource; +import com.raytheon.uf.edex.wfs.reg.IPdoGmlTranslator; +import com.raytheon.uf.edex.wfs.reg.PluginWfsSource; import com.raytheon.uf.edex.wfs.request.QualifiedName; /** @@ -63,111 +67,127 @@ import com.raytheon.uf.edex.wfs.request.QualifiedName; * @version 1.0 */ -public class MetarWfsSource extends DefaultWfsSource { +public class MetarWfsSource extends PluginWfsSource { - private static final String schemaloc = "META-INF/schema/metar.xsd"; + private static final String schemaloc = "META-INF/schema/metar.xsd"; - private WfsFeatureType feature; + private WfsFeatureType feature; - private static String schemaXml = null; + private static String schemaXml = null; - private static final String spatialKey = "location.location"; + private static final String spatialKey = "location.location"; - private static final String KEY_NAME = "metar"; + private static final String KEY_NAME = "metar"; - private static final String METAR_NS = "http://metar.edex.uf.raytheon.com"; + private static final String METAR_NS = "http://metar.edex.uf.raytheon.com"; - private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(MetarWfsSource.class); - - private static final Map fieldMap = new HashMap(1); - - static { - fieldMap.put("obsLocation.location", spatialKey); - fieldMap.put("obsLocation.stationId", "location.stationId"); - fieldMap.put("obsLocation.elevation", "location.elevation"); - Collections.unmodifiableMap(fieldMap); - } + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(MetarWfsSource.class); - public MetarWfsSource(PluginProperties props) { - super(props, KEY_NAME, new MetarTranslator(), new MetarFeatureFactory()); - feature = new WfsFeatureType(new QualifiedName(METAR_NS, key, key), - key, defaultCRS, fullBbox); - } + private static final Map fieldMap = new HashMap( + 1); - @Override - public Map getFieldMap() { - return fieldMap; - } - - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wfs.reg.WfsSource#listFeatureTypes() - */ - @Override - public List listFeatureTypes() { - return Arrays.asList(feature); - } + static { + fieldMap.put("obsLocation.location", spatialKey); + fieldMap.put("obsLocation.stationId", "location.stationId"); + fieldMap.put("obsLocation.elevation", "location.elevation"); + Collections.unmodifiableMap(fieldMap); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wfs.reg.WfsSource#describeFeatureType(com.raytheon - * .uf.edex.wfs.request.QualifiedName) - */ - @Override - public String describeFeatureType(QualifiedName feature) { - // we only advertise one feature - String rval; - try { - if (schemaXml == null) { - ClassLoader loader = MetarWfsSource.class.getClassLoader(); - schemaXml = getResource(loader, schemaloc); - } - rval = schemaXml; - } catch (Exception e) { - statusHandler.error("Problem reading metar schema", e); - rval = "Internal Error"; // TODO better default - } - return rval; - } + public MetarWfsSource(PluginProperties props, IPdoGmlTranslator translator, + SingleLayerCollector, PluginDataObject> collector) { + super(props, KEY_NAME, Arrays.asList(translator), + new MetarFeatureFactory(), collector); + feature = new WfsFeatureType(new QualifiedName(METAR_NS, key, key), + key, defaultCRS, fullBbox); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wfs.reg.WfsSource#getFeatureSpatialField(com.raytheon - * .uf.edex.wfs.request.QualifiedName) - */ - @Override - public String getFeatureSpatialField(QualifiedName feature) { - // we only advertise one feature - return spatialKey; - } + @Override + public Map getFieldMap() { + return fieldMap; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wfs.reg.WfsSource#getFeatureEntity(com.raytheon. - * uf.edex.wfs.request.QualifiedName) - */ - @Override - public Class getFeatureEntity(QualifiedName feature) { - // we only advertise one feature - return MetarRecord.class; - } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.WfsSource#listFeatureTypes() + */ + @Override + public List getFeatureTypes() { + return Arrays.asList(feature); + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wfs.reg.WfsSource#getJaxbClasses() - */ - @Override - public Class[] getJaxbClasses() { - return new Class[] { MetarObjectFactory.class, Metar.class }; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsSource#describeFeatureType(com.raytheon + * .uf.edex.wfs.request.QualifiedName) + */ + @Override + public String describeFeatureType(QualifiedName feature) { + // we only advertise one feature + String rval; + try { + if (schemaXml == null) { + ClassLoader loader = MetarWfsSource.class.getClassLoader(); + schemaXml = getResource(loader, schemaloc); + } + rval = schemaXml; + } catch (Exception e) { + statusHandler.error("Problem reading metar schema", e); + rval = "Internal Error"; // TODO better default + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsSource#getFeatureSpatialField(com.raytheon + * .uf.edex.wfs.request.QualifiedName) + */ + @Override + public String getFeatureSpatialField(QualifiedName feature) { + // we only advertise one feature + return spatialKey; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsSource#getFeatureEntity(com.raytheon. + * uf.edex.wfs.request.QualifiedName) + */ + @Override + public Class getFeatureEntity(QualifiedName feature) { + // we only advertise one feature + return MetarRecord.class; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.WfsSource#getJaxbClasses() + */ + @Override + public Class[] getJaxbClasses() { + return new Class[] { MetarObjectFactory.class, Metar.class }; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsSource#getFeatureVerticalField(com.raytheon + * .uf.edex.wfs.request.QualifiedName) + */ + @Override + public String getFeatureVerticalField(QualifiedName feature) { + // surface obs don't have vertical fields + return null; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWmsSource.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWmsSource.java index 032f8749bb..9424f47758 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWmsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/src/com/raytheon/uf/edex/plugin/obs/ogc/metar/MetarWmsSource.java @@ -34,6 +34,7 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.raytheon.uf.common.dataplugin.PluginProperties; import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.edex.ogc.common.db.DefaultPointDataDimension; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; import com.raytheon.uf.edex.wms.WmsException; import com.raytheon.uf.edex.wms.reg.PointDataWmsSource; @@ -45,7 +46,8 @@ import com.raytheon.uf.edex.wms.styling.FeatureStyleProvider; * @author bclement * @version 1.0 */ -public class MetarWmsSource extends PointDataWmsSource { +public class MetarWmsSource extends + PointDataWmsSource { private static final String geometryField = "location.location"; @@ -59,10 +61,10 @@ public class MetarWmsSource extends PointDataWmsSource { * @param styles * @throws Exception */ - public MetarWmsSource(PluginProperties props, LayerTransformer transformer) - throws Exception { - super(props, "metar", transformer, - new MetarFeatureFactory()); + public MetarWmsSource(PluginProperties props, + LayerTransformer transformer) + throws Exception { + super(props, "metar", transformer, new MetarFeatureFactory()); } /* diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/utility/edex_static/base/sld/metar/defaultMetar.sld b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/utility/edex_static/base/sld/metar/defaultMetar.sld index 1e9e4ed39d..ede616a9e5 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/utility/edex_static/base/sld/metar/defaultMetar.sld +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.ogc/utility/edex_static/base/sld/metar/defaultMetar.sld @@ -1,3 +1,4 @@ + - - + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/.project b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/.project new file mode 100644 index 0000000000..96485925d4 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.edex.plugin.obs.registry + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..08f83c8a93 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/META-INF/MANIFEST.MF @@ -0,0 +1,22 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Obs OGC Registry +Bundle-SymbolicName: com.raytheon.uf.edex.plugin.obs.registry +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: com.raytheon.uf.common.status;bundle-version="1.12.1174", + com.raytheon.uf.edex.ogc.common;bundle-version="1.0.0", + com.raytheon.uf.edex.ogc.registry;bundle-version="1.0.0", + com.raytheon.uf.edex.plugin.obs.ogc;bundle-version="1.0.0", + com.raytheon.uf.edex.wfs;bundle-version="1.0.0", + com.raytheon.edex.plugin.obs;bundle-version="1.12.1174", + com.raytheon.uf.common.dataplugin.obs;bundle-version="1.0.0", + com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174", + com.raytheon.edex.common;bundle-version="1.12.1174", + com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", + com.raytheon.uf.edex.datadelivery.registry;bundle-version="1.0.0", + com.raytheon.uf.common.pointdata;bundle-version="1.12.1174", + com.raytheon.uf.common.datadelivery.harvester;bundle-version="1.0.0", + com.raytheon.uf.edex.datadelivery.harvester;bundle-version="1.0.0" +Export-Package: com.raytheon.uf.edex.plugin.obs.registry diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/build.properties b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/res/spring/obs-ogc-registry.xml b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/res/spring/obs-ogc-registry.xml new file mode 100644 index 0000000000..2f6d8d9a5f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/res/spring/obs-ogc-registry.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/src/com/raytheon/uf/edex/plugin/obs/registry/ObsRegistryCollectorAddon.java b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/src/com/raytheon/uf/edex/plugin/obs/registry/ObsRegistryCollectorAddon.java new file mode 100644 index 0000000000..a132741b5b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.obs.registry/src/com/raytheon/uf/edex/plugin/obs/registry/ObsRegistryCollectorAddon.java @@ -0,0 +1,126 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.obs.registry; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.dataplugin.obs.metar.MetarRecord; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.edex.ogc.common.db.DefaultPointDataDimension; +import com.raytheon.uf.edex.ogc.common.db.LayerCollector; +import com.raytheon.uf.edex.ogc.common.util.PluginIngestFilter; +import com.raytheon.uf.edex.ogc.registry.WfsRegistryCollectorAddon; +import com.raytheon.uf.edex.plugin.obs.ogc.metar.MetarLayer; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +/** + * Registry Collector for Observations + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 26, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class ObsRegistryCollectorAddon + extends + WfsRegistryCollectorAddon + implements PluginIngestFilter { + + /** + * @param layerName + */ + public ObsRegistryCollectorAddon(String layerName) { + super(layerName); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.registry.WfsRegistryCollectorAddon#getTime(com + * .raytheon.uf.common.dataplugin.PluginDataObject) + */ + @Override + protected Date getTime(MetarRecord record) { + Calendar time = record.getTimeObs(); + return LayerCollector.roundToHour(time.getTime(), roundCutoff); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.registry.WfsRegistryCollectorAddon#copy(com. + * raytheon.uf.edex.ogc.common.db.SimpleLayer) + */ + @Override + protected MetarLayer copy(MetarLayer layer) { + return new MetarLayer(layer); + } + + /** + * Filter geographically + */ + public PluginDataObject[] filter(PluginDataObject[] pdos) { + + Collection withInGeoConstraint = new ArrayList(); + PluginDataObject[] pdor = null; + + for (PluginDataObject record : pdos) { + + MetarRecord rec = (MetarRecord) record; + + if (rec != null) { + + Envelope e = getCoverage().getEnvelope(); + + if (rec.getLocation() != null) { + + Coordinate c = rec.getLocation().getLocation() + .getCoordinate(); + + if (c != null) { + + if (e.contains(c)) { + withInGeoConstraint.add(rec); + } else { + statusHandler.handle( + Priority.DEBUG, + "Obs record discarded: outside of range: " + + rec.getLatitude() + " " + + rec.getLongitude()); + } + } + } + } + } + + if (!withInGeoConstraint.isEmpty()) { + int size = withInGeoConstraint.size(); + pdor = withInGeoConstraint.toArray(new PluginDataObject[size]); + } + + return pdor; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.classpath b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.project b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.project new file mode 100644 index 0000000000..67f0a9ae82 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.edex.plugin.unitconverter + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..e2978d4662 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Thu May 09 11:58:40 CDT 2013 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..3e753930ef --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Unitconverter +Bundle-SymbolicName: com.raytheon.uf.edex.plugin.unitconverter +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: ucar.nc2;bundle-version="1.0.0", + javax.measure;bundle-version="1.0.0", + com.raytheon.uf.common.localization;bundle-version="1.12.1174", + com.raytheon.uf.common.status;bundle-version="1.12.1174" +Export-Package: com.raytheon.uf.edex.plugin.unitconverter diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/build.properties b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/src/com/raytheon/uf/edex/plugin/unitconverter/UnitLookup.java b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/src/com/raytheon/uf/edex/plugin/unitconverter/UnitLookup.java new file mode 100644 index 0000000000..f4926adbf8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/src/com/raytheon/uf/edex/plugin/unitconverter/UnitLookup.java @@ -0,0 +1,199 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.plugin.unitconverter; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.text.ParseException; +import java.util.HashMap; +import java.util.Map; + +import javax.measure.unit.UnitFormat; + +import ucar.units.NoSuchUnitException; +import ucar.units.PrefixDBException; +import ucar.units.SpecificationException; +import ucar.units.UnitDBException; +import ucar.units.UnitFormatManager; +import ucar.units.UnitParseException; +import ucar.units.UnitSystemException; + +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; +import com.raytheon.uf.common.localization.LocalizationFile; +import com.raytheon.uf.common.localization.PathManagerFactory; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 9, 2013            ekladstrup     Initial creation
+ * 
+ * 
+ * + * @author ekladstrup + * @version 1.0 + */ + +public class UnitLookup { + + private final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + protected static UnitLookup instance = null; + + protected Map, ucar.units.Unit> jsrToUcarMap = new HashMap, ucar.units.Unit>(); + + protected Map> ucarToJsrMap = new HashMap>(); + + protected UnitLookup() { + init(); + } + + protected void init() { + IPathManager pm = PathManagerFactory.getPathManager(); + + LocalizationContext[] searchHierarchy = pm + .getLocalSearchHierarchy(LocalizationType.EDEX_STATIC); + + LocalizationFile unitFile = null; + + for (LocalizationContext ctx : searchHierarchy) { + LocalizationFile localizationFile = pm.getLocalizationFile(ctx, + "wxsrv" + IPathManager.SEPARATOR + "units" + + IPathManager.SEPARATOR + "unitMapping.tsv"); + + if (localizationFile.exists() && unitFile == null) { + unitFile = localizationFile; + } + } + + File file = unitFile.getFile(); + + BufferedReader reader = null; + + try { + if (file.exists() && file.canRead()) { + reader = new BufferedReader(new FileReader(file)); + + String line = reader.readLine(); + + while (line != null) { + if (!line.startsWith("#") && !line.trim().isEmpty()) { + String[] unitStrings = line.split("\t"); + String jsrUnitString = unitStrings[0]; + String udunitString = unitStrings[1]; + + try { + if (jsrUnitString != null + && !jsrUnitString.isEmpty() + && udunitString != null + && !udunitString.isEmpty()) { + javax.measure.unit.Unit jsrUnit = (javax.measure.unit.Unit) UnitFormat + .getUCUMInstance().parseObject( + jsrUnitString); + ucar.units.Unit udunit = UnitFormatManager + .instance().parse(udunitString); + + jsrToUcarMap.put(jsrUnit, udunit); + ucarToJsrMap.put(udunit, jsrUnit); + } + } catch (ParseException e) { + log.warn("Unable to parse javax unit string \"" + + jsrUnitString + "\""); + } catch (NoSuchUnitException e) { + log.warn("Unable to parse ucar unit string \"" + + udunitString + "\""); + } catch (UnitParseException e) { + log.warn("Unable to parse ucar unit string \"" + + udunitString + "\""); + } catch (SpecificationException e) { + log.warn("Unable to parse ucar unit string \"" + + udunitString + "\""); + } catch (UnitDBException e) { + log.warn("Unable to parse ucar unit string \"" + + udunitString + "\""); + } catch (PrefixDBException e) { + log.warn("Unable to parse ucar unit string \"" + + udunitString + "\""); + } catch (UnitSystemException e) { + log.warn("Unable to parse ucar unit string \"" + + udunitString + "\""); + } + } + line = reader.readLine(); + } + } else { + log.error("Unable to open unit mapping file " + + file.getAbsolutePath()); + } + } catch (FileNotFoundException e1) { + // file not found even after file.exists() check + log.error( + "unit mapping file not found at " + file.getAbsolutePath(), + e1); + } catch (IOException e1) { + // failed to read file even after file.canRead() check + log.error( + "Unable to read unit mapping file " + + file.getAbsolutePath(), e1); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (Exception e) { + } + } + } + } + + public static UnitLookup getInstance() { + if (instance == null) { + synchronized (UnitLookup.class) { + if (instance == null) { + instance = new UnitLookup(); + } + } + } + + return instance; + } + + /** + * From a ucar unit return the jsr unit, or null if not found + * + * @param ucarUnit + * @return a jsr unit or null if not found + */ + public javax.measure.unit.Unit getJsrFromUcar(ucar.units.Unit ucarUnit) { + return ucarToJsrMap.get(ucarUnit); + } + + /** + * From a jsr unit return the ucar unit or null if not found + * + * @param jsrUnit + * @return + */ + public ucar.units.Unit getUcarFromJsr(javax.measure.unit.Unit jsrUnit) { + return jsrToUcarMap.get(jsrUnit); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/utility/edex_static/base/wxsrv/units/unitMapping.tsv b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/utility/edex_static/base/wxsrv/units/unitMapping.tsv new file mode 100644 index 0000000000..e9363696b3 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.plugin.unitconverter/utility/edex_static/base/wxsrv/units/unitMapping.tsv @@ -0,0 +1,16 @@ +# jsr ucar +#tab separated +Pa*s^-1 kg.m-1.s-3 +mm*s^-1 0.0010 m.s-1 +mm 0.0010 m +Pa Pa +s^-1 s-1 +m m +K K +K*s^-1 K.s-1 +m*s^-1 m.s-1 +degree_angle 0.017453292519943295 rad +s s +J*kg^-1 m2.s-2 +% 0.01 +kg*m^-2 kg.m-2 diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.wcs/META-INF/MANIFEST.MF index 75be18c86c..ad0782b697 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.wcs/META-INF/MANIFEST.MF @@ -9,7 +9,6 @@ Require-Bundle: com.raytheon.uf.edex.ogc.common;bundle-version="1.0.0", net.opengis;bundle-version="1.0.2", org.geotools;bundle-version="2.6.4", com.raytheon.edex.common;bundle-version="1.12.1174", - ucar.nc2;bundle-version="1.0.0", com.raytheon.uf.common.localization;bundle-version="1.12.1174", javax.measure;bundle-version="1.0.0", org.apache.commons.codec;bundle-version="1.4.0", @@ -17,12 +16,20 @@ Require-Bundle: com.raytheon.uf.edex.ogc.common;bundle-version="1.0.0", ogc.tools.gml;bundle-version="1.0.2", org.apache.commons.lang;bundle-version="2.3.0", org.apache.camel;bundle-version="1.0.0", - com.raytheon.uf.common.spatial;bundle-version="1.0.0" + org.apache.commons.cxf;bundle-version="1.0.0", + javax.persistence;bundle-version="1.0.0", + com.raytheon.uf.common.nc4;bundle-version="1.0.0", + com.raytheon.uf.edex.plugin.dataset.urn;bundle-version="1.0.0", + ucar.nc2;bundle-version="1.0.0", + org.apache.commons.collections;bundle-version="3.2.0", + com.raytheon.uf.edex.plugin.unitconverter;bundle-version="1.0.0", + com.raytheon.uf.common.spatial;bundle-version="1.0.0", + org.eclipse.jetty;bundle-version="7.6.9", + com.raytheon.uf.common.status;bundle-version="1.12.1174" Export-Package: com.raytheon.uf.edex.wcs, com.raytheon.uf.edex.wcs.format, com.raytheon.uf.edex.wcs.provider, + com.raytheon.uf.edex.wcs.querystore, com.raytheon.uf.edex.wcs.reg, - com.raytheon.uf.edex.wcs.request -Import-Package: javax.servlet, - javax.servlet.http, - org.apache.commons.logging + com.raytheon.uf.edex.wcs.request, + com.raytheon.uf.edex.wcs.soap1_1_2 diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/META-INF/wsdl/wcs.wsdl b/edexOsgi/com.raytheon.uf.edex.wcs/META-INF/wsdl/wcs.wsdl new file mode 100644 index 0000000000..c412c5ea99 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/META-INF/wsdl/wcs.wsdl @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/ingest.uml b/edexOsgi/com.raytheon.uf.edex.wcs/ingest.uml new file mode 100644 index 0000000000..228dace649 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/ingest.uml @@ -0,0 +1,19 @@ +@startuml + +node "EDEX Data Plug-in Adapter" { + () "Ingest Endpoint" as ingest + [Plug-in Data Decoder] as decoder + [Plug-in Layer Metadata Collector] as collector +} + +database "PostgreSQL" { + frame "MetaData" { + [Layer Metadata] as layer + } +} + +ingest -> decoder +decoder -> collector +collector -> layer + +@enduml \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/request.uml b/edexOsgi/com.raytheon.uf.edex.wcs/request.uml new file mode 100644 index 0000000000..4c5305e41e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/request.uml @@ -0,0 +1,42 @@ +@startuml + +package "EDEX WCS Component" { + [WCS HTTP Endpoint] as wcshttp + [WCS SOAP Endpoint] as wcssoap + () "HTTP/REST/JETTY" -- wcshttp + () "HTTP/SOAP/CXF" -- wcssoap + + [WCS 1.1.2 Provider] as wcs112 + + () "WCS Source" as isrc +} + +node "EDEX Data Plug-in Adapter" { + [Plug-in WCS Source] as psrc +} + +database "PostgreSQL" { + frame "MetaData" { + [Coverage Metadata] as layer + } +} + + +database "PyPies" { + frame "Data" { + [Data Record] as record + } +} + + +wcshttp -- wcs112 +wcssoap -- wcs112 + +wcs112 -- isrc + +isrc -left- psrc + +psrc <-up- record +psrc <-up- layer + +@enduml \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-request.xml b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-request.xml index f8dcfe84aa..7c0518bd29 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-request.xml +++ b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-request.xml @@ -1,39 +1,51 @@ + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> - + + + - - - - - - - - - - - - + + + + + + + + net.opengis.wcs.v_1_1_2.ObjectFactory + net.opengis.ows.v_1_1_0.ObjectFactory + net.opengis.gml.v_3_1_1.ObjectFactory + net.opengis.wms.v_1_3_0.ObjectFactory + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-rest-request.xml b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-rest-request.xml new file mode 100644 index 0000000000..9d85bba35b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-rest-request.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-soap-request.xml b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-soap-request.xml new file mode 100644 index 0000000000..d49df5cb5c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-soap-request.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-soap-wsdl.xml b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-soap-wsdl.xml new file mode 100644 index 0000000000..21fcd07baf --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/res/spring/wcs-ogc-soap-wsdl.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/CoverageStoreEndpoint.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/CoverageStoreEndpoint.java new file mode 100644 index 0000000000..bfe40508ab --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/CoverageStoreEndpoint.java @@ -0,0 +1,130 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.OutputStream; +import java.security.InvalidParameterException; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.cxf.helpers.IOUtils; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.BasicFileStore; +import com.raytheon.uf.edex.wcs.format.NetCdfFormatter; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 25, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoverageStoreEndpoint implements Processor { + + private final BasicFileStore store; + + private final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + public static final String ID_HEADER = "id"; + + /** + * @param store + */ + public CoverageStoreEndpoint(BasicFileStore store) { + this.store = store; + } + + /* + * (non-Javadoc) + * + * @see org.apache.camel.Processor#process(org.apache.camel.Exchange) + */ + @Override + public void process(Exchange ex) throws Exception { + HttpServletResponse response = ex.getIn().getBody( + HttpServletResponse.class); + Map headers = ex.getIn().getHeaders(); + + OutputStream out = null; + try { + String id = (String) headers.get(ID_HEADER); + File cov = getCoverage(id); + response.setContentType(NetCdfFormatter.CONTENT_TYPE); + out = response.getOutputStream(); + sendFile(out, cov); + out.flush(); + store.remove(id); + } catch (InvalidParameterException e) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + } catch (FileNotFoundException e) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + } catch (Exception e) { + log.error("Problem retrieving file from store", e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * Retrieve file from store + * + * @param id + * @return + * @throws FileNotFoundException + * if file is not in store + */ + private File getCoverage(String id) throws FileNotFoundException { + File rval = store.getFile(id); + if (rval == null) { + throw new FileNotFoundException("No file in store with id: " + id); + } + return rval; + } + + /** + * Stream file to out + * + * @param out + * @param f + * @throws Exception + */ + private void sendFile(OutputStream out, File f) throws Exception { + FileInputStream in = null; + try { + in = new FileInputStream(f); + IOUtils.copy(in, out); + } finally { + if (in != null) { + in.close(); + } + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/CoveragesHolder.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/CoveragesHolder.java new file mode 100644 index 0000000000..4aff546a2c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/CoveragesHolder.java @@ -0,0 +1,102 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs; + +import java.util.Map; + +import net.opengis.wcs.v_1_1_2.CoveragesType; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 19, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoveragesHolder { + + protected CoveragesType metadata; + + protected Map data; + + protected String contentType; + + /** + * @param metadata + * @param data + */ + public CoveragesHolder(CoveragesType metadata, Map data) { + super(); + this.metadata = metadata; + this.data = data; + } + + /** + * + */ + public CoveragesHolder() { + // TODO Auto-generated constructor stub + } + + /** + * @return the metadata + */ + public CoveragesType getMetadata() { + return metadata; + } + + /** + * @param metadata + * the metadata to set + */ + public void setMetadata(CoveragesType metadata) { + this.metadata = metadata; + } + + /** + * @return the data + */ + public Map getData() { + return data; + } + + /** + * @param data + * the data to set + */ + public void setData(Map data) { + this.data = data; + } + + /** + * @return the contentType + */ + public String getContentType() { + return contentType; + } + + /** + * @param contentType + * the contentType to set + */ + public void setContentType(String contentType) { + this.contentType = contentType; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsException.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsException.java index f885c10cf6..2dfadc7d86 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsException.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsException.java @@ -49,9 +49,19 @@ public class WcsException extends Exception { protected Code code; public WcsException(OgcException ogc) { - this(Code.valueOf(ogc.getCode().toString()), ogc.getMessage()); + this(decode(ogc.getCode().toString()), ogc.getMessage()); } + private static Code decode(String code) { + Code rval; + try { + rval = Code.valueOf(code); + } catch (Throwable t) { + rval = Code.NoApplicableCode; + } + return rval; + } + public WcsException(Code code) { super(); this.code = code; diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsHttpFactory.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsHttpFactory.java deleted file mode 100644 index 5355a9066b..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsHttpFactory.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * - * - */ -package com.raytheon.uf.edex.wcs; - -import org.apache.commons.pool.KeyedPoolableObjectFactory; - -import com.raytheon.uf.edex.wcs.provider.OgcWcsProvider; - -/** - * @author bclement - * - */ -public class WcsHttpFactory implements KeyedPoolableObjectFactory { - - public WcsHttpFactory() { - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.pool.KeyedPoolableObjectFactory#activateObject(java - * .lang.Object, java.lang.Object) - */ - @Override - public void activateObject(Object arg0, Object arg1) throws Exception { - // TODO Auto-generated method stub - - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.pool.KeyedPoolableObjectFactory#destroyObject(java - * .lang.Object, java.lang.Object) - */ - @Override - public void destroyObject(Object arg0, Object arg1) throws Exception { - // TODO Auto-generated method stub - - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.pool.KeyedPoolableObjectFactory#makeObject(java.lang - * .Object) - */ - @Override - public Object makeObject(Object arg0) throws Exception { - return new WcsHttpHandler(new OgcWcsProvider()); - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.pool.KeyedPoolableObjectFactory#passivateObject(java - * .lang.Object, java.lang.Object) - */ - @Override - public void passivateObject(Object arg0, Object arg1) throws Exception { - // TODO Auto-generated method stub - - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.pool.KeyedPoolableObjectFactory#validateObject(java - * .lang.Object, java.lang.Object) - */ - @Override - public boolean validateObject(Object arg0, Object arg1) { - // TODO Auto-generated method stub - return false; - } - -} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsHttpHandler.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsHttpHandler.java index 373b41d62f..5893799c8e 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsHttpHandler.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsHttpHandler.java @@ -21,24 +21,29 @@ package com.raytheon.uf.edex.wcs; import java.io.InputStream; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import javax.xml.bind.DatatypeConverter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import net.opengis.ows.v_1_1_0.BoundingBoxType; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; +import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; import com.raytheon.uf.edex.ogc.common.http.OgcHttpRequest; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; +import com.raytheon.uf.edex.ogc.common.output.ServletOgcResponse; import com.raytheon.uf.edex.wcs.WcsException.Code; import com.raytheon.uf.edex.wcs.provider.OgcWcsProvider.WcsOpType; import com.raytheon.uf.edex.wcs.reg.RangeField; @@ -65,7 +70,7 @@ import com.raytheon.uf.edex.wcs.request.WcsRequest.Type; * @author * @version 1 */ -public class WcsHttpHandler implements OgcHttpHandler { +public class WcsHttpHandler extends OgcHttpHandler { protected WcsProvider provider; @@ -117,7 +122,7 @@ public class WcsHttpHandler implements OgcHttpHandler { protected static final String GRID_OFFSETS = "gridoffsets"; - private Log log = LogFactory.getLog(this.getClass()); + private final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); public WcsHttpHandler(WcsProvider provider) { this.provider = provider; @@ -133,7 +138,8 @@ public class WcsHttpHandler implements OgcHttpHandler { } protected void handleInternal(OgcHttpRequest ogcRequest) throws Exception { - HttpServletResponse response = ogcRequest.getResponse(); + IOgcHttpResponse response = new ServletOgcResponse( + ogcRequest.getResponse()); HttpServletRequest httpRequest = ogcRequest.getRequest(); Map headers = ogcRequest.getHeaders(); OgcResponse rval = null; @@ -175,6 +181,11 @@ public class WcsHttpHandler implements OgcHttpHandler { case ERROR: rval = (OgcResponse) request.getRequest(); break; + default: + rval = provider.getError(new WcsException( + Code.OperationNotSupported, request.getType() + + " not supported"), null); + break; } sendResponse(response, rval); @@ -185,9 +196,9 @@ public class WcsHttpHandler implements OgcHttpHandler { * @return */ private OgcResponse validateExceptionFormat(WcsRequest request) { - if (!request.getExceptionFormat().equalsIgnoreCase( + if (!request.getExceptionFormat().equalsIgnoreParams( OgcResponse.TEXT_HTML_MIME) - && !request.getExceptionFormat().equalsIgnoreCase( + && !request.getExceptionFormat().equalsIgnoreParams( OgcResponse.TEXT_XML_MIME)) { return provider.getError( new WcsException(Code.InvalidParameterValue, @@ -204,13 +215,13 @@ public class WcsHttpHandler implements OgcHttpHandler { if (port != 80) { base += ":" + port; } - base += request.getPathInfo(); + base += request.getPathInfo() + "?service=wcs"; OgcServiceInfo rval = new OgcServiceInfo(base); - rval.addOperationInfo(getOp(base + "?request=" + CAP_PARAM, base, + rval.addOperationInfo(getOp(base, base, WcsOpType.GetCapabilities)); - rval.addOperationInfo(getOp(base + "?request=describecoverage", base, + rval.addOperationInfo(getOp(base, base, WcsOpType.DescribeCoverage)); - rval.addOperationInfo(getOp(base + "?request=getcoverage", base, + rval.addOperationInfo(getOp(base, base, WcsOpType.GetCoverage)); return rval; @@ -226,70 +237,18 @@ public class WcsHttpHandler implements OgcHttpHandler { rval.addAcceptVersions("1.1.2"); rval.addService("WCS"); rval.addFormat("text/xml"); + rval.setPostEncoding("XML"); return rval; } - protected String getString(Object obj) { - String rval = null; - if (obj != null) { - if (obj instanceof String) { - rval = (String) obj; - } - } - return rval; - } - - protected String[] getStringArr(Object obj) { - String[] rval = null; - if (obj != null) { - if (obj instanceof String[]) { - rval = (String[]) obj; - } else if (obj instanceof String) { - rval = ((String) obj).split(","); - } - } - return rval; - } - - protected Integer getInt(Object obj) { - Integer rval = null; - if (obj != null) { - if (obj instanceof Integer) { - rval = (Integer) obj; - } else if (obj instanceof String) { - try { - rval = Integer.parseInt((String) obj); - } catch (Exception e) { - // leave rval as null - } - } - } - return rval; - } - - protected Boolean getBool(Object obj) { - Boolean rval = null; - if (obj != null) { - if (obj instanceof Boolean) { - rval = (Boolean) obj; - } else if (obj instanceof String) { - try { - rval = Boolean.parseBoolean((String) obj); - } catch (Exception e) { - // leave rval as null - } - } - } - return rval; - } - - protected WcsRequest getRequestFromHeaders(Map headers) { + protected WcsRequest getRequestFromHeaders(Map headers) + throws OgcException { WcsRequest rval = null; Object obj = headers.get(REQUEST_HEADER); - String exceptionFormat = OgcResponse.TEXT_XML_MIME; + MimeType exceptionFormat = OgcResponse.TEXT_XML_MIME; if (obj instanceof String) { - exceptionFormat = getString(headers.get(EXCEP_FORMAT_HEADER)); - if (exceptionFormat == null || exceptionFormat.isEmpty()) { + exceptionFormat = getMimeType(headers, EXCEP_FORMAT_HEADER); + if (exceptionFormat == null) { exceptionFormat = OgcResponse.TEXT_XML_MIME; } String req = (String) obj; @@ -301,7 +260,7 @@ public class WcsHttpHandler implements OgcHttpHandler { try { rval = buildGetCoverageRequest(headers); } catch (RangeParseException e) { - log.error(e); + log.error(e.getLocalizedMessage(), e); rval = new WcsRequest(Type.ERROR); String msg = "Invalid range parameter"; WcsException ex = new WcsException( @@ -364,7 +323,11 @@ public class WcsHttpHandler implements OgcHttpHandler { String bbox = getHeader(BBOX_HEADER, headers); if (bbox != null) { - rval.setBbox(parseBbox(bbox)); + try { + rval.setBbox(parseBbox(bbox)); + } catch (OgcException e) { + throw new RangeParseException(e.getMessage()); + } } return rval; @@ -392,21 +355,30 @@ public class WcsHttpHandler implements OgcHttpHandler { return rval; } - protected OgcBoundingBox parseBbox(String bbox) { + protected BoundingBoxType parseBbox(String bbox) throws RangeParseException { String[] parts = bbox.split(","); - OgcBoundingBox rval = null; - if (parts.length == 5) { - rval = new OgcBoundingBox(); + BoundingBoxType rval = null; + if (parts.length == 5 || parts.length == 7) { + rval = new BoundingBoxType(); try { - rval.setMinx(Double.parseDouble(parts[0])); - rval.setMiny(Double.parseDouble(parts[1])); - rval.setMaxx(Double.parseDouble(parts[2])); - rval.setMaxy(Double.parseDouble(parts[3])); - rval.setCrs(parts[4]); + final int pivot = parts.length / 2; + List mins = new ArrayList(pivot); + for (int i = 0; i < pivot; ++i) { + mins.add(Double.parseDouble(parts[i])); + } + List maxs = new ArrayList(pivot); + for (int i = pivot; i < pivot * 2; ++i) { + maxs.add(Double.parseDouble(parts[i])); + } + rval.setLowerCorner(mins); + rval.setUpperCorner(maxs); + rval.setCrs(parts[parts.length - 1]); } catch (NumberFormatException e) { - // FIXME return error + throw new RangeParseException("Unable to parse bounding box"); } - }// else TODO handle non 2d WGS84 + } else { + throw new RangeParseException("Invalid bounding box format"); + } return rval; } @@ -430,7 +402,7 @@ public class WcsHttpHandler implements OgcHttpHandler { return rval; } - protected void sendResponse(HttpServletResponse httpRes, + protected void sendResponse(IOgcHttpResponse httpRes, OgcResponse response) throws Exception { OgcResponseOutput.output(response, httpRes); } @@ -456,4 +428,16 @@ public class WcsHttpHandler implements OgcHttpHandler { return layerValue; } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler#handleError(com.raytheon + * .uf.edex.ogc.common.OgcException, java.lang.String) + */ + @Override + protected OgcResponse handleError(OgcException e, MimeType exceptionFormat) { + return provider.getError(new WcsException(e), exceptionFormat); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsProvider.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsProvider.java index ab1e442e6f..2a512bd5f8 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsProvider.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/WcsProvider.java @@ -22,10 +22,10 @@ package com.raytheon.uf.edex.wcs; import java.io.InputStream; -import javax.servlet.http.HttpServletResponse; - import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; import com.raytheon.uf.edex.wcs.provider.OgcWcsProvider.WcsOpType; import com.raytheon.uf.edex.wcs.request.DescCoverageRequest; import com.raytheon.uf.edex.wcs.request.GetCapRequest; @@ -57,10 +57,10 @@ public interface WcsProvider { OgcServiceInfo serviceinfo, DescCoverageRequest request); public void getCoverage(OgcServiceInfo serviceinfo, - GetCoverageRequest request, HttpServletResponse response); + GetCoverageRequest request, IOgcHttpResponse response); public WcsRequest getRequest(InputStream in); - public OgcResponse getError(WcsException e, String exceptionFormat); + public OgcResponse getError(WcsException e, MimeType exceptionFormat); } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ByteNcWriter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ByteNcWriter.java new file mode 100644 index 0000000000..7efc918172 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ByteNcWriter.java @@ -0,0 +1,63 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.format; + +import com.raytheon.uf.common.datastorage.records.ByteDataRecord; +import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.nc4.NcVariable; +import com.raytheon.uf.common.nc4.NcVariable.ByteVariable; +import com.raytheon.uf.common.nc4.NetcdfException; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 12, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class ByteNcWriter extends NcWriter { + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.format.NcWriter#getVarClass() + */ + @Override + public Class getVarClass() { + return ByteVariable.class; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.format.NcWriter#write(com.raytheon.uf.common + * .nc4.NcVariable, com.raytheon.uf.common.datastorage.records.IDataRecord) + */ + @Override + public void write(NcVariable var, int[] start, IDataRecord irecord) + throws NetcdfException { + ByteDataRecord record = (ByteDataRecord) irecord; + ByteVariable variable = (ByteVariable) var; + int[] shape = getShape(record); + variable.putVar(start, shape, record.getByteData()); + } + + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/FloatNcWriter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/FloatNcWriter.java new file mode 100644 index 0000000000..37589d4e4e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/FloatNcWriter.java @@ -0,0 +1,62 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.format; + +import com.raytheon.uf.common.datastorage.records.FloatDataRecord; +import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.nc4.NcVariable; +import com.raytheon.uf.common.nc4.NcVariable.FloatVariable; +import com.raytheon.uf.common.nc4.NetcdfException; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 12, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class FloatNcWriter extends NcWriter { + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.format.NcWriter#getVarClass() + */ + @Override + public Class getVarClass() { + return FloatVariable.class; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.format.NcWriter#write(com.raytheon.uf.common + * .nc4.NcVariable, com.raytheon.uf.common.datastorage.records.IDataRecord) + */ + @Override + public void write(NcVariable var, int[] start, IDataRecord irecord) + throws NetcdfException { + FloatDataRecord record = (FloatDataRecord) irecord; + FloatVariable variable = (FloatVariable) var; + int[] shape = getShape(record); + variable.putVar(start, shape, record.getFloatData()); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/WcsDataFormatter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/IWcsDataFormatter.java similarity index 62% rename from edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/WcsDataFormatter.java rename to edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/IWcsDataFormatter.java index 959f8d9bfe..d714e1639d 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/WcsDataFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/IWcsDataFormatter.java @@ -30,7 +30,8 @@ */ package com.raytheon.uf.edex.wcs.format; -import java.io.OutputStream; +import java.io.File; +import java.io.InputStream; import com.raytheon.uf.edex.wcs.reg.Coverage; @@ -39,10 +40,35 @@ import com.raytheon.uf.edex.wcs.reg.Coverage; * @author bclement * @version 1.0 */ -public interface WcsDataFormatter { +public interface IWcsDataFormatter { - public String getIdentifier(); + /** + * + * @return + */ + public String getIdentifier(); + + /** + * get coverage identifier + * @param format + * @return + */ + public boolean matchesFormat(String format); + + /** + * Format coverage + * @param coverage + * @return + * @throws Exception + */ + public InputStream format(Coverage coverage) throws Exception; + + /** + * Store coverage + * @param coverage + * @return + * @throws Exception + */ + public File store(Coverage coverage) throws Exception; - public void format(Coverage coverage, OutputStream out, boolean base64) - throws Exception; } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/IntNcWriter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/IntNcWriter.java new file mode 100644 index 0000000000..62039631e1 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/IntNcWriter.java @@ -0,0 +1,62 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.format; + +import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.datastorage.records.IntegerDataRecord; +import com.raytheon.uf.common.nc4.NcVariable; +import com.raytheon.uf.common.nc4.NcVariable.IntVariable; +import com.raytheon.uf.common.nc4.NetcdfException; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 12, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class IntNcWriter extends NcWriter { + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.format.NcWriter#getVarClass() + */ + @Override + public Class getVarClass() { + return IntVariable.class; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.format.NcWriter#write(com.raytheon.uf.common + * .nc4.NcVariable, com.raytheon.uf.common.datastorage.records.IDataRecord) + */ + @Override + public void write(NcVariable var, int[] start, IDataRecord irecord) + throws NetcdfException { + IntegerDataRecord record = (IntegerDataRecord) irecord; + IntVariable variable = (IntVariable) var; + int[] shape = getShape(record); + variable.putVar(start, shape, record.getIntData()); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/NcWriter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/NcWriter.java new file mode 100644 index 0000000000..6132f80bec --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/NcWriter.java @@ -0,0 +1,86 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.format; + +import com.raytheon.uf.common.datastorage.records.ByteDataRecord; +import com.raytheon.uf.common.datastorage.records.FloatDataRecord; +import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.datastorage.records.IntegerDataRecord; +import com.raytheon.uf.common.datastorage.records.ShortDataRecord; +import com.raytheon.uf.common.nc4.NcVariable; +import com.raytheon.uf.common.nc4.NetcdfException; + +/** + * Abstraction for data type specific writing from data record to netcdf file + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 12, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class NcWriter { + + public abstract Class getVarClass(); + + /** + * Write data record to variable + * + * @param var + * @param irecord + * @throws NetcdfException + */ + public abstract void write(NcVariable var, int[] start, IDataRecord irecord) + throws NetcdfException; + + /** + * Converts the dimensions of the record to netcdf shape. This will be + * reverse from the data record sizes; + * + * @param record + * @return + */ + protected int[] getShape(IDataRecord record) { + long[] sizes = record.getSizes(); + return new int[] { 1, 1, (int) sizes[1], (int) sizes[0] }; + } + + /** + * Factory method for ncwriters + * + * @param record + * @return + * @throws Exception + * if the data record's data type is not supported by the netcdf + * library + */ + public static NcWriter create(IDataRecord record) + throws Exception { + if (record instanceof ByteDataRecord) { + return new ByteNcWriter(); + } else if (record instanceof ShortDataRecord) { + return new ShortNcWriter(); + } else if (record instanceof IntegerDataRecord) { + return new IntNcWriter(); + } else if (record instanceof FloatDataRecord) { + return new FloatNcWriter(); + } else { + throw new Exception("Unsupported data record type: " + + record.getClass()); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/NetCdfFormatter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/NetCdfFormatter.java index f5ad4e34bf..ec137d07f1 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/NetCdfFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/NetCdfFormatter.java @@ -30,229 +30,630 @@ */ package com.raytheon.uf.edex.wcs.format; -import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.OutputStream; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import javax.measure.unit.NonSI; -import javax.measure.unit.Unit; - -import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.geotools.coverage.grid.GridEnvelope2D; import org.geotools.coverage.grid.GridGeometry2D; +import org.geotools.coverage.grid.InvalidGridGeometryException; +import org.geotools.geometry.DirectPosition2D; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.parameter.Parameter; +import org.geotools.referencing.CRS; +import org.geotools.referencing.operation.transform.ConcatenatedTransform; +import org.opengis.geometry.MismatchedDimensionException; import org.opengis.metadata.spatial.PixelOrientation; -import org.opengis.referencing.operation.MathTransform2D; +import org.opengis.parameter.GeneralParameterValue; +import org.opengis.parameter.ParameterValueGroup; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.crs.GeographicCRS; +import org.opengis.referencing.crs.ProjectedCRS; +import org.opengis.referencing.cs.CartesianCS; +import org.opengis.referencing.cs.CoordinateSystemAxis; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.Projection; +import org.opengis.referencing.operation.TransformException; -import ucar.ma2.Array; -import ucar.ma2.DataType; -import ucar.nc2.Attribute; -import ucar.nc2.Dimension; -import ucar.nc2.NetcdfFile; -import ucar.nc2.NetcdfFileWriteable; -import ucar.nc2.Variable; -import ucar.nc2.iosp.IOServiceProvider; - -import com.raytheon.uf.common.datastorage.records.ByteDataRecord; -import com.raytheon.uf.common.datastorage.records.FloatDataRecord; -import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.common.nc4.NcDimension; +import com.raytheon.uf.common.nc4.NcDimension.DoubleDimension; +import com.raytheon.uf.common.nc4.NcVariable; +import com.raytheon.uf.common.nc4.NcVariable.ByteVariable; +import com.raytheon.uf.common.nc4.Netcdf; +import com.raytheon.uf.common.nc4.NetcdfException; +import com.raytheon.uf.common.nc4.cf.CfConstants; +import com.raytheon.uf.common.nc4.cf.CfDimensions; +import com.raytheon.uf.common.nc4.cf.CfGridMapper; +import com.raytheon.uf.common.nc4.cf.CfHorizontalDims; +import com.raytheon.uf.common.nc4.cf.CfNetcdf; +import com.raytheon.uf.common.spatial.reprojection.ReferencedDataRecord; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.BasicFileStore; +import com.raytheon.uf.edex.wcs.WcsException; +import com.raytheon.uf.edex.wcs.WcsException.Code; import com.raytheon.uf.edex.wcs.reg.Coverage; +import com.raytheon.uf.edex.wcs.reg.CoverageDimensions; +import com.raytheon.uf.edex.wcs.reg.CoverageField; +import com.raytheon.uf.edex.wcs.reg.CoverageTAxis; +import com.raytheon.uf.edex.wcs.reg.CoverageXYAxis; +import com.raytheon.uf.edex.wcs.reg.CoverageZAxis; +import com.raytheon.uf.edex.wcs.reg.TemporalCube; +import com.raytheon.uf.edex.wcs.reg.VerticalSlice; /** * * @author bclement * @version 1.0 */ -public class NetCdfFormatter implements WcsDataFormatter { +public class NetCdfFormatter implements IWcsDataFormatter { - private static final String CF_VERSION = "CF-1.0"; - protected String id = "application/netcdf"; + public static final String CONTENT_TYPE = "application/netcdf4"; - protected class DirectNetcdfFile extends NetcdfFile { - public DirectNetcdfFile(IOServiceProvider spi, String name) - throws IOException { - super(spi, null, name, null); - } - } + private final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wcs.format.WcsDataFormatter#getIdentifier() - */ - @Override - public String getIdentifier() { - return id; - } + private final BasicFileStore store; - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wcs.format.WcsDataFormatter#format(com.raytheon. - * uf.common.datastorage.records.IDataRecord, java.io.OutputStream, boolean) - */ - @Override - public void format(Coverage coverage, OutputStream out, boolean base64) - throws Exception { + public NetCdfFormatter(BasicFileStore store) { + this.store = store; + } - IDataRecord record = coverage.getDataRecord(); + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.format.WcsDataFormatter#getIdentifier() + */ + @Override + public String getIdentifier() { + return CONTENT_TYPE; + } - File tempFile = File.createTempFile("wcs", ".nc"); - NetcdfFileWriteable ncFile = NetcdfFileWriteable.createNew( - tempFile.getAbsolutePath(), false); + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.format.WcsDataFormatter#format(com.raytheon. + * uf.common.datastorage.records.IDataRecord, java.io.OutputStream, boolean) + */ + @Override + public InputStream format(Coverage coverage) throws Exception { + final File file = store(coverage); + // if the constructor throws, the file will be leaked + return new FileInputStream(file) { + @Override + public void close() throws IOException { + try { + super.close(); + } finally { + if (file != null) { + file.delete(); + } + } + } + }; + } - List dimList = new ArrayList(); - List dimListForDataBecauseNetcdfIsOpposite = new ArrayList(); - long[] sizes = record.getSizes(); - // int[] shape = new int[sizes.length]; - for (int i = 0; i < sizes.length; i++) { - Dimension dim = ncFile.addDimension("dim" + i, (int) sizes[i]); - dimList.add(dim); - dimListForDataBecauseNetcdfIsOpposite.add(dim); - // shape[i] = (int) sizes[i]; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.format.WcsDataFormatter#store(com.raytheon.uf + * .edex.wcs.reg.Coverage) + */ + @Override + public File store(Coverage coverage) throws Exception { + String id = createStoreId(coverage); + File file = store.reserveFile(id); + CfNetcdf ncfile = new CfNetcdf(file.getAbsolutePath(), + Netcdf.NETCDF4_CLASSIC_MODE); + try { + ncfile.putStringAttribute(CfConstants.COVERAGE_ID_ATTR, + coverage.getName()); + List fields = coverage.getFields(); + DimMapping dmap = defineDims(ncfile, fields); + List vars = new ArrayList(fields.size()); + for (CoverageField field : fields) { + vars.add(define(ncfile, dmap.fieldMap.get(field.getName()), + field)); + } + ncfile.endFileDefinition(); + for (DimWriter w : dmap.writers) { + w.write(); + } + Iterator iter = vars.iterator(); + for (CoverageField field : fields) { + NcVariable var = iter.next(); + write(field, var); + } - Class javaDataType = null; - Object dataContent = null; - DataType ncDataType = null; - if (record instanceof ByteDataRecord) { - javaDataType = byte.class; - ncDataType = DataType.BYTE; - dataContent = ((ByteDataRecord) record).getByteData(); - } else if (record instanceof FloatDataRecord) { - javaDataType = float.class; - ncDataType = DataType.FLOAT; - dataContent = ((FloatDataRecord) record).getFloatData(); - } + } finally { + ncfile.close(); + } + return file; + } - // reverse netcdf dimensions - Collections.reverse(dimListForDataBecauseNetcdfIsOpposite); + /** + * Write 4D cube in field to variable + * + * @param field + * @param var + * @throws Exception + */ + private void write(CoverageField field, NcVariable var) throws Exception { + List timeCube = field.getTimeCube(); + TemporalCube firstCube = timeCube.get(0); + VerticalSlice firstSlice = firstCube.getSlices().get(0); + ReferencedDataRecord firstRecord = firstSlice.getRecord().get(true); + NcWriter writer = NcWriter.create(firstRecord + .getRecord()); + Iterator cubeIter = timeCube.iterator(); + for (int i = 0; cubeIter.hasNext(); ++i) { + TemporalCube cube = cubeIter.next(); + Iterator sliceIter = cube.getSlices().iterator(); + for (int j = 0; sliceIter.hasNext(); ++j) { + VerticalSlice slice = sliceIter.next(); + writer.write(var, new int[] { i, j, 0, 0 }, slice.getRecord() + .get(false).getRecord()); + } + } + } - ncFile.addGlobalAttribute("Conventions", CF_VERSION); - Variable dataVariable = ncFile.addVariable("data", ncDataType, - dimListForDataBecauseNetcdfIsOpposite); + /** + * Define variable for field + * + * @param ncfile + * @param dims + * @param field + * @return + * @throws Exception + */ + private NcVariable define(CfNetcdf ncfile, + CfDimensions dims, CoverageField field) + throws Exception { + List timeCube = field.getTimeCube(); + TemporalCube firstCube = timeCube.get(0); + VerticalSlice firstSlice = firstCube.getSlices().get(0); + ReferencedDataRecord firstRecord = firstSlice.getRecord().get(true); + NcWriter writer = NcWriter.create(firstRecord + .getRecord()); + NcVariable variable = ncfile.defineVar(field.getName(), dims.toArray(), + writer.getVarClass()); + variable.putStringAttribute(CfConstants.STANDARD_NAME_ATTR, + field.getStandardName()); + variable.putStringAttribute(CfConstants.LONG_NAME_ATTR, + field.getStandardName()); + variable.putStringAttribute(CfConstants.UNITS_ATTR, field.getUnits()); + variable.putNumberAttribute(CfConstants.MISSING_VAL_ATTR, + new Number[] { field.getPaddingValue() }); + CfHorizontalDims xyDims = dims.getXyDims(); + if (xyDims.isMapped()) { + variable.putStringAttribute(CfConstants.GRID_MAP_NAME_ATTR, + xyDims.getGridMapping()); + variable.putStringAttribute(CfConstants.COORDS_ATTR, + xyDims.getCoords()); + } + return variable; + } - // TODO - (netcdf) what if I'm not using lat/lon? - dataVariable.addAttribute(new Attribute("coordinates", - "Time Latitude Longitude lat lon")); + /** + * Interface to postpone writing to dimensions until after definition phase + */ + private static interface DimWriter { + public void write() throws NetcdfException; + } + /** + * Wrapper for multi-part return + */ + private static class DimMapping { + public final Map> fieldMap; + public final List writers; - // add dimention variables + public DimMapping(Map> fieldMap, + List writers) { + this.fieldMap = fieldMap; + this.writers = writers; + } + } - GridGeometry2D gridGeom = coverage.getGridGeometry(); - MathTransform2D gridToCrs = gridGeom.getGridToCRS2D(PixelOrientation.UPPER_LEFT); + /** + * Define dimensions for fields. + * + * @param ncfile + * @param fields + * @return + * @throws Exception + */ + private DimMapping defineDims(CfNetcdf ncfile, List fields) + throws Exception { + Map> horizMap = new HashMap>(); + Map vertMap = new HashMap(); + Map timeMap = new HashMap(); + Map> fieldMap = new HashMap>(); + List writers = new ArrayList(); - int dims = sizes.length; + for (CoverageField field : fields) { + CoverageDimensions dims = field.getDimensions(); + CoverageXYAxis xyAxis = dims.getXyAxis(); + CfHorizontalDims horiz = horizMap.get(xyAxis); + if (horiz == null) { + horiz = defineXY(ncfile, xyAxis, writers, horizMap.size()); + horizMap.put(xyAxis, horiz); + } + CoverageZAxis zAxis = dims.getZAxis(); + DoubleDimension vert = vertMap.get(zAxis); + if (vert == null) { + vert = defineZ(ncfile, zAxis, writers, vertMap.size()); + vertMap.put(zAxis, vert); + } + CoverageTAxis tAxis = dims.getTAxis(); + DoubleDimension time = timeMap.get(tAxis); + if (time == null) { + time = defineT(ncfile, tAxis, writers, timeMap.size()); + timeMap.put(tAxis, time); + } + fieldMap.put(field.getName(), + new CfDimensions(horiz, vert, + time)); + } + return new DimMapping(fieldMap, writers); + } - int minMax[][] = new int[dims][2]; + /** + * Define horizontal dimensions + * + * @param ncfile + * @param xyAxis + * @param writers + * @param count + * @return + * @throws Exception + */ + private CfHorizontalDims defineXY(CfNetcdf ncfile, + CoverageXYAxis xyAxis, List writers, int count) + throws Exception { + double[][] lonLatAxis = getLonLatAxis(xyAxis.getGridGeometry()); + final double[] lonValue = lonLatAxis[0]; + final double[] latValue = lonLatAxis[1]; + final DoubleDimension lon = ncfile.defineXDim("lon" + count, + "longitude", lonValue.length, CfConstants.LON_UNITS, + DoubleDimension.class); + final DoubleDimension lat = ncfile.defineYDim("lat" + count, + "latitude", latValue.length, CfConstants.LAT_UNITS, + DoubleDimension.class); + writers.add(new DimWriter() { + @Override + public void write() throws NetcdfException { + lon.putDim(lonValue); + lat.putDim(latValue); + } + }); - for ( int dim = 0; dim < dims; ++dim ) { - minMax[dim][0] = gridGeom.getGridRange().getLow(dim); - minMax[dim][1] = gridGeom.getGridRange().getHigh(dim); + ReferencedEnvelope env = xyAxis.getEnvelope(); + CoordinateReferenceSystem crs = env.getCoordinateReferenceSystem(); + if (crs instanceof GeographicCRS) { + return new CfHorizontalDims(lon, lat); + } else if (crs instanceof ProjectedCRS) { + return defineMappedXY(ncfile, xyAxis, writers, count, lon, lat); + } else { + log.error("Unsupport CRS object type: " + crs.getClass(), + new Exception()); + throw new WcsException(Code.InternalServerError); + } + } - List dimAsList = new ArrayList(1); - dimAsList.add(dimList.get(dim)); - Variable axisVariable = ncFile.addVariable("dim" + dim, - DataType.DOUBLE, dimAsList); + /** + * Define non geographic horizontal dimensions + * + * @param ncfile + * @param xyAxis + * @param writers + * @param count + * @param lon + * @param lat + * @return + * @throws NetcdfException + * @throws TransformException + * @throws FactoryException + * @throws MismatchedDimensionException + * @throws InvalidGridGeometryException + */ + private CfHorizontalDims defineMappedXY( + CfNetcdf ncfile, CoverageXYAxis xyAxis, List writers, + int count, DoubleDimension lon, DoubleDimension lat) + throws Exception { + ReferencedEnvelope env = xyAxis.getEnvelope(); + ProjectedCRS crs = (ProjectedCRS) env.getCoordinateReferenceSystem(); + CartesianCS cs = crs.getCoordinateSystem(); + CoordinateSystemAxis xAxis = cs.getAxis(0); + CoordinateSystemAxis yAxis = cs.getAxis(1); + GridGeometry2D geom = xyAxis.getGridGeometry(); + GridEnvelope2D gridEnv = geom.getGridRange2D(); - // add attributes to the variable + final DoubleDimension x = ncfile.defineXDim("x" + count, + CfConstants.X_STD_NAME, gridEnv.width, xAxis.getUnit() + .toString(), DoubleDimension.class); + final DoubleDimension y = ncfile.defineYDim("y" + count, + CfConstants.Y_STD_NAME, gridEnv.height, yAxis.getUnit() + .toString(), DoubleDimension.class); - // units - Unit unit = coverage.getCrs().getCoordinateSystem().getAxis(dim).getUnit(); - String unitName = unit.toString(); - if (NonSI.DEGREE_ANGLE.toString().equals(unitName)) { - unitName = "degree_" - + coverage.getCrs().getCoordinateSystem().getAxis(dim) - .getDirection().name().toLowerCase(); - } + double[][] xyVals = getXYAxis(geom, crs); + final double[] xVals = xyVals[0]; + final double[] yVals = xyVals[1]; - Attribute axisUnit = new Attribute("units", unitName); - axisVariable.addAttribute(axisUnit); - // standard_name - // TODO - (netcdf) make spec - String name = coverage.getCrs().getCoordinateSystem().getAxis(dim) - .getName().toString().replaceAll(" ", "_").toLowerCase(); - Attribute axisName = new Attribute("standard_name", name); - axisVariable.addAttribute(axisName); - } + writers.add(new DimWriter() { + @Override + public void write() throws NetcdfException { + x.putDim(xVals); + y.putDim(yVals); + } + }); - // create file, then dump data into it - ncFile.create(); + Projection conv = crs.getConversionFromBase(); + ParameterValueGroup params = conv.getParameterValues(); + String projName = params.getDescriptor().getName().getCode(); - for (int dim = 0; dim < dims; ++dim) { - double axisValues[] = new double[minMax[dim][1] - minMax[dim][0] - + 1]; - for (int coord = minMax[dim][0]; coord <= minMax[dim][1]; ++coord) { - double[] point = new double[dims]; - for (int i = 0; i < dims; ++i) { - if (i == dim) { - point[i] = coord; - } else { - point[i] = minMax[i][0]; - } - } - double[] crsPoint = new double[dims]; - gridToCrs.transform(point, 0, crsPoint, 0, 1); - axisValues[coord] = crsPoint[dim]; - } + Map> paramMap = getParamMap(params); + NcVariable projVar = defineProjVar(ncfile, projName, paramMap, count); + String coords = StringUtils.join( + new String[] { lat.getName(), lon.getName() }, " "); + return new CfHorizontalDims(x, y, coords, + projVar.getName()); + } + protected static class NumberedValue implements Comparable { + public int number; - ncFile.write("dim" + dim, new int[] { 0, 0 }, - Array.factory(double.class, new int[] { minMax[dim][1] - - minMax[dim][0] + 1 }, axisValues)); - + public Object value; - // ncFile.flush(); - } + public NumberedValue(int number, Object value) { + this.number = number; + this.value = value; + } - coverage.getCrs().getCoordinateSystem().getAxis(0).getUnit(); + @Override + public int compareTo(NumberedValue o) { + return number - o.number; + } - // reverse shape - int[] shape = new int[sizes.length]; - for (int i = 0; i < sizes.length; ++i) { - shape[i] = (int) sizes[sizes.length - (i + 1)]; - } - - ncFile.write("data", new int[] { 0, 0 }, - Array.factory(javaDataType, shape, dataContent)); + } - ncFile.flush(); - ncFile.close(); + /** + * Map parameter base names to values + * + * @param params + * @return + */ + protected Map> getParamMap( + ParameterValueGroup params) { + final Pattern PARAM_PATTERN = Pattern.compile("^(.*)(_([0-9]+))$"); + Map> paramMap = new HashMap>(); + for (GeneralParameterValue v : params.values()) { + Parameter p = (Parameter) v; + String paramName = p.getDescriptor().getName().getCode().trim(); + Matcher m = PARAM_PATTERN.matcher(paramName); + int number = 0; + if (m.matches()) { + paramName = m.group(1); + number = Integer.parseInt(m.group(3)); + } + paramName = CfGridMapper.getMappingAttributeName(paramName); + List values = paramMap.get(paramName); + if (values == null) { + values = new ArrayList(2); + paramMap.put(paramName, values); + } - - byte[] data = new byte[(int) tempFile.length()]; - DataInputStream dis = new DataInputStream(new FileInputStream(tempFile)); - dis.readFully(data); - dis.close(); + values.add(new NumberedValue(number, p.getValue())); + } + return paramMap; + } - if (base64) { - Base64 b64 = new Base64(); - data = b64.encode(data); - } - out.write(data); - out.flush(); - tempFile.delete(); - } + /** + * Define grid projection mapping variable + * + * @param ncfile + * @param projName + * @param paramMap + * @param count + * @return + * @throws NetcdfException + */ + private NcVariable defineProjVar(CfNetcdf ncfile, String projName, + Map> paramMap, int count) + throws NetcdfException { + ByteVariable projVar = ncfile.defineVar(projName + count, + new NcDimension[0], ByteVariable.class); + projVar.putStringAttribute(CfConstants.GRID_MAP_NAME_ATTR, projName); + for (Entry> e : paramMap.entrySet()) { + List list = e.getValue(); + Collections.sort(list); + if (list.get(0).value instanceof Number) { + Number[] vals = new Number[list.size()]; + Iterator iter = list.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + vals[i] = (Number) iter.next().value; + } + projVar.putNumberAttribute(e.getKey(), vals); + } else { + String[] vals = new String[list.size()]; + Iterator iter = list.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + vals[i] = iter.next().value.toString(); + } + projVar.putStringsAttribute(e.getKey(), vals); + } + } + return projVar; + } - /** - * @return the id - */ - public String getId() { - return id; - } + /** + * Define vertical dimension + * + * @param ncfile + * @param zAxis + * @param writers + * @param count + * @return + * @throws NetcdfException + */ + private DoubleDimension defineZ(CfNetcdf ncfile, final CoverageZAxis zAxis, + List writers, int count) throws NetcdfException { + final DoubleDimension z = ncfile.defineZDim("level" + count, + "height level", zAxis.getValue().length, zAxis.getUnits(), + zAxis.isUpIsPositive(), DoubleDimension.class); + writers.add(new DimWriter() { + @Override + public void write() throws NetcdfException { + z.putDim(zAxis.getValue()); + } + }); + return z; + } - /** - * @param id - * the id to set - */ - public void setId(String id) { - this.id = id; - } + /** + * Define temporal dimension + * + * @param ncfile + * @param tAxis + * @param writers + * @param count + * @return + * @throws NetcdfException + */ + private DoubleDimension defineT(CfNetcdf ncfile, CoverageTAxis tAxis, + List writers, int count) throws NetcdfException { + final DoubleDimension t = ncfile.defineTimeDim("time" + count, "time", + tAxis.getTimes().length, CfConstants.UNIX_TIME_UNITS, + DoubleDimension.class); + final double[] values = getTimes(tAxis.getTimes()); + writers.add(new DimWriter() { + @Override + public void write() throws NetcdfException { + t.putDim(values); + } + }); + return t; + } + + /** + * Convert times to UNIX timestamps with milliseconds as decimal + * + * @param times + * @return + */ + private double[] getTimes(Date[] times) { + double[] rval = new double[times.length]; + for (int i = 0; i < rval.length; ++i) { + rval[i] = times[i].getTime() / 1000; + } + return rval; + } + + /** + * Convert geometry to CRS84. + * + * @param geom + * @return array of size 2. Index 0 contains longitude, index 1 contains + * latitude. Not guaranteed to be the same length. + * @throws InvalidGridGeometryException + * @throws FactoryException + * @throws MismatchedDimensionException + * @throws TransformException + */ + private double[][] getLonLatAxis(GridGeometry2D geom) + throws InvalidGridGeometryException, FactoryException, + MismatchedDimensionException, TransformException { + return getXYAxis(geom, MapUtil.LATLON_PROJECTION); + } + + /** + * Convert geometry to Target CRS. + * + * @param geom + * @param targetCRS + * @return + * @throws InvalidGridGeometryException + * @throws FactoryException + * @throws MismatchedDimensionException + * @throws TransformException + */ + private double[][] getXYAxis(GridGeometry2D geom, + CoordinateReferenceSystem targetCRS) + throws InvalidGridGeometryException, FactoryException, + MismatchedDimensionException, TransformException { + double[][] rval = new double[2][]; + GridEnvelope2D gridEnv = geom.getGridRange2D(); + MathTransform gridToCRS = geom + .getGridToCRS(PixelOrientation.UPPER_LEFT); + CoordinateReferenceSystem origCrs = geom.getCoordinateReferenceSystem(); + MathTransform toTarget = CRS + .findMathTransform(origCrs, targetCRS, true); + MathTransform transform = ConcatenatedTransform.create(gridToCRS, + toTarget); + rval[0] = new double[gridEnv.width]; + rval[1] = new double[gridEnv.height]; + int maxLen = Math.max(gridEnv.width, gridEnv.height); + int xIndex = 0; + int yIndex = 0; + for (int i = 0; i < maxLen; ++i) { + DirectPosition2D point = new DirectPosition2D(xIndex, yIndex); + DirectPosition2D target = new DirectPosition2D(); + transform.transform(point, target); + rval[0][xIndex] = target.getX(); + rval[1][yIndex] = target.getY(); + xIndex = Math.min(++xIndex, gridEnv.width - 1); + yIndex = Math.min(++yIndex, gridEnv.height - 1); + } + return rval; + } + + /** + * Create unique id for file store + * + * @param coverage + * @return + */ + private String createStoreId(Coverage coverage) { + String name = coverage.getName(); + String rval; + do { + HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(name).append(System.currentTimeMillis()); + String hash = Integer.toHexString(builder.toHashCode()); + rval = name + hash + ".nc"; + } while (store.getFile(rval) != null); + + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.format.WcsDataFormatter#matchesFormat(java.lang + * .String) + */ + @Override + public boolean matchesFormat(String format) { + return format.toLowerCase().contains("netcdf"); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ShortNcWriter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ShortNcWriter.java new file mode 100644 index 0000000000..c1d8670cde --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ShortNcWriter.java @@ -0,0 +1,62 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.format; + +import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.datastorage.records.ShortDataRecord; +import com.raytheon.uf.common.nc4.NcVariable; +import com.raytheon.uf.common.nc4.NcVariable.ShortVariable; +import com.raytheon.uf.common.nc4.NetcdfException; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 12, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class ShortNcWriter extends NcWriter { + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.format.NcWriter#getVarClass() + */ + @Override + public Class getVarClass() { + return ShortVariable.class; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.format.NcWriter#write(com.raytheon.uf.common + * .nc4.NcVariable, com.raytheon.uf.common.datastorage.records.IDataRecord) + */ + @Override + public void write(NcVariable var, int[] start, IDataRecord irecord) + throws NetcdfException { + ShortDataRecord record = (ShortDataRecord) irecord; + ShortVariable variable = (ShortVariable) var; + int[] shape = getShape(record); + variable.putVar(start, shape, record.getShortData()); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ThriftFormatter.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ThriftFormatter.java deleted file mode 100644 index e003bfa1c0..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/format/ThriftFormatter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * May 23, 2011 bclement Initial creation - * - */ -package com.raytheon.uf.edex.wcs.format; - -import java.io.OutputStream; - -import org.apache.commons.codec.binary.Base64; - -import com.raytheon.uf.common.serialization.SerializationUtil; -import com.raytheon.uf.edex.wcs.WcsCoverageThriftReponse; -import com.raytheon.uf.edex.wcs.reg.Coverage; - -/** - * - * @author bclement - * @version 1.0 - */ -public class ThriftFormatter implements WcsDataFormatter { - - protected String id = "application/x-thrift"; - - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wcs.format.WcsReturnFormat#getIdentifier() - */ - @Override - public String getIdentifier() { - return id; - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wcs.format.WcsReturnFormat#format(com.raytheon.uf - * .common.datastorage.records.IDataRecord, java.io.OutputStream, boolean) - */ - @Override - public void format(Coverage coverage, OutputStream out, boolean base64) - throws Exception { - WcsCoverageThriftReponse thriftable = new WcsCoverageThriftReponse(); - thriftable.setDataRecord(coverage.getDataRecord()); - thriftable.setCrsString(coverage.getCrs().getName().toString()); - thriftable.setTimeString(coverage.getTime()); - thriftable.setEnvelopeString(coverage.getEnvelope().toString()); - - byte[] data = SerializationUtil.transformToThrift(thriftable); - if (base64) { - Base64 b64 = new Base64(); - data = b64.encode(data); - } - out.write(data); - out.flush(); - } - -} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/CapabilitiesBuilder.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/CapabilitiesBuilder.java index 31ff73ee2f..c4da7f9c98 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/CapabilitiesBuilder.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/CapabilitiesBuilder.java @@ -130,6 +130,7 @@ public class CapabilitiesBuilder { to.setLowerCorner(Arrays.asList(bbox.getMinx(), bbox.getMiny())); to.setUpperCorner(Arrays.asList(bbox.getMaxx(), bbox.getMaxy())); to.setDimensions(BigInteger.valueOf(2)); + to.setCrs("urn:ogc:def:crs:OGC:2:84"); rval.add(owsFactory.createWGS84BoundingBox(to)); return rval; diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/DescCoverageBuilder.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/DescCoverageBuilder.java index e8f2423827..7a33677dcc 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/DescCoverageBuilder.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/DescCoverageBuilder.java @@ -65,6 +65,7 @@ import net.opengis.wcs.v_1_1_2.SpatialDomainType; import net.opengis.wcs.v_1_1_2.TimePeriodType; import net.opengis.wcs.v_1_1_2.TimeSequenceType; +import org.geotools.geometry.jts.ReferencedEnvelope; import org.jvnet.ogc.gml.v_3_1_1.jts.JTSToGML311CoordinateConverter; import org.jvnet.ogc.gml.v_3_1_1.jts.JTSToGML311LinearRingConverter; import org.jvnet.ogc.gml.v_3_1_1.jts.JTSToGML311PolygonConverter; @@ -72,8 +73,10 @@ import org.jvnet.ogc.gml.v_3_1_1.jts.JTSToGML311SRSReferenceGroupConverter; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.common.time.TimeRange; -import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; +import com.raytheon.uf.edex.ogc.common.spatial.CrsLookup; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; import com.raytheon.uf.edex.wcs.reg.CoverageDescription; import com.raytheon.uf.edex.wcs.reg.RangeAxis; import com.raytheon.uf.edex.wcs.reg.RangeField; @@ -111,16 +114,29 @@ public class DescCoverageBuilder { ringConv); } - protected List> getBboxes(List bboxes) { + protected List> getBboxes(List bboxes) { if (bboxes == null) { return null; } List> rval = new ArrayList>(bboxes.size()); - for (OgcBoundingBox from : bboxes) { + for (Composite3DBoundingBox from : bboxes) { BoundingBoxType to = owsFactory.createBoundingBoxType(); - to.setLowerCorner(Arrays.asList(from.getMinx(), from.getMiny())); - to.setUpperCorner(Arrays.asList(from.getMaxx(), from.getMaxy())); - to.setDimensions(BigInteger.valueOf(2)); + ReferencedEnvelope horiz = from.getHorizontal(); + List lc = new ArrayList(3); + List uc = new ArrayList(3); + lc.add(horiz.getMinX()); + lc.add(horiz.getMinY()); + uc.add(horiz.getMaxX()); + uc.add(horiz.getMaxY()); + if (from.hasVertical()) { + VerticalCoordinate vert = from.getVertical(); + lc.add(vert.getMin()); + uc.add(vert.getMax()); + } + to.setUpperCorner(uc); + to.setLowerCorner(lc); + to.setCrs(CrsLookup.createCrsURN(from)); + to.setDimensions(BigInteger.valueOf(lc.size())); rval.add(owsFactory.createBoundingBox(to)); } return rval; @@ -271,7 +287,8 @@ public class DescCoverageBuilder { return null; } FieldType rval = new FieldType(); - rval.setIdentifier(from.getIdentifier()); + + rval.setIdentifier(from.getIdentifier()); rval.setDefinition(getUnamed(from.getDefinition())); rval.setInterpolationMethods(getInterps(from.getDefaultInterpolation(), from.getAdditionalInterpolations())); diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OgcWcsProvider.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OgcWcsProvider.java index 36c2e3f0d9..d95186f15c 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OgcWcsProvider.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OgcWcsProvider.java @@ -32,12 +32,15 @@ package com.raytheon.uf.edex.wcs.provider; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.PrintStream; -import java.io.PrintWriter; +import java.io.Writer; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -45,10 +48,10 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import javax.servlet.http.HttpServletResponse; import javax.xml.bind.DatatypeConverter; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; @@ -69,6 +72,7 @@ import net.opengis.wcs.v_1_1_2.CoverageDescriptions; import net.opengis.wcs.v_1_1_2.CoveragesType; import net.opengis.wcs.v_1_1_2.DescribeCoverage; import net.opengis.wcs.v_1_1_2.DomainSubsetType; +import net.opengis.wcs.v_1_1_2.GetCapabilities; import net.opengis.wcs.v_1_1_2.GetCoverage; import net.opengis.wcs.v_1_1_2.GridCrsType; import net.opengis.wcs.v_1_1_2.ObjectFactory; @@ -78,33 +82,41 @@ import net.opengis.wcs.v_1_1_2.RangeSubsetType.FieldSubset; import net.opengis.wcs.v_1_1_2.TimePeriodType; import net.opengis.wcs.v_1_1_2.TimeSequenceType; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.apache.commons.codec.binary.Base64InputStream; +import org.apache.cxf.helpers.IOUtils; import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.springframework.context.ApplicationContext; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.common.time.TimeRange; -import com.raytheon.uf.edex.core.EDEXUtil; import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; +import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcNamespace; +import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; import com.raytheon.uf.edex.ogc.common.OgcPrefix; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcResponse.ErrorType; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; +import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.jaxb.OgcJaxbManager; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; import com.raytheon.uf.edex.ogc.common.spatial.CrsLookup; +import com.raytheon.uf.edex.wcs.CoverageStoreEndpoint; +import com.raytheon.uf.edex.wcs.CoveragesHolder; import com.raytheon.uf.edex.wcs.WcsException; import com.raytheon.uf.edex.wcs.WcsException.Code; import com.raytheon.uf.edex.wcs.WcsProvider; -import com.raytheon.uf.edex.wcs.format.WcsDataFormatter; +import com.raytheon.uf.edex.wcs.format.IWcsDataFormatter; import com.raytheon.uf.edex.wcs.reg.Coverage; import com.raytheon.uf.edex.wcs.reg.CoverageDescription; import com.raytheon.uf.edex.wcs.reg.RangeAxis; import com.raytheon.uf.edex.wcs.reg.RangeField; import com.raytheon.uf.edex.wcs.reg.RangeField.InterpolationType; -import com.raytheon.uf.edex.wcs.reg.WcsSource; +import com.raytheon.uf.edex.wcs.reg.IWcsSource; import com.raytheon.uf.edex.wcs.reg.WcsSourceAccessor; import com.raytheon.uf.edex.wcs.request.DescCoverageRequest; import com.raytheon.uf.edex.wcs.request.GetCapRequest; @@ -129,500 +141,703 @@ import com.vividsolutions.jts.geom.Envelope; */ public class OgcWcsProvider implements WcsProvider { - public enum WcsOpType { - GetCapabilities, GetCoverage, DescribeCoverage - } + public enum WcsOpType { + GetCapabilities, GetCoverage, DescribeCoverage + } - protected static final String version = "1.1.2"; + protected static final String version = "1.1.2"; - protected static final String svcTitle = "EDEX Coverage Server"; + protected static final String svcTitle = "EDEX Coverage Server"; - protected OgcJaxbManager jaxbManager; + protected final OgcJaxbManager jaxbManager; - protected String COVERAGE_ID = "cid:Coverage-"; + protected final String COVERAGE_ID = "cid:Coverage-"; - protected Log log = LogFactory.getLog(this.getClass()); + protected final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected DescCoverageBuilder descCoverage; + private volatile DescCoverageBuilder _descCoverage; - protected CapabilitiesBuilder capbuilder; + private volatile CapabilitiesBuilder _capbuilder; - protected WcsSourceAccessor reg = new WcsSourceAccessor(); + protected boolean base64 = true; - protected boolean base64 = true; + protected final net.opengis.ows.v_1_1_0.ObjectFactory owsFactory = new net.opengis.ows.v_1_1_0.ObjectFactory(); - protected net.opengis.ows.v_1_1_0.ObjectFactory owsFactory = new net.opengis.ows.v_1_1_0.ObjectFactory(); + protected final ObjectFactory wcsFactory = new ObjectFactory(); - protected ObjectFactory wcsFactory = new ObjectFactory(); + protected static final Map NS_MAP = new ConcurrentHashMap(); - protected static final Map NS_MAP = new ConcurrentHashMap(); + private int restPort = 8085; - protected static final Map formatMap = new HashMap(); + private String covStorePath = "coverage"; - static { - NS_MAP.put(OgcNamespace.EDEX, OgcPrefix.EDEX); - NS_MAP.put(OgcNamespace.GML, OgcPrefix.GML); - NS_MAP.put(OgcNamespace.OGC, OgcPrefix.OGC); - NS_MAP.put(OgcNamespace.OWS110, OgcPrefix.OWS); - NS_MAP.put(OgcNamespace.WFS, OgcPrefix.WFS); - NS_MAP.put(OgcNamespace.XSI, OgcPrefix.XSI); - NS_MAP.put(OgcNamespace.WCS112, OgcPrefix.WCS); - NS_MAP.put(OgcNamespace.XLINK, OgcPrefix.XLINK); - } + static { + NS_MAP.put(OgcNamespace.EDEX, OgcPrefix.EDEX); + NS_MAP.put(OgcNamespace.GML, OgcPrefix.GML); + NS_MAP.put(OgcNamespace.OGC, OgcPrefix.OGC); + NS_MAP.put(OgcNamespace.OWS110, OgcPrefix.OWS); + NS_MAP.put(OgcNamespace.WFS, OgcPrefix.WFS); + NS_MAP.put(OgcNamespace.XSI, OgcPrefix.XSI); + NS_MAP.put(OgcNamespace.WCS112, OgcPrefix.WCS); + NS_MAP.put(OgcNamespace.XLINK, OgcPrefix.XLINK); + } - public OgcWcsProvider() throws JAXBException { - this.jaxbManager = new OgcJaxbManager(new Class[] { - ObjectFactory.class, - net.opengis.ows.v_1_1_0.ObjectFactory.class, - net.opengis.gml.v_3_1_1.ObjectFactory.class, - net.opengis.wms.v_1_3_0.ObjectFactory.class }); - jaxbManager.setPrefixMap(NS_MAP); - ApplicationContext ctx = EDEXUtil.getSpringContext(); - String[] beans = ctx.getBeanNamesForType(WcsDataFormatter.class); - for (String bean : beans) { - WcsDataFormatter df = (WcsDataFormatter) ctx.getBean(bean); - formatMap.put(df.getIdentifier(), df); - } - List formats = new ArrayList(formatMap.keySet()); - this.descCoverage = new DescCoverageBuilder(formats); - this.capbuilder = new CapabilitiesBuilder(formats); - } + public OgcWcsProvider(OgcJaxbManager manager) throws JAXBException { + this.jaxbManager = manager; + jaxbManager.setPrefixMap(NS_MAP); + } - @Override - public OgcResponse describeCoverageType( - OgcServiceInfo serviceinfo, DescCoverageRequest request) { - CoverageDescriptions rval = new CoverageDescriptions(); - String[] ids = request.getIdentifiers(); - List descs = null; - if (ids == null) { - return getError(new WcsException(Code.MissingParameterValue), - request.getExceptionFormat()); - } - descs = new ArrayList(ids.length); - for (String id : ids) { - try { - descs.add(descCov(id)); - } catch (WcsException e) { - return getError(e, request.getExceptionFormat()); - } - } - rval.setCoverageDescription(descs); - return marshalResponse(rval); - } + protected DescCoverageBuilder getCoverageBuilder() { + if (_descCoverage == null) { + synchronized (wcsFactory) { + if (_descCoverage == null) { + List formats = WcsSourceAccessor.getFormats(); + if (formats.isEmpty()) { + // don't remember list if empty, may not be initialized + // yet + return new DescCoverageBuilder(formats); + } else { + _descCoverage = new DescCoverageBuilder(formats); + } + } + } + } + return _descCoverage; + } - protected CoverageDescriptionType descCov(String id) throws WcsException { - WcsSource source = reg.getSource(id); - if (source == null) { - throw new WcsException(Code.LayerNotDefined); - } - CoverageDescription cd = source.describeCoverage(id); - return descCoverage.getCoverageDescriptionType(cd); - } + protected CapabilitiesBuilder getCapBuilder() { + if (_capbuilder == null) { + synchronized (wcsFactory) { + if (_capbuilder == null) { + List formats = WcsSourceAccessor.getFormats(); + if (formats.isEmpty()) { + // don't remember list if empty, may not be initialized + // yet + return new CapabilitiesBuilder(formats); + } else { + _capbuilder = new CapabilitiesBuilder(formats); + } + } + } + } + return _capbuilder; + } - @Override - public OgcResponse getCapabilities(OgcServiceInfo serviceinfo, - GetCapRequest request) { - Capabilities capabilities = capbuilder.getCapabilities(serviceinfo, - reg.getCoverages()); - return marshalResponse(capabilities); - } + @Override + public OgcResponse describeCoverageType( + OgcServiceInfo serviceinfo, DescCoverageRequest request) { + CoverageDescriptions rval; + try { + rval = describeCoverage(serviceinfo, request); + return marshalResponse(rval); + } catch (WcsException e) { + return getError(e, request.getExceptionFormat()); + } + } - @Override - public void getCoverage(OgcServiceInfo serviceinfo, - GetCoverageRequest request, HttpServletResponse httpResp) { - try { - String format = request.getFormat(); - WcsDataFormatter formatter = formatMap.get(format); - if (formatter == null) { - throw new WcsException(Code.InvalidFormat); - } - String id = request.getIdentifier(); - WcsSource source = reg.getSource(id); - if (source == null) { - throw new WcsException(Code.LayerNotDefined); - } - OgcBoundingBox bbox = request.getBbox(); - CoordinateReferenceSystem crs = getCrs(bbox); - Envelope env = getEnvelope(bbox); - Coverage coverage = source.getCoverage(id, - request.getTimeSequence(), crs, env, request.getFields()); - CoveragesType coveragesType = getCoverageOgcResponse(serviceinfo, - id); + public CoverageDescriptions describeCoverage(EndpointInfo info, + DescCoverageRequest request) throws WcsException { + return describeCoverage(getServiceInfo(info), request); + } - try { - OutputStream out = httpResp.getOutputStream(); - if (request.isDefacto()) { - httpResp.setContentType(formatter.getIdentifier()); - formatter.format(coverage, out, false); - out.flush(); - out.close(); - return; - } - long timestamp = System.currentTimeMillis(); - String part = "_Part_" + timestamp; - httpResp.setContentType("multipart/related;boundary=" + part); + public CoverageDescriptions describeCoverage( + OgcServiceInfo serviceinfo, DescCoverageRequest request) + throws WcsException { - PrintStream stream = new PrintStream(out); - String cid = getCoverageId(id); + CoverageDescriptions rval = new CoverageDescriptions(); + String[] ids = request.getIdentifiers(); + List descs = null; + if (ids == null) { + throw new WcsException(Code.MissingParameterValue); + } + descs = new ArrayList(ids.length); + for (String id : ids) { + descs.add(descCov(id)); + } + rval.setCoverageDescription(descs); + return rval; + } - stream.println("--" + part); - stream.println("Content-Type: text/xml"); - stream.println("Content-ID: "); - stream.println(); - stream.println(jaxbManager.marshal(wcsFactory - .createCoverages(coveragesType))); - stream.println("--" + part); - stream.println("Content-Type: " + formatter.getIdentifier()); - if (base64) { - stream.println("Content-Transfer-Encoding: base64"); - } - stream.println("Content-ID: <" + cid + ">"); - stream.println(); - stream.flush(); - formatter.format(coverage, out, base64); - out.flush(); - out.close(); - } catch (Exception e) { - log.error("Problem formatting coverage", e); - throw new WcsException(Code.InternalServerError); - } - } catch (WcsException e) { - sendTextResponse(httpResp, - getError(e, request.getExceptionFormat())); - } - } + protected CoverageDescriptionType descCov(String id) throws WcsException { + IWcsSource source = WcsSourceAccessor.getSource(id); + if (source == null) { + throw new WcsException(Code.InvalidParameterValue, + "Coverage ID not found"); + } + CoverageDescription cd = source.describeCoverage(id); + return getCoverageBuilder().getCoverageDescriptionType(cd); + } - protected void sendTextResponse(HttpServletResponse httpRes, - OgcResponse response) { - String mimetype = response.getMimetype(); - httpRes.setContentType(mimetype); - try { - PrintWriter writer = httpRes.getWriter(); - writer.write(response.getBody().toString()); - writer.close(); - } catch (IOException e) { - log.error("Problem sending response", e); - } - } + @Override + public OgcResponse getCapabilities(OgcServiceInfo serviceinfo, + GetCapRequest request) { + Capabilities capabilities = getCapBuilder().getCapabilities( + serviceinfo, WcsSourceAccessor.getCoverages(true)); + return marshalResponse(capabilities); + } - /** - * @param bbox - * @return - * @throws WcsException - */ - protected Envelope getEnvelope(OgcBoundingBox bbox) throws WcsException { - if (bbox == null) { - throw new WcsException(Code.MissingParameterValue, - "Missing bounding box"); - } - return new Envelope(bbox.getMinx(), bbox.getMaxx(), bbox.getMiny(), - bbox.getMaxy()); - } + public Capabilities getCapabilities(EndpointInfo info, + GetCapabilities request) { + return getCapBuilder().getCapabilities(getServiceInfo(info), + WcsSourceAccessor.getCoverages(true)); + } - /** - * @param bbox - * @return - * @throws WcsException - */ - protected CoordinateReferenceSystem getCrs(OgcBoundingBox bbox) - throws WcsException { - if (bbox != null) { - try { - return CrsLookup.lookup(bbox.getCrs()); - } catch (Exception e) { - log.error("Unable to decode crs: " + bbox.getCrs(), e); - } - } - throw new WcsException(Code.MissingParameterValue, - "Missing bounding box."); - } + private OgcServiceInfo getServiceInfo(EndpointInfo info) { + int port = info.getPort(); + String base = "http://" + info.getHost(); + if (port != 80) { + base += ":" + port; + } + base += info.getPath(); + OgcServiceInfo rval = new OgcServiceInfo(base); + rval.addOperationInfo(getOp(base, base, WcsOpType.GetCapabilities, info)); + rval.addOperationInfo(getOp(base, base, WcsOpType.DescribeCoverage, + info)); + rval.addOperationInfo(getOp(base, base, WcsOpType.GetCoverage, info)); + return rval; + } - protected String getCoverageId(String identifier) { - return COVERAGE_ID + identifier; - } + protected OgcOperationInfo getOp(String get, String post, + WcsOpType type, EndpointInfo info) { + OgcOperationInfo rval = new OgcOperationInfo(type); + if (!info.isPostOnly()) { + rval.setHttpGetRes(get); + } + rval.setHttpPostRes(post); + rval.addVersion(version); + rval.addAcceptVersions(version); + rval.addService("WCS"); + rval.addFormat("text/xml"); + rval.setPostEncoding(info.getEncoding()); + return rval; + } - protected CoveragesType getCoverageOgcResponse( - OgcServiceInfo serviceinfo, String identifier) { + public CoveragesHolder getCoverage(EndpointInfo info, + GetCoverageRequest request) throws WcsException { + String format = request.getFormat(); + // try fast lookup first + Map formatMap = WcsSourceAccessor + .getFormatMap(); + IWcsDataFormatter formatter = formatMap.get(format); + if (formatter == null) { + // check to see if any formatter handles it + for (Entry e : formatMap.entrySet()) { + if (e.getValue().matchesFormat(format)) { + formatter = e.getValue(); + break; + } + } + if (formatter == null) { + // no match found + throw new WcsException(Code.InvalidFormat); + } - CoveragesType coverages = new CoveragesType(); - List coverageList = new ArrayList(); - ReferenceGroupType rgt = new ReferenceGroupType(); + } + String id = request.getIdentifier(); + Coverage coverage = requestCoverage(request); + CoveragesHolder holder = new CoveragesHolder(); + holder.setContentType(format); + Map data = new HashMap(); + String href; + if (request.isStore()) { + try { + File f = formatter.store(coverage); + href = String.format("http://%s:%d/%s?%s=%s", info.getHost(), + restPort, covStorePath, + CoverageStoreEndpoint.ID_HEADER, f.getName()); + } catch (Exception e) { + log.error("Problem formatting coverage", e); + throw new WcsException(Code.InternalServerError); + } + } else { + href = getCoverageId(id); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + InputStream in = null; + try { + in = formatter.format(coverage); + IOUtils.copy(in, out); + out.flush(); + } catch (Exception e) { + log.error("Problem formatting coverage", e); + throw new WcsException(Code.InternalServerError); + } finally { + close(in, out); + } + data.put(href, out.toByteArray()); + } + CoveragesType rval = getCoverageOgcResponse(id, href); + holder.setMetadata(rval); + holder.setData(data); + return holder; + } - // Abstract - // rgt.setAbstract(WcsJaxbUtils.getAsLangString("Abstract for " - // + request.getIdentifier())); - // Title - // rgt.setTitle(WcsJaxbUtils.getAsLangString(request.getIdentifier())); + private Coverage requestCoverage(GetCoverageRequest request) + throws WcsException { + String id = request.getIdentifier(); + IWcsSource source = WcsSourceAccessor.getSource(id); + if (source == null) { + throw new WcsException(Code.InvalidParameterValue, + "Coverage ID not found"); + } + Composite3DBoundingBox bbox = request.getBbox(); + return source.getCoverage(id, request.getTimeSequence(), bbox, + request.getFields()); + } - // Identifier - CodeType ident = new CodeType(); - ident.setValue(identifier); - rgt.setIdentifier(ident); + private void close(InputStream in, OutputStream out) { + try { + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } catch (Throwable t) { + log.error("Unable to close streams", t); + } + } - // Data reference - String cid = getCoverageId(identifier); - ReferenceType rt = new ReferenceType(); - rt.setHref(cid); + @Override + public void getCoverage(OgcServiceInfo serviceinfo, + GetCoverageRequest request, IOgcHttpResponse httpResp) { + try { + String format = request.getFormat(); + IWcsDataFormatter formatter = WcsSourceAccessor.getFormatMap().get( + format); + if (formatter == null) { + throw new WcsException(Code.InvalidFormat); + } + String id = request.getIdentifier(); + IWcsSource source = WcsSourceAccessor.getSource(id); + if (source == null) { + throw new WcsException(Code.LayerNotDefined); + } + Composite3DBoundingBox bbox = request.getBbox(); + Coverage coverage = source.getCoverage(id, + request.getTimeSequence(), bbox, request.getFields()); + CoveragesType coveragesType = getCoverageOgcResponse(id, + getCoverageId(id)); - List> refTypeList = new ArrayList>(); - refTypeList.add(owsFactory.createReference(rt)); - rgt.setAbstractReferenceBase(refTypeList); - coverageList.add(rgt); - coverages.setCoverage(coverageList); + try { + // FIXME this code block makes my eyes bleed, needs to be + // refactored + OutputStream out = httpResp.getOutputStream(); + if (request.isDefacto()) { + httpResp.setContentType(formatter.getIdentifier()); + InputStream in = formatter.format(coverage); + if (base64) { + in = new Base64InputStream(in, true); + } + IOUtils.copy(in, out); + out.flush(); + out.close(); + in.close(); + return; + } + long timestamp = System.currentTimeMillis(); + String part = "_Part_" + timestamp; + httpResp.setContentType("multipart/related;boundary=" + part); - return coverages; + PrintStream stream = new PrintStream(out); + String cid = getCoverageId(id); - } + stream.println("--" + part); + stream.println("Content-Type: text/xml"); + stream.println("Content-ID: "); + stream.println(); + stream.println(jaxbManager.marshal(wcsFactory + .createCoverages(coveragesType))); + stream.println("--" + part); + stream.println("Content-Type: " + formatter.getIdentifier()); + if (base64) { + stream.println("Content-Transfer-Encoding: base64"); + } + stream.println("Content-ID: <" + cid + ">"); + stream.println(); + stream.flush(); + InputStream in = formatter.format(coverage); + if (base64) { + in = new Base64InputStream(in, true); + } + IOUtils.copy(in, out); + out.flush(); + out.close(); + in.close(); + } catch (Exception e) { + log.error("Problem formatting coverage", e); + throw new WcsException(Code.InternalServerError); + } + } catch (WcsException e) { + sendTextResponse(httpResp, + getError(e, request.getExceptionFormat())); + } + } - @Override - public OgcResponse getError(WcsException e, String exceptionFormat) { + protected void sendTextResponse(IOgcHttpResponse httpRes, + OgcResponse response) { + MimeType mimetype = response.getMimetype(); + httpRes.setContentType(mimetype.toString()); + try { + Writer writer = new OutputStreamWriter(httpRes.getOutputStream()); + writer.write(response.getBody().toString()); + writer.close(); + } catch (IOException e) { + log.error("Problem sending response", e); + } + } - net.opengis.ows.v_1_1_0.ExceptionType et = new ExceptionType(); - et.setExceptionCode(e.getCode().toString()); - et.setExceptionText(getAsList(e.getMessage())); - net.opengis.ows.v_1_1_0.ExceptionReport report = new ExceptionReport(); - report.setException(getAsList(et)); - String rval = ""; - String mimeType = OgcResponse.TEXT_XML_MIME; - if (exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_XML_MIME)) { - try { - rval = jaxbManager.marshal(report); - mimeType = OgcResponse.TEXT_XML_MIME; - } catch (JAXBException e1) { - log.error("Unable to marshal WCS response", e1); - rval = ""; - rval += ""; - rval += "" + e.getMessage() - + ""; - rval += ""; - mimeType = OgcResponse.TEXT_XML_MIME; - } - } else if (exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_HTML_MIME)) { - rval = ""; - rval += "
An error occurred performing the request:
"; - rval += "
Error Code: " + e.getCode().toString(); - rval += "
Message: " + e.getMessage() + ""; - mimeType = OgcResponse.TEXT_HTML_MIME; - } + /** + * @param bbox + * @return + * @throws WcsException + */ + protected Envelope getEnvelope(OgcBoundingBox bbox) throws WcsException { + if (bbox == null) { + throw new WcsException(Code.MissingParameterValue, + "Missing bounding box"); + } + return new Envelope(bbox.getMinx(), bbox.getMaxx(), bbox.getMiny(), + bbox.getMaxy()); + } - OgcResponse resp = new OgcResponse(rval, mimeType, TYPE.TEXT); - switch (e.getCode()) { - case InternalServerError: - resp.setError(ErrorType.INT_ERR); - break; - case OperationNotSupported: - resp.setError(ErrorType.NOT_IMPLEMENTED); - break; - default: - resp.setError(ErrorType.BAD_REQ); - } - return resp; - } + /** + * @param bbox + * @return + * @throws WcsException + */ + protected CoordinateReferenceSystem getCrs(OgcBoundingBox bbox) + throws WcsException { + if (bbox != null) { + try { + return CrsLookup.lookup(bbox.getCrs()); + } catch (Exception e) { + log.error("Unable to decode crs: " + bbox.getCrs(), e); + } + } + throw new WcsException(Code.MissingParameterValue, + "Missing bounding box."); + } - protected net.opengis.wms.v_1_3_0.Exception getExceptionInfo() { - net.opengis.wms.v_1_3_0.Exception rval = new net.opengis.wms.v_1_3_0.Exception(); - rval.setFormat(getAsList("XML")); - return rval; - } + protected String getCoverageId(String identifier) { + return COVERAGE_ID + identifier; + } - @Override - public WcsRequest getRequest(InputStream in) { - Object obj; - WcsRequest rval; - try { - String xml = getXml(in); - obj = jaxbManager.unmarshal(xml); - rval = getType(obj); - } catch (Throwable e) { - log.error("Unable to decode request", e); - rval = new WcsRequest(Type.ERROR); - } - if (rval.getType().equals(Type.ERROR)) { - OgcResponse error = getError(new WcsException(Code.InvalidRequest, - "Unable to decode request"), OgcResponse.TEXT_XML_MIME); - rval.setRequest(error); - } - return rval; - } + protected CoveragesType getCoverageOgcResponse(String identifier, + String href) { - public List getAsList(T... args) { - List rval = new LinkedList(); - for (T t : args) { - rval.add(t); - } - return rval; - } + CoveragesType coverages = new CoveragesType(); + List coverageList = new ArrayList(); + ReferenceGroupType rgt = new ReferenceGroupType(); - protected WcsRequest getType(Object obj) { - WcsRequest rval; - if (obj instanceof GetCapabilitiesType) { - rval = new GetCapRequest(); - } else if (obj instanceof GetCoverage) { - rval = unwrap((GetCoverage) obj); - } else if (obj instanceof DescribeCoverage) { - DescribeCoverage req = (DescribeCoverage) obj; - List ids = req.getIdentifier(); - DescCoverageRequest dcr = new DescCoverageRequest(); - dcr.setIdentifiers(ids.toArray(new String[ids.size()])); - rval = dcr; - } else { - rval = new WcsRequest(Type.ERROR); - } - return rval; - } + // Abstract + // rgt.setAbstract(WcsJaxbUtils.getAsLangString("Abstract for " + // + request.getIdentifier())); + // Title + // rgt.setTitle(WcsJaxbUtils.getAsLangString(request.getIdentifier())); - /** - * @param obj - * @return - */ - protected WcsRequest unwrap(GetCoverage req) { - GetCoverageRequest rval = new GetCoverageRequest(); - DomainSubsetType ds = req.getDomainSubset(); - rval.setTimeSequence(getTime(ds.getTemporalSubset())); - BoundingBoxType bbox = (BoundingBoxType) ds.getBoundingBox().getValue(); - rval.setBbox(transform(bbox)); - rval.setIdentifier(req.getIdentifier().getValue()); - OutputType output = req.getOutput(); - rval.setFormat(output.getFormat()); - GridCrsType gridCRS = output.getGridCRS(); - if (gridCRS != null) { - rval.setGridBaseCrs(gridCRS.getGridBaseCRS()); - rval.setGridOffsets(gridCRS.getGridOffsets()); - rval.setGridOrigin(gridCRS.getGridOrigin()); - rval.setGridType(gridCRS.getGridType()); - } - rval.setFields(transform(req.getRangeSubset())); - return rval; - } + // Identifier + CodeType ident = new CodeType(); + ident.setValue(identifier); + rgt.setIdentifier(ident); - protected List transform(RangeSubsetType subset) { - if (subset == null) { - return null; - } - List fields = subset.getFieldSubset(); - if (fields == null || fields.isEmpty()) { - return null; - } - List rval = new ArrayList(fields.size()); - for (FieldSubset fs : fields) { - rval.add(transform(fs)); - } - return rval; - } + // Data reference + ReferenceType rt = new ReferenceType(); + rt.setHref(href); - protected RangeField transform(FieldSubset fs) { - String id = fs.getIdentifier().getValue(); + List> refTypeList = new ArrayList>(); + refTypeList.add(owsFactory.createReference(rt)); + rgt.setAbstractReferenceBase(refTypeList); + coverageList.add(rgt); + coverages.setCoverage(coverageList); - RangeField rval = new RangeField(id, null); - String interp = fs.getInterpolationType(); - if (interp != null) { - rval.setDefaultInterpolation(InterpolationType.valueOf(interp)); - } - rval.setAxis(transform(fs.getAxisSubset())); - return rval; - } + return coverages; - /** - * @param axisSubset - * @return - */ - protected List transform(List axisSubset) { - if (axisSubset == null || axisSubset.isEmpty()) { - return null; - } - List rval = new ArrayList(axisSubset.size()); - for (AxisSubset as : axisSubset) { - Set keys = new HashSet(as.getKey()); - rval.add(new RangeAxis(as.getIdentifier(), keys)); - } - return rval; - } + } - protected OgcBoundingBox transform(BoundingBoxType bbox) { - OgcBoundingBox rval = new OgcBoundingBox(); - rval.setCrs(bbox.getCrs()); - List lower = bbox.getLowerCorner(); - List upper = bbox.getUpperCorner(); - rval.setMaxx(upper.get(0)); - rval.setMaxy(upper.get(1)); - rval.setMinx(lower.get(0)); - rval.setMiny(lower.get(1)); - return rval; - } + @Override + public OgcResponse getError(WcsException e, MimeType exceptionFormat) { - protected DataTime getTime(TimeSequenceType tst) { - if (tst == null) { - return null; - } - List times = tst.getTimePositionOrTimePeriod(); - if (times == null || times.isEmpty()) { - return null; - } - if (times.size() != 1) { - log.warn("multiple times not supported in request, taking first"); - } - Object timeObj = times.get(0); - return parseTime(timeObj); - } + net.opengis.ows.v_1_1_0.ExceptionType et = new ExceptionType(); + et.setExceptionCode(e.getCode().toString()); + et.setExceptionText(getAsList(e.getMessage())); + net.opengis.ows.v_1_1_0.ExceptionReport report = new ExceptionReport(); + report.setException(getAsList(et)); + String rval = ""; + MimeType mimeType = OgcResponse.TEXT_XML_MIME; + if (exceptionFormat.equalsIgnoreParams(OgcResponse.TEXT_XML_MIME)) { + try { + rval = jaxbManager.marshal(report); + mimeType = OgcResponse.TEXT_XML_MIME; + } catch (JAXBException e1) { + log.error("Unable to marshal WCS response", e1); + rval = ""; + rval += ""; + rval += "" + e.getMessage() + + ""; + rval += ""; + mimeType = OgcResponse.TEXT_XML_MIME; + } + } else if (exceptionFormat + .equalsIgnoreParams(OgcResponse.TEXT_HTML_MIME)) { + rval = ""; + rval += "
An error occurred performing the request:
"; + rval += "
Error Code: " + e.getCode().toString(); + rval += "
Message: " + e.getMessage() + ""; + mimeType = OgcResponse.TEXT_HTML_MIME; + } - protected DataTime parseTime(Object timeObj) { - if (timeObj instanceof TimePositionType) { - TimePositionType pos = (TimePositionType) timeObj; - return new DataTime(getTime(pos)); - } else { - TimePeriodType period = (TimePeriodType) timeObj; - Date start = getTime(period.getBeginPosition()); - Date end = getTime(period.getEndPosition()); - TimeRange range = new TimeRange(start, end); - DataTime rval = new DataTime(start); - rval.setValidPeriod(range); - return rval; - } - } + OgcResponse resp = new OgcResponse(rval, mimeType, TYPE.TEXT); + switch (e.getCode()) { + case InternalServerError: + resp.setError(ErrorType.INT_ERR); + break; + case OperationNotSupported: + resp.setError(ErrorType.NOT_IMPLEMENTED); + break; + default: + resp.setError(ErrorType.BAD_REQ); + } + return resp; + } - protected Date getTime(TimePositionType pos) { - List values = pos.getValue(); - if (values == null || values.isEmpty()) { - log.error("unable to parse time"); - return null; - } - return DatatypeConverter.parseDateTime(values.get(0)).getTime(); - } + protected net.opengis.wms.v_1_3_0.Exception getExceptionInfo() { + net.opengis.wms.v_1_3_0.Exception rval = new net.opengis.wms.v_1_3_0.Exception(); + rval.setFormat(getAsList("XML")); + return rval; + } - protected String getXml(InputStream in) throws IOException { + @Override + public WcsRequest getRequest(InputStream in) { + Object obj; + WcsRequest rval; + try { + String xml = getXml(in); + obj = jaxbManager.unmarshal(xml); + rval = getType(obj); + } catch (Throwable e) { + log.error("Unable to decode request", e); + rval = new WcsRequest(Type.ERROR); + } + if (rval.getType().equals(Type.ERROR)) { + OgcResponse error = getError(new WcsException(Code.InvalidRequest, + "Unable to decode request"), OgcResponse.TEXT_XML_MIME); + rval.setRequest(error); + } + return rval; + } - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - String rval = ""; - String line = ""; - while ((line = reader.readLine()) != null) { - rval += line + "\n"; - } - return rval; - } + public List getAsList(T... args) { + List rval = new LinkedList(); + for (T t : args) { + rval.add(t); + } + return rval; + } - protected OgcResponse marshalResponse(Object jaxbobject) { - OgcResponse rval; - try { - String xml = jaxbManager.marshal(jaxbobject); - rval = new OgcResponse(xml, "text/xml", TYPE.TEXT); - } catch (JAXBException e) { - log.error("Unable to marshal WCS response", e); - // TODO: real error code - rval = getError(new WcsException(Code.OperationNotSupported), - OgcResponse.TEXT_XML_MIME); - } - return rval; - } + protected WcsRequest getType(Object obj) { + WcsRequest rval; + if (obj instanceof GetCapabilitiesType) { + rval = new GetCapRequest(); + } else if (obj instanceof GetCoverage) { + rval = unwrap((GetCoverage) obj); + } else if (obj instanceof DescribeCoverage) { + DescribeCoverage req = (DescribeCoverage) obj; + List ids = req.getIdentifier(); + DescCoverageRequest dcr = new DescCoverageRequest(); + dcr.setIdentifiers(ids.toArray(new String[ids.size()])); + rval = dcr; + } else { + rval = new WcsRequest(Type.ERROR); + } + return rval; + } - public boolean isBase64() { - return base64; - } + /** + * @param obj + * @return + */ + protected WcsRequest unwrap(GetCoverage req) { + GetCoverageRequest rval = new GetCoverageRequest(); + DomainSubsetType ds = req.getDomainSubset(); + rval.setTimeSequence(getTime(ds.getTemporalSubset())); + BoundingBoxType bbox = (BoundingBoxType) ds.getBoundingBox().getValue(); + try { + rval.setBbox(bbox); + } catch (OgcException e) { + return new WcsRequest(Type.ERROR); + } + rval.setIdentifier(req.getIdentifier().getValue()); + OutputType output = req.getOutput(); + rval.setFormat(output.getFormat()); + GridCrsType gridCRS = output.getGridCRS(); + if (gridCRS != null) { + rval.setGridBaseCrs(gridCRS.getGridBaseCRS()); + rval.setGridOffsets(gridCRS.getGridOffsets()); + rval.setGridOrigin(gridCRS.getGridOrigin()); + rval.setGridType(gridCRS.getGridType()); + } + rval.setFields(transform(req.getRangeSubset())); + return rval; + } - public void setBase64(boolean base64) { - this.base64 = base64; - } + protected List transform(RangeSubsetType subset) { + if (subset == null) { + return null; + } + List fields = subset.getFieldSubset(); + if (fields == null || fields.isEmpty()) { + return null; + } + List rval = new ArrayList(fields.size()); + for (FieldSubset fs : fields) { + rval.add(transform(fs)); + } + return rval; + } + + protected RangeField transform(FieldSubset fs) { + String id = fs.getIdentifier().getValue(); + + RangeField rval = new RangeField(id, null); + String interp = fs.getInterpolationType(); + if (interp != null) { + rval.setDefaultInterpolation(InterpolationType.valueOf(interp)); + } + rval.setAxis(transform(fs.getAxisSubset())); + return rval; + } + + /** + * @param axisSubset + * @return + */ + protected List transform(List axisSubset) { + if (axisSubset == null || axisSubset.isEmpty()) { + return null; + } + List rval = new ArrayList(axisSubset.size()); + for (AxisSubset as : axisSubset) { + Set keys = new HashSet(as.getKey()); + rval.add(new RangeAxis(as.getIdentifier(), keys)); + } + return rval; + } + + protected OgcBoundingBox transform(BoundingBoxType bbox) { + OgcBoundingBox rval = new OgcBoundingBox(); + rval.setCrs(bbox.getCrs()); + List lower = bbox.getLowerCorner(); + List upper = bbox.getUpperCorner(); + rval.setMaxx(upper.get(0)); + rval.setMaxy(upper.get(1)); + rval.setMinx(lower.get(0)); + rval.setMiny(lower.get(1)); + return rval; + } + + protected DataTime getTime(TimeSequenceType tst) { + if (tst == null) { + return null; + } + List times = tst.getTimePositionOrTimePeriod(); + if (times == null || times.isEmpty()) { + return null; + } + if (times.size() != 1) { + log.warn("multiple times not supported in request, taking first"); + } + Object timeObj = times.get(0); + return parseTime(timeObj); + } + + protected DataTime parseTime(Object timeObj) { + if (timeObj instanceof TimePositionType) { + TimePositionType pos = (TimePositionType) timeObj; + return new DataTime(getTime(pos)); + } else { + TimePeriodType period = (TimePeriodType) timeObj; + Date start = getTime(period.getBeginPosition()); + Date end = getTime(period.getEndPosition()); + TimeRange range = new TimeRange(start, end); + DataTime rval = new DataTime(start); + rval.setValidPeriod(range); + return rval; + } + } + + protected Date getTime(TimePositionType pos) { + List values = pos.getValue(); + if (values == null || values.isEmpty()) { + log.error("unable to parse time"); + return null; + } + return DatatypeConverter.parseDateTime(values.get(0)).getTime(); + } + + protected String getXml(InputStream in) throws IOException { + + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String rval = ""; + String line = ""; + while ((line = reader.readLine()) != null) { + rval += line + "\n"; + } + return rval; + } + + protected OgcResponse marshalResponse(Object jaxbobject) { + OgcResponse rval; + try { + String xml = jaxbManager.marshal(jaxbobject); + rval = new OgcResponse(xml, OgcResponse.TEXT_XML_MIME, TYPE.TEXT); + } catch (JAXBException e) { + log.error("Unable to marshal WCS response", e); + // TODO: real error code + rval = getError(new WcsException(Code.OperationNotSupported), + OgcResponse.TEXT_XML_MIME); + } + return rval; + } + + public boolean isBase64() { + return base64; + } + + public void setBase64(boolean base64) { + this.base64 = base64; + } + + /** + * @return the restPort + */ + public int getRestPort() { + return restPort; + } + + /** + * @param restPort + * the restPort to set + */ + public void setRestPort(int restPort) { + this.restPort = restPort; + } + + /** + * @return the covStorePath + */ + public String getCovStorePath() { + return covStorePath; + } + + /** + * @param covStorePath + * the covStorePath to set + */ + public void setCovStorePath(String covStorePath) { + this.covStorePath = covStorePath; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OperationsDescriber.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OperationsDescriber.java index 68d9c26e7f..3258bc31bd 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OperationsDescriber.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/OperationsDescriber.java @@ -32,21 +32,13 @@ package com.raytheon.uf.edex.wcs.provider; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.LinkedList; import java.util.List; -import javax.xml.bind.JAXBElement; - -import net.opengis.ows.v_1_1_0.AllowedValues; -import net.opengis.ows.v_1_1_0.DCP; import net.opengis.ows.v_1_1_0.DomainType; -import net.opengis.ows.v_1_1_0.HTTP; import net.opengis.ows.v_1_1_0.ObjectFactory; -import net.opengis.ows.v_1_1_0.Operation; -import net.opengis.ows.v_1_1_0.OperationsMetadata; -import net.opengis.ows.v_1_1_0.RequestMethodType; +import com.raytheon.uf.edex.ogc.common.AbstractOpDescriber; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.wcs.provider.OgcWcsProvider.WcsOpType; @@ -56,131 +48,91 @@ import com.raytheon.uf.edex.wcs.provider.OgcWcsProvider.WcsOpType; * @author bclement * @version 1.0 */ -public class OperationsDescriber { +public class OperationsDescriber extends AbstractOpDescriber { - protected ObjectFactory owsFactory = new ObjectFactory(); + protected ObjectFactory owsFactory = new ObjectFactory(); - public OperationsMetadata getOpData(OgcServiceInfo serviceinfo) { - OperationsMetadata rval = new OperationsMetadata(); - List operations = new LinkedList(); - for (OgcOperationInfo op : serviceinfo.getOperations()) { - Operation to = new Operation(); - to.setName(op.getType().toString()); - to.setDCP(getDcpList(op)); - to.setParameter(getOpParams(op)); - operations.add(to); - } - rval.setOperation(operations); - rval.setParameter(getParams(serviceinfo)); - return rval; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.AbstractOpDescriber#getParams(com.raytheon + * .uf.edex.ogc.common.OgcServiceInfo) + */ + @Override + protected List getParams(OgcServiceInfo serviceinfo) { + List rval = new LinkedList(); + // TODO: this info should be passed in from somewhere + DomainType parameter = new DomainType(); + parameter.setName("srsName"); + List value = new LinkedList(); + value.add("EPSG:4326"); + rval.add(parameter); + return rval; + } - protected List getParams(OgcServiceInfo serviceinfo) { - List rval = new LinkedList(); - // TODO: this info should be passed in from somewhere - DomainType parameter = new DomainType(); - parameter.setName("srsName"); - List value = new LinkedList(); - value.add("EPSG:4326"); - rval.add(parameter); - return rval; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.AbstractOpDescriber#getOpParams(com.raytheon + * .uf.edex.ogc.common.OgcOperationInfo) + */ + @Override + protected List getOpParams(OgcOperationInfo op) { - protected List getDcpList(OgcOperationInfo op) { - List rval = new LinkedList(); - DCP dcp = new DCP(); - HTTP http = new HTTP(); - List> value = new LinkedList>(); - if (op.hasHttpGet()) { - RequestMethodType req = getRequestType(op.getHttpGetRes()); - value.add(owsFactory.createHTTPPost(req)); - } - if (op.hasHttpPost()) { - RequestMethodType req = getRequestType(op.getHttpPostRes()); - value.add(owsFactory.createHTTPPost(req)); - } - http.setGetOrPost(value); - dcp.setHTTP(http); - rval.add(dcp); - return rval; - } + List opParamList = new ArrayList(); - protected RequestMethodType getRequestType(String value) { - RequestMethodType rval = owsFactory.createRequestMethodType(); - rval.setHref(value); - return rval; - } + switch (op.getType()) { + case GetCapabilities: + opParamList = Arrays.asList( + getAsDomainType("AcceptVersions", op.getVersions()), + getAsDomainType("AcceptFormats", op.getFormats()), + getAsDomainType("service", op.getServices())); + break; + case DescribeCoverage: + opParamList = Arrays.asList( + getAsDomainType("AcceptVersions", op.getVersions()), + getAsDomainType("AcceptFormats", op.getFormats()), + getAsDomainType("service", op.getServices()));// , + // getAsDomainType("Identifier", getLayerIdentifierList())); + break; + case GetCoverage: + opParamList = Arrays + .asList(getAsDomainType("AcceptVersions", op.getVersions()), + getAsDomainType("AcceptFormats", op.getFormats()), + getAsDomainType("service", op.getServices()), + // getAsDomainType("Identifier", + // getLayerIdentifierList()), + getAsDomainType("InterpolationType", + getInterpolationType()), + getAsDomainType("store", + Arrays.asList("true", "false"))); + break; + default: - private List getOpParams(OgcOperationInfo op) { + } - List opParamList = new ArrayList(); + return opParamList; + } - switch (op.getType()) { - case GetCapabilities: - opParamList = Arrays.asList( - getAsDomainType("AcceptVersions", op.getVersions()), - getAsDomainType("AcceptFormats", op.getFormats()), - getAsDomainType("service", op.getServices())); - break; - case DescribeCoverage: - opParamList = Arrays.asList( - getAsDomainType("AcceptVersions", op.getVersions()), - getAsDomainType("AcceptFormats", op.getFormats()), - getAsDomainType("service", op.getServices()));// , - // getAsDomainType("Identifier", getLayerIdentifierList())); - break; - case GetCoverage: - opParamList = Arrays - .asList(getAsDomainType("AcceptVersions", op.getVersions()), - getAsDomainType("AcceptFormats", op.getFormats()), - getAsDomainType("service", op.getServices()), - // getAsDomainType("Identifier", - // getLayerIdentifierList()), - getAsDomainType("InterpolationType", - getInterpolationType()), - getAsDomainType("format", getFormat())); - break; - default: + /** + * @return default interpolation types + */ + protected List getInterpolationType() { + List interpolationType = new ArrayList(); - } + interpolationType.add("nearest"); + interpolationType.add("linear"); - return opParamList; - } + return interpolationType; + } - protected List getInterpolationType() { - List interpolationType = new ArrayList(); + /** + * @return default formats + */ + protected List getFormat() { + return new ArrayList(); + } - interpolationType.add("nearest"); - interpolationType.add("linear"); - - return interpolationType; - } - - protected List getFormat() { - List format = new ArrayList(); - - format.add("IDataRecord"); - // format.add("image/tiff"); - // format.add("image/jpeg"); - // format.add("image/netcdf"); - - return format; - } - - protected DomainType getAsDomainType(String name, Collection values) { - DomainType rval = new DomainType(); - rval.setName(name); - - AllowedValues avs = new AllowedValues(); - - List toVals = new LinkedList(); - for (String val : values) { - toVals.add(val); - } - - avs.setValueOrRange(toVals); - rval.setAllowedValues(avs); - - return rval; - } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/WcsJaxbUtils.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/WcsJaxbUtils.java index 2300c0b4df..4181425307 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/WcsJaxbUtils.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/provider/WcsJaxbUtils.java @@ -55,6 +55,7 @@ public class WcsJaxbUtils { LanguageStringType lst = new LanguageStringType(); lst.setLang(DEFAULT_LANGUAGE); lst.setValue(str); + rval.add(lst); } return rval; } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/querystore/WcsQueryStore.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/querystore/WcsQueryStore.java new file mode 100644 index 0000000000..a645c76d11 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/querystore/WcsQueryStore.java @@ -0,0 +1,95 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.querystore; + +import java.io.File; + +import javax.xml.bind.JAXBException; + +import net.opengis.wcs.v_1_1_2.GetCoverage; + +import com.raytheon.uf.edex.ogc.common.AbstractFSQueryStore; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.jaxb.OgcJaxbManager; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 18, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class WcsQueryStore extends AbstractFSQueryStore { + + private static final String STORE_NAME = "wcsquerystore"; + + protected final OgcJaxbManager jaxbManager; + + /** + * @param registry + * @param storeLocation + * @throws IllegalArgumentException + * if storage location cannot be created or is not a writable + * directory + */ + public WcsQueryStore(OgcJaxbManager jaxbManager, File storeLocation) + throws IllegalArgumentException { + super(storeLocation); + this.jaxbManager = jaxbManager; + } + + public WcsQueryStore(OgcJaxbManager jaxbManager) { + super(findStore(STORE_NAME)); + this.jaxbManager = jaxbManager; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.AbstractFSQueryStore#marshal(java.lang + * .Object) + */ + @Override + protected String marshal(GetCoverage query) throws OgcException { + try { + return jaxbManager.marshal(query); + } catch (JAXBException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.AbstractFSQueryStore#unmarshal(java.lang + * .String) + */ + @Override + protected GetCoverage unmarshal(String xml) throws OgcException { + try { + return (GetCoverage) jaxbManager.unmarshal(xml); + } catch (JAXBException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/Coverage.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/Coverage.java index 4f0fc81d71..f33cb1e603 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/Coverage.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/Coverage.java @@ -30,94 +30,43 @@ */ package com.raytheon.uf.edex.wcs.reg; -import org.geotools.coverage.grid.GridGeometry2D; -import org.opengis.referencing.crs.CoordinateReferenceSystem; - -import com.raytheon.uf.common.datastorage.records.IDataRecord; -import com.vividsolutions.jts.geom.Envelope; +import java.util.List; /** + * WCS Coverage * * @author bclement * @version 1.0 */ public class Coverage { - protected IDataRecord dataRecord; - private CoordinateReferenceSystem crs; - private Envelope envelope; - private String time; - private GridGeometry2D gridGeometry; + private final String name; - /** - * @return the crs - */ - public CoordinateReferenceSystem getCrs() { - return crs; - } + private final List fields; - /** - * @return the envelope - */ - public Envelope getEnvelope() { - return envelope; - } + /** + * @param name + * @param fields + */ + public Coverage(String name, List fields) { + super(); + this.name = name; + this.fields = fields; + } - /** - * @return the dataRecord - */ - public IDataRecord getDataRecord() { - return dataRecord; - } + /** + * @return the name + */ + public String getName() { + return name; + } - /** - * @param dataRecord - * the dataRecord to set - */ - public void setDataRecord(IDataRecord dataRecord) { - this.dataRecord = dataRecord; - } + /** + * @return the fields + */ + public List getFields() { + return fields; + } - /** - * @param envelope - */ - public void setEnvelope(Envelope env) { - this.envelope = env; - } - - /** - * @param crs - */ - public void setCrs(CoordinateReferenceSystem crs) { - this.crs = crs; - } - - /** - * @param timeString - */ - public void setTime(String timeString) { - this.time = timeString; - } - - /** - * @return the time - */ - public String getTime() { - return time; - } - - /** - * @param gridGeometry the gridGeometry to set - */ - public void setGridGeometry(GridGeometry2D gridGeometry) { - this.gridGeometry = gridGeometry; - } - - /** - * @return the gridGeometry - */ - public GridGeometry2D getGridGeometry() { - return gridGeometry; - } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageDescription.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageDescription.java index 46d23f91b5..def17cd35f 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageDescription.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageDescription.java @@ -33,8 +33,8 @@ package com.raytheon.uf.edex.wcs.reg; import java.util.List; import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; import com.vividsolutions.jts.geom.Polygon; /** @@ -56,7 +56,7 @@ public class CoverageDescription { protected List times; - protected List bboxes; + protected List bboxes; protected List rangeFields; @@ -178,11 +178,11 @@ public class CoverageDescription { this.times = times; } - public List getBboxes() { + public List getBboxes() { return bboxes; } - public void setBboxes(List bboxes) { + public void setBboxes(List bboxes) { this.bboxes = bboxes; } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageDimensions.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageDimensions.java new file mode 100644 index 0000000000..1b2e17a036 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageDimensions.java @@ -0,0 +1,117 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 2, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoverageDimensions { + + private final CoverageXYAxis xyAxis; + + private final CoverageZAxis zAxis; + + private final CoverageTAxis tAxis; + + /** + * @param xyAxis + * @param zAxis + * @param times + */ + public CoverageDimensions(CoverageXYAxis xyAxis, CoverageZAxis zAxis, + CoverageTAxis tAxis) { + this.xyAxis = xyAxis; + this.zAxis = zAxis; + this.tAxis = tAxis; + } + + /** + * @return the xyAxis + */ + public CoverageXYAxis getXyAxis() { + return xyAxis; + } + + /** + * @return the zAxis + */ + public CoverageZAxis getZAxis() { + return zAxis; + } + + /** + * @return the tAxis + */ + public CoverageTAxis getTAxis() { + return tAxis; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((tAxis == null) ? 0 : tAxis.hashCode()); + result = prime * result + ((xyAxis == null) ? 0 : xyAxis.hashCode()); + result = prime * result + ((zAxis == null) ? 0 : zAxis.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CoverageDimensions other = (CoverageDimensions) obj; + if (tAxis == null) { + if (other.tAxis != null) + return false; + } else if (!tAxis.equals(other.tAxis)) + return false; + if (xyAxis == null) { + if (other.xyAxis != null) + return false; + } else if (!xyAxis.equals(other.xyAxis)) + return false; + if (zAxis == null) { + if (other.zAxis != null) + return false; + } else if (!zAxis.equals(other.zAxis)) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageField.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageField.java new file mode 100644 index 0000000000..5c03cc104d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageField.java @@ -0,0 +1,128 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + +import java.util.List; + +/** + * 4D coverage for a specific field value + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 2, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoverageField { + + private String name; + + private String standardName; + + private final List timeCube; + + private final CoverageDimensions dimensions; + + private String units; + + private Number paddingValue; + + /** + * @param timeCube + */ + public CoverageField(List timeCube, CoverageDimensions dims) { + this.timeCube = timeCube; + this.dimensions = dims; + } + + /** + * @return the timeCube + */ + public List getTimeCube() { + return timeCube; + } + + /** + * @return the units + */ + public String getUnits() { + return units; + } + + /** + * @param units + * the units to set + */ + public void setUnits(String units) { + this.units = units; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the standardName + */ + public String getStandardName() { + return standardName; + } + + /** + * @param standardName + * the standardName to set + */ + public void setStandardName(String standardName) { + this.standardName = standardName; + } + + /** + * May be null + * + * @return the paddingValue + */ + public Number getPaddingValue() { + return paddingValue; + } + + /** + * @param paddingValue + * the paddingValue to set + */ + public void setPaddingValue(Number paddingValue) { + this.paddingValue = paddingValue; + } + + /** + * @return the dimensions + */ + public CoverageDimensions getDimensions() { + return dimensions; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageTAxis.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageTAxis.java new file mode 100644 index 0000000000..ac6bcd1a98 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageTAxis.java @@ -0,0 +1,81 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + +import java.util.Arrays; +import java.util.Date; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 3, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoverageTAxis { + + private final Date[] times; + + /** + * @param times + */ + public CoverageTAxis(Date[] times) { + this.times = times; + } + + /** + * @return the times + */ + public Date[] getTimes() { + return times; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(times); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CoverageTAxis other = (CoverageTAxis) obj; + if (!Arrays.equals(times, other.times)) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageTransform.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageTransform.java index 7d63c2f716..e2239c1623 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageTransform.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageTransform.java @@ -37,13 +37,22 @@ import java.util.List; import java.util.Set; import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; +import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; +import com.raytheon.uf.edex.ogc.common.spatial.CrsLookup; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; +import com.raytheon.uf.edex.plugin.dataset.urn.URNLookup; +import com.raytheon.uf.edex.wcs.WcsException; +import com.raytheon.uf.edex.wcs.WcsException.Code; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LinearRing; @@ -53,9 +62,9 @@ import com.vividsolutions.jts.geom.LinearRing; * @author bclement * @version 1.0 */ -public abstract class CoverageTransform { +public abstract class CoverageTransform> { - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); protected String key; @@ -63,50 +72,55 @@ public abstract class CoverageTransform { this.key = key; } - public List transform( - List layers, boolean summaryOnly) { + public List transform(List layers, + boolean summaryOnly) + throws WcsException { if (layers == null) { return null; } List rval = new ArrayList( layers.size()); - for (SimpleLayer layer : layers) { + for (L layer : layers) { rval.add(transform(layer, summaryOnly)); } return rval; } - public CoverageDescription transform(SimpleLayer layer, boolean summaryOnly) { + public CoverageDescription transform(L layer, + boolean summaryOnly) throws WcsException { CoverageDescription rval = new CoverageDescription(); - rval.setIdentifier(layer.getName()); + rval.setIdentifier(URNLookup.localToUrn(layer.getName())); OgcGeoBoundingBox bbox = LayerTransformer.getGeoBoundingBox(layer); + List bboxes = getBboxes(layer); if (bbox != null) { rval.setCrs84Bbox(bbox); + rval.setCrs(getSupportedCrsList(layer.getTargetCrsCode(), bboxes)); } else { log.warn("Unable to get geographic information for layer: " + layer.getName()); } if (!summaryOnly) { - describe(rval, layer); + describe(rval, layer, bboxes); } return rval; } + /** + * @param rval + * @param layer + * @throws WcsException + */ + protected void describe(CoverageDescription rval, L layer, + List bboxes) throws WcsException { - /** - * @param rval - * @param layer - */ - protected void describe(CoverageDescription rval, SimpleLayer layer) { rval.setGridOffsets(Arrays.asList((double) layer.getNx(), (double) layer.getNy())); - String targetCrs = translateCrs(layer.getTargetCrsCode()); - rval.setGridBaseCrs(targetCrs); - rval.setCrs(Arrays.asList(targetCrs)); + double minx = layer.getTargetMinx(); double miny = layer.getTargetMiny(); double maxx = layer.getTargetMaxx(); double maxy = layer.getTargetMaxy(); + GeometryFactory geomFact = new GeometryFactory(); Coordinate[] coords = new Coordinate[5]; coords[0] = new Coordinate(minx, miny); @@ -114,19 +128,91 @@ public abstract class CoverageTransform { coords[2] = new Coordinate(maxx, maxy); coords[3] = new Coordinate(maxx, miny); coords[4] = new Coordinate(minx, miny); + LinearRing ring = geomFact.createLinearRing(coords); rval.setTimes(getTimes(layer.getTimes())); rval.setRangeFields(getRangeFields(layer)); rval.setPolygon(geomFact.createPolygon(ring, new LinearRing[0])); rval.setGridType("urn:ogc:def:method:WCS:1.1:grid2dIn2dMethod"); rval.setGridOrigin(Arrays.asList(minx, maxy)); + int nx = layer.getNx(); int ny = layer.getNy(); + rval.setGridOffsets(Arrays.asList(getDn(nx, minx, maxx), 0.0, 0.0, -getDn(ny, miny, maxy))); - rval.setGridCs("urn:ogc:def:cs:OGC:0.0:Grid2dSquareCS"); + rval.setGridCs("urn:ogc:def:cs:OGC:0.0:Grid2dSquareCS"); + + rval.setBboxes(bboxes); + + String targetCrs = translateCrs(layer.getTargetCrsCode()); + rval.setGridBaseCrs(targetCrs); + + //add all the crs' from the bounding boxes + List crs = new ArrayList(Arrays.asList(targetCrs)); + for(Composite3DBoundingBox bBox : bboxes) { + String bBoxCrs = CrsLookup.createCrsURN(bBox); + if(bBoxCrs != null && !crs.contains(bBoxCrs)) { + crs.add(bBoxCrs); + } + } + rval.setCrs(crs); + } + /** + * Create a list composed of target crs and bounding box CRS URNs + * + * @param targetCrs + * @param bboxes + * @return + */ + private List getSupportedCrsList(String targetCrs, + List bboxes) { + List rval = new ArrayList(Arrays.asList(targetCrs)); + for (Composite3DBoundingBox bBox : bboxes) { + String bBoxCrs = CrsLookup.createCrsURN(bBox); + if (bBoxCrs != null && !rval.contains(bBoxCrs)) { + rval.add(bBoxCrs); + } + } + return rval; + } + + protected List getBboxes(L layer) + throws WcsException { + Composite3DBoundingBox bbox = new Composite3DBoundingBox( + getHorizontal(layer), getVertical(layer)); + return Arrays.asList(bbox); + } + + /** + * @param layer + * @return null if layer doesn't have vertical information + * @throws WcsException + */ + protected abstract VerticalCoordinate getVertical(L layer) + throws WcsException; + + /** + * @param layer + * @return + * @throws WcsException + */ + protected ReferencedEnvelope getHorizontal(L layer) + throws WcsException { + CoordinateReferenceSystem crs2d; + try { + crs2d = CrsLookup.lookup(layer.getTargetCrsCode()); + } catch (Exception e) { + log.error("Unable to parse target crs", e); + throw new WcsException(Code.InternalServerError); + } + return new ReferencedEnvelope(layer.getTargetMinx(), + layer.getTargetMaxx(), layer.getTargetMiny(), + layer.getTargetMaxy(), crs2d); + } + protected double getDn(int nn, double n1, double n2) { return Math.abs(n1 - n2) / (double) nn; } @@ -155,7 +241,7 @@ public abstract class CoverageTransform { * @param layer * @return */ - protected abstract List getRangeFields(SimpleLayer layer); + protected abstract List getRangeFields(L layer); protected List getTimes(Set times) { if (times == null) { diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageXYAxis.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageXYAxis.java new file mode 100644 index 0000000000..323823a91e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageXYAxis.java @@ -0,0 +1,103 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + +import org.geotools.coverage.grid.GridGeometry2D; +import org.geotools.geometry.jts.ReferencedEnvelope; + +/** + * Metadata for coverage X and Y axis + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 12, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoverageXYAxis { + + private final GridGeometry2D gridGeometry; + + private final ReferencedEnvelope envelope; + + /** + * @param gridGeometry + * @param crs + */ + public CoverageXYAxis(GridGeometry2D gridGeometry,ReferencedEnvelope envelope) { + this.gridGeometry = gridGeometry; + this.envelope = envelope; + } + + /** + * @return the gridGeometry + */ + public GridGeometry2D getGridGeometry() { + return gridGeometry; + } + + /** + * @return the envelope + */ + public ReferencedEnvelope getEnvelope() { + return envelope; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((envelope == null) ? 0 : envelope.hashCode()); + result = prime * result + + ((gridGeometry == null) ? 0 : gridGeometry.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CoverageXYAxis other = (CoverageXYAxis) obj; + if (envelope == null) { + if (other.envelope != null) + return false; + } else if (!envelope.equals(other.envelope)) + return false; + if (gridGeometry == null) { + if (other.gridGeometry != null) + return false; + } else if (!gridGeometry.equals(other.gridGeometry)) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageZAxis.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageZAxis.java new file mode 100644 index 0000000000..57ba7b47bb --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/CoverageZAxis.java @@ -0,0 +1,129 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + +import java.util.Arrays; + +/** + * Metadata for coverage Z axis + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 12, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class CoverageZAxis { + + private final double[] value; + + private final String units; + + private final String reference; + + private final boolean upIsPositive; + + /** + * @param value + * @param units + * @param upIsPositive + */ + public CoverageZAxis(double[] value, String units, String reference, + boolean upIsPositive) { + this.value = value; + this.units = units; + this.reference = reference; + this.upIsPositive = upIsPositive; + } + + /** + * @return the value + */ + public double[] getValue() { + return value; + } + + /** + * @return the units + */ + public String getUnits() { + return units; + } + + /** + * @return the upIsPositive + */ + public boolean isUpIsPositive() { + return upIsPositive; + } + + /** + * @return the reference + */ + public String getReference() { + return reference; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((reference == null) ? 0 : reference.hashCode()); + result = prime * result + ((units == null) ? 0 : units.hashCode()); + result = prime * result + (upIsPositive ? 1231 : 1237); + result = prime * result + Arrays.hashCode(value); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CoverageZAxis other = (CoverageZAxis) obj; + if (reference == null) { + if (other.reference != null) + return false; + } else if (!reference.equals(other.reference)) + return false; + if (units == null) { + if (other.units != null) + return false; + } else if (!units.equals(other.units)) + return false; + if (upIsPositive != other.upIsPositive) + return false; + if (!Arrays.equals(value, other.value)) + return false; + return true; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/DefaultWcsSource.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/DefaultWcsSource.java index 28b61e746f..48a15a841a 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/DefaultWcsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/DefaultWcsSource.java @@ -30,21 +30,40 @@ */ package com.raytheon.uf.edex.wcs.reg; -import java.lang.Thread.State; +import java.awt.Point; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; -import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import javax.measure.unit.Unit; + +import org.apache.commons.collections.map.LRUMap; import org.geotools.coverage.grid.GeneralGridEnvelope; import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.geometry.DirectPosition2D; import org.geotools.geometry.GeneralEnvelope; import org.geotools.geometry.jts.ReferencedEnvelope; +import org.hibernate.Criteria; +import org.hibernate.SessionFactory; +import org.hibernate.classic.Session; +import org.hibernate.criterion.Conjunction; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.Order; +import org.hibernate.criterion.Restrictions; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.metadata.spatial.PixelOrientation; @@ -56,6 +75,10 @@ import org.opengis.referencing.operation.TransformException; import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.PluginException; import com.raytheon.uf.common.dataplugin.PluginProperties; +import com.raytheon.uf.common.dataplugin.persist.IPersistable; +import com.raytheon.uf.common.datastorage.DataStoreFactory; +import com.raytheon.uf.common.datastorage.IDataStore; +import com.raytheon.uf.common.datastorage.Request; import com.raytheon.uf.common.datastorage.records.ByteDataRecord; import com.raytheon.uf.common.datastorage.records.FloatDataRecord; import com.raytheon.uf.common.datastorage.records.IDataRecord; @@ -63,14 +86,34 @@ import com.raytheon.uf.common.datastorage.records.IntegerDataRecord; import com.raytheon.uf.common.datastorage.records.LongDataRecord; import com.raytheon.uf.common.datastorage.records.ShortDataRecord; import com.raytheon.uf.common.datastorage.records.StringDataRecord; +import com.raytheon.uf.common.geospatial.ISpatialEnabled; +import com.raytheon.uf.common.geospatial.ISpatialObject; +import com.raytheon.uf.common.spatial.reprojection.AbstractDataReprojector.RequestWrapper; +import com.raytheon.uf.common.spatial.reprojection.ByteDataReprojector; +import com.raytheon.uf.common.spatial.reprojection.DataReprojector; +import com.raytheon.uf.common.spatial.reprojection.FloatDataReprojector; +import com.raytheon.uf.common.spatial.reprojection.IntDataReprojector; import com.raytheon.uf.common.spatial.reprojection.ReferencedDataRecord; +import com.raytheon.uf.common.spatial.reprojection.ShortDataReprojector; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.edex.database.DataAccessLayerException; +import com.raytheon.uf.common.time.TimeRange; import com.raytheon.uf.edex.database.plugin.PluginDao; import com.raytheon.uf.edex.database.plugin.PluginFactory; +import com.raytheon.uf.edex.ogc.common.AbstractOgcSource; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.PeekingIterator; import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; +import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.filter.TemporalFilter; +import com.raytheon.uf.edex.ogc.common.spatial.AltUtil; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; import com.raytheon.uf.edex.ogc.common.spatial.RecordUtil; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; +import com.raytheon.uf.edex.plugin.dataset.urn.URNLookup; +import com.raytheon.uf.edex.plugin.unitconverter.UnitLookup; import com.raytheon.uf.edex.wcs.WcsException; import com.raytheon.uf.edex.wcs.WcsException.Code; import com.vividsolutions.jts.geom.Envelope; @@ -81,743 +124,1480 @@ import com.vividsolutions.jts.geom.Envelope; * @author jelkins * @version 1.0 */ -public abstract class DefaultWcsSource implements WcsSource { +public abstract class DefaultWcsSource, T extends PluginDataObject> + extends AbstractOgcSource implements IWcsSource { - protected LayerTransformer transformer; - private PluginDao _dao; - protected PluginProperties props; - protected Log log = LogFactory.getLog(this.getClass()); - protected Set idCache = new HashSet(); - protected Thread idUpdateThread; + protected LayerTransformer transformer; - abstract protected CoverageTransform getCoverageTransform(); + private PluginDao _dao; - /** + protected PluginProperties props; + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + private static final String VALID_START = "dataTime.validPeriod.start"; + + @SuppressWarnings("unchecked") + private final Map fillCache = Collections + .synchronizedMap(new LRUMap(2)); + + /** * */ - public DefaultWcsSource(PluginProperties props, LayerTransformer transformer) { - this.props = props; - this.transformer = transformer; - } + public DefaultWcsSource(PluginProperties props, + LayerTransformer transformer) { + this.props = props; + this.transformer = transformer; + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wcs.reg.WcsSource#listCoverages() - */ - @Override - public List listCoverages() { - return getCoverageList(false); - } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.reg.WcsSource#listCoverages() + */ + @Override + public List listCoverages(boolean summary) { + return getCoverageList(false, summary); + } - /** - * @param wait - * @return - */ - protected List getCoverageList(boolean wait) { - List coverageList = null; - try { - coverageList = getCoverageTransform().transform( - transformer.getLayers(), true); - } catch (Exception e) { - log.error("Unable to get plugin dao", e); - return new ArrayList(0); + /** + * @param wait + * @return + */ + protected List getCoverageList(boolean wait, + boolean summary) { + List coverageList = null; + try { + coverageList = getCoverageTransform().transform( + transformer.getLayers(), summary); + } catch (Exception e) { + log.error("Unable to get plugin dao", e); + return new ArrayList(0); - } - updateIdCache(coverageList, wait); - return coverageList; - } + } + return coverageList; + } - protected PluginDao getDao() throws PluginException { - if (_dao == null) { - _dao = PluginFactory.getInstance().getPluginDao( - props.getPluginName()); - } - return _dao; - } + /** + * @return + * @throws PluginException + */ + protected PluginDao getDao() throws PluginException { + if (_dao == null) { + _dao = PluginFactory.getInstance().getPluginDao( + props.getPluginName()); + } + return _dao; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wcs.reg.WcsSource#describeCoverage(java.lang.String) - */ - @Override - public CoverageDescription describeCoverage(String identifier) - throws WcsException { - CoverageDescription rval; - try { - SimpleLayer layer = transformer.find(identifier); - if (layer == null) { - throw new WcsException(Code.LayerNotDefined); - } - rval = getCoverageTransform().transform(layer, false); - } catch (DataAccessLayerException e) { - log.error("Problem accessing layers", e); - throw new WcsException(Code.InternalServerError, e); - } catch (Exception e) { - log.error("Unable to get plugin dao", e); - throw new WcsException(Code.InternalServerError); - } - return rval; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.reg.WcsSource#describeCoverage(java.lang.String) + */ + @Override + public CoverageDescription describeCoverage(String rawId) + throws WcsException { + String identifier = URNLookup.urnToLocal(rawId); + return describeCoverageParsedId(identifier); + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wcs.reg.WcsSource#getCoverage(java.lang.String, - * com.raytheon.uf.common.time.DataTime, - * org.opengis.referencing.crs.CoordinateReferenceSystem, - * com.vividsolutions.jts.geom.Envelope) - */ - @Override - public Coverage getCoverage(String identifier, DataTime time, - CoordinateReferenceSystem crs, Envelope bbox, - List rangeFields) throws WcsException { - PluginDataObject record = getRecord(identifier, time, rangeFields); - time = record.getDataTime(); - ReferencedDataRecord dataRecord = getDataRecord(record, crs, bbox); - if (dataRecord == null) { - return null; - } - Coverage c = new Coverage(); - c.setDataRecord(dataRecord.getRecord()); - c.setEnvelope(dataRecord.getEnvelope()); - c.setCrs(crs); - String timeString = LayerTransformer.format(time.getRefTime()); - c.setTime(timeString); - GridGeometry2D gridGeom = getGridGeometry(dataRecord.getRecord(), - dataRecord.getEnvelope()); - c.setGridGeometry(gridGeom); - return c; - } + /** + * Describe coverage using a parsed ID + * + * @param parsedId + * @return + * @throws WcsException + */ + public CoverageDescription describeCoverageParsedId(String parsedId) + throws WcsException { + CoverageDescription rval; + try { + L layer = transformer.find(parsedId); + if (layer == null) { + throw new WcsException(Code.LayerNotDefined); + } + rval = getCoverageTransform().transform(layer, false); + } catch (OgcException e) { + log.error("Problem accessing layers", e); + throw new WcsException(Code.InternalServerError, e); + } catch (Exception e) { + log.error("Unable to get plugin dao", e); + throw new WcsException(Code.InternalServerError); + } + return rval; + } - /** - * @param identifier - * @return - */ - protected Date getDefaultTime(String identifier) throws WcsException { - try { - SimpleLayer layer = transformer.find(identifier); - return layer.getDefaultTime(); - } catch (DataAccessLayerException e) { - log.error("Problem accessing layers", e); - throw new WcsException(Code.InternalServerError, e); - } catch (Exception e) { - log.error("Unable to get plugin dao", e); - throw new WcsException(Code.InternalServerError); - } - } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.reg.WcsSource#getCoverage(java.lang.String, + * com.raytheon.uf.common.time.DataTime, + * org.opengis.referencing.crs.CoordinateReferenceSystem, + * com.vividsolutions.jts.geom.Envelope) + */ + @Override + public Coverage getCoverage(String rawId, DataTime time, + Composite3DBoundingBox bbox, List rangeFields) + throws WcsException { + String identifier = URNLookup.urnToLocal(rawId); + List fields = getRecords(identifier, time, bbox, + rangeFields); + Coverage rval = new Coverage(rawId, fields); + return rval; + } - /** - * @param record - * @param crs - * @param bbox - * @return - * @throws WcsException - */ - protected ReferencedDataRecord getDataRecord(PluginDataObject record, - CoordinateReferenceSystem crs, Envelope bbox) throws WcsException { - try { + /* + * convenience wrapper for query arguments + */ + protected static class QueryPackage { + + public String id; + + public Conjunction query; + + public Composite3DBoundingBox bbox; + + public DataTime time; + + /** + * @param query + * @param bbox + * @param time + */ + public QueryPackage(String id, Conjunction query, + Composite3DBoundingBox bbox, DataTime time) { + this.id = id; + this.query = query; + this.bbox = bbox; + this.time = time; + } + + } + + /** + * Query and organize records for coverage + * + * @param identifier + * @param time + * @param bbox + * @param rangeFields + * @return + * @throws WcsException + */ + protected List getRecords(String identifier, DataTime time, + Composite3DBoundingBox bbox, List rangeFields) + throws WcsException { + Map> fields = parseFields(rangeFields); + Set scalarValues = fields.get(getScalarKey()); + Conjunction and = getFilterClause(identifier, time, fields); + + List rval; + QueryPackage pkg = new QueryPackage(identifier, and, bbox, time); + if (scalarValues == null || scalarValues.isEmpty()) { + // all parameters + rval = queryAllFieldValues(pkg); + } else if (scalarValues.size() == 1) { + // only one requested + String param = scalarValues.iterator().next(); + rval = Arrays.asList(getFieldForScalar(param, pkg)); + } else { + // for each requested + // criterion aren't reusable + byte[] orig = serialize(and); + rval = new ArrayList(scalarValues.size()); + for (String param : scalarValues) { + pkg.query = deserialize(orig); + rval.add(getFieldForScalar(param, pkg)); + } + } + + return rval; + } + + /** + * Extract range fields into keyed values + * + * @param rangeFields + * @return + * @throws WcsException + */ + protected abstract Map> parseFields( + List rangeFields) throws WcsException; + + /** + * @return field name of scalar parameter + */ + protected abstract String getScalarField(); + + /** + * @return key for scalar values in map returned by + * {@link DefaultWcsSource#parseFields(List)} + */ + protected abstract String getScalarKey(); + + /** + * Get query for coverage records + * + * @param identifier + * @param time + * @param fields + * @return + * @throws WcsException + */ + protected abstract Conjunction getFilterClause(String identifier, + DataTime time, Map> fields) throws WcsException; + + /** + * Retrieve data for all values of the scalar field + * + * @param restrictions + * @param crs + * @param bbox + * @return + * @throws WcsException + */ + protected List queryAllFieldValues(QueryPackage pkg) + throws WcsException { + List records = query(pkg.query); + Map> groups = groupByField(records); + List rval = new ArrayList(groups.size()); + for (String param : groups.keySet()) { + CoverageField field = createField(param, groups.get(param), pkg); + if (field != null) { + rval.add(field); + } + } + if (rval.isEmpty()) { + String sampleField; + if (!groups.isEmpty()) { + sampleField = groups.keySet().iterator().next(); + } else { + // panic, get first field for id + CoverageDescription desc = describeCoverageParsedId(pkg.id); + sampleField = desc.getRangeFields().get(0).getIdentifier(); + } + rval.add(createFillField(sampleField, pkg)); + } + return rval; + } + + /** + * Group records by scalar field value + * + * @param records + * @return + * @throws WcsException + */ + protected Map> groupByField(List records) + throws WcsException { + Map> rval = new TreeMap>(); + for (T record : records) { + String value = getScalarValue(record); + List list = rval.get(value); + if (list == null) { + list = new ArrayList(); + rval.put(value, list); + } + list.add(record); + } + return rval; + } + + /** + * Get scalar field value from record + * + * @param record + * @return + * @throws WcsException + */ + protected abstract String getScalarValue(T record) throws WcsException; + + /** + * convert criterion to byte array + * + * @param crit + * @return + * @throws WcsException + */ + protected byte[] serialize(Criterion crit) throws WcsException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = null; + try { + out = new ObjectOutputStream(baos); + out.writeObject(crit); + out.close(); + return baos.toByteArray(); + } catch (IOException e) { + log.error("Problem cloning criterion", e); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * convert byte array to criterion + * + * @param arr + * @return + * @throws WcsException + */ + protected Conjunction deserialize(byte[] arr) throws WcsException { + ByteArrayInputStream bais = new ByteArrayInputStream(arr); + try { + ObjectInputStream in = new ObjectInputStream(bais); + Conjunction rval = (Conjunction) in.readObject(); + in.close(); + return rval; + } catch (Exception e) { + log.error("Problem cloning criterion", e); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * Build CoverageField for scalar value + * + * @param value + * @return + * @throws WcsException + */ + protected CoverageField getFieldForScalar(String value, QueryPackage pkg) + throws WcsException { + List results = queryScalar(value, pkg); + CoverageField rval = createField(value, results, pkg); + if (rval == null) { + rval = createFillField(value, pkg); + } + return rval; + } + + /** + * Query for records that match specified scalar value + * + * @param value + * @param pkg + * @return + * @throws WcsException + */ + protected List queryScalar(String value, QueryPackage pkg) + throws WcsException { + pkg.query.add(getScalarCrit(value)); + return query(pkg.query); + } + + /** + * Create criterion for scalar value + * + * @param value + * @return + */ + protected Criterion getScalarCrit(String value) { + return Restrictions.eq(getScalarField(), value); + } + + /** + * Group results of query into coverage field + * + * @param param + * @return + * @throws WcsException + */ + protected CoverageField createField(String param, List records, + QueryPackage pkg) throws WcsException { + if (records.isEmpty()) { + return createFillField(param, pkg); + } + LinkedHashMap> map = groupByTime(records); + LinkedHashMap> cubes = new LinkedHashMap>( + map.size()); + T sample = map.get(map.keySet().iterator().next()).get(0); + Composite3DBoundingBox target3d = getTarget3d(pkg.bbox, sample); + for (Date time : map.keySet()) { + List slices = groupByAlt(map.get(time), target3d); + if (!slices.isEmpty()) { + cubes.put(time, slices); + } + } + if (cubes.isEmpty()) { + return null; + } + List rval = fillGaps(sample, pkg, cubes, target3d); + IDataRecordFetcher fetcher = rval.get(0).getSlices().get(0).getRecord(); + ReferencedDataRecord rdr = fetcher.get(true); + CoverageXYAxis xyAxis = new CoverageXYAxis(getGridGeometry(rdr), + rdr.getEnvelope()); + return createField(rval, param, sample, xyAxis); + } + + /** + * Ensure that we have a filter for 3 dimensions. If bbox doesn't have + * vertical bounds, an all-inclusive vertical bounding box is added + * + * @param bbox + * @param sample + * @return + * @throws WcsException + */ + protected Composite3DBoundingBox getTarget3d(Composite3DBoundingBox bbox, + T sample) throws WcsException { + VerticalCoordinate sampleAlt = getAltitude(sample); + if (sampleAlt == null) { + log.error("Sample record has null altitude: " + sample.getDataURI()); + throw new WcsException(Code.InternalServerError); + } + if (bbox.hasVertical()) { + Unit units = sampleAlt.getUnits(); + if (units == null) { + throw new WcsException(Code.InvalidParameterValue, + "3D query not applicable to 2D coverage"); + } + return bbox; + } + VerticalCoordinate allFilter = new VerticalCoordinate( + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, + sampleAlt.getUnits(), sampleAlt.getRef()); + return new Composite3DBoundingBox(bbox.getHorizontal(), allFilter); + } + + /** + * Construct coverage field + * + * @param cubes + * @param param + * @param sample + * @return + * @throws WcsException + */ + protected CoverageField createField(List cubes, String param, + T sample, CoverageXYAxis xyAxis) throws WcsException { + Date[] times = new Date[cubes.size()]; + Iterator iter = cubes.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + TemporalCube cube = iter.next(); + times[i] = cube.getTime(); + } + CoverageZAxis zAxis = cubes.get(0).getzAxis(); + CoverageDimensions dims = new CoverageDimensions(xyAxis, zAxis, + new CoverageTAxis(times)); + CoverageField rval = new CoverageField(cubes, dims); + rval.setName(param); + rval.setStandardName(param); + rval.setUnits(unidataUnitToString(getUcarUnit(sample))); + rval.setPaddingValue(getFillValue(sample)); + return rval; + } + + /** + * Create a coverage field that is all fill values + * + * @param param + * @param pkg + * @return + * @throws WcsException + */ + protected CoverageField createFillField(String param, QueryPackage pkg) + throws WcsException { + Criterion crit = getScalarCrit(param); + T sample = querySample(crit); + if (sample == null) { + throw new WcsException(Code.InvalidParameterValue, + "Unable to find scalar field: " + param); + } + TemporalCube cube = createFillCube(getTarget3d(pkg.bbox, sample), + sample, pkg); + ReferencedEnvelope bbox = pkg.bbox.getHorizontal(); + CoverageXYAxis xyAxis = new CoverageXYAxis(getFillGeom(sample, bbox), + bbox); + return createField(Arrays.asList(cube), param, sample, xyAxis); + } + + /** + * Create a temporal cube that is all fill values + * + * @param target3d + * @param sample + * @param pkg + * @return + */ + protected TemporalCube createFillCube(Composite3DBoundingBox target3d, + T sample, QueryPackage pkg) { + VerticalCoordinate vert = target3d.getVertical(); + String units = unidataUnitToString(UnitLookup.getInstance() + .getUcarFromJsr(vert.getUnits())); + VerticalSlice slice = createFillSlice(sample, pkg, vert.getMin()); + CoverageZAxis zAxis = new CoverageZAxis( + new double[] { slice.getLevel() }, units, + vert.getRef().longName, isUpPositive(sample)); + Date time; + if (pkg.time != null) { + time = pkg.time.getRefTime(); + } else { + time = sample.getDataTime().getValidTime().getTime(); + } + return new TemporalCube(Arrays.asList(slice), time, zAxis); + } + + /** + * Create a vertical slice that is all fill values + * + * @param sample + * @param pkg + * @param level + * @return + */ + protected VerticalSlice createFillSlice(final T sample, + final QueryPackage pkg, double level) { + final ReferencedEnvelope bbox = pkg.bbox.getHorizontal(); + IDataRecordFetcher fillFetcher = new IDataRecordFetcher() { + @Override + public ReferencedDataRecord get(boolean cache) throws WcsException { + return getFillRecord(sample, bbox); + } + }; + return new VerticalSlice(fillFetcher, level); + } + + /** + * Fill levels that are not in all cubes + * + * @param sample + * @param pkg + * @param cubes + * @param target3d + * @return + * @throws WcsException + */ + protected List fillGaps(T sample, QueryPackage pkg, + LinkedHashMap> cubes, + Composite3DBoundingBox target3d) throws WcsException { + TreeSet union = new TreeSet(); + for (Entry> e : cubes.entrySet()) { + List slices = e.getValue(); + for (VerticalSlice slice : slices) { + union.add(slice.getLevel()); + } + } + + VerticalCoordinate vert = target3d.getVertical(); + double[] levels = new double[union.size()]; + Iterator iter = union.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + levels[i] = iter.next(); + } + String unitStr = vert.getUnits() == null ? "" : vert.getUnits() + .toString(); + String refName = vert.getRef() == null ? "" : vert.getRef().longName; + CoverageZAxis zAxis = new CoverageZAxis(levels, unitStr, refName, + isUpPositive(sample)); + List rval = new ArrayList(cubes.size()); + for (Entry> e : cubes.entrySet()) { + rval.add(fillGaps(sample, pkg, e.getValue(), e.getKey(), zAxis)); + } + return rval; + } + + /** + * Fill levels that are in the expected set of levels but not in the cube + * + * @param sample + * @param pkg + * @param slices + * @param time + * @param zAxis + * @return + */ + protected TemporalCube fillGaps(T sample, QueryPackage pkg, + List slices, Date time, CoverageZAxis zAxis) { + PeekingIterator from = new PeekingIterator( + slices.iterator()); + double[] expected = zAxis.getValue(); + List target = new ArrayList( + expected.length); + for (double level : expected) { + if (!from.hasNext()) { + // ran out of from, rest will be fills + target.add(createFillSlice(sample, pkg, level)); + continue; + } + VerticalSlice possible = from.peek(); + if (possible.getLevel() == level) { + target.add(possible); + from.next(); // progress iterator + } else { + // missing level, use fill + target.add(createFillSlice(sample, pkg, level)); + } + } + return new TemporalCube(target, time, zAxis); + } + + /** + * Safely convert units to string + * + * @param u + * @return + */ + protected String javaxUnitToString(Unit u) { + return u != null ? u.toString() : ""; + } + + protected String unidataUnitToString(ucar.units.Unit u) { + return u != null ? u.toString() : ""; + } + + /** + * get field units from record + * + * @param record + * @return + */ + protected abstract Unit getScalarUnit(T record); + + protected abstract ucar.units.Unit getUcarUnit(T record); + + /** + * @param record + * @return true if increasing z values is up + */ + protected abstract boolean isUpPositive(T record); + + /** + * @param records + * @return + */ + private LinkedHashMap> groupByTime(List records) { + LinkedHashMap> rval = new LinkedHashMap>(); + for (T record : records) { + Date time = record.getDataTime().getValidTime().getTime(); + List list = rval.get(time); + if (list == null) { + list = new ArrayList(); + rval.put(time, list); + } + list.add(record); + } + return rval; + } + + /** + * Group records into vertical slices + * + * @param records + * @param targetUnits + * @param bbox + * @return + * @throws WcsException + */ + protected List groupByAlt(List records, + final Composite3DBoundingBox bbox) throws WcsException { + final ReferencedEnvelope horiz = bbox.getHorizontal(); + VerticalCoordinate vertFilter = bbox.getVertical(); + List rval = new ArrayList(records.size()); + for (final T r : records) { + VerticalCoordinate altitude = getAltitude(r); + if (altitude == null) { + log.error("Record missing altitude: " + r.getDataURI()); + continue; + } + VerticalCoordinate vertValue; + try { + vertValue = AltUtil.convert(vertFilter.getUnits(), + vertFilter.getRef(), altitude); + } catch (Exception e) { + log.debug("Unable to convert level", e.getMessage()); + continue; + } + if (vertFilter.compareTo(vertValue) != 0) { + continue; + } + IDataRecordFetcher fetcher = new IDataRecordFetcher() { + ReferencedDataRecord record; + + @Override + public ReferencedDataRecord get(boolean cache) + throws WcsException { + if (record != null) { + return record; + } + ReferencedDataRecord rval = getDataRecord(r, horiz); + if (cache) { + record = rval; + } + return rval; + } + }; + rval.add(new VerticalSlice(fetcher, vertValue.getValue())); + } + Collections.sort(rval); + return rval; + } + + /** + * get z value for record + * + * @param record + * @return + * @throws WcsException + */ + protected abstract VerticalCoordinate getAltitude(T record) + throws WcsException; + + /** + * @param time + * @return null if time is null + */ + protected Criterion parseTime(DataTime time) { + if (time == null) { + return null; + } + Criterion rval; + if (TemporalFilter.isRange(time)) { + TimeRange period = time.getValidPeriod(); + rval = Restrictions.between(VALID_START, period.getStart(), + period.getEnd()); + } else { + rval = Restrictions.eq(VALID_START, time.getRefTime()); + } + return rval; + } + + @SuppressWarnings("unchecked") + public T querySample(Criterion crit) throws WcsException { + Session sess = null; + try { + PluginDao dao = getDao(); + SessionFactory sessFact = dao.getSessionFactory(); + sess = sessFact.openSession(); + Criteria criteria = sess.createCriteria(props.getRecord()); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + criteria.setMaxResults(1); + criteria.add(crit); + criteria = modCriteria(criteria); + return (T) criteria.uniqueResult(); + } catch (Exception e) { + log.error("Problem querying", e); + throw new WcsException(Code.InternalServerError); + } finally { + if (sess != null) { + sess.close(); + } + } + } + + @SuppressWarnings("unchecked") + public List query(Criterion crit) throws WcsException { + Session sess = null; + try { + PluginDao dao = getDao(); + SessionFactory sessFact = dao.getSessionFactory(); + sess = sessFact.openSession(); + Criteria criteria = sess.createCriteria(props.getRecord()); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + criteria.add(crit); + criteria = modCriteria(criteria); + criteria.addOrder(Order.asc(VALID_START)); + return (List) criteria.list(); + } catch (Exception e) { + log.error("Problem querying", e); + throw new WcsException(Code.InternalServerError); + } finally { + if (sess != null) { + sess.close(); + } + } + } + + /** + * Hook to add aliases to criteria, default is no change + * + * @param criteria + * @return + */ + protected Criteria modCriteria(Criteria criteria) { + return criteria; + } + + /** + * @param identifier + * @return + */ + protected Date getDefaultTime(String identifier) throws WcsException { + try { + SimpleLayer layer = transformer.find(identifier); + return layer.getDefaultTime(); + } catch (OgcException e) { + log.error("Problem accessing layers", e); + throw new WcsException(Code.InternalServerError, e); + } catch (Exception e) { + log.error("Unable to get plugin dao", e); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * @param record + * @param bbox + * @return + * @throws WcsException + */ + protected ReferencedDataRecord getDataRecord(PluginDataObject record, + ReferencedEnvelope bbox) throws WcsException { + try { // get the projected slice from the DAO - ReferencedDataRecord projectedRecord = RecordUtil.getProjected( - getDao(), record, crs, bbox); - - ReferencedDataRecord rval; - if (projectedRecord != null) { - rval = projectedRecord; - } else { - rval = null; - } - - // check if we need to pad ( possibly have no data and need to - // create all "null" response - if (projectedRecord == null) { - // Need all "null" response - Object padValue = getNullPadValue(); - // Make an empty record with the proper data type - IDataRecord emptyRecord = makeEmptyRecord(padValue, "Data-" - + crs.getName().toString(), record.getDataURI()); - // make an envelope for the empty record ( covers no area ) - ReferencedEnvelope emptyEnvelope = new ReferencedEnvelope(0, 0, - 0, 0, crs); - - projectedRecord = new ReferencedDataRecord(emptyRecord, - emptyEnvelope); - - GridGeometry2D dataGridGeom = getGridGeometry(emptyRecord, - emptyEnvelope); - - // send through padder to get all nulls - ReferencedDataRecord resultingRecord = padData(projectedRecord, - dataGridGeom, bbox); - rval = resultingRecord; - - } else if (projectedRecord.getEnvelope().equals(bbox) - || projectedRecord.getEnvelope().contains(bbox)) { - // All is well - } else { - // need to resize (grow only) and pad with nulls - GridGeometry2D dataGridGeom = getGridGeometry( - projectedRecord.getRecord(), - projectedRecord.getEnvelope()); - ReferencedDataRecord resultingRecord = padData(projectedRecord, - dataGridGeom, bbox); - rval = resultingRecord; - - } - - return rval; - } catch (Exception e) { - log.error("Unable to get reprojected data for record: " + record, e); - throw new WcsException(Code.InternalServerError); - } - } - - /** - * @param padValue - * @return - */ - private IDataRecord makeEmptyRecord(Object padValue, String name, - String group) throws WcsException { - - if (padValue instanceof byte[] || padValue instanceof Byte) { - byte[] data = new byte[] {}; - ByteDataRecord record = new ByteDataRecord(name, group, data, 2, - new long[] { 0, 0 }); - return record; - } else if (padValue instanceof float[] || padValue instanceof Float) { - float[] data = new float[] {}; - FloatDataRecord record = new FloatDataRecord(name, group, data, 2, - new long[] { 0, 0 }); - return record; - } else if (padValue instanceof short[] || padValue instanceof Short) { - short[] data = new short[] {}; - ShortDataRecord record = new ShortDataRecord(name, group, data, 2, - new long[] { 0, 0 }); - return record; - } else if (padValue instanceof int[] || padValue instanceof Integer) { - int[] data = new int[] {}; - IntegerDataRecord record = new IntegerDataRecord(name, group, data, - 2, new long[] { 0, 0 }); - return record; - } else if (padValue instanceof long[] || padValue instanceof Long) { - long[] data = new long[] {}; - LongDataRecord record = new LongDataRecord(name, group, data, 2, - new long[] { 0, 0 }); - return record; - } else if (padValue instanceof String[] || padValue instanceof String) { - String[] data = new String[] {}; - StringDataRecord record = new StringDataRecord(name, group, data, - 2, new long[] { 0, 0 }); - return record; - } else { - log.error("bad type when making record, " - + padValue.getClass().toString(), new Exception()); - throw new WcsException(Code.InternalServerError); - } - } - - /** - * @param projectedRecord - * @return - */ - private ReferencedDataRecord padData( - ReferencedDataRecord projectedRecord, GridGeometry2D gridGeom, - Envelope targetEnv) throws WcsException { - if (projectedRecord.getEnvelope().contains(targetEnv)) { - // no need to pad - return projectedRecord; - } else if (projectedRecord.getEnvelope().intersects(targetEnv)) { - // there is some padding - try { - int[][] dataRange = getContainingGridPoints( - gridGeom.getCRSToGrid2D(PixelOrientation.UPPER_LEFT), - projectedRecord.getEnvelope()); - int[][] targetRange = getContainingGridPoints( - gridGeom.getCRSToGrid2D(PixelOrientation.UPPER_LEFT), - targetEnv); - - int[][] padRange = calculatePadRange(dataRange, targetRange); - - int[] dataSize = new int[2]; - - dataSize[0] = (int) projectedRecord.getRecord().getSizes()[0]; - dataSize[1] = (int) projectedRecord.getRecord().getSizes()[1]; - - IDataRecord paddedDataRecord = padDataInternal( - projectedRecord.getRecord(), dataSize, padRange); - - // make an adjusted grid geometry to account for padding - // shift old grid corners by minimum pad - GridGeometry2D adjustedGridGeom = getGridGeometry( - padRange[0][0], dataSize[0] + padRange[0][0] - 1, - padRange[0][1], dataSize[1] + padRange[0][1] - 1, - projectedRecord.getEnvelope()); - - ReferencedEnvelope finalEnvelope = makeReferencedEnvelope( - adjustedGridGeom, paddedDataRecord); - - ReferencedDataRecord record = new ReferencedDataRecord( - paddedDataRecord, finalEnvelope); - - return record; - - } catch (TransformException e) { - log.error("Transform Exception while padding partial record", e); - throw new WcsException(Code.InternalServerError); - } - - } else { - // need 100% nulls - try { - int[][] targetRange = getContainingGridPoints( - gridGeom.getCRSToGrid2D(), targetEnv); - int[] targetDims = new int[] { - Math.abs(targetRange[0][0]) - + Math.abs(targetRange[1][0]), - Math.abs(targetRange[0][1]) - + Math.abs(targetRange[1][1]) }; - int targetSize = targetDims[0] * targetDims[1]; - - IDataRecord record = projectedRecord.getRecord(); - Object sourceData = record.getDataObject(); - - Object targetArray = makeArrayTypeFromRecord(record, targetSize); - - fillArray(targetArray, getNullPadValueFromType(sourceData)); - - IDataRecord paddedDataRecord = makeDataRecordOfSameType(record, - targetArray, 2, new long[] { targetDims[0], - targetDims[1] }); - - ReferencedEnvelope finalEnvelope = makeReferencedEnvelope( - gridGeom, paddedDataRecord); - - ReferencedDataRecord referencedRecord = new ReferencedDataRecord( - paddedDataRecord, finalEnvelope); - - return referencedRecord; - - } catch (TransformException e) { - log.error("Transform Exception while making all null pads", e); - throw new WcsException(Code.InternalServerError); - } - } - } - - /** - * makes a geospatial referenced envelope - * - * @param gridGeom - * @param paddedDataRecord - * @return - */ - protected ReferencedEnvelope makeReferencedEnvelope( - GridGeometry2D gridGeom, IDataRecord dataRecord) - throws WcsException, TransformException { - MathTransform transform = gridGeom - .getGridToCRS(PixelOrientation.UPPER_LEFT); - - DirectPosition srcUpperLeft = new DirectPosition2D(0, 0); - DirectPosition srcLowerRight = new DirectPosition2D( - dataRecord.getSizes()[0], dataRecord.getSizes()[1]); - - try { - DirectPosition destUpperLeft = transform.transform(srcUpperLeft, - null); - DirectPosition destLowerRight = transform.transform(srcLowerRight, - null); - - ReferencedEnvelope rval = new ReferencedEnvelope( - destUpperLeft.getOrdinate(0), - destLowerRight.getOrdinate(0), - destLowerRight.getOrdinate(1), - destUpperLeft.getOrdinate(1), - gridGeom.getCoordinateReferenceSystem()); - - return rval; - } catch (MismatchedDimensionException e) { - log.error( - "error while transforming grid coordinates to referenced envelope", - e); - throw new WcsException(Code.InternalServerError); - } - } - - /** - * @param record - * @param dataSize - * @param padRange - * @return - * @throws WcsBadTypeException - */ - private IDataRecord padDataInternal(IDataRecord record, int[] dataSize, - int[][] padRange) throws WcsException { - - int[] newSize = new int[] { - dataSize[0] + padRange[0][0] + padRange[1][0], - dataSize[1] + padRange[0][1] + padRange[1][1] }; - int newTotalSize = newSize[0] * newSize[1]; - - int dataArraySize = dataSize[0] * dataSize[1]; - - Object sourceData = record.getDataObject(); - - Object targetArray = makeArrayTypeFromRecord(record, newTotalSize); - - fillArray(targetArray, getNullPadValueFromType(sourceData)); - - for (int srcIndex = 0; srcIndex < dataArraySize; ++srcIndex) { - - // get row and column index from data - int srcRow = srcIndex / dataSize[0]; - int srcColumn = srcIndex % dataSize[0]; - - // calculate new row and column - // add min y pad to source row to get destination row - int destRow = padRange[0][1] + srcRow; - // add min x pad to source column for destination column - int destColumn = padRange[0][0] + srcColumn; - - int targetIndex = (destRow * newSize[0]) + destColumn; - - copyValue(sourceData, srcIndex, targetArray, targetIndex); - } - - IDataRecord rval = makeDataRecordOfSameType(record, targetArray, 2, - new long[] { newSize[0], newSize[1] }); - - return rval; - } - - private IDataRecord makeDataRecordOfSameType(IDataRecord record, - Object newDataArray, int dims, long[] sizes) - throws WcsException { - IDataRecord rval = null; - - if (record instanceof ByteDataRecord) { - rval = new ByteDataRecord(record.getName(), record.getGroup(), - (byte[]) newDataArray, dims, sizes); - } else if (record instanceof FloatDataRecord) { - rval = new FloatDataRecord(record.getName(), record.getGroup(), - (float[]) newDataArray, dims, sizes); - } else if (record instanceof IntegerDataRecord) { - rval = new IntegerDataRecord(record.getName(), record.getGroup(), - (int[]) newDataArray, dims, sizes); - } else if (record instanceof LongDataRecord) { - rval = new LongDataRecord(record.getName(), record.getGroup(), - (long[]) newDataArray, dims, sizes); - } else if (record instanceof ShortDataRecord) { - rval = new ShortDataRecord(record.getName(), record.getGroup(), - (short[]) newDataArray, dims, sizes); - } else if (record instanceof StringDataRecord) { - rval = new StringDataRecord(record.getName(), record.getGroup(), - (String[]) newDataArray, dims, sizes); - } else { - log.error("Unknown IDataRecord type. type: " - + record.getClass().toString(), new Exception()); - throw new WcsException(Code.InternalServerError); - } - - return rval; - } - - private Object makeArrayTypeFromRecord(IDataRecord record, int size) - throws WcsException { - Object targetArray = null; - - - if (record instanceof ByteDataRecord) { - targetArray = new byte[size]; - } else if (record instanceof FloatDataRecord) { - targetArray = new float[size]; - } else if (record instanceof IntegerDataRecord) { - targetArray = new int[size]; - } else if (record instanceof LongDataRecord) { - targetArray = new long[size]; - } else if (record instanceof ShortDataRecord) { - targetArray = new short[size]; - } else if (record instanceof StringDataRecord) { - targetArray = new String[size]; - } else { - log.error("Unknown IDataRecord type when making array. type: " - + record.getClass().toString(), new Exception()); - throw new WcsException(Code.InternalServerError); - } - - return targetArray; - } - - /** - * @param sourceData - * @param srcIndex - * @param targetArray - * @param targetIndex - */ - private void copyValue(Object sourceData, int srcIndex, Object targetArray, - int targetIndex) throws WcsException { - - if (sourceData instanceof byte[] && targetArray instanceof byte[]) { - ((byte[]) targetArray)[targetIndex] = ((byte[]) sourceData)[srcIndex]; - } else if (sourceData instanceof float[] - && targetArray instanceof float[]) { - ((float[]) targetArray)[targetIndex] = ((float[]) sourceData)[srcIndex]; - } else if (sourceData instanceof short[] - && targetArray instanceof short[]) { - ((short[]) targetArray)[targetIndex] = ((short[]) sourceData)[srcIndex]; - } else if (sourceData instanceof int[] && targetArray instanceof int[]) { - ((int[]) targetArray)[targetIndex] = ((int[]) sourceData)[srcIndex]; - } else if (sourceData instanceof long[] - && targetArray instanceof long[]) { - ((long[]) targetArray)[targetIndex] = ((long[]) sourceData)[srcIndex]; - } else if (sourceData instanceof String[] - && targetArray instanceof String[]) { - ((String[]) targetArray)[targetIndex] = ((String[]) sourceData)[srcIndex]; - } else { - log.error("bad type when making record, " - + sourceData.getClass().toString() + " and " - + targetArray.getClass().toString(), new Exception( - "bad type when making record")); - throw new WcsException(Code.InternalServerError); - } - - } - - /** - * @param targetArray - * @param nullPadValue - */ - private void fillArray(Object targetArray, Object nullPadValue) - throws WcsException { - - if (targetArray instanceof byte[]) { - Arrays.fill((byte[]) targetArray, ((Byte) nullPadValue).byteValue()); - } else if (targetArray instanceof float[]) { - Arrays.fill((float[]) targetArray, - ((Float) nullPadValue).floatValue()); - } else if (targetArray instanceof short[]) { - Arrays.fill((short[]) targetArray, - ((Short) nullPadValue).shortValue()); - } else if (targetArray instanceof int[]) { - Arrays.fill((int[]) targetArray, - ((Integer) nullPadValue).intValue()); - } else if (targetArray instanceof long[]) { - Arrays.fill((long[]) targetArray, ((Long) nullPadValue).longValue()); - } else if (targetArray instanceof String[]) { - Arrays.fill((String[]) targetArray, (String) nullPadValue); - } else { - log.error("Unknown array type when trying to fill array. type: " - + targetArray.getClass().toString(), new Exception()); - throw new WcsException(Code.InternalServerError); - } - - } - - protected abstract Object getNullPadValue(); - - /** - * @param targetArray - * @return - */ - protected Object getNullPadValueFromType(Object typeOrArray) - throws WcsException { - - if (typeOrArray instanceof byte[]) { - return new Byte((byte) 0); - } else if (typeOrArray instanceof float[]) { - return new Float(0.0f); - } else if (typeOrArray instanceof short[]) { - return new Short((short) 0); - } else if (typeOrArray instanceof int[]) { - return new Integer(0); - } else if (typeOrArray instanceof long[]) { - return new Long(0L); - } else if (typeOrArray instanceof String[]) { - return new String(); - } else { - log.error("Unknown type when getting default fill value. type: " - + typeOrArray.getClass().toString(), new Exception()); - throw new WcsException(Code.InternalServerError); - } - } - - /** - * @param dataRange - * @param targetRange - * @return - */ - private int[][] calculatePadRange(int[][] dataRange, int[][] targetRange) { - // for minimum we expect dataRange to be less than or equal to - // targetRange, if the difference is negative we need to pad - int minxDiff = targetRange[0][0] - dataRange[0][0]; - int minyDiff = targetRange[0][1] - dataRange[0][1]; - // for maximum we expect dataRange to be greater than or equal to - // targetRange, if the difference is positive we need to pad - // swap min/max order because grid and crs count y differently - int maxxDiff = targetRange[1][0] - dataRange[1][0]; - int maxyDiff = targetRange[1][1] - dataRange[1][1]; - - // only pad, do not trim. so we need to check if the dataRange was - // bigger - if (minxDiff > 0) { - minxDiff = 0; - } - if (minyDiff > 0) { - minyDiff = 0; - } - - if (maxxDiff < 0) { - maxxDiff = 0; - } - if (maxyDiff < 0) { - maxyDiff = 0; - } - - return new int[][] { { Math.abs(minxDiff), Math.abs(minyDiff) }, - { Math.abs(maxxDiff), Math.abs(maxyDiff) } }; - } - - protected int[][] getContainingGridPoints(MathTransform2D crsToGrid, - Envelope env) throws TransformException { - DirectPosition lower = new DirectPosition2D(env.getMinX(), - env.getMinY()); - DirectPosition upper = new DirectPosition2D(env.getMaxX(), - env.getMaxY()); - DirectPosition lowerGrid = crsToGrid.transform(lower, null); - DirectPosition upperGrid = crsToGrid.transform(upper, null); - - // make sure to "grow" in the proper direction - - // x axis "direction" is the same in geo and grid - double minx = lowerGrid.getOrdinate(0); - double maxx = upperGrid.getOrdinate(0); - - // y axis "direction" is swapped between geo and grid - double maxy = lowerGrid.getOrdinate(1); - double miny = upperGrid.getOrdinate(1); - - minx = Math.floor(minx); - maxx = Math.ceil(maxx); - - miny = Math.floor(miny); - maxy = Math.ceil(maxy); - - return new int[][] { { (int) minx, (int) miny }, - { (int) maxx, (int) maxy } }; - } - - protected GridGeometry2D getGridGeometry(IDataRecord record, - ReferencedEnvelope env) { - return getGridGeometry(0, (int) record.getSizes()[0] - 1, 0, - (int) record.getSizes()[1] - 1, env); - } - - protected GridGeometry2D getGridGeometry(int gridXmin, int gridXmax, - int gridYmin, int gridYmax, ReferencedEnvelope env) { - GeneralEnvelope genEnvelope = convertEnvelopeToGeneralEnvelope(env); - genEnvelope.setCoordinateReferenceSystem(env - .getCoordinateReferenceSystem()); - GridGeometry2D gridGeom = new GridGeometry2D(new GeneralGridEnvelope( - new int[] { gridXmin, gridYmin }, new int[] { gridXmax, - gridYmax }, true), genEnvelope); - - return gridGeom; - } - - /** - * @param identifier - * @param time - * @return - * @throws WcsException - */ - protected PluginDataObject getRecord(String identifier, DataTime time, - List rangeFields) throws WcsException { - if (time == null) { - time = new DataTime(getDefaultTime(identifier)); - } - String uri = buildUri(identifier, time); - PluginDataObject rval; - try { - PluginDao dao = getDao(); - rval = dao.getMetadata(uri); - } catch (PluginException e) { - log.error("Unable to query metdata", e); - throw new WcsException(Code.InternalServerError); - } - if (rval == null) { - throw new WcsException(Code.LayerNotDefined); - } - return rval; - } - - protected String buildUri(String identifier, DataTime time) { - return ("/" + getKey() + '/' + time + '/' + identifier).replaceAll(" ", - "_"); - } - - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wcs.reg.WcsSource#getKey() - */ - @Override - public String getKey() { - return props.getPluginName(); - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wcs.reg.WcsSource#hasCoverageDescription(java.lang - * .String) - */ - @Override - public boolean hasCoverageDescription(String identifier) { - if (idCache.isEmpty()) { - getCoverageList(true); - } - return idCache.contains(identifier); - } - - /** - * @param coverageList - * list of coverages to add to the Cache - * @param wait - * set to true to wait for the updateThread to complete - */ - protected void updateIdCache(final List coverageList, - boolean wait) { - - if (idUpdateThread == null - || idUpdateThread.getState().equals(State.TERMINATED)) { - idUpdateThread = new Thread() { - public void run() { - for (CoverageDescription cd : coverageList) { - idCache.add(cd.getIdentifier()); - } - }; - }; - } - if (!idUpdateThread.isAlive()) { - idUpdateThread.start(); - if (wait) { - try { - idUpdateThread.join(); - } catch (InterruptedException e) { - log.warn("cache update interrupted", e); - } - } - } - } - - protected GeneralEnvelope convertEnvelopeToGeneralEnvelope( - Envelope env) { - GeneralEnvelope rval = new GeneralEnvelope(2); - rval.setRange(0, env.getMinX(), env.getMaxX()); - rval.setRange(1, env.getMinY(), env.getMaxY()); - return rval; - } + PluginDao dao = getDao(); + ReferencedDataRecord rval = RecordUtil.getProjected(dao, record, + bbox); + + // check if we need to pad ( possibly have no data and need to + // create all "null" response + if (rval == null) { + // Need all "null" response + rval = getFillRecord(record, bbox); + } else if (rval.getEnvelope().equals(bbox) + || rval.getEnvelope().contains((Envelope) bbox)) { + // All is well + } else { + // need to resize (grow only) and pad with nulls + ReferencedDataRecord resultingRecord = padData(rval, bbox); + rval = resultingRecord; + } + + return rval; + } catch (Exception e) { + log.error("Unable to get reprojected data for record: " + record, e); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * Get a referenced data record that is full of fill values. This method + * caches internally. + * + * @param record + * example record that is used as a template + * @param bbox + * target bounds of record + * @return + * @throws WcsException + */ + protected ReferencedDataRecord getFillRecord(PluginDataObject record, + ReferencedEnvelope bbox) throws WcsException { + ISpatialObject spatial = ((ISpatialEnabled) record).getSpatialObject(); + String key = toKey(spatial, bbox); + ReferencedDataRecord rval = fillCache.get(key); + if (rval != null) { + return rval; + } + RequestWrapper req = getSlicedRequest(spatial, bbox); + Point slicedDims = getSlicedDims(req); + IDataRecord sample = getSample(record); + Object array = makeArrayTypeFromRecord(sample, slicedDims.x + * slicedDims.y); + IDataRecord fill = makeDataRecordOfSameType(sample, array, 2, + new long[] { slicedDims.x, slicedDims.y }); + ReferencedDataRecord tmp = new ReferencedDataRecord(fill, req.env); + rval = padData(tmp, bbox); + fillCache.put(key, rval); + return rval; + } + + /** + * Create a cache key from spatial object and target bounds + * + * @param spatial + * @param env + * @return + */ + protected String toKey(ISpatialObject spatial, ReferencedEnvelope env) { + StringBuilder b = new StringBuilder(); + b.append(spatial.getCrs().toWKT()).append(":"); + b.append(spatial.getGeometry().toString()).append(":"); + b.append(spatial.getNx()).append(":"); + b.append(spatial.getNy()).append(":"); + b.append(env.getCoordinateReferenceSystem().toWKT()).append(":"); + b.append(env.toString()); + return b.toString(); + } + + /** + * Get target dimensions for fill record + * + * @param req + * @return + * @throws WcsException + */ + protected Point getSlicedDims(RequestWrapper req) throws WcsException { + int[] maxes = req.req.getMaxIndexForSlab(); + int[] mins = req.req.getMinIndexForSlab(); + return new Point(maxes[0] - mins[0], maxes[1] - mins[1]); + } + + /** + * Get grid bounds and associated bounding box for slice + * + * @param record + * @param bbox + * @return + * @throws WcsException + */ + protected RequestWrapper getSlicedRequest(ISpatialObject spatial, + ReferencedEnvelope bbox) throws WcsException { + try { + ReferencedEnvelope nativeEnvelope = RecordUtil + .getNativeEnvelope(spatial); + RequestWrapper rval = DataReprojector.getRequest(spatial, + nativeEnvelope, bbox); + if (rval == null) { + rval = new RequestWrapper(); + rval.req = Request.buildSlab(new int[] { 0, 0 }, new int[] { 1, + 1 }); + CoordinateReferenceSystem targetCrs = bbox + .getCoordinateReferenceSystem(); + ReferencedEnvelope dataBounds = nativeEnvelope.transform( + targetCrs, true); + double dx = dataBounds.getWidth() / spatial.getNx(); + double dy = dataBounds.getHeight() / spatial.getNy(); + double maxx = bbox.getMinX() + dx; + double maxy = bbox.getMinY() + dy; + rval.env = new ReferencedEnvelope(bbox.getMinX(), maxx, + bbox.getMinY(), maxy, + bbox.getCoordinateReferenceSystem()); + } + return rval; + } catch (Exception e) { + log.error("Unable to make fill record", e); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * Get grid geometry for fill record + * + * @param record + * example record + * @param bbox + * bounds of return + * @return + * @throws WcsException + */ + protected GridGeometry2D getFillGeom(PluginDataObject record, + ReferencedEnvelope bbox) throws WcsException { + ReferencedDataRecord fill = getFillRecord(record, bbox); + IDataRecord rec = fill.getRecord(); + int nx = (int) rec.getSizes()[0]; + int ny = (int) rec.getSizes()[1]; + return getGridGeometry(0, nx - 1, 0, ny - 1, bbox); + } + + /** + * Get small sample from record + * + * @param record + * @return + * @throws WcsException + */ + protected IDataRecord getSample(PluginDataObject record) + throws WcsException { + try { + IDataStore store = getDao().getDataStore((IPersistable) record); + Request request = Request.buildPointRequest(new Point(0, 0)); + return store.retrieve(record.getDataURI(), + DataStoreFactory.DEF_DATASET_NAME, request); + } catch (Exception e) { + log.error("Unable to sample data", e); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * @param projectedRecord + * @return + */ + protected ReferencedDataRecord padData( + ReferencedDataRecord projectedRecord, Envelope targetEnv) + throws WcsException { + GridGeometry2D gridGeom = getGridGeometry(projectedRecord.getRecord(), + projectedRecord.getEnvelope()); + if (projectedRecord.getEnvelope().contains(targetEnv)) { + // no need to pad + return projectedRecord; + } else if (projectedRecord.getEnvelope().intersects(targetEnv)) { + // there is some padding + try { + int[][] dataRange = getContainingGridPoints( + gridGeom.getCRSToGrid2D(PixelOrientation.UPPER_LEFT), + projectedRecord.getEnvelope()); + int[][] targetRange = getContainingGridPoints( + gridGeom.getCRSToGrid2D(PixelOrientation.UPPER_LEFT), + targetEnv); + + int[][] padRange = calculatePadRange(dataRange, targetRange); + + int[] dataSize = new int[2]; + + dataSize[0] = (int) projectedRecord.getRecord().getSizes()[0]; + dataSize[1] = (int) projectedRecord.getRecord().getSizes()[1]; + + IDataRecord paddedDataRecord = padDataInternal( + projectedRecord.getRecord(), dataSize, padRange); + + // make an adjusted grid geometry to account for padding + // shift old grid corners by minimum pad + GridGeometry2D adjustedGridGeom = getGridGeometry( + padRange[0][0], dataSize[0] + padRange[0][0] - 1, + padRange[0][1], dataSize[1] + padRange[0][1] - 1, + projectedRecord.getEnvelope()); + + ReferencedEnvelope finalEnvelope = makeReferencedEnvelope( + adjustedGridGeom, paddedDataRecord); + + ReferencedDataRecord record = new ReferencedDataRecord( + paddedDataRecord, finalEnvelope); + + return record; + + } catch (TransformException e) { + log.error("Transform Exception while padding partial record", e); + throw new WcsException(Code.InternalServerError); + } + + } else { + // need 100% nulls + try { + int[][] targetRange = getContainingGridPoints( + gridGeom.getCRSToGrid2D(), targetEnv); + int[] targetDims = new int[] { + Math.abs(targetRange[0][0]) + + Math.abs(targetRange[1][0]), + Math.abs(targetRange[0][1]) + + Math.abs(targetRange[1][1]) }; + int targetSize = targetDims[0] * targetDims[1]; + + IDataRecord record = projectedRecord.getRecord(); + + Object targetArray = makeArrayTypeFromRecord(record, targetSize); + + fillArray(targetArray); + + IDataRecord paddedDataRecord = makeDataRecordOfSameType(record, + targetArray, 2, new long[] { targetDims[0], + targetDims[1] }); + + ReferencedEnvelope finalEnvelope = makeReferencedEnvelope( + gridGeom, paddedDataRecord); + + ReferencedDataRecord referencedRecord = new ReferencedDataRecord( + paddedDataRecord, finalEnvelope); + + return referencedRecord; + + } catch (TransformException e) { + log.error("Transform Exception while making all null pads", e); + throw new WcsException(Code.InternalServerError); + } + } + } + + /** + * makes a geospatial referenced envelope + * + * @param gridGeom + * @param paddedDataRecord + * @return + */ + protected ReferencedEnvelope makeReferencedEnvelope( + GridGeometry2D gridGeom, IDataRecord dataRecord) + throws WcsException, TransformException { + MathTransform transform = gridGeom + .getGridToCRS(PixelOrientation.UPPER_LEFT); + + DirectPosition srcUpperLeft = new DirectPosition2D(0, 0); + DirectPosition srcLowerRight = new DirectPosition2D( + dataRecord.getSizes()[0], dataRecord.getSizes()[1]); + + try { + DirectPosition destUpperLeft = transform.transform(srcUpperLeft, + null); + DirectPosition destLowerRight = transform.transform(srcLowerRight, + null); + + ReferencedEnvelope rval = new ReferencedEnvelope( + destUpperLeft.getOrdinate(0), + destLowerRight.getOrdinate(0), + destLowerRight.getOrdinate(1), + destUpperLeft.getOrdinate(1), + gridGeom.getCoordinateReferenceSystem()); + + return rval; + } catch (MismatchedDimensionException e) { + log.error( + "error while transforming grid coordinates to referenced envelope", + e); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * @param record + * @param dataSize + * @param padRange + * @return + * @throws WcsBadTypeException + */ + protected IDataRecord padDataInternal(IDataRecord record, int[] dataSize, + int[][] padRange) throws WcsException { + + int[] newSize = new int[] { + dataSize[0] + padRange[0][0] + padRange[1][0], + dataSize[1] + padRange[0][1] + padRange[1][1] }; + int newTotalSize = newSize[0] * newSize[1]; + + int dataArraySize = dataSize[0] * dataSize[1]; + + Object sourceData = record.getDataObject(); + + Object targetArray = makeArrayTypeFromRecord(record, newTotalSize); + fillArray(targetArray); + + for (int srcIndex = 0; srcIndex < dataArraySize; ++srcIndex) { + + // get row and column index from data + int srcRow = srcIndex / dataSize[0]; + int srcColumn = srcIndex % dataSize[0]; + + // calculate new row and column + // add min y pad to source row to get destination row + int destRow = padRange[0][1] + srcRow; + // add min x pad to source column for destination column + int destColumn = padRange[0][0] + srcColumn; + + int targetIndex = (destRow * newSize[0]) + destColumn; + + copyValue(sourceData, srcIndex, targetArray, targetIndex); + } + + IDataRecord rval = makeDataRecordOfSameType(record, targetArray, 2, + new long[] { newSize[0], newSize[1] }); + + return rval; + } + + /** + * @param record + * @param newDataArray + * @param dims + * @param sizes + * @return + * @throws WcsException + */ + protected IDataRecord makeDataRecordOfSameType(IDataRecord record, + Object newDataArray, int dims, long[] sizes) throws WcsException { + IDataRecord rval = null; + + if (record instanceof ByteDataRecord) { + rval = new ByteDataRecord(record.getName(), record.getGroup(), + (byte[]) newDataArray, dims, sizes); + } else if (record instanceof FloatDataRecord) { + rval = new FloatDataRecord(record.getName(), record.getGroup(), + (float[]) newDataArray, dims, sizes); + } else if (record instanceof IntegerDataRecord) { + rval = new IntegerDataRecord(record.getName(), record.getGroup(), + (int[]) newDataArray, dims, sizes); + } else if (record instanceof LongDataRecord) { + rval = new LongDataRecord(record.getName(), record.getGroup(), + (long[]) newDataArray, dims, sizes); + } else if (record instanceof ShortDataRecord) { + rval = new ShortDataRecord(record.getName(), record.getGroup(), + (short[]) newDataArray, dims, sizes); + } else if (record instanceof StringDataRecord) { + rval = new StringDataRecord(record.getName(), record.getGroup(), + (String[]) newDataArray, dims, sizes); + } else { + log.error("Unknown IDataRecord type. type: " + + record.getClass().toString(), new Exception()); + throw new WcsException(Code.InternalServerError); + } + + return rval; + } + + /** + * @param record + * @param size + * @return + * @throws WcsException + */ + protected Object makeArrayTypeFromRecord(IDataRecord record, int size) + throws WcsException { + Object targetArray = null; + + if (record instanceof ByteDataRecord) { + targetArray = new byte[size]; + byte fill = new ByteDataReprojector().getFill(); + Arrays.fill((byte[]) targetArray, fill); + } else if (record instanceof FloatDataRecord) { + targetArray = new float[size]; + float fill = new FloatDataReprojector().getFill(); + Arrays.fill((float[]) targetArray, fill); + } else if (record instanceof IntegerDataRecord) { + targetArray = new int[size]; + int fill = new IntDataReprojector().getFill(); + Arrays.fill((int[]) targetArray, fill); + } else if (record instanceof LongDataRecord) { + targetArray = new long[size]; + long fill = 0l; + Arrays.fill((long[]) targetArray, fill); + } else if (record instanceof ShortDataRecord) { + targetArray = new short[size]; + short fill = new ShortDataReprojector().getFill(); + Arrays.fill((short[]) targetArray, fill); + } else if (record instanceof StringDataRecord) { + targetArray = new String[size]; + } else { + log.error("Unknown IDataRecord type when making array. type: " + + record.getClass().toString(), new Exception()); + throw new WcsException(Code.InternalServerError); + } + + return targetArray; + } + + /** + * Get fill value for record + * + * @param record + * @return + * @throws WcsException + */ + protected Number getFillValue(T record) throws WcsException { + IDataRecord sample = getSample(record); + if (sample instanceof ByteDataRecord) { + return new ByteDataReprojector().getFill(); + } else if (sample instanceof FloatDataRecord) { + return new FloatDataReprojector().getFill(); + } else if (sample instanceof IntegerDataRecord) { + return new IntDataReprojector().getFill(); + } else if (sample instanceof LongDataRecord) { + return 0l; + } else if (sample instanceof ShortDataRecord) { + return new ShortDataReprojector().getFill(); + } else { + log.error( + "Unknown IDataRecord type when getting fill value. type: " + + record.getClass().toString(), new Exception()); + throw new WcsException(Code.InternalServerError); + } + } + + /** + * @param sourceData + * @param srcIndex + * @param targetArray + * @param targetIndex + */ + protected void copyValue(Object sourceData, int srcIndex, + Object targetArray, int targetIndex) throws WcsException { + + if (sourceData instanceof byte[] && targetArray instanceof byte[]) { + ((byte[]) targetArray)[targetIndex] = ((byte[]) sourceData)[srcIndex]; + } else if (sourceData instanceof float[] + && targetArray instanceof float[]) { + ((float[]) targetArray)[targetIndex] = ((float[]) sourceData)[srcIndex]; + } else if (sourceData instanceof short[] + && targetArray instanceof short[]) { + ((short[]) targetArray)[targetIndex] = ((short[]) sourceData)[srcIndex]; + } else if (sourceData instanceof int[] && targetArray instanceof int[]) { + ((int[]) targetArray)[targetIndex] = ((int[]) sourceData)[srcIndex]; + } else if (sourceData instanceof long[] + && targetArray instanceof long[]) { + ((long[]) targetArray)[targetIndex] = ((long[]) sourceData)[srcIndex]; + } else if (sourceData instanceof String[] + && targetArray instanceof String[]) { + ((String[]) targetArray)[targetIndex] = ((String[]) sourceData)[srcIndex]; + } else { + log.error("bad type when making record, " + + sourceData.getClass().toString() + " and " + + targetArray.getClass().toString(), new Exception( + "bad type when making record")); + throw new WcsException(Code.InternalServerError); + } + + } + + /** + * @param targetArray + * @param nullPadValue + */ + protected void fillArray(Object targetArray) throws WcsException { + + if (targetArray instanceof byte[]) { + byte fill = new ByteDataReprojector().getFill(); + Arrays.fill((byte[]) targetArray, fill); + } else if (targetArray instanceof float[]) { + float fill = new FloatDataReprojector().getFill(); + Arrays.fill((float[]) targetArray, fill); + } else if (targetArray instanceof short[]) { + short fill = new ShortDataReprojector().getFill(); + Arrays.fill((short[]) targetArray, fill); + } else if (targetArray instanceof int[]) { + int fill = new IntDataReprojector().getFill(); + Arrays.fill((int[]) targetArray, fill); + } else if (targetArray instanceof long[]) { + long fill = 0l; + Arrays.fill((long[]) targetArray, fill); + } else { + log.error("Unknown array type when trying to fill array. type: " + + targetArray.getClass().toString(), new Exception()); + throw new WcsException(Code.InternalServerError); + } + + } + + /** + * @param dataRange + * @param targetRange + * @return + */ + protected int[][] calculatePadRange(int[][] dataRange, int[][] targetRange) { + // for minimum we expect dataRange to be less than or equal to + // targetRange, if the difference is negative we need to pad + int minxDiff = targetRange[0][0] - dataRange[0][0]; + int minyDiff = targetRange[0][1] - dataRange[0][1]; + // for maximum we expect dataRange to be greater than or equal to + // targetRange, if the difference is positive we need to pad + // swap min/max order because grid and crs count y differently + int maxxDiff = targetRange[1][0] - dataRange[1][0]; + int maxyDiff = targetRange[1][1] - dataRange[1][1]; + + // only pad, do not trim. so we need to check if the dataRange was + // bigger + if (minxDiff > 0) { + minxDiff = 0; + } + if (minyDiff > 0) { + minyDiff = 0; + } + + if (maxxDiff < 0) { + maxxDiff = 0; + } + if (maxyDiff < 0) { + maxyDiff = 0; + } + + return new int[][] { { Math.abs(minxDiff), Math.abs(minyDiff) }, + { Math.abs(maxxDiff), Math.abs(maxyDiff) } }; + } + + /** + * @param crsToGrid + * @param env + * @return + * @throws TransformException + */ + protected int[][] getContainingGridPoints(MathTransform2D crsToGrid, + Envelope env) throws TransformException { + DirectPosition lower = new DirectPosition2D(env.getMinX(), + env.getMinY()); + DirectPosition upper = new DirectPosition2D(env.getMaxX(), + env.getMaxY()); + DirectPosition lowerGrid = crsToGrid.transform(lower, null); + DirectPosition upperGrid = crsToGrid.transform(upper, null); + + // make sure to "grow" in the proper direction + + // x axis "direction" is the same in geo and grid + double minx = lowerGrid.getOrdinate(0); + double maxx = upperGrid.getOrdinate(0); + + // y axis "direction" is swapped between geo and grid + double maxy = lowerGrid.getOrdinate(1); + double miny = upperGrid.getOrdinate(1); + + minx = Math.round(minx); + maxx = Math.round(maxx); + + miny = Math.round(miny); + maxy = Math.round(maxy); + + return new int[][] { { (int) minx, (int) miny }, + { (int) maxx, (int) maxy } }; + } + + /** + * @param ref + * @return + */ + protected GridGeometry2D getGridGeometry(ReferencedDataRecord ref) { + return getGridGeometry(ref.getRecord(), ref.getEnvelope()); + } + + /** + * @param record + * @param env + * @return + */ + protected GridGeometry2D getGridGeometry(IDataRecord record, + ReferencedEnvelope env) { + return getGridGeometry(0, (int) record.getSizes()[0] - 1, 0, + (int) record.getSizes()[1] - 1, env); + } + + /** + * @param gridXmin + * @param gridXmax + * @param gridYmin + * @param gridYmax + * @param env + * @return + */ + protected GridGeometry2D getGridGeometry(int gridXmin, int gridXmax, + int gridYmin, int gridYmax, ReferencedEnvelope env) { + GeneralEnvelope genEnvelope = convertEnvelopeToGeneralEnvelope(env); + genEnvelope.setCoordinateReferenceSystem(env + .getCoordinateReferenceSystem()); + GridGeometry2D gridGeom = new GridGeometry2D(new GeneralGridEnvelope( + new int[] { gridXmin, gridYmin }, new int[] { gridXmax, + gridYmax }, true), genEnvelope); + + return gridGeom; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.reg.WcsSource#getKey() + */ + @Override + public String getKey() { + return props.getPluginName(); + } + + /** + * @param env + * @return + */ + protected GeneralEnvelope convertEnvelopeToGeneralEnvelope(Envelope env) { + GeneralEnvelope rval = new GeneralEnvelope(2); + rval.setRange(0, env.getMinX(), env.getMaxX()); + rval.setRange(1, env.getMinY(), env.getMaxY()); + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wcs.reg.WcsSource#hasId(java.lang.String) + */ + @Override + public boolean hasCoverage(String id) throws WcsException { + try { + return transformer.find(URNLookup.urnToLocal(id)) != null; + } catch (OgcException e) { + log.error("problem finding coverage", e); + throw new WcsException(e); + } + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/FieldAdapterFactory.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/FieldAdapterFactory.java new file mode 100644 index 0000000000..6677e006e6 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/FieldAdapterFactory.java @@ -0,0 +1,90 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.context.ApplicationContext; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.core.EDEXUtil; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalSpatialFactory; + +/** + * Factory for getting coverage field for plugin data object + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 5, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class FieldAdapterFactory { + private static Map, IFieldAdapted> REGISTRY = null; + + private static final IUFStatusHandler log = UFStatus + .getHandler(FieldAdapterFactory.class); + + private static final class Init implements Runnable { + @Override + public void run() { + while (!EDEXUtil.isRunning()) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + } + } + try { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx.getBeanNamesForType(IFieldAdapted.class); + HashMap, IFieldAdapted> map = new HashMap, IFieldAdapted>( + beans.length); + for (String bean : beans) { + IFieldAdapted fa = (IFieldAdapted) ctx.getBean(bean); + map.put(fa.getSupportedClass(), fa); + } + REGISTRY = Collections.unmodifiableMap(map); + } catch (Throwable e) { + log.error("Unable to init " + VerticalSpatialFactory.class, e); + } + } + } + + static { + new Thread(new Init()).start(); + } + + /** + * @param c + * @return null if factory isn't initialized or no adapter found for c + */ + @SuppressWarnings("unchecked") + public static IFieldAdapted getAdapted(Class c) { + if (REGISTRY == null) { + return null; + } + return (IFieldAdapted) REGISTRY.get(c); + } + + public static boolean isInitialized() { + return REGISTRY != null; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IDataRecordFetcher.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IDataRecordFetcher.java new file mode 100644 index 0000000000..0330050c69 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IDataRecordFetcher.java @@ -0,0 +1,53 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + **/ +package com.raytheon.uf.edex.wcs.reg; + +import com.raytheon.uf.common.spatial.reprojection.ReferencedDataRecord; +import com.raytheon.uf.edex.wcs.WcsException; + +/** + * Data Record Fetcher for WCS + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 3, 2013            bclement     Initial creation
+ * Aug 18, 2013 #2097      dhladky     interface standards
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface IDataRecordFetcher { + + /** + * @param cache + * true if the record will likely be retrieved again + * @return + * @throws Exception + */ + public ReferencedDataRecord get(boolean cache) throws WcsException; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IFieldAdapted.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IFieldAdapted.java new file mode 100644 index 0000000000..74e1e9b3aa --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IFieldAdapted.java @@ -0,0 +1,53 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + **/ +package com.raytheon.uf.edex.wcs.reg; + +/** + * Adapter for coverage field information + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 5, 2013            bclement     Initial creation
+ * Aug 18, 2013 #2097      dhladky     interface standards
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface IFieldAdapted { + + /** + * @param obj + * @return + */ + public String getCoverageField(T obj); + + /** + * @return class supported by adapter + */ + public Class getSupportedClass(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IWcsSource.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IWcsSource.java new file mode 100644 index 0000000000..4559fab702 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/IWcsSource.java @@ -0,0 +1,68 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * May 5, 2011 bclement Initial creation + * Aug 18, 2013 #2097 dhladky interface standards + * + */ + +package com.raytheon.uf.edex.wcs.reg; + +import java.util.List; + +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.edex.ogc.common.db.SimpleDimension; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; +import com.raytheon.uf.edex.wcs.WcsException; + +public interface IWcsSource> { + + /** + * long name attribute for coverages + */ + public static final String LONG_NAME_ATTR = "long_name"; + + public List listCoverages(boolean summary); + + public CoverageDescription describeCoverage(String identifier) + throws WcsException; + + public CoverageTransform getCoverageTransform(); + + public Coverage getCoverage(String identifier, DataTime time, + Composite3DBoundingBox bbox, List rangeFields) + throws WcsException; + + public String getKey(); + + public boolean hasCoverage(String id) throws WcsException; + + /** + * @param c + * extension class + * @return extension object for class, null if none registered + */ + public T getExtension(Class c); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/TemporalCube.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/TemporalCube.java new file mode 100644 index 0000000000..781a8f56a7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/TemporalCube.java @@ -0,0 +1,130 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 2, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class TemporalCube implements Comparable { + + private final List slices; + + private final Date time; + + private final CoverageZAxis zAxis; + + /** + * + */ + public TemporalCube(Date time, CoverageZAxis zAxis) { + this(new ArrayList(), time, zAxis); + } + + /** + * @param cube + */ + public TemporalCube(List slices, Date time, + CoverageZAxis zAxis) { + this.slices = slices; + this.time = time; + this.zAxis = zAxis; + } + + /** + * @return the cube + */ + public List getSlices() { + return slices; + } + + public void add(VerticalSlice slice) { + this.slices.add(slice); + } + + /** + * @return the time + */ + public Date getTime() { + return time; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((time == null) ? 0 : time.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TemporalCube other = (TemporalCube) obj; + if (time == null) { + if (other.time != null) + return false; + } else if (!time.equals(other.time)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(TemporalCube o) { + if (o == null) { + return 1; + } + return this.time.compareTo(o.time); + } + + /** + * @return the zAxis + */ + public CoverageZAxis getzAxis() { + return zAxis; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/VerticalSlice.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/VerticalSlice.java new file mode 100644 index 0000000000..e8803f3651 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/VerticalSlice.java @@ -0,0 +1,105 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.reg; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Apr 2, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class VerticalSlice implements Comparable { + + private final IDataRecordFetcher record; + + private final double level; + + /** + * @param record + * @param level + */ + public VerticalSlice(IDataRecordFetcher record, double level) { + this.record = record; + this.level = level; + } + + /** + * @return the record + */ + public IDataRecordFetcher getRecord() { + return record; + } + + /** + * @return the level + */ + public double getLevel() { + return level; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(level); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + VerticalSlice other = (VerticalSlice) obj; + if (Double.doubleToLongBits(level) != Double + .doubleToLongBits(other.level)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(VerticalSlice o) { + if (o == null) { + return 1; + } + return Double.compare(this.level, o.level); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/WcsSource.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/WcsSource.java deleted file mode 100644 index 4234c1cffa..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/WcsSource.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * May 5, 2011 bclement Initial creation - * - */ - -package com.raytheon.uf.edex.wcs.reg; - -import java.util.List; - -import org.opengis.referencing.crs.CoordinateReferenceSystem; - -import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.edex.wcs.WcsException; -import com.vividsolutions.jts.geom.Envelope; - -public interface WcsSource { - - public List listCoverages(); - - public CoverageDescription describeCoverage(String identifier) - throws WcsException; - - public Coverage getCoverage(String identifier, DataTime time, - CoordinateReferenceSystem crs, Envelope bbox, - List rangeFields) throws WcsException; - - public String getKey(); - - /** - * Get a quick true or false answer to the question - * "Does this WcsSource have a coverage description for this id" - *

- * Implementations should maintain a cache of valid identifiers so that this - * lookup is performed quickly. A for-loop is not a recommended solution. - * - * @param identifier - * @return true if the wcs source has a coverage description for the given - * identifier, false otherwise - */ - public boolean hasCoverageDescription(String identifier); -} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/WcsSourceAccessor.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/WcsSourceAccessor.java index b2a5d198ea..03c81d8274 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/WcsSourceAccessor.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/reg/WcsSourceAccessor.java @@ -31,11 +31,18 @@ package com.raytheon.uf.edex.wcs.reg; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.springframework.context.ApplicationContext; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.core.EDEXUtil; +import com.raytheon.uf.edex.wcs.WcsException; +import com.raytheon.uf.edex.wcs.format.IWcsDataFormatter; /** * @@ -44,27 +51,109 @@ import com.raytheon.uf.edex.core.EDEXUtil; */ public class WcsSourceAccessor { - public synchronized List getCoverages() { - ApplicationContext ctx = EDEXUtil.getSpringContext(); - String[] beans = ctx.getBeanNamesForType(WcsSource.class); - List cd = new ArrayList( - beans.length); - for (String bean : beans) { - WcsSource s = (WcsSource) ctx.getBean(bean); - cd.addAll(s.listCoverages()); - } - return cd; - } + private static Map> cache; - public synchronized WcsSource getSource(String id) { - ApplicationContext ctx = EDEXUtil.getSpringContext(); - String[] beans = ctx.getBeanNamesForType(WcsSource.class); - for (String bean : beans) { - WcsSource s = (WcsSource) ctx.getBean(bean); - if (s.hasCoverageDescription(id)) { - return s; - } - } - return null; - } + private static Map formatMap; + + private static IUFStatusHandler log = UFStatus + .getHandler(WcsSourceAccessor.class); + + private WcsSourceAccessor() { + + } + + static { + new Thread(new Runnable() { + @Override + public void run() { + while (!EDEXUtil.isRunning()) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + } + } + try { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx.getBeanNamesForType(IWcsSource.class); + cache = new HashMap>(beans.length); + for (String bean : beans) { + IWcsSource s = (IWcsSource) ctx + .getBean(bean); + cache.put(s.getKey(), s); + } + } catch (Throwable e) { + log.error("Unable to init wcs sources", e); + } + try { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx + .getBeanNamesForType(IWcsDataFormatter.class); + HashMap map = new HashMap( + beans.length); + for (String bean : beans) { + IWcsDataFormatter df = (IWcsDataFormatter) ctx + .getBean(bean); + map.put(df.getIdentifier(), df); + } + formatMap = Collections.unmodifiableMap(map); + } catch (Throwable e) { + log.error("Unable to init wcs formats", e); + } + } + }).run(); + } + + /** + * @param summary + * @return empty list if accessor isn't initialized + */ + public static List getCoverages(boolean summary) { + if (cache == null) { + return new ArrayList(0); + } + List cd = new ArrayList(); + for (String key : cache.keySet()) { + IWcsSource s = cache.get(key); + cd.addAll(s.listCoverages(summary)); + } + return cd; + } + + /** + * @param id + * @return null if source is not found or accessor isn't initialized + * @throws WcsException + */ + public static IWcsSource getSource(String id) throws WcsException { + if (cache == null) { + return null; + } + for (String key : cache.keySet()) { + IWcsSource s = cache.get(key); + if (s.hasCoverage(id)) { + return s; + } + } + return null; + } + + /** + * @return empty map if accessor isn't initialized + */ + public static Map getFormatMap() { + if (formatMap == null) { + return new HashMap(0); + } + return formatMap; + } + + /** + * @return empty list if accessor isn't initialized + */ + public static List getFormats() { + if (formatMap == null) { + return new ArrayList(0); + } + return new ArrayList(formatMap.keySet()); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/DescCoverageRequest.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/DescCoverageRequest.java index 831095d581..f2c4024f49 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/DescCoverageRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/DescCoverageRequest.java @@ -30,6 +30,9 @@ */ package com.raytheon.uf.edex.wcs.request; +import java.util.List; + +import net.opengis.wcs.v_1_1_2.DescribeCoverage; public class DescCoverageRequest extends WcsRequest{ @@ -41,6 +44,13 @@ public class DescCoverageRequest extends WcsRequest{ super(Type.DescribeCoverage); } + public DescCoverageRequest(DescribeCoverage req) { + super(Type.DescribeCoverage); + this.request = req; + List ids = req.getIdentifier(); + identifiers = ids.toArray(new String[ids.size()]); + } + public String getOutputformat() { return outputformat; } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/GetCoverageRequest.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/GetCoverageRequest.java index d88ca42163..30ed88c999 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/GetCoverageRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/GetCoverageRequest.java @@ -30,133 +30,447 @@ */ package com.raytheon.uf.edex.wcs.request; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashSet; import java.util.List; +import javax.xml.bind.DatatypeConverter; + +import net.opengis.gml.v_3_1_1.EnvelopeType; +import net.opengis.gml.v_3_1_1.TimeInstantPropertyType; +import net.opengis.gml.v_3_1_1.TimeInstantType; +import net.opengis.gml.v_3_1_1.TimePeriodPropertyType; +import net.opengis.gml.v_3_1_1.TimePeriodType; +import net.opengis.gml.v_3_1_1.TimePositionType; +import net.opengis.ows.v_1_1_0.BoundingBoxType; +import net.opengis.wcs.v_1_1_2.AxisSubset; +import net.opengis.wcs.v_1_1_2.DomainSubsetType; +import net.opengis.wcs.v_1_1_2.GetCoverage; +import net.opengis.wcs.v_1_1_2.GridCrsType; +import net.opengis.wcs.v_1_1_2.OutputType; +import net.opengis.wcs.v_1_1_2.RangeSubsetType; +import net.opengis.wcs.v_1_1_2.RangeSubsetType.FieldSubset; +import net.opengis.wcs.v_1_1_2.TimeSequenceType; + +import org.geotools.geometry.jts.ReferencedEnvelope; + import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; +import com.raytheon.uf.common.time.TimeRange; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.gml3_1_1.EnvelopeConverter; +import com.raytheon.uf.edex.ogc.common.spatial.BoundingBoxUtil; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; +import com.raytheon.uf.edex.wcs.WcsException; +import com.raytheon.uf.edex.wcs.reg.RangeAxis; import com.raytheon.uf.edex.wcs.reg.RangeField; public class GetCoverageRequest extends WcsRequest { - protected String identifier; + protected String identifier; - protected String format; + protected String format; - protected OgcBoundingBox bbox; + protected Composite3DBoundingBox bbox; - protected List fields; + protected List fields; - protected boolean store = false; + protected boolean store = false; - protected DataTime timeSequence; + protected DataTime timeSequence; - protected String gridBaseCrs; + protected String gridBaseCrs; - protected String gridType; + protected String gridType; - protected List gridOrigin; + protected List gridOrigin; - protected List gridOffsets; + protected List gridOffsets; - protected boolean defacto = false; + protected boolean defacto = false; - public GetCoverageRequest() { - super(Type.GetCoverage); - } + public GetCoverageRequest() { + super(Type.GetCoverage); + } - public String getIdentifier() { - return identifier; - } + public GetCoverageRequest(GetCoverage req) throws Exception { + super(Type.GetCoverage); + this.request = req; + if (req.isSetIdentifier()) { + this.identifier = req.getIdentifier().getValue(); + } + if (req.isSetOutput()) { + setOutput(req.getOutput()); + } + if (req.isSetDomainSubset()) { + setDomain(req.getDomainSubset()); + } + if (req.isSetRangeSubset()) { + setRange(req.getRangeSubset()); + } + } - public void setIdentifier(String identifier) { - this.identifier = identifier; - } + /** + * Set range fields from jaxb object + * + * @param rangeSubset + */ + private void setRange(RangeSubsetType range) { + List subsets = range.getFieldSubset(); + if (subsets == null) { + return; + } + this.fields = new ArrayList(subsets.size()); + for (FieldSubset sub : subsets) { + this.fields.add(getField(sub)); + } + } - public String getFormat() { - return format; - } + /** + * Convert jaxb field object to internal representation + * + * @param sub + * @return + */ + private RangeField getField(FieldSubset sub) { + String id = sub.getIdentifier().getValue(); + RangeField rval = new RangeField(id, null); + List axisList = sub.getAxisSubset(); + List target = new ArrayList(axisList.size()); + for (AxisSubset axis : axisList) { + String axisId = axis.getIdentifier(); + List keys = axis.getKey(); + target.add(new RangeAxis(axisId, new HashSet(keys))); + } + rval.setAxis(target); + return rval; + } - public void setFormat(String format) { - this.format = format; - } + /** + * Set domain from jaxb object + * + * @param domain + * @throws Exception + */ + private void setDomain(DomainSubsetType domain) throws WcsException { + if (domain.isSetBoundingBox()) { + try { + Object obj = domain.getBoundingBox().getValue(); + if (obj instanceof EnvelopeType) { + setBbox((EnvelopeType) obj); + } else if (obj instanceof BoundingBoxType) { + setBbox((BoundingBoxType) obj); + } else { + throw new IllegalArgumentException(); + } + } catch (OgcException e) { + throw new WcsException(e); + } + } + if (domain.isSetTemporalSubset()) { + TimeSequenceType tseq = domain.getTemporalSubset(); + setTime(tseq); + } + } - public OgcBoundingBox getBbox() { - return bbox; - } + /** + * Set bounding box from jaxb object + * + * @param etype + * @throws OgcException + */ + public void setBbox(EnvelopeType etype) throws OgcException { + if (EnvelopeConverter.getDims(etype) == 2) { + ReferencedEnvelope ref = BoundingBoxUtil.convert2D(etype); + this.bbox = new Composite3DBoundingBox(ref); + } else if (EnvelopeConverter.getDims(etype) == 3) { + this.bbox = BoundingBoxUtil.separate3DEnvelope(etype); + } else { + throw new OgcException( + com.raytheon.uf.edex.ogc.common.OgcException.Code.InvalidCRS, + "Unsupported number of dimensions"); + } + } - public void setBbox(OgcBoundingBox bbox) { - this.bbox = bbox; - } + /** + * Set bounding box from jaxb object + * + * @param bbt + * @throws OgcException + */ + public void setBbox(BoundingBoxType bbt) throws OgcException { + int dims = bbt.getLowerCorner().size(); + if (dims == 2) { + this.bbox = new Composite3DBoundingBox( + BoundingBoxUtil.convert2D(bbt)); + } else if (dims == 3) { + this.bbox = BoundingBoxUtil.separate3DEnvelope(bbt); + } else { + throw new OgcException( + com.raytheon.uf.edex.ogc.common.OgcException.Code.InvalidCRS, + "Unsupported number of dimensions"); + } + } - public List getFields() { - return fields; - } + /** + * Set time from jaxb object + * + * @param tseq + */ + private void setTime(TimeSequenceType tseq) { + List times = parseTime(tseq); + if (!times.isEmpty()) { + // TODO handle multiple times + this.timeSequence = times.get(0); + } + } - public void setFields(List fields) { - this.fields = fields; - } + /** + * Convert jaxb time sequence into internal representation. + * + * Returned data times will have instances in the refTime field and ranges + * in the valid range field + * + * @param tseq + * @return + */ + public static List parseTime(TimeSequenceType tseq) { + if (!tseq.isSetTimePositionOrTimePeriod()) { + return new ArrayList(0); + } + List times = tseq.getTimePositionOrTimePeriod(); + List rval = new ArrayList(times.size()); + for (Object obj : times) { + if (obj instanceof TimeInstantType) { + TimeInstantType inst = (TimeInstantType) obj; + rval.add(getInstant(inst.getTimePosition())); + } else if (obj instanceof TimePositionType) { + rval.add(getInstant((TimePositionType) obj)); + } else if (obj instanceof TimeInstantPropertyType) { + TimeInstantPropertyType prop = (TimeInstantPropertyType) obj; + TimeInstantType inst = prop.getTimeInstant(); + rval.add(getInstant(inst.getTimePosition())); + } else if (obj instanceof TimePeriodType) { + TimePeriodType period = (TimePeriodType) obj; + rval.add(getPeriod(period)); + } else if (obj instanceof TimePeriodPropertyType) { + TimePeriodPropertyType prop = (TimePeriodPropertyType) obj; + rval.add(getPeriod(prop.getTimePeriod())); + } else if (obj instanceof net.opengis.wcs.v_1_1_2.TimePeriodType) { + rval.add(getPeriod((net.opengis.wcs.v_1_1_2.TimePeriodType) obj)); + } + } + return rval; + } - public boolean isStore() { - return store; - } + /** + * Convert jaxb time position to data time + * + * Returned data time will have position value in refTime field + * + * @param pos + * @return + */ + private static DataTime getInstant(TimePositionType pos) { + return new DataTime(getTime(pos)); + } - public void setStore(boolean store) { - this.store = store; - } + /** + * Convert jaxb time period to data time + * + * returned data time will have period value in valid period field + * + * @param period + * @return + */ + private static DataTime getPeriod( + net.opengis.wcs.v_1_1_2.TimePeriodType period) { + TimePositionType begin = period.getBeginPosition(); + TimePositionType end = period.getEndPosition(); + return getPeriod(begin, end); + } - public DataTime getTimeSequence() { - return timeSequence; - } + /** + * Convert jaxb time period to data time + * + * returned data time will have period value in valid period field + * + * @param period + * @return + */ + private static DataTime getPeriod(TimePeriodType period) { + TimePositionType begin; + TimePositionType end; + if (period.isSetBegin()) { + TimeInstantPropertyType b = period.getBegin(); + TimeInstantType inst = b.getTimeInstant(); + begin = inst.getTimePosition(); + } else if (period.isSetBeginPosition()) { + begin = period.getBeginPosition(); + } else { + throw new IllegalArgumentException("No begin found in period"); + } + if (period.isSetEnd()) { + TimeInstantPropertyType b = period.getEnd(); + TimeInstantType inst = b.getTimeInstant(); + end = inst.getTimePosition(); + } else if (period.isSetEndPosition()) { + end = period.getEndPosition(); + } else { + throw new IllegalArgumentException("No end found in period"); + } + return getPeriod(begin, end); + } - public void setTimeSequence(DataTime timeSequence) { - this.timeSequence = timeSequence; - } + /** + * Convert jaxb time period to data time + * + * returned data time will have period value in valid period field + * + * @param begin + * @param end + * @return + */ + private static DataTime getPeriod(TimePositionType begin, + TimePositionType end) { + Calendar beginCal = getTime(begin); + Calendar endCal = getTime(end); + TimeRange validPeriod = new TimeRange(beginCal, endCal); + return new DataTime(beginCal, validPeriod); + } - public String getGridBaseCrs() { - return gridBaseCrs; - } + /** + * Convert jaxb object to java calendar + * + * @param pos + * @return + */ + private static Calendar getTime(TimePositionType pos) { + String val = pos.getValue().get(0); + return DatatypeConverter.parseDateTime(val); + } - public void setGridBaseCrs(String gridBaseCrs) { - this.gridBaseCrs = gridBaseCrs; - } + /** + * Set output format from jaxb object + * + * @param output + */ + private void setOutput(OutputType output) { + if (output.isSetFormat()) { + this.format = output.getFormat(); + } + if (output.isSetGridCRS()) { + GridCrsType base = output.getGridCRS(); + this.gridBaseCrs = base.getGridBaseCRS(); + this.gridType = base.getGridCS(); + this.gridOffsets = base.getGridOffsets(); + this.gridOrigin = base.getGridOrigin(); + } + if (output.isSetStore()) { + this.store = output.isStore(); + } + } - public String getGridType() { - return gridType; - } + public String getIdentifier() { + return identifier; + } - public void setGridType(String gridType) { - this.gridType = gridType; - } + public void setIdentifier(String identifier) { + this.identifier = identifier; + } - public List getGridOrigin() { - return gridOrigin; - } + public String getFormat() { + return format; + } - public void setGridOrigin(List gridOrigin) { - this.gridOrigin = gridOrigin; - } + public void setFormat(String format) { + this.format = format; + } - public List getGridOffsets() { - return gridOffsets; - } + public List getFields() { + return fields; + } - public void setGridOffsets(List gridOffsets) { - this.gridOffsets = gridOffsets; - } + public void setFields(List fields) { + this.fields = fields; + } - /** - * @param defacto - * the defacto to set - */ - public void setDefacto(boolean defacto) { - this.defacto = defacto; - } + public boolean isStore() { + return store; + } - /** - * @return the defacto - */ - public boolean isDefacto() { - return defacto; - } + public void setStore(boolean store) { + this.store = store; + } + + /** + * @return the bbox + */ + public Composite3DBoundingBox getBbox() { + return bbox; + } + + /** + * @param bbox + * the bbox to set + */ + public void setBbox(Composite3DBoundingBox bbox) { + this.bbox = bbox; + } + + public DataTime getTimeSequence() { + return timeSequence; + } + + public void setTimeSequence(DataTime timeSequence) { + this.timeSequence = timeSequence; + } + + public String getGridBaseCrs() { + return gridBaseCrs; + } + + public void setGridBaseCrs(String gridBaseCrs) { + this.gridBaseCrs = gridBaseCrs; + } + + public String getGridType() { + return gridType; + } + + public void setGridType(String gridType) { + this.gridType = gridType; + } + + public List getGridOrigin() { + return gridOrigin; + } + + public void setGridOrigin(List gridOrigin) { + this.gridOrigin = gridOrigin; + } + + public List getGridOffsets() { + return gridOffsets; + } + + public void setGridOffsets(List gridOffsets) { + this.gridOffsets = gridOffsets; + } + + /** + * @param defacto + * the defacto to set + */ + public void setDefacto(boolean defacto) { + this.defacto = defacto; + } + + /** + * @return the defacto + */ + public boolean isDefacto() { + return defacto; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/WcsRequest.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/WcsRequest.java index 0d3568cc6a..55adb04c92 100644 --- a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/WcsRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/request/WcsRequest.java @@ -21,6 +21,7 @@ package com.raytheon.uf.edex.wcs.request; import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * TODO - Class comment here @@ -48,7 +49,7 @@ public class WcsRequest { protected Object request; - protected String exceptionFormat = OgcResponse.TEXT_XML_MIME; + protected MimeType exceptionFormat = OgcResponse.TEXT_XML_MIME; public WcsRequest(Type type) { this.type = type; @@ -73,7 +74,7 @@ public class WcsRequest { /** * @return the exceptionFormat */ - public String getExceptionFormat() { + public MimeType getExceptionFormat() { return exceptionFormat; } @@ -81,7 +82,7 @@ public class WcsRequest { * @param exceptionFormat * the exceptionFormat to set */ - public void setExceptionFormat(String exceptionFormat) { + public void setExceptionFormat(MimeType exceptionFormat) { this.exceptionFormat = exceptionFormat; } diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/soap1_1_2/IWcsPortType.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/soap1_1_2/IWcsPortType.java new file mode 100644 index 0000000000..b3e0f10037 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/soap1_1_2/IWcsPortType.java @@ -0,0 +1,75 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + +package com.raytheon.uf.edex.wcs.soap1_1_2; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.xml.ws.BindingType; + +import net.opengis.wcs.v_1_1_2.Capabilities; +import net.opengis.wcs.v_1_1_2.CoverageDescriptions; +import net.opengis.wcs.v_1_1_2.CoveragesType; +import net.opengis.wcs.v_1_1_2.DescribeCoverage; +import net.opengis.wcs.v_1_1_2.GetCapabilities; +import net.opengis.wcs.v_1_1_2.GetCoverage; + +import com.raytheon.uf.edex.ogc.common.soap.ServiceExceptionReport; + +/** + * This class was generated by the JAX-WS RI. JAX-WS RI 2.1.6 in JDK 6 Generated + * source version: 2.1 + * + */ +@WebService(name = "WcsPortType", targetNamespace = "http://wcs.edex.uf.raytheon.com") +@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING) +@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) +public interface IWcsPortType { + + /** + * + * @param body + * @return returns net.opengis.wcs._1.Capabilities + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "GetCapabilitiesOperation") + @WebResult(name = "Capabilities", targetNamespace = "http://www.opengis.net/wcs/1.1", partName = "Body") + public Capabilities getCapabilitiesOperation( + @WebParam(name = "GetCapabilities", targetNamespace = "http://www.opengis.net/wcs/1.1", partName = "Body") + GetCapabilities body) throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wcs._1.CoverageDescriptions + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "DescribeCoverageOperation") + @WebResult(name = "CoverageDescriptions", targetNamespace = "http://www.opengis.net/wcs/1.1", partName = "Body") + public CoverageDescriptions describeCoverageOperation( + @WebParam(name = "DescribeCoverage", targetNamespace = "http://www.opengis.net/wcs/1.1", partName = "Body") + DescribeCoverage body) throws ServiceExceptionReport; + + /** + * @param body + * @param response + * @param coverageData + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "GetCoverageOperation") + @WebResult(name = "Coverages", targetNamespace = "http://www.opengis.net/wcs/1.1", partName = "Body") + public CoveragesType getCoverageOperation( + @WebParam(name = "GetCoverage", targetNamespace = "http://www.opengis.net/wcs/1.1", partName = "Body") + GetCoverage body) throws ServiceExceptionReport; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/soap1_1_2/WcsImpl.java b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/soap1_1_2/WcsImpl.java new file mode 100644 index 0000000000..1e83c199d9 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wcs/src/com/raytheon/uf/edex/wcs/soap1_1_2/WcsImpl.java @@ -0,0 +1,188 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wcs.soap1_1_2; + +import java.util.HashMap; +import java.util.Map; + +import javax.activation.DataHandler; +import javax.annotation.Resource; +import javax.xml.ws.WebServiceContext; +import javax.xml.ws.handler.MessageContext; + +import net.opengis.wcs.v_1_1_2.Capabilities; +import net.opengis.wcs.v_1_1_2.CoverageDescriptions; +import net.opengis.wcs.v_1_1_2.CoveragesType; +import net.opengis.wcs.v_1_1_2.DescribeCoverage; +import net.opengis.wcs.v_1_1_2.GetCapabilities; +import net.opengis.wcs.v_1_1_2.GetCoverage; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.soap.AbstractOwsService; +import com.raytheon.uf.edex.ogc.common.soap.ServiceExceptionReport; +import com.raytheon.uf.edex.ogc.common.stats.OgcStatsRecorder; +import com.raytheon.uf.edex.ogc.common.stats.StatsRecorderFinder; +import com.raytheon.uf.edex.wcs.CoveragesHolder; +import com.raytheon.uf.edex.wcs.WcsException; +import com.raytheon.uf.edex.wcs.WcsException.Code; +import com.raytheon.uf.edex.wcs.provider.OgcWcsProvider; +import com.raytheon.uf.edex.wcs.request.DescCoverageRequest; +import com.raytheon.uf.edex.wcs.request.GetCoverageRequest; + +/** + * TODO Add Description + * + *
+ * R
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 28, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class WcsImpl extends AbstractOwsService implements IWcsPortType { + + protected OgcWcsProvider provider; + + @Resource + protected WebServiceContext context; + + private static final String VERSION = "1.1.2"; + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + public WcsImpl(OgcWcsProvider provider) { + this.provider = provider; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.soap1_1_2.WcsPortType#getCapabilitiesOperation + * (net.opengis.wcs.v_1_1_2.GetCapabilities) + */ + @Override + public Capabilities getCapabilitiesOperation(GetCapabilities body) + throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + return provider.getCapabilities(getInfo(), body); + } catch (Exception e) { + success = false; + log.error("Problem with get coverage", e); + throw getReport(Code.InternalServerError.toString(), + "Internal Server Error", VERSION); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WCS", success); + } + } + + protected ServiceExceptionReport getReport(WcsException e) { + return super.getReport(e.getCode().toString(), e.getMessage(), VERSION); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.soap1_1_2.WcsPortType#describeCoverageOperation + * (net.opengis.wcs.v_1_1_2.DescribeCoverage) + */ + @Override + public CoverageDescriptions describeCoverageOperation(DescribeCoverage body) + throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + return provider.describeCoverage(getInfo(), + new DescCoverageRequest(body)); + } catch (WcsException e) { + success = false; + throw getReport(e); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WCS", success); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wcs.soap1_1_2.WcsPortType#getCoverageOperation(net + * .opengis.wcs.v_1_1_2.GetCoverage) + */ + @Override + public CoveragesType getCoverageOperation(GetCoverage body) + throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + CoveragesHolder holder = provider.getCoverage(getInfo(), + new GetCoverageRequest(body)); + Map attachments = getAttachments(holder); + context.getMessageContext().put( + MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS, attachments); + return holder.getMetadata(); + } catch (WcsException e) { + success = false; + throw getReport(e); + } catch (Exception e) { + success = false; + log.error("Problem with get coverage", e); + throw getReport(Code.InternalServerError.toString(), + "Internal Server Error", VERSION); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WCS", success); + } + } + + /** + * Wrap attachments in data handlers + * + * @param holder + * @return + */ + private Map getAttachments(CoveragesHolder holder) { + String contentType = holder.getContentType(); + Map data = holder.getData(); + Map rval = new HashMap(data.size()); + for (String id : data.keySet()) { + DataHandler h = new DataHandler(data.get(id), contentType); + rval.put(id, h); + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.soap.AbstractOwsService#getContext() + */ + @Override + protected WebServiceContext getContext() { + return context; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/.classpath b/edexOsgi/com.raytheon.uf.edex.wfs/.classpath index ad32c83a78..1fa3e6803d 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/.classpath +++ b/edexOsgi/com.raytheon.uf.edex.wfs/.classpath @@ -1,6 +1,6 @@ - + diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF index b541b3fe05..0a92b39f84 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF @@ -17,15 +17,32 @@ Require-Bundle: org.geotools;bundle-version="2.6.4", com.raytheon.uf.common.datadelivery.harvester;bundle-version="1.0.0", com.raytheon.uf.common.status;bundle-version="1.12.1174", com.raytheon.uf.common.datadelivery.retrieval;bundle-version="1.0.0", - com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0" + com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", + com.raytheon.uf.common.localization;bundle-version="1.12.1174", + javax.measure;bundle-version="1.0.0", + com.sun.xml.bind;bundle-version="1.0.0", + com.raytheon.uf.common.spatial;bundle-version="1.0.0", + org.w3.XMLSchema;bundle-version="1.0.0", + com.raytheon.uf.common.pointdata;bundle-version="1.12.1174", + com.raytheon.uf.edex.plugin.dataset.urn;bundle-version="1.0.0", + org.apache.commons.collections;bundle-version="3.2.0", + org.apache.commons.cxf;bundle-version="1.0.0" Export-Package: com.raytheon.uf.edex.wfs, com.raytheon.uf.edex.wfs.feature, com.raytheon.uf.edex.wfs.filter, + com.raytheon.uf.edex.wfs.filter.v1_1_0, + com.raytheon.uf.edex.wfs.filter.v2_0_0, com.raytheon.uf.edex.wfs.gml, com.raytheon.uf.edex.wfs.provider, + com.raytheon.uf.edex.wfs.querystore, com.raytheon.uf.edex.wfs.reg, com.raytheon.uf.edex.wfs.request, - com.raytheon.uf.edex.wfs.util + com.raytheon.uf.edex.wfs.soap2_0_0, + com.raytheon.uf.edex.wfs.soap2_0_0.util, + com.raytheon.uf.edex.wfs.util, + com.raytheon.uf.edex.wfs.v1_1_0, + com.raytheon.uf.edex.wfs.v2_0_0, + com.raytheon.uf.edex.wfs.wxxm Import-Package: javax.servlet, javax.servlet.http, org.apache.commons.logging diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/wsdl/wfs.wsdl b/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/wsdl/wfs.wsdl new file mode 100644 index 0000000000..f9038ceb1f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/wsdl/wfs.wsdl @@ -0,0 +1,23 @@ + + + + + + + + + + + + A WFS implementation + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/overview.uml b/edexOsgi/com.raytheon.uf.edex.wfs/overview.uml new file mode 100644 index 0000000000..10224e277e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/overview.uml @@ -0,0 +1,41 @@ +@startuml + +package "EDEX WFS Component" { + [WFS HTTP Endpoint] as wfshttp + [WFS SOAP Endpoint] as wfssoap + + [WFS 1.1.0 Provider] as wfs110 + [WFS 2.0.0 Provider] as wfs200 + + () "WFS Source" as isrc + + [WFS Registry] as reg + + [Abstract WFS Source] as absrc +} + +node "EDEX Data Plug-in Adapter" { + [Plug-in WFS Source] as psrc + [Data Record Translator] as trans +} + + + + +wfshttp *-- wfs110 +wfshttp *-- wfs200 + +wfssoap *-- wfs200 + +reg o-- "*" isrc + +wfs110 *-- reg +wfs200 *-- reg + +isrc -- absrc +psrc --|> absrc + +psrc o-- "1..*" trans + + +@enduml \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/request.uml b/edexOsgi/com.raytheon.uf.edex.wfs/request.uml new file mode 100644 index 0000000000..2dc26e5fd5 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/request.uml @@ -0,0 +1,42 @@ +@startuml + +package "EDEX WFS Component" { + [WFS HTTP Endpoint] as wfshttp + [WFS SOAP Endpoint] as wfssoap + () "HTTP/REST/JETTY" -- wfshttp + () "HTTP/SOAP/CXF" -- wfssoap + + [WFS 1.1.0 Provider] as wfs110 + [WFS 2.0.0 Provider] as wfs200 + + () "WFS Source" as isrc +} + +node "EDEX Data Plug-in Adapter" { + [Plug-in WFS Source] as psrc + [Data Record Translator] as trans +} + + +database "PostgreSQL" { + frame "Data" { + [Data Record] as record + } +} + + +wfshttp -- wfs110 +wfshttp -- wfs200 + +wfssoap -- wfs200 + +wfs110 -- isrc +wfs200 -- isrc + +isrc -left- psrc + + +psrc <-up- trans : "to WXXM" +trans <-up- record + +@enduml \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-request.xml b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-request.xml index 28eff1fe4c..8fe5ef4cd6 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-request.xml +++ b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-request.xml @@ -1,32 +1,12 @@ - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> + - - - + + + - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-rest-request.xml b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-rest-request.xml new file mode 100644 index 0000000000..2dd3d5b382 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-rest-request.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-soap-request.xml b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-soap-request.xml new file mode 100644 index 0000000000..b38c6b04ad --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-soap-request.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-soap-wsdl.xml b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-soap-wsdl.xml new file mode 100644 index 0000000000..052d89cfa1 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/res/spring/wfs-ogc-soap-wsdl.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/IWfsProvider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/IWfsProvider.java new file mode 100644 index 0000000000..8f43092a17 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/IWfsProvider.java @@ -0,0 +1,51 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * Aug 18, 2013 #2097 dhladky renamed for standards + * + */ +package com.raytheon.uf.edex.wfs; + +import java.io.InputStream; +import java.util.Map; + +import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; + +public interface IWfsProvider { + + public enum WfsOpType { + GetCapabilities, GetFeature, DescribeFeatureType, ListStoredQueries, DescribeStoredQueries, GetPropertyValue + } + + public String getVersion(); + + public void handlePost(InputStream body, EndpointInfo info, + IOgcHttpResponse response) throws Exception; + + public void handleGet(Map headers, EndpointInfo info, + IOgcHttpResponse response) throws Exception; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsException.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsException.java index bff335429c..11f01f282e 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsException.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsException.java @@ -30,16 +30,36 @@ */ package com.raytheon.uf.edex.wfs; +import com.raytheon.uf.edex.ogc.common.OgcException; + public class WfsException extends Exception { public enum Code { - INVALID_REQUEST, INTERNAL_SERVER_ERROR, INVALID_PARAMETER_VALUE + INVALID_REQUEST, InvalidParameterValue, CannotLockAllFeatures, DuplicateStoredQueryIdValue, DuplicateStoredQueryParameterName, FeaturesNotLocked, InvalidLockId, InvalidValue, LockHasExpired, OperationParsingFailed, OperationProcessingFailed, ResponseCacheExpired, OperationNotSupported, OptionNotSupported, MissingParameterValue } private static final long serialVersionUID = 8797482743733419169L; protected Code code; + public WfsException(OgcException e) { + super(e.getMessage()); + switch (e.getCode()) { + case InternalServerError: + this.code = Code.OperationProcessingFailed; + break; + case InvalidRequest: + this.code = Code.INVALID_REQUEST; + break; + case InvalidParameterValue: + this.code = Code.InvalidParameterValue; + break; + default: + this.code = Code.OperationProcessingFailed; + break; + } + } + public WfsException(Code code) { this.code = code; } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpFactory.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpFactory.java index 79af11db5e..ba79ea18d6 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpFactory.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpFactory.java @@ -32,8 +32,8 @@ package com.raytheon.uf.edex.wfs; import org.apache.commons.pool.KeyedPoolableObjectFactory; -import com.raytheon.uf.edex.wfs.provider.OgcWfsProvider; import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.v1_1_0.Wfs1_1_0Provider; /** * TODO Add Description @@ -63,7 +63,7 @@ public class WfsHttpFactory implements KeyedPoolableObjectFactory { */ @Override public Object makeObject(Object key) throws Exception { - return new WfsHttpHandler(new OgcWfsProvider(registry)); + return new WfsHttpHandler(new Wfs1_1_0Provider(registry)); } /* diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpHandler.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpHandler.java index 17962c612e..a99514e2e3 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpHandler.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsHttpHandler.java @@ -1,654 +1,206 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * * SOFTWARE HISTORY * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Apr 22, 2011 bclement Initial creation * May 30. 2013 753 dhladky updates - * Jun 11, 2013 2101 dhladky More speed improvements * */ package com.raytheon.uf.edex.wfs; +import java.io.BufferedInputStream; +import java.io.IOException; import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.TreeMap; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.xml.stream.XMLStreamException; -import com.raytheon.uf.common.datadelivery.registry.Provider.ServiceType; -import com.raytheon.uf.common.datadelivery.retrieval.util.HarvesterServiceManager; -import com.raytheon.uf.common.datadelivery.retrieval.xml.ServiceConfig; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; -import com.raytheon.uf.edex.ogc.common.OgcNamespace; -import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; -import com.raytheon.uf.edex.ogc.common.OgcPrefix; +import com.raytheon.uf.edex.ogc.common.InvalidVersionException; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; import com.raytheon.uf.edex.ogc.common.OgcResponse; -import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; -import com.raytheon.uf.edex.ogc.common.OgcTimeRange; -import com.raytheon.uf.edex.ogc.common.feature.JsonFeatureFormatter; -import com.raytheon.uf.edex.ogc.common.feature.ShpFeatureFormatter; +import com.raytheon.uf.edex.ogc.common.Version; +import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; import com.raytheon.uf.edex.ogc.common.http.OgcHttpRequest; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; -import com.raytheon.uf.edex.wfs.WfsException.Code; -import com.raytheon.uf.edex.wfs.WfsProvider.WfsOpType; -import com.raytheon.uf.edex.wfs.request.DescFeatureTypeReq; -import com.raytheon.uf.edex.wfs.request.FeatureQuery; -import com.raytheon.uf.edex.wfs.request.FeatureQuery.QFilterType; -import com.raytheon.uf.edex.wfs.request.GetCapReq; -import com.raytheon.uf.edex.wfs.request.GetFeatureReq; -import com.raytheon.uf.edex.wfs.request.GetFeatureReq.ResultType; -import com.raytheon.uf.edex.wfs.request.QualifiedName; -import com.raytheon.uf.edex.wfs.request.SortBy; -import com.raytheon.uf.edex.wfs.request.SortBy.Order; -import com.raytheon.uf.edex.wfs.request.TransReq; -import com.raytheon.uf.edex.wfs.request.WfsRequest; -import com.raytheon.uf.edex.wfs.request.WfsRequest.Type; +import com.raytheon.uf.edex.ogc.common.output.ServletOgcResponse; -public class WfsHttpHandler implements OgcHttpHandler { +public class WfsHttpHandler extends OgcHttpHandler { - protected final String REQUEST_HEADER; - - protected final String BLANK; - - protected final String CAP_PARAM; - - protected final String DESC_PARAM; - - protected final String GET_PARAM; - - protected final String OUTFORMAT_HEADER; - - protected final String RESTYPE_HEADER; - - protected final String PROPNAME_HEADER; - - protected final String MAXFEAT_HEADER; - - protected final String SRSNAME_HEADER; - - protected final String TYPENAME_HEADER; - - protected final String FEATID_HEADER; - - protected final String FILTER_HEADER; - - protected final String BBOX_HEADER; - - protected final String SORTBY_HEADER; - - protected final String NS_HEADER; - - protected final String PORT_HEADER; - - protected final String TIME_HEADER; - - protected final String PLUS; - - protected final String SPACE; - - protected int PORT; - - protected final String WFS; - - protected final String VERSION; - - protected final String OUTPUTFORMAT; - - protected static final Pattern nspattern = Pattern - .compile("xmlns\\((\\S+)=(\\S+)\\)"); - - protected static final Pattern doubleBackSlash = Pattern.compile("\\\\"); - - protected static final Pattern slash = Pattern.compile("/"); - - protected static final String comma = ","; - - protected static final Pattern commaPattern = Pattern.compile(","); - - protected static final String parenMatcher = "\\s*\\("; - - protected static final String questionMark = "?"; - - protected static final String equals = "="; - - protected static final String lamdas = "λλλ"; - - protected static final String escapedComma = "\\\\,"; - - protected static final Pattern sortBys = Pattern.compile("\\s+"); - - protected final String COLON = ":"; - - protected static final Pattern parensPattern = Pattern.compile(parenMatcher); - - protected static final Pattern escapedCommaPattern = Pattern.compile(escapedComma); - - protected static final Pattern lamdasPattern = Pattern.compile(lamdas); - - protected WfsProvider provider; + protected final TreeMap providers; private static final IUFStatusHandler statusHandler = UFStatus .getHandler(WfsHttpHandler.class); - protected static ServiceConfig wfsServiceConfig; + protected static final int READ_LIMIT = 8 * 1024; - private static ThreadLocal ogcDateFormat = new ThreadLocal() { - - @Override - protected SimpleDateFormat initialValue() { - - SimpleDateFormat sdf = new SimpleDateFormat(getServiceConfig() - .getDateConfig().getFormats().get(0)); - return sdf; + public WfsHttpHandler(IWfsProvider... providers) { + this.providers = new TreeMap(); + for (IWfsProvider p : providers) { + try { + Version v = new Version(p.getVersion()); + this.providers.put(v, p); + } catch (InvalidVersionException e) { + statusHandler.error("Invalid version for provider: " + p, e); + } } - - }; - - public WfsHttpHandler(WfsProvider provider) { - - REQUEST_HEADER = getServiceConfig().getConstantByName("REQUEST_HEADER") - .getValue(); - TIME_HEADER = getServiceConfig().getConstantByName("TIME_HEADER") - .getValue(); - CAP_PARAM = getServiceConfig().getConstantByName("CAP_PARAM") - .getValue(); - DESC_PARAM = getServiceConfig().getConstantByName("DESC_PARAM") - .getValue(); - GET_PARAM = getServiceConfig().getConstantByName("GET_PARAM") - .getValue(); - OUTFORMAT_HEADER = getServiceConfig().getConstantByName( - "OUTFORMAT_HEADER").getValue(); - RESTYPE_HEADER = getServiceConfig().getConstantByName("RESTYPE_HEADER") - .getValue(); - PROPNAME_HEADER = getServiceConfig().getConstantByName( - "PROPNAME_HEADER").getValue(); - MAXFEAT_HEADER = getServiceConfig().getConstantByName("MAXFEAT_HEADER") - .getValue(); - SRSNAME_HEADER = getServiceConfig().getConstantByName("SRSNAME_HEADER") - .getValue(); - TYPENAME_HEADER = getServiceConfig().getConstantByName( - "TYPENAME_HEADER").getValue(); - FEATID_HEADER = getServiceConfig().getConstantByName("FEATID_HEADER") - .getValue(); - FILTER_HEADER = getServiceConfig().getConstantByName("FILTER_HEADER") - .getValue(); - BBOX_HEADER = getServiceConfig().getConstantByName("BBOX_HEADER") - .getValue(); - SORTBY_HEADER = getServiceConfig().getConstantByName("SORTBY_HEADER") - .getValue(); - VERSION = getServiceConfig().getConstantByName("VERSION").getValue(); - PORT_HEADER = getServiceConfig().getConstantByName("PORT_HEADER") - .getValue(); - PORT = Integer.valueOf(getServiceConfig().getConstantByName("PORT") - .getValue()); - WFS = getServiceConfig().getConstantByName("WFS").getValue(); - NS_HEADER = getServiceConfig().getConstantByName("NS_HEADER") - .getValue(); - BLANK = getServiceConfig().getConstantByName("BLANK").getValue(); - OUTPUTFORMAT = getServiceConfig().getConstantByName("OUTPUTFORMAT") - .getValue(); - PLUS = getServiceConfig().getConstantByName("PLUS").getValue(); - SPACE = getServiceConfig().getConstantByName("SPACE").getValue(); - - this.provider = provider; } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler#handle(javax.servlet - * .http.HttpServletRequest, javax.servlet.http.HttpServletResponse, - * java.util.Map) - */ @Override public void handle(OgcHttpRequest req) { try { - statusHandler.info("Request from: "+req.getRequest().getRemoteAddr()); + statusHandler.info("Request from: " + + req.getRequest().getRemoteAddr()); long time = System.currentTimeMillis(); handleInternal(req); long time2 = System.currentTimeMillis(); - statusHandler.info("Processed: " - + req.getRequest().getQueryString() + " in " - + (time2 - time) + " ms"); + statusHandler.info("Processed: " + req.getRequest().getRemoteAddr() + + " in " + (time2 - time) + " ms"); } catch (Exception e) { statusHandler.error("Unable to handle request", e); } } protected void handleInternal(OgcHttpRequest req) throws Exception { - OgcResponse rval = null; Map headers = req.getHeaders(); - HttpServletResponse response = req.getResponse(); - OgcServiceInfo serviceInfo = getServiceInfo(req.getRequest()); - WfsRequest request; - if (req.isPost()) { - InputStream is = req.getInputStream(); - request = provider.getRequest(is); - } else { - request = getRequestFromHeaders(headers); - } - - rval = validateExceptionFormat(request); - if (rval != null) { - sendResponse(response, rval); - } - - String username = (String) headers.get(USER_HEADER); - String[] roles = (String[]) headers.get(ROLES_HEADER); - request.setUsername(username); - request.setRoles(roles); - switch (request.getType()) { - case DescribeFeature: - rval = provider.describeFeatureType((DescFeatureTypeReq) request, - serviceInfo); - break; - case GetCapabilities: - rval = provider.getCapabilities((GetCapReq) request, serviceInfo); - break; - case GetFeature: - rval = provider.getFeature((GetFeatureReq) request, serviceInfo); - break; - case Transaction: - rval = provider.transaction((TransReq) request); - break; - case ERROR: - rval = (OgcResponse) request.getRawrequest(); - break; - } - sendResponse(response, rval); - } - - /** - * @param request - * @return - */ - private OgcResponse validateExceptionFormat(WfsRequest request) { - if (!request.getExceptionFormat().equalsIgnoreCase( - OgcResponse.TEXT_HTML_MIME) - && !request.getExceptionFormat().equalsIgnoreCase( - OgcResponse.TEXT_XML_MIME)) { - return provider.getError(new WfsException( - Code.INVALID_PARAMETER_VALUE, - "exceptions parameter invalid"), OgcResponse.TEXT_XML_MIME); - } - return null; - } - - protected WfsRequest getRequestFromHeaders(Map headers) { - WfsRequest rval = null; - Object obj = headers.get(REQUEST_HEADER); - if (obj instanceof String) { - String req = (String) obj; - if (req.equalsIgnoreCase(CAP_PARAM)) { - rval = new GetCapReq(); - } else if (req.equalsIgnoreCase(DESC_PARAM)) { - rval = buildDescFeatureReq(headers); - } else if (req.equalsIgnoreCase(GET_PARAM)) { - rval = buildGetFeatureReq(headers); - } - } - String exceptionFormat = getHeader(EXCEP_FORMAT_HEADER, headers); - if (exceptionFormat == null || exceptionFormat.isEmpty()) { - exceptionFormat = OgcResponse.TEXT_XML_MIME; - } - if (rval == null) { - OgcResponse error = provider.getError(new WfsException( - Code.INVALID_REQUEST, "Unable to decode request"), - exceptionFormat); - rval = new WfsRequest(Type.ERROR); - rval.setRawrequest(error); - } - - return rval; - } - - protected Map getNameSpaceMap(Map headers) { - Map nsmap = new HashMap(); - String ns = getHeader(NS_HEADER, headers); - if (ns != null) { - for (String s : splitOnComma(ns)) { - Matcher matcher = nspattern.matcher(s); - if (matcher.matches()) { - nsmap.put(matcher.group(1), matcher.group(2)); - } - } - } else { - nsmap.put(OgcPrefix.EDEX, OgcNamespace.EDEX); - } - return nsmap; - } - - protected String[] splitOnComma(String str) { - - String[] rval = commaPattern.split(escapedCommaPattern.matcher(str).replaceAll(lamdas)); - for (int i = 0; i < rval.length; ++i) { - rval[i] = lamdasPattern.matcher(rval[i]).replaceAll(comma); - } - return rval; - } - - protected String[] splitOnSlash(String str) { - String[] times = slash.split(str); - return times; - } - - /** - * @param headers - * @return - */ - protected GetFeatureReq buildGetFeatureReq(Map headers) { - GetFeatureReq rval = new GetFeatureReq(); - String resType = getHeader(RESTYPE_HEADER, headers); - if (resType != null) { - ResultType valueOf = GetFeatureReq.ResultType.valueOf(resType); - if (valueOf != null) { - rval.setResulttype(valueOf); - } - } - String max = getHeader(MAXFEAT_HEADER, headers); - if (max != null) { - try { - rval.setMaxFeatures(Integer.parseInt(max)); - } catch (NumberFormatException e) { - statusHandler - .warn("Can't read the max number of features in request! " - + max); - } - } - String outputformat = getHeader(OUTFORMAT_HEADER, headers); - if (outputformat != null) { - rval.setOutputformat(outputformat); - } - Map nsmap = getNameSpaceMap(headers); - String[] bboxes = splitOnParens(BBOX_HEADER, headers); - String[] times = splitOnParens(TIME_HEADER, headers); - String[] filters = splitOnParens(FILTER_HEADER, headers); - String[] sorts = splitOnParens(SORTBY_HEADER, headers); - String[] props = splitOnParens(PROPNAME_HEADER, headers); - String[] srsnames = splitOnParens(SRSNAME_HEADER, headers); - String[] types = getHeaderArr(TYPENAME_HEADER, headers); - for (int i = 0; i < types.length; ++i) { - FeatureQuery fq = new FeatureQuery(); - if (bboxes.length > 0) { - fq.setFilter(getBoundingBox(bboxes[i]), QFilterType.BBOX); - } else if (filters.length > 0) { - fq.setFilter(filters[i], QFilterType.XML); - } - fq.setTypeNames(getTypeNames(types[i], nsmap)); - if (i < sorts.length) { - fq.setSortBys(getSortBys(sorts[i])); - } - if (i < props.length) { - fq.setPropertyNames(Arrays.asList(splitOnComma(props[i]))); - } - if (i < srsnames.length) { - fq.setSrsName(srsnames[i]); - } - if (i < times.length) { - fq.setTimeRange(getTimeRange(times[i])); - } - rval.addQuery(fq); - } - return rval; - } - - /** - * @param nsmap - * @param string - * @return - */ - protected List getTypeNames(String typename, - Map nsmap) { - int index = typename.lastIndexOf(":"); - String type = typename.substring(index + 1); - String namespace = typename.substring(0, index); - List rval = new LinkedList(); - if (index == 0) { - // default names to the edex namespace - rval.add(new QualifiedName(OgcNamespace.EDEX, typename, null)); - } else { - rval.add(new QualifiedName(namespace, type, type)); - } - return rval; - } - - protected String[] splitOnParens(String name, Map headers) { - String val = getHeader(name, headers); - String[] rval; - if (val != null) { - rval = doubleBackSlash.split(parensPattern.matcher(val).replaceAll(BLANK)); - } else { - rval = new String[0]; - } - return rval; - } - - /** - * @param headers - * @return - */ - protected List getSortBys(String sortby) { - List rval = new LinkedList(); - String[] sorts = splitOnComma(sortby); - for (String s : sorts) { - String[] parts = sortBys.split(s); - SortBy.Order order = Order.Ascending; - if (parts.length == 2) { - if (parts[1].trim().equalsIgnoreCase("D")) { - order = Order.Descending; - } - } - rval.add(new SortBy(parts[0].trim(), order)); - } - return rval; - } - - /** - * @param bboxes - * @return - */ - protected OgcBoundingBox getBoundingBox(String bbox) { - String[] parts = splitOnComma(bbox); - OgcBoundingBox rval = null; - if (parts.length == 4) { - rval = new OgcBoundingBox(); - try { - rval.setMinx(Double.parseDouble(parts[0])); - rval.setMiny(Double.parseDouble(parts[1])); - rval.setMaxx(Double.parseDouble(parts[2])); - rval.setMaxy(Double.parseDouble(parts[3])); - } catch (NumberFormatException e) { - statusHandler.error("couldn't parse Bounding Box!", e); - } - }// else TODO handle non 2d WGS84 - return rval; - } - - protected OgcTimeRange getTimeRange(String stimes) { - OgcTimeRange otr = null; - // we assume it is a start time going up to present + IOgcHttpResponse response = new ServletOgcResponse(req.getResponse()); + HttpServletRequest httpReq = req.getRequest(); + int port = httpReq.getLocalPort(); + String host = httpReq.getServerName(); + String path = "wfs"; + // TODO dynamic path and protocol + EndpointInfo info = new EndpointInfo(host, port, path); try { - - String[] intimes = splitOnSlash(stimes); - String[] times = new String[intimes.length]; - - for (int i = 0; i < intimes.length; i++) { - // TODO figure out why "+" for TimeZone gets hacked out of times - String newtime = intimes[i].replace(SPACE, PLUS); - times[i] = newtime; + if (req.isPost()) { + InputStream is = req.getInputStream(); + BufferedInputStream bufin = new BufferedInputStream(is); + IWfsProvider provider = getProviderPost(bufin); + provider.handlePost(bufin, info, response); + is.close(); + } else { + IWfsProvider provider = getProviderGet(headers); + provider.handleGet(headers, info, response); } + } catch (OgcException e) { + // this will only work if response hasn't been used yet + OgcResponse err = handleError(e, OgcResponse.TEXT_XML_MIME); + OgcResponseOutput.output(err, response); + } - if (times.length > 0) { - Date endDate = null; - Date startDate = null; + } - if (times.length == 1) { - endDate = new Date(System.currentTimeMillis()); - startDate = ogcDateFormat.get().parse(times[0]); + protected IWfsProvider getProviderGet(Map headers) + throws OgcException { + String vstr = getVersionInHeader(headers); + String[] vstrs; + IWfsProvider rval; + if (vstr != null) { + rval = match(vstr); + } else if ((vstrs = getAcceptVersionInHeader(headers)) != null) { + rval = match(vstrs); + } else { + rval = providers.lastEntry().getValue(); + } + return rval; + } - } else { - endDate = ogcDateFormat.get().parse(times[1]); - startDate = ogcDateFormat.get().parse(times[0]); - } + protected IWfsProvider getProviderPost(BufferedInputStream bufin) + throws OgcException { + bufin.mark(READ_LIMIT); + String vstr = getVersion(bufin); + String[] vstrs; + IWfsProvider rval; + if (vstr != null) { + rval = match(vstr); + } else if ((vstrs = getAcceptVersions(bufin)) != null) { + rval = match(vstrs); + } else { + rval = providers.lastEntry().getValue(); + } + return rval; + } - otr = new OgcTimeRange(startDate, endDate); + private IWfsProvider match(String... versions) throws OgcException { + for (String s : versions) { + Version v = parseVersion(s); + IWfsProvider provider = providers.get(v); + if (provider != null) { + return provider; } - } catch (ParseException pe) { - statusHandler.error("couldn't parse times!", pe); } - - return otr; + throw new OgcException(Code.VersionNegotiationFailed, + "Unsupported version(s): " + Arrays.toString(versions)); } - /** - * @param headers - * @return - */ - protected DescFeatureTypeReq buildDescFeatureReq(Map headers) { - DescFeatureTypeReq rval = new DescFeatureTypeReq(); - String outputformat = getHeader(OUTFORMAT_HEADER, headers); - if (outputformat != null) { - rval.setOutputformat(outputformat); + private Version parseVersion(String version) throws OgcException { + Version v; + try { + v = new Version(version); + } catch (InvalidVersionException e) { + throw new OgcException(Code.InvalidParameterValue, + "Invalid version string: " + version); } - String typename = getHeader(TYPENAME_HEADER, headers); - if (typename != null) { - Map nsmap = getNameSpaceMap(headers); - rval.setTypenames(getTypeNames(typename, nsmap)); - } - return rval; + return v; } - protected String getHeader(String name, Map headers) { - Object obj = headers.get(name); - String rval = null; - if (obj != null && obj instanceof String) { - rval = (String) obj; + private String getVersion(BufferedInputStream bufin) throws OgcException { + String vstr; + try { + vstr = getAttributeInRoot(bufin, VERSION_HEADER); + } catch (XMLStreamException e) { + throw new OgcException(Code.InvalidRequest, + "Unable to parse request XML"); } - return rval; + reset(bufin); + return vstr; } - protected String[] getHeaderArr(String name, Map headers) { + private String[] getAcceptVersions(BufferedInputStream bufin) + throws OgcException { String[] rval; - String value = getHeader(name, headers); - if (value != null) { - rval = splitOnComma(value); - } else { - rval = new String[0]; + try { + rval = getAttributeArrInRoot(bufin, ACCEPT_VERSIONS_HEADER); + } catch (XMLStreamException e) { + throw new OgcException(Code.InvalidRequest, + "Unable to parse request XML"); } + reset(bufin); return rval; } - protected String[] getHeaderTimes(String name, Map headers) { - String[] rval; - String value = getHeader(name, headers); - if (value != null) { - rval = splitOnSlash(value); - } else { - rval = new String[0]; + private void reset(BufferedInputStream bufin) throws OgcException { + try { + bufin.reset(); + } catch (IOException e) { + statusHandler.error("Unable to reset buffer", e); + throw new OgcException(Code.InternalServerError); } - return rval; - } - - /** - * @param httpRequest - * @return - */ - protected OgcServiceInfo getServiceInfo( - HttpServletRequest request) { - return getServiceInfo(request.getServerName(), request.getServerPort()); - } - - public OgcServiceInfo getServiceInfo(String host, int port) { - String base = PORT_HEADER + host; - if (port != PORT) { - base += COLON + port; - } - base += slash.pattern() + WFS; - OgcServiceInfo rval = new OgcServiceInfo(base); - StringBuilder getCapGet = new StringBuilder(); - getCapGet.append(base).append(questionMark).append(REQUEST_HEADER) - .append(equals).append(CAP_PARAM); - StringBuffer getFeatureGet = new StringBuffer(); - getFeatureGet.append(base).append(questionMark).append(REQUEST_HEADER) - .append(equals).append(GET_PARAM); - StringBuffer descFeatureGet = new StringBuffer(); - descFeatureGet.append(base).append(questionMark).append(REQUEST_HEADER) - .append(equals).append(DESC_PARAM); - rval.addOperationInfo(getOp(getCapGet.toString(), base, - WfsOpType.GetCapabilities)); - rval.addOperationInfo(getOp(descFeatureGet.toString(), base, - WfsOpType.DescribeFeatureType)); - OgcOperationInfo getFeat = getOp(getFeatureGet.toString(), - base, WfsOpType.GetFeature); - getFeat.addFormat(ShpFeatureFormatter.mimeType); - getFeat.addFormat(JsonFeatureFormatter.mimeType); - rval.addOperationInfo(getFeat); - return rval; - } - - protected OgcOperationInfo getOp(String get, String post, - WfsOpType type) { - OgcOperationInfo rval = new OgcOperationInfo(type); - rval.setHttpGetRes(get); - rval.setHttpPostRes(post); - rval.addVersion(VERSION); - rval.addFormat(OUTPUTFORMAT); - return rval; - } - - protected void sendResponse(HttpServletResponse httpRes, - OgcResponse response) throws Exception { - OgcResponseOutput.output(response, httpRes); - } - - /** - * Get service config - * - * @return - */ - protected static ServiceConfig getServiceConfig() { - if (wfsServiceConfig == null) { - wfsServiceConfig = HarvesterServiceManager.getInstance() - .getServiceConfig(ServiceType.WFS); - } - - return wfsServiceConfig; } } \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsProvider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsProvider.java deleted file mode 100644 index 484afd162e..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/WfsProvider.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * Apr 22, 2011 bclement Initial creation - * - */ -package com.raytheon.uf.edex.wfs; - -import java.io.InputStream; - -import com.raytheon.uf.edex.ogc.common.OgcResponse; -import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; -import com.raytheon.uf.edex.wfs.request.DescFeatureTypeReq; -import com.raytheon.uf.edex.wfs.request.GetCapReq; -import com.raytheon.uf.edex.wfs.request.GetFeatureReq; -import com.raytheon.uf.edex.wfs.request.TransReq; -import com.raytheon.uf.edex.wfs.request.WfsRequest; - -public interface WfsProvider { - - public enum WfsOpType { - GetCapabilities, GetFeature, DescribeFeatureType - } - - public OgcResponse getCapabilities(GetCapReq request, - OgcServiceInfo serviceInfo); - - public OgcResponse describeFeatureType(DescFeatureTypeReq request, - OgcServiceInfo serviceInfo); - - public OgcResponse getFeature(GetFeatureReq request, - OgcServiceInfo serviceInfo); - - public WfsRequest getRequest(InputStream in); - - public OgcResponse getError(WfsException e, String exceptionFormat); - - /** - * @param request - * @return - */ - public OgcResponse transaction(TransReq request); -} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/FeatureTypeCache.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/FeatureTypeCache.java deleted file mode 100644 index b2f06e3ef6..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/FeatureTypeCache.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * Jul 19, 2011 bclement Initial creation - * - */ -package com.raytheon.uf.edex.wfs.feature; - -import org.opengis.feature.type.FeatureType; -import org.opengis.referencing.FactoryException; -import org.opengis.referencing.NoSuchAuthorityCodeException; - -/** - * - * @author bclement - * @version 1.0 - */ -public interface FeatureTypeCache { - - public FeatureType getFeatureType(FeatureTypeConfig config) - throws NoSuchAuthorityCodeException, FactoryException; - - public FeatureTypeCache removeClass(FeatureTypeConfig config); - - public FeatureTypeCache clear(); - -} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/IFeatureTypeCache.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/IFeatureTypeCache.java new file mode 100644 index 0000000000..e133e2dafe --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/IFeatureTypeCache.java @@ -0,0 +1,51 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Jul 19, 2011 bclement Initial creation + * Aug 18, 2013 #2097 dhladky renamed for standards + * + */ +package com.raytheon.uf.edex.wfs.feature; + +import org.opengis.feature.type.FeatureType; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.NoSuchAuthorityCodeException; + +import com.raytheon.uf.edex.ogc.common.OgcException; + +/** + * + * @author bclement + * @version 1.0 + */ +public interface IFeatureTypeCache { + + public FeatureType getFeatureType(FeatureTypeConfig config) + throws OgcException, NoSuchAuthorityCodeException, FactoryException; + + public IFeatureTypeCache removeClass(FeatureTypeConfig config); + + public IFeatureTypeCache clear(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/SimpleFeatureTypeCache.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/SimpleFeatureTypeCache.java index 833e1499fd..2740ba0056 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/SimpleFeatureTypeCache.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/feature/SimpleFeatureTypeCache.java @@ -36,14 +36,15 @@ import java.util.concurrent.ConcurrentHashMap; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.opengis.feature.type.FeatureType; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.spatial.CrsLookup; /** @@ -51,109 +52,110 @@ import com.raytheon.uf.edex.ogc.common.spatial.CrsLookup; * @author bclement * @version 1.0 */ -public class SimpleFeatureTypeCache implements FeatureTypeCache { +public class SimpleFeatureTypeCache implements IFeatureTypeCache { - protected ConcurrentHashMap cache = new ConcurrentHashMap(); + protected ConcurrentHashMap cache = new ConcurrentHashMap(); - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wfs.feature.FeatureTypeCache#getFeatureType(java - * .lang.Class) - */ - @Override - public FeatureType getFeatureType(FeatureTypeConfig config) - throws NoSuchAuthorityCodeException, FactoryException { - if (config == null) { - return null; - } - FeatureType rval = cache.get(config); - if (rval == null) { - rval = extractFeatureType(config); - cache.put(config, rval); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.feature.FeatureTypeCache#getFeatureType(java + * .lang.Class) + */ + @Override + public FeatureType getFeatureType(FeatureTypeConfig config) + throws NoSuchAuthorityCodeException, FactoryException, OgcException { + if (config == null) { + return null; + } + FeatureType rval = cache.get(config); + if (rval == null) { + rval = extractFeatureType(config); + cache.put(config, rval); + } - return rval; - } + return rval; + } - protected FeatureType extractFeatureType(FeatureTypeConfig config) - throws NoSuchAuthorityCodeException, FactoryException { - switch (config.method) { - case JAXB: - return extractFromJaxb(config); - default: - throw new RuntimeException("Invalid featuretype extraction method"); - } - } + protected FeatureType extractFeatureType(FeatureTypeConfig config) + throws NoSuchAuthorityCodeException, FactoryException, OgcException { + switch (config.method) { + case JAXB: + return extractFromJaxb(config); + default: + throw new RuntimeException("Invalid featuretype extraction method"); + } + } - /** - * Naive implementation. Does not account for embedded types, lists (arrays) - * or adapters. - * - * @param config - * @return - * @throws NoSuchAuthorityCodeException - * @throws FactoryException - */ - protected FeatureType extractFromJaxb(FeatureTypeConfig config) - throws NoSuchAuthorityCodeException, FactoryException { - SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); - builder.setName(config.getName()); - builder.setNamespaceURI(config.getNamespace()); - CoordinateReferenceSystem crs = CrsLookup.lookup(config.getCrs()); - builder.setDefaultGeometry(config.getGeomName()); - builder.setCRS(crs); - Class binding = config.getBinding(); - Field[] fields = binding.getFields(); - for (Field f : fields) { - if (hasJaxb(f)) { - String name = f.getName(); - Class c = f.getDeclaringClass(); - builder.add(name, c); - } - } - return builder.buildFeatureType(); - } + /** + * Naive implementation. Does not account for embedded types, lists (arrays) + * or adapters. + * + * @param config + * @return + * @throws NoSuchAuthorityCodeException + * @throws FactoryException + * @throws OgcException + */ + protected FeatureType extractFromJaxb(FeatureTypeConfig config) + throws NoSuchAuthorityCodeException, FactoryException, OgcException { + SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); + builder.setName(config.getName()); + builder.setNamespaceURI(config.getNamespace()); + CoordinateReferenceSystem crs = CrsLookup.lookup(config.getCrs()); + builder.setDefaultGeometry(config.getGeomName()); + builder.setCRS(crs); + Class binding = config.getBinding(); + Field[] fields = binding.getFields(); + for (Field f : fields) { + if (hasJaxb(f)) { + String name = f.getName(); + Class c = f.getDeclaringClass(); + builder.add(name, c); + } + } + return builder.buildFeatureType(); + } - protected boolean hasJaxb(Field f) { - XmlElement xmle = f.getAnnotation(XmlElement.class); - if (xmle != null) { - return true; - } - XmlAttribute xmla = f.getAnnotation(XmlAttribute.class); - if (xmla != null) { - return true; - } - return false; - } + protected boolean hasJaxb(Field f) { + XmlElement xmle = f.getAnnotation(XmlElement.class); + if (xmle != null) { + return true; + } + XmlAttribute xmla = f.getAnnotation(XmlAttribute.class); + if (xmla != null) { + return true; + } + return false; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wfs.feature.FeatureTypeCache#removeClass(java.lang - * .Class) - */ - @Override - public FeatureTypeCache removeClass(FeatureTypeConfig config) { - if (config != null) { - cache.remove(config); - } - return this; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.feature.FeatureTypeCache#removeClass(java.lang + * .Class) + */ + @Override + public IFeatureTypeCache removeClass(FeatureTypeConfig config) { + if (config != null) { + cache.remove(config); + } + return this; + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wfs.feature.FeatureTypeCache#clear() - */ - @Override - public FeatureTypeCache clear() { - cache.clear(); - return this; - } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.feature.FeatureTypeCache#clear() + */ + @Override + public IFeatureTypeCache clear() { + cache.clear(); + return this; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/AbstractCompOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/AbstractCompOp.java index da8e7b6d0a..27a417f4f2 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/AbstractCompOp.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/AbstractCompOp.java @@ -42,8 +42,8 @@ import net.opengis.filter.v_1_1_0.PropertyIsBetweenType; import net.opengis.filter.v_1_1_0.PropertyIsLikeType; import net.opengis.filter.v_1_1_0.PropertyIsNullType; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; /** * @@ -52,150 +52,150 @@ import org.apache.commons.logging.LogFactory; */ public abstract class AbstractCompOp { - protected static final Map binaryMap; + protected static final Map binaryMap; - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - static { - binaryMap = new HashMap(); - binaryMap.put("PropertyIsEqualTo", new Equal()); - binaryMap.put("PropertyIsNotEqualTo", new NotEqual()); - binaryMap.put("PropertyIsLessThan", new LessThan()); - binaryMap.put("PropertyIsGreaterThan", new GreaterThan()); - binaryMap.put("PropertyIsLessThanOrEqualTo", new LessThanEqual()); - binaryMap.put("PropertyIsGreaterThanOrEqualTo", new GreaterThanEqual()); - } + static { + binaryMap = new HashMap(); + binaryMap.put("PropertyIsEqualTo", new Equal()); + binaryMap.put("PropertyIsNotEqualTo", new NotEqual()); + binaryMap.put("PropertyIsLessThan", new LessThan()); + binaryMap.put("PropertyIsGreaterThan", new GreaterThan()); + binaryMap.put("PropertyIsLessThanOrEqualTo", new LessThanEqual()); + binaryMap.put("PropertyIsGreaterThanOrEqualTo", new GreaterThanEqual()); + } - public abstract Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception; + public abstract Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception; - public static class Like extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - return visitor.isLike((PropertyIsLikeType) op.getValue(), obj); - } - } + public static class Like extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + return visitor.isLike((PropertyIsLikeType) op.getValue(), obj); + } + } - public static class Null extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - return visitor.isNull((PropertyIsNullType) op.getValue(), obj); - } - } + public static class Null extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + return visitor.isNull((PropertyIsNullType) op.getValue(), obj); + } + } - public static class Between extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - PropertyIsBetweenType between = (PropertyIsBetweenType) op - .getValue(); - ExpressionProcessor exp = new ExpressionProcessor( - between.getExpression()); - ExpressionProcessor lower = new ExpressionProcessor(between - .getLowerBoundary().getExpression()); - ExpressionProcessor upper = new ExpressionProcessor(between - .getUpperBoundary().getExpression()); - return visitor.between(lower, exp, upper, obj); - } - } + public static class Between extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + PropertyIsBetweenType between = (PropertyIsBetweenType) op + .getValue(); + ExpressionProcessor exp = new ExpressionProcessor( + between.getExpression()); + ExpressionProcessor lower = new ExpressionProcessor(between + .getLowerBoundary().getExpression()); + ExpressionProcessor upper = new ExpressionProcessor(between + .getUpperBoundary().getExpression()); + return visitor.between(lower, exp, upper, obj); + } + } - public static class BinaryOp extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - String name = op.getName().getLocalPart(); - AbstractCompOp compOp = binaryMap.get(name); - if (compOp != null) { - return compOp.visit(op, visitor, obj); - } else { - throw new Exception("Unknown binary operator: " + name); - } - } - } + public static class BinaryOp extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + String name = op.getName().getLocalPart(); + AbstractCompOp compOp = binaryMap.get(name); + if (compOp != null) { + return compOp.visit(op, visitor, obj); + } else { + throw new Exception("Unknown binary operator: " + name); + } + } + } - public static class Equal extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - BinaryComparisonOpType binary = (BinaryComparisonOpType) op - .getValue(); - List> expressions = binary.getExpression(); - return visitor.equal(new ExpressionProcessor(expressions.get(0)), - new ExpressionProcessor(expressions.get(1)), - binary.isMatchCase(), obj); - } - } + public static class Equal extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.equal(new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } - public static class NotEqual extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - BinaryComparisonOpType binary = (BinaryComparisonOpType) op - .getValue(); - List> expressions = binary.getExpression(); - return visitor.notEqual( - new ExpressionProcessor(expressions.get(0)), - new ExpressionProcessor(expressions.get(1)), - binary.isMatchCase(), obj); - } - } + public static class NotEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.notEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } - public static class LessThan extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - BinaryComparisonOpType binary = (BinaryComparisonOpType) op - .getValue(); - List> expressions = binary.getExpression(); - return visitor.lessThan( - new ExpressionProcessor(expressions.get(0)), - new ExpressionProcessor(expressions.get(1)), - binary.isMatchCase(), obj); - } - } + public static class LessThan extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.lessThan( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } - public static class GreaterThan extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - BinaryComparisonOpType binary = (BinaryComparisonOpType) op - .getValue(); - List> expressions = binary.getExpression(); - return visitor.greaterThan( - new ExpressionProcessor(expressions.get(0)), - new ExpressionProcessor(expressions.get(1)), - binary.isMatchCase(), obj); - } - } + public static class GreaterThan extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.greaterThan( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } - public static class LessThanEqual extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - BinaryComparisonOpType binary = (BinaryComparisonOpType) op - .getValue(); - List> expressions = binary.getExpression(); - return visitor.lessThanEqual( - new ExpressionProcessor(expressions.get(0)), - new ExpressionProcessor(expressions.get(1)), - binary.isMatchCase(), obj); - } - } + public static class LessThanEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.lessThanEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } - public static class GreaterThanEqual extends AbstractCompOp { - @Override - public Object visit(JAXBElement op, - OgcFilterVisitor visitor, Object obj) throws Exception { - BinaryComparisonOpType binary = (BinaryComparisonOpType) op - .getValue(); - List> expressions = binary.getExpression(); - return visitor.greaterThanEqual( - new ExpressionProcessor(expressions.get(0)), - new ExpressionProcessor(expressions.get(1)), - binary.isMatchCase(), obj); - } - } + public static class GreaterThanEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.greaterThanEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/EscapingLikeExpression.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/EscapingLikeExpression.java new file mode 100644 index 0000000000..72b0e5e5c8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/EscapingLikeExpression.java @@ -0,0 +1,96 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.filter; + +import org.hibernate.criterion.LikeExpression; +import org.hibernate.criterion.MatchMode; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 17, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class EscapingLikeExpression extends LikeExpression { + + private static final long serialVersionUID = 1L; + + protected String propertyName; + + protected String value; + + protected Character escapeChar; + + /** + * @param propertyName + * @param value + */ + public EscapingLikeExpression(String propertyName, String value) { + super(propertyName, value); + this.propertyName = propertyName; + this.value = value; + } + + /** + * @param propertyName + * @param value + * @param matchMode + */ + public EscapingLikeExpression(String propertyName, String value, + MatchMode matchMode) { + super(propertyName, value, matchMode); + } + + /** + * @param propertyName + * @param value + * @param escapeChar + * @param ignoreCase + */ + public EscapingLikeExpression(String propertyName, String value, + Character escapeChar, boolean ignoreCase) { + super(propertyName, value, escapeChar, ignoreCase); + this.propertyName = propertyName; + this.value = value; + this.escapeChar = escapeChar; + } + + /** + * @param propertyName + * @param value + * @param matchMode + * @param escapeChar + * @param ignoreCase + */ + public EscapingLikeExpression(String propertyName, String value, + MatchMode matchMode, Character escapeChar, boolean ignoreCase) { + super(propertyName, value, matchMode, escapeChar, ignoreCase); + this.propertyName = propertyName; + this.escapeChar = escapeChar; + this.value = value; + } + + public String toString(){ + return String.format("%s like '%s' escape '%s'", propertyName, value, + escapeChar); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbsExpressionOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbsExpressionOp.java new file mode 100644 index 0000000000..3c677f471c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbsExpressionOp.java @@ -0,0 +1,134 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_1_1_0.BinaryOperatorType; +import net.opengis.filter.v_1_1_0.FunctionType; +import net.opengis.filter.v_1_1_0.LiteralType; +import net.opengis.filter.v_1_1_0.PropertyNameType; + +/** + * + * @author bclement + * @version 1.0 + */ +public abstract class AbsExpressionOp { + + public abstract Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception; + + public static class Literal extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception { + LiteralType literal = (LiteralType) element.getValue(); + return visitor.literal(literal.getContent(), obj); + } + } + + public static class Add extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception { + BinaryOperatorType binary = (BinaryOperatorType) element.getValue(); + List> exprs = binary.getExpression(); + ExpressionProcessor left = new ExpressionProcessor(exprs.get(0)); + ExpressionProcessor right = new ExpressionProcessor(exprs.get(1)); + return visitor.add(left, right, obj); + } + } + + public static class Sub extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception { + BinaryOperatorType binary = (BinaryOperatorType) element.getValue(); + List> exprs = binary.getExpression(); + ExpressionProcessor left = new ExpressionProcessor(exprs.get(0)); + ExpressionProcessor right = new ExpressionProcessor(exprs.get(1)); + return visitor.sub(left, right, obj); + } + } + + public static class Mul extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception { + BinaryOperatorType binary = (BinaryOperatorType) element.getValue(); + List> exprs = binary.getExpression(); + ExpressionProcessor left = new ExpressionProcessor(exprs.get(0)); + ExpressionProcessor right = new ExpressionProcessor(exprs.get(1)); + return visitor.mul(left, right, obj); + } + } + + public static class Div extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception { + BinaryOperatorType binary = (BinaryOperatorType) element.getValue(); + List> exprs = binary.getExpression(); + ExpressionProcessor left = new ExpressionProcessor(exprs.get(0)); + ExpressionProcessor right = new ExpressionProcessor(exprs.get(1)); + return visitor.div(left, right, obj); + } + } + + public static class Property extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception { + PropertyNameType prop = (PropertyNameType) element.getValue(); + return visitor.property(prop, obj); + } + } + + public static class Function extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, + OgcExpressionVisitor visitor, Object obj) throws Exception { + FunctionType f = (FunctionType) element.getValue(); + String name = f.getName(); + List> exprs = f.getExpression(); + List procs = new ArrayList( + exprs.size()); + for (JAXBElement expr : exprs) { + procs.add(new ExpressionProcessor(expr)); + } + return visitor.function(procs, name, obj); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractCompOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractCompOp.java new file mode 100644 index 0000000000..718c3ff07a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractCompOp.java @@ -0,0 +1,201 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 20, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_1_1_0.BinaryComparisonOpType; +import net.opengis.filter.v_1_1_0.ComparisonOpsType; +import net.opengis.filter.v_1_1_0.PropertyIsBetweenType; +import net.opengis.filter.v_1_1_0.PropertyIsLikeType; +import net.opengis.filter.v_1_1_0.PropertyIsNullType; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + +/** + * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractCompOp { + + protected static final Map binaryMap; + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + static { + binaryMap = new HashMap(); + binaryMap.put("PropertyIsEqualTo", new Equal()); + binaryMap.put("PropertyIsNotEqualTo", new NotEqual()); + binaryMap.put("PropertyIsLessThan", new LessThan()); + binaryMap.put("PropertyIsGreaterThan", new GreaterThan()); + binaryMap.put("PropertyIsLessThanOrEqualTo", new LessThanEqual()); + binaryMap.put("PropertyIsGreaterThanOrEqualTo", new GreaterThanEqual()); + } + + public abstract Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception; + + public static class Like extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + return visitor.isLike((PropertyIsLikeType) op.getValue(), obj); + } + } + + public static class Null extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + return visitor.isNull((PropertyIsNullType) op.getValue(), obj); + } + } + + public static class Between extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + PropertyIsBetweenType between = (PropertyIsBetweenType) op + .getValue(); + ExpressionProcessor exp = new ExpressionProcessor( + between.getExpression()); + ExpressionProcessor lower = new ExpressionProcessor(between + .getLowerBoundary().getExpression()); + ExpressionProcessor upper = new ExpressionProcessor(between + .getUpperBoundary().getExpression()); + return visitor.between(lower, exp, upper, obj); + } + } + + public static class BinaryOp extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + String name = op.getName().getLocalPart(); + AbstractCompOp compOp = binaryMap.get(name); + if (compOp != null) { + return compOp.visit(op, visitor, obj); + } else { + throw new Exception("Unknown binary operator: " + name); + } + } + } + + public static class Equal extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.equal(new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class NotEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.notEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class LessThan extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.lessThan( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class GreaterThan extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.greaterThan( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class LessThanEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.lessThanEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class GreaterThanEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.greaterThanEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractLogicOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractLogicOp.java new file mode 100644 index 0000000000..35a5b07946 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractLogicOp.java @@ -0,0 +1,145 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 21, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_1_1_0.BinaryLogicOpType; +import net.opengis.filter.v_1_1_0.ComparisonOpsType; +import net.opengis.filter.v_1_1_0.FilterType; +import net.opengis.filter.v_1_1_0.LogicOpsType; +import net.opengis.filter.v_1_1_0.SpatialOpsType; +import net.opengis.filter.v_1_1_0.UnaryLogicOpType; + +/** + * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractLogicOp { + + public abstract Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception; + + protected Map, List>> sortByType( + List> elements) { + Map, List>> rval = new HashMap, List>>(); + for (JAXBElement e : elements) { + List> list = rval.get(e.getDeclaredType()); + if (list == null) { + list = new ArrayList>(); + rval.put(e.getDeclaredType(), list); + } + list.add(e); + } + return rval; + } + + @SuppressWarnings("unchecked") + protected List getProcessors(List> elements) + throws Exception { + List rval = new ArrayList( + elements.size()); + for (JAXBElement e : elements) { + Class type = e.getDeclaredType(); + FilterProcessor p; + // FIXME this is slow + if (ComparisonOpsType.class.isAssignableFrom(type)) { + p = FilterProcessor + .newFromComparison((JAXBElement) e); + } else if (LogicOpsType.class.isAssignableFrom(type)) { + p = FilterProcessor + .newFromLogic((JAXBElement) e); + } else if (SpatialOpsType.class.isAssignableFrom(type)) { + p = FilterProcessor + .newFromSpatial((JAXBElement) e); + } else { + throw new Exception("Unknown operator: " + type); + } + rval.add(p); + } + return rval; + } + + protected FilterType createFilter( + JAXBElement comps, + JAXBElement spats, + JAXBElement logic) { + FilterType rval = new FilterType(); + rval.setComparisonOps(comps); + rval.setLogicOps(logic); + rval.setSpatialOps(spats); + return rval; + } + + public static class And extends AbstractLogicOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryLogicOpType and = (BinaryLogicOpType) op.getValue(); + List> gah = and + .getComparisonOpsOrSpatialOpsOrLogicOps(); + List processors = getProcessors(gah); + return visitor.and(processors, obj); + } + } + + public static class Or extends AbstractLogicOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinaryLogicOpType or = (BinaryLogicOpType) op.getValue(); + List> gah = or + .getComparisonOpsOrSpatialOpsOrLogicOps(); + List processors = getProcessors(gah); + return visitor.or(processors, obj); + } + } + + public static class Not extends AbstractLogicOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + UnaryLogicOpType not = (UnaryLogicOpType) op.getValue(); + JAXBElement comps = not + .getComparisonOps(); + JAXBElement spats = not.getSpatialOps(); + JAXBElement logics = not.getLogicOps(); + FilterType filter = createFilter(comps, spats, logics); + return visitor.not(new FilterProcessor(filter), obj); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractSpatialOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractSpatialOp.java new file mode 100644 index 0000000000..73db95014f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/AbstractSpatialOp.java @@ -0,0 +1,148 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 21, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_1_1_0.BBOXType; +import net.opengis.filter.v_1_1_0.BinarySpatialOpType; +import net.opengis.filter.v_1_1_0.DistanceBufferType; +import net.opengis.filter.v_1_1_0.SpatialOpsType; + +/** + * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractSpatialOp { + + public abstract Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception; + + public static class SpatialEquals extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.spatialEquals(binary, obj); + } + } + + public static class Disjoint extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.disjoint(binary, obj); + } + } + + public static class Touches extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.touches(binary, obj); + } + } + + public static class Within extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.within(binary, obj); + } + } + + public static class Overlaps extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.overlaps(binary, obj); + } + } + + public static class Crosses extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.crosses(binary, obj); + } + } + + public static class Intersects extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.intersects(binary, obj); + } + } + + public static class Contains extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.contains(binary, obj); + } + } + + public static class DWithin extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + DistanceBufferType dist = (DistanceBufferType) op.getValue(); + return visitor.dWithin(dist, obj); + } + } + + public static class Beyond extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + DistanceBufferType dist = (DistanceBufferType) op.getValue(); + return visitor.beyond(dist, obj); + } + } + + public static class Bbox extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + OgcFilterVisitor visitor, Object obj) throws Exception { + BBOXType bbox = (BBOXType) op.getValue(); + return visitor.bbox(bbox, obj); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/ExpressionProcessor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/ExpressionProcessor.java new file mode 100644 index 0000000000..11f7459da2 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/ExpressionProcessor.java @@ -0,0 +1,74 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 21, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.HashMap; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +/** + * + * @author bclement + * @version 1.0 + */ +public class ExpressionProcessor { + + protected static final Map expressionMap; + static { + expressionMap = new HashMap(); + expressionMap.put("Literal", new AbsExpressionOp.Literal()); + expressionMap.put("Add", new AbsExpressionOp.Add()); + expressionMap.put("Sub", new AbsExpressionOp.Sub()); + expressionMap.put("Mul", new AbsExpressionOp.Mul()); + expressionMap.put("Div", new AbsExpressionOp.Div()); + expressionMap.put("Function", new AbsExpressionOp.Function()); + expressionMap.put("PropertyName", new AbsExpressionOp.Property()); + } + + JAXBElement expression; + + /** + * @param expression + */ + public ExpressionProcessor(JAXBElement expression) { + super(); + this.expression = expression; + } + + public Object accept(OgcExpressionVisitor visitor, Object obj) + throws Exception { + AbsExpressionOp op = expressionMap.get(expression.getName() + .getLocalPart()); + return op.visit(expression, visitor, obj); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/FilterProcessor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/FilterProcessor.java new file mode 100644 index 0000000000..ebc5a782eb --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/FilterProcessor.java @@ -0,0 +1,164 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 20, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_1_1_0.AbstractIdType; +import net.opengis.filter.v_1_1_0.BinaryComparisonOpType; +import net.opengis.filter.v_1_1_0.ComparisonOpsType; +import net.opengis.filter.v_1_1_0.FeatureIdType; +import net.opengis.filter.v_1_1_0.FilterType; +import net.opengis.filter.v_1_1_0.GmlObjectIdType; +import net.opengis.filter.v_1_1_0.LogicOpsType; +import net.opengis.filter.v_1_1_0.PropertyIsBetweenType; +import net.opengis.filter.v_1_1_0.PropertyIsLikeType; +import net.opengis.filter.v_1_1_0.PropertyIsNullType; +import net.opengis.filter.v_1_1_0.SpatialOpsType; + +import com.raytheon.uf.edex.wfs.filter.v1_1_0.AbstractCompOp.BinaryOp; + +/** + * + * @author bclement + * @version 1.0 + */ +public class FilterProcessor { + + protected static final Map, AbstractCompOp> compMap; + static { + compMap = new HashMap, AbstractCompOp>(); + compMap.put(BinaryComparisonOpType.class, new BinaryOp()); + compMap.put(PropertyIsLikeType.class, new AbstractCompOp.Like()); + compMap.put(PropertyIsNullType.class, new AbstractCompOp.Null()); + compMap.put(PropertyIsBetweenType.class, new AbstractCompOp.Between()); + } + + protected static final Map logicMap; + static { + logicMap = new HashMap(); + logicMap.put("And", new AbstractLogicOp.And()); + logicMap.put("Or", new AbstractLogicOp.Or()); + logicMap.put("Not", new AbstractLogicOp.Not()); + } + + protected static final Map spatialMap; + static { + spatialMap = new HashMap(); + spatialMap.put("Equals", new AbstractSpatialOp.SpatialEquals()); + spatialMap.put("Disjoint", new AbstractSpatialOp.Disjoint()); + spatialMap.put("Touches", new AbstractSpatialOp.Touches()); + spatialMap.put("Within", new AbstractSpatialOp.Within()); + spatialMap.put("Overlaps", new AbstractSpatialOp.Overlaps()); + spatialMap.put("Crosses", new AbstractSpatialOp.Crosses()); + spatialMap.put("Intersects", new AbstractSpatialOp.Intersects()); + spatialMap.put("Contains", new AbstractSpatialOp.Contains()); + spatialMap.put("DWithin", new AbstractSpatialOp.DWithin()); + spatialMap.put("Beyond", new AbstractSpatialOp.Beyond()); + spatialMap.put("BBOX", new AbstractSpatialOp.Bbox()); + } + + protected FilterType filter; + + public FilterProcessor(FilterType filter) { + this.filter = filter; + } + + public static FilterProcessor newFromLogic( + JAXBElement ops) { + FilterType f = new FilterType(); + f.setLogicOps(ops); + return new FilterProcessor(f); + } + + public static FilterProcessor newFromComparison( + JAXBElement ops) { + FilterType f = new FilterType(); + f.setComparisonOps(ops); + return new FilterProcessor(f); + } + + public static FilterProcessor newFromSpatial( + JAXBElement ops) { + FilterType f = new FilterType(); + f.setSpatialOps(ops); + return new FilterProcessor(f); + } + + public Object accept(OgcFilterVisitor visitor, Object obj) throws Exception { + JAXBElement comps = filter + .getComparisonOps(); + JAXBElement logics = filter.getLogicOps(); + JAXBElement spats = filter.getSpatialOps(); + List> ids = filter.getId(); + Object rval; + if (logics != null && !logics.isNil()) { + String name = logics.getName().getLocalPart(); + AbstractLogicOp op = logicMap.get(name); + rval = op.visit(logics, visitor, obj); + } else if (comps != null && !comps.isNil()) { + Class type = comps.getDeclaredType(); + AbstractCompOp op = compMap.get(type); + rval = op.visit(comps, visitor, obj); + } else if (spats != null && !spats.isNil()) { + String name = spats.getName().getLocalPart(); + AbstractSpatialOp op = spatialMap.get(name); + rval = op.visit(spats, visitor, obj); + } else if (ids != null && !ids.isEmpty()) { + rval = visitor.id(getIds(ids), obj); + } else { + rval = null; + } + return rval; + } + + protected List getIds( + List> ids) { + List rval = new ArrayList(ids.size()); + for (JAXBElement e : ids) { + AbstractIdType id = e.getValue(); + if (id instanceof GmlObjectIdType) { + GmlObjectIdType gml = (GmlObjectIdType) id; + rval.add(gml.getId()); + } else if (id instanceof FeatureIdType) { + FeatureIdType fid = (FeatureIdType) id; + rval.add(fid.getFid()); + } + } + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/styling/WmsDataRetriever.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/OgcExpressionVisitor.java similarity index 50% rename from edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/styling/WmsDataRetriever.java rename to edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/OgcExpressionVisitor.java index 5600a0bfad..ba5c364c21 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/styling/WmsDataRetriever.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/OgcExpressionVisitor.java @@ -25,29 +25,38 @@ * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Mar 29, 2012 bclement Initial creation + * Apr 21, 2011 bclement Initial creation * */ -package com.raytheon.uf.edex.wms.styling; +package com.raytheon.uf.edex.wfs.filter.v1_1_0; -import org.geotools.coverage.grid.GridCoverage2D; -import org.geotools.geometry.jts.ReferencedEnvelope; +import java.util.List; -import com.raytheon.uf.common.dataplugin.PluginDataObject; -import com.raytheon.uf.common.spatial.reprojection.ReferencedDataRecord; -import com.raytheon.uf.edex.wms.WmsException; +import net.opengis.filter.v_1_1_0.PropertyNameType; /** * * @author bclement * @version 1.0 */ -public interface WmsDataRetriever { +public interface OgcExpressionVisitor { - public GridCoverage2D getGridCoverage(PluginDataObject record, - ReferencedEnvelope envelope) throws WmsException; + public Object add(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception; - public ReferencedDataRecord getDataRecord(PluginDataObject record, - ReferencedEnvelope envelope) throws WmsException; + public Object sub(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception; + public Object mul(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception; + + public Object div(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception; + + public Object literal(List values, Object obj) throws Exception; + + public Object property(PropertyNameType prop, Object obj) throws Exception; + + public Object function(List expressions, String name, + Object obj) throws Exception; } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/OgcFilterVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/OgcFilterVisitor.java new file mode 100644 index 0000000000..dd995bd55f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/OgcFilterVisitor.java @@ -0,0 +1,118 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 20, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.List; + +import net.opengis.filter.v_1_1_0.BBOXType; +import net.opengis.filter.v_1_1_0.BinarySpatialOpType; +import net.opengis.filter.v_1_1_0.DistanceBufferType; +import net.opengis.filter.v_1_1_0.PropertyIsLikeType; +import net.opengis.filter.v_1_1_0.PropertyIsNullType; + +/** + * + * @author bclement + * @version 1.0 + */ +public interface OgcFilterVisitor { + + // comparison + + public Object equal(ExpressionProcessor left, ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception; + + public Object notEqual(ExpressionProcessor left, ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception; + + public Object lessThan(ExpressionProcessor left, ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception; + + public Object greaterThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception; + + public Object greaterThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception; + + public Object lessThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception; + + public Object isLike(PropertyIsLikeType op, Object obj) throws Exception; + + public Object isNull(PropertyIsNullType op, Object obj) throws Exception; + + public Object between(ExpressionProcessor lower, ExpressionProcessor exp, + ExpressionProcessor upper, Object obj) throws Exception; + + // logic + + public Object and(List filters, Object obj) + throws Exception; + + public Object or(List filters, Object obj) + throws Exception; + + public Object not(FilterProcessor filter, Object obj) throws Exception; + + // spatial + + public Object spatialEquals(BinarySpatialOpType op, Object obj) + throws Exception; + + public Object disjoint(BinarySpatialOpType op, Object obj) throws Exception; + + public Object touches(BinarySpatialOpType op, Object obj) throws Exception; + + public Object within(BinarySpatialOpType op, Object obj) throws Exception; + + public Object overlaps(BinarySpatialOpType op, Object obj) throws Exception; + + public Object crosses(BinarySpatialOpType op, Object obj) throws Exception; + + public Object intersects(BinarySpatialOpType op, Object obj) + throws Exception; + + public Object contains(BinarySpatialOpType op, Object obj) throws Exception; + + public Object dWithin(DistanceBufferType op, Object obj) throws Exception; + + public Object beyond(DistanceBufferType op, Object obj) throws Exception; + + public Object bbox(BBOXType op, Object obj) throws Exception; + + // id + + public Object id(List ids, Object obj) throws Exception; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/QueryExpressionVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/QueryExpressionVisitor.java new file mode 100644 index 0000000000..a4f10046e5 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/QueryExpressionVisitor.java @@ -0,0 +1,150 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.List; + +import net.opengis.filter.v_1_1_0.PropertyNameType; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + + +/** + * + * @author bclement + * @version 1.0 + */ +public class QueryExpressionVisitor implements OgcExpressionVisitor { + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#add(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public Object add(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception { + throw new Exception("Unsupported expression: add"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#sub(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public Object sub(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception { + throw new Exception("Unsupported expression: sub"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#mul(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public Object mul(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception { + throw new Exception("Unsupported expression: mul"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#div(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public Object div(ExpressionProcessor left, ExpressionProcessor right, + Object obj) throws Exception { + throw new Exception("Unsupported expression: div"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#literal(java.util.List, + * java.lang.Object) + */ + @Override + public Object literal(List values, Object obj) throws Exception { + if (values.size() != 1) { + log.warn("Unsupported literal values: " + values.toArray()); + } + return values.get(0); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#property(net.opengis + * .filter.v_1_1_0.PropertyNameType, java.lang.Object) + */ + @Override + public Object property(PropertyNameType prop, Object obj) throws Exception { + List content = prop.getContent(); + if (content.size() != 1) { + log.warn("Unsupported property name values: " + content.toArray()); + } + return content.get(0); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#function(java.util.List, + * java.lang.String, java.lang.Object) + */ + @Override + public Object function(List expressions, String name, + Object obj) throws Exception { + throw new Exception("Unsupported expression type: function"); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/QueryFilterVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/QueryFilterVisitor.java new file mode 100644 index 0000000000..affa1a616f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v1_1_0/QueryFilterVisitor.java @@ -0,0 +1,562 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v1_1_0; + +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_1_1_0.BBOXType; +import net.opengis.filter.v_1_1_0.BinarySpatialOpType; +import net.opengis.filter.v_1_1_0.DistanceBufferType; +import net.opengis.filter.v_1_1_0.PropertyIsLikeType; +import net.opengis.filter.v_1_1_0.PropertyIsNullType; +import net.opengis.gml.v_3_1_1.AbstractGeometryType; +import net.opengis.gml.v_3_1_1.EnvelopeType; + +import org.apache.commons.lang.StringUtils; +import org.geotools.geometry.jts.JTS; +import org.hibernate.criterion.Conjunction; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.Disjunction; +import org.hibernate.criterion.Junction; +import org.hibernate.criterion.MatchMode; +import org.hibernate.criterion.Restrictions; +import org.hibernatespatial.criterion.SpatialRestrictions; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.gml3_1_1.EnvelopeConverter; +import com.raytheon.uf.edex.ogc.common.gml3_1_1.GeometryConverter; +import com.raytheon.uf.edex.ogc.common.util.ConvertService; +import com.raytheon.uf.edex.wfs.provider.VisitorBag; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +/** + * + * @author bclement + * @version 1.0 + */ +public class QueryFilterVisitor implements OgcFilterVisitor { + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + protected GeometryConverter geomConverter = new GeometryConverter(); + + protected EnvelopeConverter envConverter = new EnvelopeConverter(); + + protected QueryExpressionVisitor exprVisitor = new QueryExpressionVisitor(); + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#equal(com.raytheon.uf.edex + * .filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion equal(ExpressionProcessor left, + ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.eq(e.getKey(), e.getValue()); + } + + protected Entry getBinaryProps(ExpressionProcessor left, + ExpressionProcessor right, VisitorBag bag) throws Exception { + String prop = (String) left.accept(exprVisitor, bag); + String value = (String) right.accept(exprVisitor, bag); + Class ent = bag.getRootEntity(); + String[] path = parseProp(prop); + String field = StringUtils.join(path, "."); + String entityField = bag.filterField(field); + if (!field.equals(entityField)) { + path = entityField.split("\\."); + } + Object val = ConvertService.get().convertAsType(value, ent, path); + return new SimpleEntry(entityField, val); + } + + protected String[] parseProp(String prop) { + // TODO we may want to keep the namespaces + String[] rval = prop.trim().split("\\/"); + for (int i = 0; i < rval.length; ++i) { + int index = rval[i].lastIndexOf(':'); + if (index > -1) { + rval[i] = rval[i].substring(index + 1); + } + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#notEqual(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion notEqual(ExpressionProcessor left, + ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.ne(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThan(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion lessThan(ExpressionProcessor left, + ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.lt(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThan(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion greaterThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.gt(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion greaterThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.ge(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion lessThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.le(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isLike(net.opengis.filter + * .v_1_1_0.PropertyIsLikeType, java.lang.Object) + */ + @Override + public Criterion isLike(PropertyIsLikeType op, Object obj) + throws Exception { + // FIXME this is not correct, needs to take wildcard, anychar and + // escapes into account + VisitorBag bag = (VisitorBag) obj; + String prop = (String) op.getPropertyName().getContent().get(0); + String value = (String) op.getLiteral().getContent().get(0); + return Restrictions.like(bag.filterField(prop), value, + MatchMode.ANYWHERE); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isNull(net.opengis.filter + * .v_1_1_0.PropertyIsNullType, java.lang.Object) + */ + @Override + public Criterion isNull(PropertyIsNullType op, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + String field = (String) op.getPropertyName().getContent().get(0); + return Restrictions.isNull(bag.filterField(field)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#between(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public Criterion between(ExpressionProcessor lower, + ExpressionProcessor exp, + ExpressionProcessor upper, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + + Entry lowerPart = getBinaryProps(exp, lower, bag); + Entry upperPart = getBinaryProps(exp, upper, bag); + + return Restrictions.between(lowerPart.getKey(), lowerPart.getValue(), + upperPart.getValue()); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#and(java.util.List, + * java.lang.Object) + */ + @Override + public Criterion and(List filters, Object obj) + throws Exception { + Conjunction rval = Restrictions.conjunction(); + acceptAll(filters, obj, rval); + return rval; + } + + protected void acceptAll(List filters, Object obj, + Junction junc) throws Exception { + Iterator i = filters.iterator(); + while (i.hasNext()) { + junc.add((Criterion) i.next().accept(this, obj)); + } + } + + protected List addAll(List l1, List l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + ArrayList rval = new ArrayList(l1.size() + l2.size()); + rval.addAll(l1); + rval.addAll(l2); + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#or(java.util.List, + * java.lang.Object) + */ + @Override + public Criterion or(List filters, Object obj) + throws Exception { + Disjunction rval = Restrictions.disjunction(); + acceptAll(filters, obj, rval); + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#not(com.raytheon.uf.edex + * .filter.FilterProcessor, java.lang.Object) + */ + @Override + public Criterion not(FilterProcessor filter, Object obj) throws Exception { + return Restrictions.not((Criterion) filter.accept(this, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#spatialEquals(net.opengis + * .filter.v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion spatialEquals(BinarySpatialOpType op, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinarySpatial(op, bag); + return SpatialRestrictions.eq(bag.filterField(e.getKey()), e.getValue()); + } + + + protected Entry getBinarySpatial( + BinarySpatialOpType binary, VisitorBag bag) throws Exception { + List lst = binary.getPropertyName().getContent(); + String str = getStringWarn(lst, "Unsupported property name type"); + String prop = StringUtils.join(parseProp(str), '.'); + Geometry shape = getGeometry(binary); + return new SimpleEntry(bag.filterField(prop), shape); + } + + protected Geometry getGeometry(BinarySpatialOpType binary) throws Exception { + JAXBElement env = binary.getEnvelope(); + JAXBElement geom = binary.getGeometry(); + Geometry shape; + if (env != null && !env.isNil()) { + Envelope envelope = envConverter.convert(env.getValue()); + shape = geomConverter.convert(envelope); + } else if (geom != null && !geom.isNil()) { + shape = geomConverter.convert(geom.getValue()); + } else { + throw new Exception("Unsupported geometry format"); + } + return shape; + } + + protected String getStringWarn(List lst, String msg) { + if (lst.size() != 1) { + log.warn(msg); + } + return (String) lst.get(0); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#disjoint(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion disjoint(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.disjoint(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#touches(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion touches(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.touches(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#within(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion within(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.within(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#overlaps(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion overlaps(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.overlaps(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#crosses(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion crosses(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.crosses(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#intersects(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion intersects(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.intersects(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#contains(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion contains(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.contains(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#dWithin(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public Object dWithin(DistanceBufferType op, Object obj) + throws Exception { + throw new Exception("dWithin queries not supported"); + } + + // public RangeParameter getDistance(DistanceBufferType dist, RangeOperand + // op, + // VisitorBag bag) throws Exception { + // List lst = dist.getPropertyName().getContent(); + // String str = getStringWarn(lst, "Unsupported property name type"); + // String prop = StringUtils.join(parseProp(str), '.'); + // AbstractGeometryType geom = dist.getGeometry().getValue(); + // Geometry res = geomConverter.convert(geom); + // if (!(res instanceof Point)) { + // throw new Exception("Unsupported distance geometry" + // + res.getClass()); + // } + // double distance = 0;// FIXME jaxb classes do not contain distance value + // RangeParameter param = new RangeParameter(prop, (Point) res, distance, + // op); + // throw new Exception("Distance types not supported"); + // // return rval; + // } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#beyond(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public Object beyond(DistanceBufferType op, Object obj) + throws Exception { + throw new Exception("Beyond queries not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#bbox(net.opengis.filter. + * v_1_1_0.BBOXType, java.lang.Object) + */ + @Override + public Criterion bbox(BBOXType op, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + List lst = op.getPropertyName().getContent(); + String str = getStringWarn(lst, "Unsupported property name type"); + String prop = StringUtils.join(parseProp(str), '.'); + EnvelopeType value = op.getEnvelope().getValue(); + Envelope env = envConverter.convert(value); + return SpatialRestrictions.within(bag.filterField(prop), + JTS.toGeometry(env)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v1_1_0.OgcFilterVisitor#id(java.util. + * List, java.lang.Object) + */ + @Override + public Object id(List ids, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + String idField = bag.getIdField(); + Conjunction rval = Restrictions.conjunction(); + for (String id : ids) { + rval.add(Restrictions.eq(idField, id)); + } + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbsExpressionOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbsExpressionOp.java new file mode 100644 index 0000000000..07a0bfb726 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbsExpressionOp.java @@ -0,0 +1,102 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.FunctionType; +import net.opengis.filter.v_2_0_0.LiteralType; + +/** + * Visitor pattern support classes for filter expression operations + * + * @author bclement + * @version 1.0 + */ +public abstract class AbsExpressionOp { + + /** + * @param element + * @param visitor + * @param obj + * @return + * @throws Exception + */ + public abstract Object visit(JAXBElement element, + IExpressionVisitor visitor, Object obj) throws Exception; + + /** + * processes literal values + */ + public static class Literal extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, IExpressionVisitor visitor, + Object obj) throws Exception { + LiteralType literal = (LiteralType) element.getValue(); + return visitor.literal(literal.getContent(), obj); + } + } + + /** + * processes value references + */ + public static class ValueRef extends AbsExpressionOp { + @Override + public Object visit(JAXBElement element, IExpressionVisitor visitor, + Object obj) throws Exception { + Object value = element.getValue(); + return visitor.valueRef(value.toString(), obj); + } + + } + + /** + * processes custom functions + */ + public static class Function extends AbsExpressionOp { + @Override + public FilterFunction visit(JAXBElement element, + IExpressionVisitor visitor, Object obj) throws Exception { + FunctionType f = (FunctionType) element.getValue(); + String name = f.getName(); + List> exprs = f.getExpression(); + List procs = new ArrayList( + exprs.size()); + for (JAXBElement expr : exprs) { + procs.add(new ExpressionProcessor(expr)); + } + return visitor.function(procs, name, obj); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbsTemporalOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbsTemporalOp.java new file mode 100644 index 0000000000..3beb80718e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbsTemporalOp.java @@ -0,0 +1,214 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.BinaryTemporalOpType; +import net.opengis.filter.v_2_0_0.TemporalOpsType; + +/** + * Visitor pattern support classes for temporal operations + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 17, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public abstract class AbsTemporalOp { + + /** + * @param op + * @param visitor + * @param obj + * @return + * @throws Exception + */ + public abstract Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception; + + /** + * tests if time instance/range is after other time instance/range + */ + public static class After extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.after(bin, obj); + } + } + + /** + * tests if time instance/range is before other time instance/range + */ + public static class Before extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.before(bin, obj); + } + } + + /** + * tests if time instance is the start of time range + */ + public static class Begins extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.begins(bin, obj); + } + } + + /** + * tests if time instance is the end of time range + */ + public static class Ends extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.ends(bin, obj); + } + } + + /** + * tests if time range is started by time instance + */ + public static class BegunBy extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.begunBy(bin, obj); + } + } + + /** + * tests if time range contains time instance + */ + public static class TContains extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.tContains(bin, obj); + } + } + + /** + * tests if time instance is contained by time range + */ + public static class During extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.during(bin, obj); + } + } + + /** + * tests if time instance/range is equal to other time instance/range + */ + public static class TEquals extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.tEquals(bin, obj); + } + } + + /** + * tests if time range overlaps other time range + */ + public static class TOverlaps extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.tOverlaps(bin, obj); + } + } + + /** + * tests if time range is right before other time range + */ + public static class Meets extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.meets(bin, obj); + } + } + + /** + * tests if time range is overlapped by other time range + */ + public static class OverlappedBy extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.overlappedBy(bin, obj); + } + } + + /** + * tests if time range is right after other time range + */ + public static class MetBy extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.metBy(bin, obj); + } + } + + /** + * tests if time range is ended by time instance + */ + public static class EndedBy extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.endedBy(bin, obj); + } + } + + /** + * tests if time range intersects other time range + */ + public static class AnyInteracts extends AbsTemporalOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryTemporalOpType bin = (BinaryTemporalOpType) op.getValue(); + return visitor.anyInteracts(bin, obj); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractCompOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractCompOp.java new file mode 100644 index 0000000000..38dbaff444 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractCompOp.java @@ -0,0 +1,233 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 20, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.BinaryComparisonOpType; +import net.opengis.filter.v_2_0_0.ComparisonOpsType; +import net.opengis.filter.v_2_0_0.PropertyIsBetweenType; +import net.opengis.filter.v_2_0_0.PropertyIsLikeType; +import net.opengis.filter.v_2_0_0.PropertyIsNilType; +import net.opengis.filter.v_2_0_0.PropertyIsNullType; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; + +/** + * Visitor pattern support classes for comparison operators + * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractCompOp { + + protected static final Map binaryMap; + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + static { + binaryMap = new HashMap(); + binaryMap.put("PropertyIsEqualTo", new Equal()); + binaryMap.put("PropertyIsNotEqualTo", new NotEqual()); + binaryMap.put("PropertyIsLessThan", new LessThan()); + binaryMap.put("PropertyIsGreaterThan", new GreaterThan()); + binaryMap.put("PropertyIsLessThanOrEqualTo", new LessThanEqual()); + binaryMap.put("PropertyIsGreaterThanOrEqualTo", new GreaterThanEqual()); + } + + /** + * @param op + * @param visitor + * @param obj + * @return + * @throws Exception + */ + public abstract Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception; + + /** + * like expression akin to SQL LIKE + */ + public static class Like extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + return visitor.isLike((PropertyIsLikeType) op.getValue(), obj); + } + } + + /** + * test if property is null + */ + public static class Null extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + return visitor.isNull((PropertyIsNullType) op.getValue(), obj); + } + } + + /** + * test if property is nil + */ + public static class Nil extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + return visitor.isNil((PropertyIsNilType) op.getValue(), obj); + } + } + + /** + * test if property's value is between two values + */ + public static class Between extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + PropertyIsBetweenType between = (PropertyIsBetweenType) op + .getValue(); + ExpressionProcessor exp = new ExpressionProcessor( + between.getExpression()); + ExpressionProcessor lower = new ExpressionProcessor(between + .getLowerBoundary().getExpression()); + ExpressionProcessor upper = new ExpressionProcessor(between + .getUpperBoundary().getExpression()); + return visitor.between(lower, exp, upper, obj); + } + } + + /** + * top level binary operator visitation site, delegates to other classes + */ + public static class BinaryOp extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + String name = op.getName().getLocalPart(); + AbstractCompOp compOp = binaryMap.get(name); + if (compOp != null) { + return compOp.visit(op, visitor, obj); + } else { + throw new Exception("Unknown binary operator: " + name); + } + } + } + + public static class Equal extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.equal(new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class NotEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.notEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class LessThan extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.lessThan( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class GreaterThan extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.greaterThan( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class LessThanEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.lessThanEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + + public static class GreaterThanEqual extends AbstractCompOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryComparisonOpType binary = (BinaryComparisonOpType) op + .getValue(); + List> expressions = binary.getExpression(); + return visitor.greaterThanEqual( + new ExpressionProcessor(expressions.get(0)), + new ExpressionProcessor(expressions.get(1)), + binary.isMatchCase(), obj); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractLogicOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractLogicOp.java new file mode 100644 index 0000000000..0c1f9505bf --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractLogicOp.java @@ -0,0 +1,153 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 21, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.BinaryLogicOpType; +import net.opengis.filter.v_2_0_0.ComparisonOpsType; +import net.opengis.filter.v_2_0_0.FilterType; +import net.opengis.filter.v_2_0_0.LogicOpsType; +import net.opengis.filter.v_2_0_0.SpatialOpsType; +import net.opengis.filter.v_2_0_0.TemporalOpsType; +import net.opengis.filter.v_2_0_0.UnaryLogicOpType; + +/** + * Visitor pattern support classes for logic operators + * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractLogicOp { + + /** + * @param op + * @param visitor + * @param obj + * @return + * @throws Exception + */ + public abstract Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception; + + @SuppressWarnings("unchecked") + protected List getProcessors(List> elements) + throws Exception { + List rval = new ArrayList( + elements.size()); + for (JAXBElement e : elements) { + Class type = e.getDeclaredType(); + Filter2Processor p; + if (ComparisonOpsType.class.isAssignableFrom(type)) { + p = Filter2Processor + .newFromComparison((JAXBElement) e); + } else if (LogicOpsType.class.isAssignableFrom(type)) { + p = Filter2Processor + .newFromLogic((JAXBElement) e); + } else if (SpatialOpsType.class.isAssignableFrom(type)) { + p = Filter2Processor + .newFromSpatial((JAXBElement) e); + } else if (TemporalOpsType.class.isAssignableFrom(type)) { + p = Filter2Processor + .newFromTemporal((JAXBElement) e); + } else { + throw new Exception("Unknown operator: " + type); + } + rval.add(p); + } + return rval; + } + + /** + * Create filter that is composed of the given operations. Uneeded + * parameters can be null. + * + * @param comps + * @param spats + * @param logic + * @param temps + * @return + */ + protected FilterType createFilter( + JAXBElement comps, + JAXBElement spats, + JAXBElement logic, + JAXBElement temps) { + FilterType rval = new FilterType(); + rval.setComparisonOps(comps); + rval.setLogicOps(logic); + rval.setSpatialOps(spats); + rval.setTemporalOps(temps); + return rval; + } + + public static class And extends AbstractLogicOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryLogicOpType and = (BinaryLogicOpType) op.getValue(); + List> gah = and + .getComparisonOpsOrSpatialOpsOrTemporalOps(); + List processors = getProcessors(gah); + return visitor.and(processors, obj); + } + } + + public static class Or extends AbstractLogicOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinaryLogicOpType or = (BinaryLogicOpType) op.getValue(); + List> gah = or + .getComparisonOpsOrSpatialOpsOrTemporalOps(); + List processors = getProcessors(gah); + return visitor.or(processors, obj); + } + } + + public static class Not extends AbstractLogicOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + UnaryLogicOpType not = (UnaryLogicOpType) op.getValue(); + JAXBElement comps = not + .getComparisonOps(); + JAXBElement spats = not.getSpatialOps(); + JAXBElement logics = not.getLogicOps(); + JAXBElement temps = not.getTemporalOps(); + FilterType filter = createFilter(comps, spats, logics, temps); + return visitor.not(new Filter2Processor(filter), obj); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractQueryFilterVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractQueryFilterVisitor.java new file mode 100644 index 0000000000..ebc95cf59e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractQueryFilterVisitor.java @@ -0,0 +1,593 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.lang.reflect.Field; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.regex.Pattern; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.BinarySpatialOpType; +import net.opengis.filter.v_2_0_0.BinaryTemporalOpType; +import net.opengis.gml.v_3_2_1.AbstractGeometryType; +import net.opengis.gml.v_3_2_1.EnvelopeType; +import net.opengis.gml.v_3_2_1.TimeInstantPropertyType; +import net.opengis.gml.v_3_2_1.TimeInstantType; +import net.opengis.gml.v_3_2_1.TimePeriodType; +import net.opengis.gml.v_3_2_1.TimePositionType; + +import org.apache.commons.lang.StringUtils; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.Junction; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.gml3_2_1.EnvelopeConverter; +import com.raytheon.uf.edex.ogc.common.gml3_2_1.GeometryConverter; +import com.raytheon.uf.edex.ogc.common.util.ConvertService; +import com.raytheon.uf.edex.wfs.provider.VisitorBag; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.io.WKTReader; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 15, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractQueryFilterVisitor implements IFilter2Visitor { + + protected QueryExpressionVisitor exprVisitor = new QueryExpressionVisitor(); + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + protected GeometryConverter geomConverter = new GeometryConverter(); + + protected EnvelopeConverter envConverter = new EnvelopeConverter(); + + /** + * Extract left and right side of binary operator + * + * @param left + * @param right + * @param bag + * @return entry with field as key and filter object as value + * @throws Exception + */ + protected Operand getBinaryProps(ExpressionProcessor left, + ExpressionProcessor right, VisitorBag bag) throws Exception { + OpField field = getRef(left, bag); + Object value = right.accept(exprVisitor, bag); + + if (!field.sql) { + Class ent = bag.getRootEntity(); + String[] path = field.value.split("\\."); + value = ConvertService.get().convertAsType((String) value, ent, + path); + } + + Operand operand = new Operand(field.value, value); + operand.sql = field.sql; + return operand; + } + + /** + * Parse reference string as dotted field path + * + * @param refProc + * @param bag + * @return + * @throws Exception + */ + protected OpField getRef(ExpressionProcessor refProc, VisitorBag bag) + throws Exception { + + OpField field = new OpField(); + Object obj = refProc.accept(exprVisitor, bag); + if (obj instanceof FilterFunction) { + field.value = ((FilterFunction) obj).toSql(); + field.sql = true; + } else { + String prop = (String) refProc.accept(exprVisitor, bag); + String[] path = parseProp(prop); + field.value = bag.filterField(StringUtils.join(path, ".")); + } + + return field; + } + + /** + * Parse reference string into field path parts + * + * @param prop + * @return + */ + protected String[] parseProp(String prop) { + // TODO we may want to keep the namespaces + String[] rval = prop.trim().split("\\/"); + for (int i = 0; i < rval.length; ++i) { + int index = rval[i].lastIndexOf(':'); + if (index > -1) { + rval[i] = rval[i].substring(index + 1); + } + } + return rval; + } + + /** + * Sends this object to all filters in list as visitor. Adds results to + * junction. + * + * @param filters + * @param obj + * @param junc + * @throws Exception + */ + protected void acceptAll(List filters, Object obj, + Junction junc) throws Exception { + Iterator i = filters.iterator(); + while (i.hasNext()) { + junc.add((Criterion) i.next().accept(this, obj)); + } + } + + /** + * Combine two lists. May reuse parameters as return value. + * + * @param + * @param l1 + * @param l2 + * @return + */ + protected List addAll(List l1, List l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + ArrayList rval = new ArrayList(l1.size() + l2.size()); + rval.addAll(l1); + rval.addAll(l2); + return rval; + } + + /** + * Get operands of binary spatial operator + * + * @param binary + * @param bag + * @return entry that has the field path as key and filter geometry as the + * value + * @throws Exception + */ + protected Entry getBinarySpatial( + BinarySpatialOpType binary, VisitorBag bag) throws Exception { + String str = binary.getValueReference(); + String prop = StringUtils.join(parseProp(str), '.'); + Geometry shape = getGeometry(binary, bag); + return new SimpleEntry(bag.filterField(prop), shape); + } + + /** + * Extract JTS geometry from spatial operator + * + * @param binary + * @param bag + * @return + * @throws Exception + */ + protected Geometry getGeometry(BinarySpatialOpType binary, VisitorBag bag) + throws Exception { + if (binary.isSetAny()) { + return getGeometry(binary.getAny()); + } else if (binary.isSetExpression()) { + JAXBElement exp = binary.getExpression(); + return getGeometry(new ExpressionProcessor(exp)); + } else { + throw new Exception("Missing geometry value"); + } + } + + /** + * Convert XSD 'any' reference to JTS geometry if possible. + * + * @param obj + * @return + * @throws Exception + */ + protected Geometry getGeometry(Object obj) throws Exception { + if (obj instanceof JAXBElement) { + obj = ((JAXBElement) obj).getValue(); + } + Geometry shape; + if (obj instanceof EnvelopeType) { + Envelope envelope = envConverter.convert((EnvelopeType) obj); + shape = geomConverter.convert(envelope); + } else if (obj instanceof AbstractGeometryType) { + shape = geomConverter.convert((AbstractGeometryType) obj); + } else { + throw new Exception("Unsupported geometry format"); + } + return shape; + } + + /** + * Convert WKT literal expression to JTS geometry + * + * @param proc + * @param bag + * @return + * @throws Exception + */ + protected Geometry getGeometry(ExpressionProcessor proc, VisitorBag bag) + throws Exception { + Object literal = proc.accept(exprVisitor, bag); + if (!(literal instanceof String)) { + throw new Exception("Geometry literals must be WKT"); + } + try { + return new WKTReader().read((String) literal); + } catch (Exception e) { + throw new Exception("Geometry literals must be WKT"); + } + } + + /** + * Log warning if list is not of size 1 + * + * @param lst + * @param msg + * @return + */ + protected String getStringWarn(List lst, String msg) { + if (lst.size() != 1) { + log.warn(msg); + } + return (String) lst.get(0); + } + + /** + * Sreies of inner classes to facilitate passing parsed fields with select + * metadata obtained during the parsing + */ + protected static class OpField { + public String value; + + public boolean sql = false; + + public OpField() { + this.value = ""; + } + + public OpField(String val) { + this.value = val; + } + } + + protected static class Operand { + public Object right; + + public Object left; + + public boolean sql = false; + + public Operand(Object left, Object right) { + this.right = right; + this.left = left; + } + } + + protected static class TimeOperand { + public Object start; + + public Object end; + + public boolean instance = false; + + public boolean sql = false; + + public TimeOperand(Object instance) { + start = instance; + this.instance = true; + } + + public TimeOperand(Object start, Object end) { + this.start = start; + this.end = end; + } + } + + /** + * Get right operand of binary temporal operation + * + * @param binary + * @param timeClass + * class of left operand for the right to match + * @param obj + * visitor object + * @return either an instance or period time operand + * @throws Exception + */ + protected TimeOperand getOperand(BinaryTemporalOpType binary, + Class timeClass, Object obj) throws Exception { + TimeOperand rval; + if (binary.isSetExpression()) { + ExpressionProcessor eproc = new ExpressionProcessor( + binary.getExpression()); + Object timeObj = eproc.accept(exprVisitor, obj); + if (timeObj instanceof TimeFunction) { + rval = new TimeOperand(((TimeFunction) timeObj).toSql()); + rval.sql = true; + } else { + rval = parseTimeString((String) timeObj, timeClass); + } + } else if (binary.isSetAny()) { + Object any = binary.getAny(); + if (any instanceof JAXBElement) { + any = ((JAXBElement) any).getValue(); + } + rval = extractTime(any, timeClass); + } else { + throw new Exception( + "No temporal value set for binary temporal operation"); + } + return rval; + } + + /** + * Parse right operand from string + * + * @param time + * ISO 8601 formatted time instance or period + * @param timeClass + * class of left operand for the right to match + * @return either an instance or period time operand + */ + protected TimeOperand parseTimeString(String time, Class timeClass) { + TimeOperand rval; + if (time.contains("/")) { + // range + String[] parts = StringUtils.split(time, '/'); + Object start = parseInstance(parts[0], timeClass); + Object end = parseInstance(parts[1], timeClass); + rval = new TimeOperand(start, end); + } else { + // instance + Object instance = parseInstance(time, timeClass); + rval = new TimeOperand(instance); + } + return rval; + } + + /** + * Get time operand from GML time object + * + * @param obj + * GML time primitive type + * @param timeClass + * class of left operand for the right to match + * @return either an instance or period time operand + * @throws Exception + */ + protected TimeOperand extractTime(Object obj, Class timeClass) + throws Exception { + TimeOperand rval; + if (obj instanceof TimeInstantType) { + Object inst = parseInstance((TimeInstantType) obj, timeClass); + rval = new TimeOperand(inst); + } else if (obj instanceof TimePositionType) { + Object inst = parseInstance((TimePositionType) obj, timeClass); + rval = new TimeOperand(inst); + } else if (obj instanceof TimePeriodType) { + rval = parsePeriod((TimePeriodType) obj, timeClass); + } else { + throw new Exception("Unsupported time type: " + obj.getClass()); + } + return rval; + } + + /** + * Get field path and type for left operand + * + * @param binary + * @param bag + * @return pair of dotted field and target class + * @throws Exception + */ + protected Entry> getRef(BinaryTemporalOpType binary, + VisitorBag bag) throws Exception { + String prop = binary.getValueReference(); + String[] unfilteredPath = parseProp(prop); + String unfilteredField = StringUtils.join(unfilteredPath, "."); + String field = bag.filterField(unfilteredField); + String[] path = field.split("\\."); + Class fieldType = getFieldType(bag.getRootEntity(), path); + return new SimpleEntry>(field, fieldType); + } + + /** + * Determine class for field + * + * @param entity + * @param fieldPath + * @return + * @throws SecurityException + * @throws NoSuchFieldException + */ + protected static Class getFieldType(Class entity, String[] fieldPath) + throws SecurityException, NoSuchFieldException { + Field f = getField(fieldPath[0], entity); + for (int i = 1; i < fieldPath.length; ++i) { + f = getField(fieldPath[i], f.getType()); + } + return f.getType(); + } + + /** + * Extract field from class, searches parent classes + * + * @param fieldName + * @param c + * @return + * @throws SecurityException + * @throws NoSuchFieldException + */ + protected static Field getField(String fieldName, Class c) + throws SecurityException, NoSuchFieldException { + Field rval; + try { + rval = c.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + Class parent = c.getSuperclass(); + if (parent.isInstance(Object.class)) { + throw e; + } else { + rval = getField(fieldName, c.getSuperclass()); + } + } + return rval; + } + + /** + * Get time instance for right operand + * + * @param binary + * @param timeClass + * class of left operand for the right to match + * @param obj + * visitor object + * @return object of type timeClass + * @throws Exception + */ + protected Object getInstance(BinaryTemporalOpType binary, + Class timeClass, Object obj) throws Exception { + if (binary.isSetExpression()) { + ExpressionProcessor eproc = new ExpressionProcessor( + binary.getExpression()); + String timeStr = (String) eproc.accept(exprVisitor, obj); + return parseInstance(timeStr, timeClass); + } else if (binary.isSetAny()) { + Object any = binary.getAny(); + if (any instanceof JAXBElement) { + any = ((JAXBElement) any).getValue(); + } + if (any instanceof TimeInstantType) { + return parseInstance((TimeInstantType) any, timeClass); + } else { + throw new Exception("Unsupported time instance type: " + + any.getClass()); + } + } + throw new Exception( + "No temporal value set for binary temporal operation"); + } + + @SuppressWarnings("unchecked") + protected T parseInstance(String str, Class timeClass) { + return (T) ConvertService.get().convertObject(str, timeClass); + } + + /** + * Get time instance from GML time primitive + * + * @param ttype + * @param timeClass + * class of left operand for the right to match + * @return object of type timeClass + * @throws Exception + */ + protected Object parseInstance(TimeInstantType ttype, Class timeClass) + throws Exception { + TimePositionType pos = ttype.getTimePosition(); + return parseInstance(pos, timeClass); + } + + /** + * Get time instance from GML time primitive + * + * @param pos + * @param timeClass + * class of left operand for the right to match + * @return object of type timeClass + * @throws Exception + */ + protected Object parseInstance(TimePositionType pos, Class timeClass) + throws Exception { + if (pos.isSetFrame()) { + Pattern p = Pattern.compile("^.*ISO.?8601.*$", + Pattern.CASE_INSENSITIVE); + String frame = pos.getFrame(); + if (!p.matcher(frame).matches()) { + throw new Exception("Only ISO-8601 times are supported"); + } + } + List values = pos.getValue(); + if (values.size() > 1) { + throw new Exception( + "Multiple values per time position not supported"); + } + String value = values.get(0); + return parseInstance(value, timeClass); + } + + /** + * Get time period from GML time primitive + * + * @param ttype + * @param timeClass + * class of left operand for the right to match + * @return period time operand + * @throws Exception + */ + protected TimeOperand parsePeriod(TimePeriodType ttype, Class timeClass) + throws Exception { + Object begin; + Object end; + if (ttype.isSetBegin()) { + TimeInstantPropertyType prop = ttype.getBegin(); + TimeInstantType inst = prop.getTimeInstant(); + begin = parseInstance(inst, timeClass); + } else if (ttype.isSetBeginPosition()) { + TimePositionType pos = ttype.getBeginPosition(); + begin = parseInstance(pos, timeClass); + } else { + throw new Exception("Unable to locate beginning of time period"); + } + if (ttype.isSetBegin()) { + TimeInstantPropertyType prop = ttype.getEnd(); + TimeInstantType inst = prop.getTimeInstant(); + end = parseInstance(inst, timeClass); + } else if (ttype.isSetEndPosition()) { + TimePositionType pos = ttype.getEndPosition(); + end = parseInstance(pos, timeClass); + } else { + throw new Exception("Unable to locate end of time period"); + } + return new TimeOperand(begin, end); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractSpatialOp.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractSpatialOp.java new file mode 100644 index 0000000000..805dbff479 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/AbstractSpatialOp.java @@ -0,0 +1,162 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 21, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.BBOXType; +import net.opengis.filter.v_2_0_0.BinarySpatialOpType; +import net.opengis.filter.v_2_0_0.DistanceBufferType; +import net.opengis.filter.v_2_0_0.SpatialOpsType; + +/** + * Visitor pattern support classes for spatial operations + * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractSpatialOp { + + /** + * @param op + * @param visitor + * @param obj + * @return + * @throws Exception + */ + public abstract Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception; + + public static class SpatialEquals extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.spatialEquals(binary, obj); + } + } + + public static class Disjoint extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.disjoint(binary, obj); + } + } + + public static class Touches extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.touches(binary, obj); + } + } + + public static class Within extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.within(binary, obj); + } + } + + public static class Overlaps extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.overlaps(binary, obj); + } + } + + public static class Crosses extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.crosses(binary, obj); + } + } + + public static class Intersects extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.intersects(binary, obj); + } + } + + public static class Contains extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BinarySpatialOpType binary = (BinarySpatialOpType) op.getValue(); + return visitor.contains(binary, obj); + } + } + + /** + * distance within + */ + public static class DWithin extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + DistanceBufferType dist = (DistanceBufferType) op.getValue(); + return visitor.dWithin(dist, obj); + } + } + + public static class Beyond extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + DistanceBufferType dist = (DistanceBufferType) op.getValue(); + return visitor.beyond(dist, obj); + } + } + + /** + * bounding box + */ + public static class Bbox extends AbstractSpatialOp { + @Override + public Object visit(JAXBElement op, + IFilter2Visitor visitor, Object obj) throws Exception { + BBOXType bbox = (BBOXType) op.getValue(); + return visitor.bbox(bbox, obj); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/ExpressionProcessor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/ExpressionProcessor.java new file mode 100644 index 0000000000..b3850a1f42 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/ExpressionProcessor.java @@ -0,0 +1,78 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 21, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.HashMap; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +/** + * Top level visitor pattern support class for expressions + * + * @author bclement + * @version 1.0 + */ +public class ExpressionProcessor { + + protected static final Map expressionMap; + static { + expressionMap = new HashMap(); + expressionMap.put("Literal", new AbsExpressionOp.Literal()); + expressionMap.put("ValueReference", new AbsExpressionOp.ValueRef()); + expressionMap.put("Function", new AbsExpressionOp.Function()); + } + + protected JAXBElement expression; + + /** + * @param expression + */ + public ExpressionProcessor(JAXBElement expression) { + this.expression = expression; + } + + /** + * Entry point for visitor + * + * @param visitor + * @param obj + * @return + * @throws Exception + */ + public Object accept(IExpressionVisitor visitor, Object obj) + throws Exception { + AbsExpressionOp op = expressionMap.get(expression.getName() + .getLocalPart()); + return op.visit(expression, visitor, obj); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/Filter2Processor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/Filter2Processor.java new file mode 100644 index 0000000000..9148412dcd --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/Filter2Processor.java @@ -0,0 +1,226 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 20, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.AbstractIdType; +import net.opengis.filter.v_2_0_0.BinaryComparisonOpType; +import net.opengis.filter.v_2_0_0.ComparisonOpsType; +import net.opengis.filter.v_2_0_0.FilterType; +import net.opengis.filter.v_2_0_0.LogicOpsType; +import net.opengis.filter.v_2_0_0.PropertyIsBetweenType; +import net.opengis.filter.v_2_0_0.PropertyIsLikeType; +import net.opengis.filter.v_2_0_0.PropertyIsNilType; +import net.opengis.filter.v_2_0_0.PropertyIsNullType; +import net.opengis.filter.v_2_0_0.SpatialOpsType; +import net.opengis.filter.v_2_0_0.TemporalOpsType; + +import com.raytheon.uf.edex.wfs.filter.v2_0_0.AbstractCompOp.Between; +import com.raytheon.uf.edex.wfs.filter.v2_0_0.AbstractCompOp.BinaryOp; +import com.raytheon.uf.edex.wfs.filter.v2_0_0.AbstractCompOp.Like; +import com.raytheon.uf.edex.wfs.filter.v2_0_0.AbstractCompOp.Nil; +import com.raytheon.uf.edex.wfs.filter.v2_0_0.AbstractCompOp.Null; + +/** + * Top level visitor pattern support class for filters + * + * @author bclement + * @version 1.0 + */ +public class Filter2Processor { + + protected static final Map, AbstractCompOp> compMap; + static { + compMap = new HashMap, AbstractCompOp>(); + compMap.put(BinaryComparisonOpType.class, new BinaryOp()); + compMap.put(PropertyIsLikeType.class, new Like()); + compMap.put(PropertyIsNullType.class, new Null()); + compMap.put(PropertyIsNilType.class, new Nil()); + compMap.put(PropertyIsBetweenType.class, new Between()); + } + + protected static final Map logicMap; + static { + logicMap = new HashMap(); + logicMap.put("And", new AbstractLogicOp.And()); + logicMap.put("Or", new AbstractLogicOp.Or()); + logicMap.put("Not", new AbstractLogicOp.Not()); + } + + protected static final Map spatialMap; + static { + spatialMap = new HashMap(); + spatialMap.put("Equals", new AbstractSpatialOp.SpatialEquals()); + spatialMap.put("Disjoint", new AbstractSpatialOp.Disjoint()); + spatialMap.put("Touches", new AbstractSpatialOp.Touches()); + spatialMap.put("Within", new AbstractSpatialOp.Within()); + spatialMap.put("Overlaps", new AbstractSpatialOp.Overlaps()); + spatialMap.put("Crosses", new AbstractSpatialOp.Crosses()); + spatialMap.put("Intersects", new AbstractSpatialOp.Intersects()); + spatialMap.put("Contains", new AbstractSpatialOp.Contains()); + spatialMap.put("DWithin", new AbstractSpatialOp.DWithin()); + spatialMap.put("Beyond", new AbstractSpatialOp.Beyond()); + spatialMap.put("BBOX", new AbstractSpatialOp.Bbox()); + } + + protected static final Map temporalMap; + static { + temporalMap = new HashMap(); + temporalMap.put("After", new AbsTemporalOp.After()); + temporalMap.put("Before", new AbsTemporalOp.Before()); + temporalMap.put("Begins", new AbsTemporalOp.Begins()); + temporalMap.put("BegunBy", new AbsTemporalOp.BegunBy()); + temporalMap.put("TContains", new AbsTemporalOp.TContains()); + temporalMap.put("During", new AbsTemporalOp.During()); + temporalMap.put("EndedBy", new AbsTemporalOp.EndedBy()); + temporalMap.put("Ends", new AbsTemporalOp.Ends()); + temporalMap.put("TEquals", new AbsTemporalOp.TEquals()); + temporalMap.put("Meets", new AbsTemporalOp.Meets()); + temporalMap.put("MetBy", new AbsTemporalOp.MetBy()); + temporalMap.put("TOverlaps", new AbsTemporalOp.TOverlaps()); + temporalMap.put("OverlappedBy", new AbsTemporalOp.OverlappedBy()); + temporalMap.put("AnyInteracts", new AbsTemporalOp.AnyInteracts()); + } + + protected FilterType filter; + + /** + * @param filter + * filter to process + */ + public Filter2Processor(FilterType filter) { + this.filter = filter; + } + + /** + * Utility method to create processor from logic operators + * + * @param ops + * @return + */ + public static Filter2Processor newFromLogic( + JAXBElement ops) { + FilterType f = new FilterType(); + f.setLogicOps(ops); + return new Filter2Processor(f); + } + + /** + * Utility method to create processor from comparison operators + * + * @param ops + * @return + */ + public static Filter2Processor newFromComparison( + JAXBElement ops) { + FilterType f = new FilterType(); + f.setComparisonOps(ops); + return new Filter2Processor(f); + } + + /** + * Utility method to create processor from spatial operators + * + * @param ops + * @return + */ + public static Filter2Processor newFromSpatial( + JAXBElement ops) { + FilterType f = new FilterType(); + f.setSpatialOps(ops); + return new Filter2Processor(f); + } + + /** + * Utility method to create processor from temporal operators + * + * @param ops + * @return + */ + public static Filter2Processor newFromTemporal( + JAXBElement ops) { + FilterType f = new FilterType(); + f.setTemporalOps(ops); + return new Filter2Processor(f); + } + + /** + * Entry point for visitor + * + * @param visitor + * @param obj + * @return + * @throws Exception + */ + public Object accept(IFilter2Visitor visitor, Object obj) throws Exception { + JAXBElement comps = filter + .getComparisonOps(); + JAXBElement logics = filter.getLogicOps(); + JAXBElement spats = filter.getSpatialOps(); + JAXBElement temps = filter.getTemporalOps(); + List> ids = filter.getId(); + Object rval; + if (logics != null && !logics.isNil()) { + String name = logics.getName().getLocalPart(); + AbstractLogicOp op = logicMap.get(name); + rval = op.visit(logics, visitor, obj); + } else if (comps != null && !comps.isNil()) { + Class type = comps.getDeclaredType(); + AbstractCompOp op = compMap.get(type); + rval = op.visit(comps, visitor, obj); + } else if (spats != null && !spats.isNil()) { + String name = spats.getName().getLocalPart(); + AbstractSpatialOp op = spatialMap.get(name); + rval = op.visit(spats, visitor, obj); + } else if (temps != null && !temps.isNil()) { + String name = temps.getName().getLocalPart(); + AbsTemporalOp op = temporalMap.get(name); + rval = op.visit(temps, visitor, obj); + } else if (ids != null && !ids.isEmpty()) { + List bareIds = new ArrayList( + ids.size()); + for (JAXBElement idElem : ids) { + bareIds.add(idElem.getValue()); + } + rval = visitor.id(bareIds, obj); + } else { + rval = null; + } + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/FilterFunction.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/FilterFunction.java new file mode 100644 index 0000000000..f935607f81 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/FilterFunction.java @@ -0,0 +1,38 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 20, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class FilterFunction { + + public abstract String toSql(); + + public static FilterFunction create(String name, String[] args) + throws Exception { + // TODO Time functions are the only functions for now, + // need to put logic to call appropriate functions, not always time + return TimeFunction.create(name, args); + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/IExpressionVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/IExpressionVisitor.java new file mode 100644 index 0000000000..67f893a375 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/IExpressionVisitor.java @@ -0,0 +1,72 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 21, 2011 bclement Initial creation + * Aug 18, 2013 #2097 dhladky renamed for standards + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.List; + +/** + * Visitor interface for expressions + * + * @author bclement + * @version 1.0 + */ +public interface IExpressionVisitor { + + /** + * Process literal values + * + * @param values + * @param obj + * @return + * @throws Exception + */ + public Object literal(List values, Object obj) throws Exception; + + /** + * Process value references + * + * @param ref + * @param obj + * @return + * @throws Exception + */ + public Object valueRef(String ref, Object obj) throws Exception; + + /** + * Process custom functions + * + * @param expressions + * @param name + * @param obj + * @return + * @throws Exception + */ + public FilterFunction function(List expressions, + String name, Object obj) throws Exception; +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/IFilter2Visitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/IFilter2Visitor.java new file mode 100644 index 0000000000..6535a63c38 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/IFilter2Visitor.java @@ -0,0 +1,478 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 20, 2011 bclement Initial creation + * Aug 18, 2013 #2097 dhladky renamed for standards + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.List; + +import net.opengis.filter.v_2_0_0.AbstractIdType; +import net.opengis.filter.v_2_0_0.BBOXType; +import net.opengis.filter.v_2_0_0.BinarySpatialOpType; +import net.opengis.filter.v_2_0_0.BinaryTemporalOpType; +import net.opengis.filter.v_2_0_0.DistanceBufferType; +import net.opengis.filter.v_2_0_0.PropertyIsLikeType; +import net.opengis.filter.v_2_0_0.PropertyIsNilType; +import net.opengis.filter.v_2_0_0.PropertyIsNullType; + +/** + * Filter 2.0 visitor interface + * + * @author bclement + * @version 1.0 + */ +public interface IFilter2Visitor { + + // comparison + + /** + * Filter on property equal to value + * + * @param left + * expression processor for left side of operator + * @param right + * expression processor for right side of operator + * @param matchCase + * true if comparison is case sensitive + * @param obj + * @return + * @throws Exception + */ + public Object equal(ExpressionProcessor left, ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception; + + /** + * Filter on property not equal to value + * + * @param left + * expression processor for left side of operator + * @param right + * expression processor for right side of operator + * @param matchCase + * true if comparison is case sensitive + * @param obj + * @return + * @throws Exception + */ + public Object notEqual(ExpressionProcessor left, ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception; + + /** + * Filter on property less than value + * + * @param left + * expression processor for left side of operator + * @param right + * expression processor for right side of operator + * @param matchCase + * true if comparison is case sensitive + * @param obj + * @return + * @throws Exception + */ + public Object lessThan(ExpressionProcessor left, ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception; + + /** + * Filter on property greater than value + * + * @param left + * expression processor for left side of operator + * @param right + * expression processor for right side of operator + * @param matchCase + * true if comparison is case sensitive + * @param obj + * @return + * @throws Exception + */ + public Object greaterThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception; + + /** + * Filter on property greater than or equal to value + * + * @param left + * expression processor for left side of operator + * @param right + * expression processor for right side of operator + * @param matchCase + * true if comparison is case sensitive + * @param obj + * @return + * @throws Exception + */ + public Object greaterThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception; + + /** + * Filter on property less than or equal to value + * + * @param left + * expression processor for left side of operator + * @param right + * expression processor for right side of operator + * @param matchCase + * true if comparison is case sensitive + * @param obj + * @return + * @throws Exception + */ + public Object lessThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception; + + /** + * Filter on matching + * + * @param op + * like operator + * @param obj + * @return + * @throws Exception + */ + public Object isLike(PropertyIsLikeType op, Object obj) throws Exception; + + /** + * Filter on property being null + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object isNull(PropertyIsNullType op, Object obj) throws Exception; + + /** + * Filter on property being nil + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object isNil(PropertyIsNilType op, Object obj) throws Exception; + + public Object between(ExpressionProcessor lower, ExpressionProcessor exp, + ExpressionProcessor upper, Object obj) throws Exception; + + // logic + + /** + * Conjunction for filters + * + * @param filters + * filters to be conjoined + * @param obj + * @return + * @throws Exception + */ + public Object and(List filters, Object obj) + throws Exception; + + /** + * Disjunction for filters + * + * @param filters + * filters to be disjoined + * @param obj + * @return + * @throws Exception + */ + public Object or(List filters, Object obj) + throws Exception; + + /** + * Logical inversion operator + * + * @param filter + * filter to be inverted + * @param obj + * @return + * @throws Exception + */ + public Object not(Filter2Processor filter, Object obj) throws Exception; + + // spatial + + /** + * Filter on spatial equality + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object spatialEquals(BinarySpatialOpType op, Object obj) + throws Exception; + + /** + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object disjoint(BinarySpatialOpType op, Object obj) throws Exception; + + /** + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object touches(BinarySpatialOpType op, Object obj) throws Exception; + + /** + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object within(BinarySpatialOpType op, Object obj) throws Exception; + + /** + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object overlaps(BinarySpatialOpType op, Object obj) throws Exception; + + /** + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object crosses(BinarySpatialOpType op, Object obj) throws Exception; + + /** + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object intersects(BinarySpatialOpType op, Object obj) + throws Exception; + + /** + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object contains(BinarySpatialOpType op, Object obj) throws Exception; + + /** + * Filter on distance within + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object dWithin(DistanceBufferType op, Object obj) throws Exception; + + /** + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object beyond(DistanceBufferType op, Object obj) throws Exception; + + /** + * Filter on bounding box + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object bbox(BBOXType op, Object obj) throws Exception; + + // temporal + + /** + * tests if time instance/range is after other time instance/range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object after(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time instance/range is before other time instance/range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object before(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time instance is the start of time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object begins(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time instance is the end of time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object ends(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time range is started by time instance + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object begunBy(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time range contains time instance + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object tContains(BinaryTemporalOpType op, Object obj) + throws Exception; + + /** + * tests if time instance is contained by time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object during(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time instance/range is equal to other time instance/range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object tEquals(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time range overlaps other time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object tOverlaps(BinaryTemporalOpType op, Object obj) + throws Exception; + + /** + * tests if time range is right before other time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object meets(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time range is overlapped by other time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object overlappedBy(BinaryTemporalOpType op, Object obj) + throws Exception; + + /** + * tests if time range is right after other time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object metBy(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time range is ended by time instance + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object endedBy(BinaryTemporalOpType op, Object obj) throws Exception; + + /** + * tests if time range intersects other time range + * + * @param op + * @param obj + * @return + * @throws Exception + */ + public Object anyInteracts(BinaryTemporalOpType op, Object obj) + throws Exception; + + // id + + /** + * Filter on list of feature identifiers + * + * @param ids + * @param obj + * @return + * @throws Exception + */ + public Object id(List ids, Object obj) throws Exception; +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/QueryExpressionVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/QueryExpressionVisitor.java new file mode 100644 index 0000000000..a65bd2d521 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/QueryExpressionVisitor.java @@ -0,0 +1,116 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.wfs.provider.VisitorBag; + +/** + * Visitor for query expressions + * + * @author bclement + * @version 1.0 + */ +public class QueryExpressionVisitor implements IExpressionVisitor { + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#literal(java.util.List, + * java.lang.Object) + */ + @Override + public Object literal(List values, Object obj) throws Exception { + if (values.size() != 1) { + log.warn("Unsupported literal values: " + values.toArray()); + } + return values.get(0); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcExpressionVisitor#function(java.util.List, + * java.lang.String, java.lang.Object) + */ + @Override + public FilterFunction function(List expressions, + String name, Object obj) throws Exception { + List args = new ArrayList(); + for (ExpressionProcessor expression : expressions) { + Object tmp = expression.accept(this, obj); + if (tmp instanceof String && obj instanceof VisitorBag) { + // attempts to map it to the proper field for SQL processing + String[] unfilteredPath = parseProp((String) tmp); + String unfilteredField = StringUtils.join(unfilteredPath, "."); + tmp = ((VisitorBag) obj).filterField(unfilteredField); + } + args.add(tmp); + } + String[] a = new String[args.size()]; + return FilterFunction.create(name, args.toArray(a)); + } + + protected String[] parseProp(String prop) { + // TODO we may want to keep the namespaces + String[] rval = prop.trim().split("\\/"); + for (int i = 0; i < rval.length; ++i) { + int index = rval[i].lastIndexOf(':'); + if (index > -1) { + rval[i] = rval[i].substring(index + 1); + } + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.ExpressionVisitor#valueRef(net + * .opengis.wfs.v_2_0_0.PropertyType.ValueReference, java.lang.Object) + */ + @Override + public Object valueRef(String ref, Object obj) throws Exception { + return ref; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/QueryFilterVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/QueryFilterVisitor.java new file mode 100644 index 0000000000..3f06974266 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/QueryFilterVisitor.java @@ -0,0 +1,915 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.List; +import java.util.Map.Entry; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.AbstractIdType; +import net.opengis.filter.v_2_0_0.BBOXType; +import net.opengis.filter.v_2_0_0.BinarySpatialOpType; +import net.opengis.filter.v_2_0_0.BinaryTemporalOpType; +import net.opengis.filter.v_2_0_0.DistanceBufferType; +import net.opengis.filter.v_2_0_0.PropertyIsLikeType; +import net.opengis.filter.v_2_0_0.PropertyIsNilType; +import net.opengis.filter.v_2_0_0.PropertyIsNullType; +import net.opengis.filter.v_2_0_0.ResourceIdType; +import net.opengis.gml.v_3_2_1.EnvelopeType; + +import org.geotools.geometry.jts.JTS; +import org.hibernate.criterion.Conjunction; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.Disjunction; +import org.hibernate.criterion.MatchMode; +import org.hibernate.criterion.Restrictions; +import org.hibernatespatial.criterion.SpatialRelateExpression; +import org.hibernatespatial.criterion.SpatialRestrictions; + +import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.edex.ogc.common.db.SQLParamRestriction; +import com.raytheon.uf.edex.ogc.common.gml3_2_1.EnvelopeConverter; +import com.raytheon.uf.edex.ogc.common.spatial.BoundingBoxUtil; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; +import com.raytheon.uf.edex.ogc.common.spatial.VerticalCoordinate; +import com.raytheon.uf.edex.ogc.common.util.ConvertService; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsException.Code; +import com.raytheon.uf.edex.wfs.filter.EscapingLikeExpression; +import com.raytheon.uf.edex.wfs.provider.VisitorBag; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +/** + * Visitor for building hibernate criterion from filter + * + * @author bclement + * @version 1.0 + */ +public class QueryFilterVisitor extends AbstractQueryFilterVisitor { + + private static final Character SQL_WILD = '%'; + + private static final Character SQL_SINGLE = '_'; + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#equal(com.raytheon.uf.edex + * .filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion equal(ExpressionProcessor left, + ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + + if (operand.sql) { + return SQLParamRestriction.restriction((String) operand.left + + " = " + (String) operand.right); + } else { + return Restrictions.eq((String) operand.left, operand.right); + } + + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#notEqual(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion notEqual(ExpressionProcessor left, + ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + + if (operand.sql) { + return SQLParamRestriction.restriction((String) operand.left + + " <> " + (String) operand.right); + } else { + return Restrictions.ne((String) operand.left, operand.right); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThan(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion lessThan(ExpressionProcessor left, + ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + + if (operand.sql) { + return SQLParamRestriction.restriction((String) operand.left + + " < " + (String) operand.right); + } else { + return Restrictions.lt((String) operand.left, operand.right); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThan(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion greaterThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + + if (operand.sql) { + return SQLParamRestriction.restriction((String) operand.left + + " > " + (String) operand.right); + } else { + return Restrictions.gt((String) operand.left, operand.right); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion greaterThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + + if (operand.sql) { + return SQLParamRestriction.restriction((String) operand.left + + " >= " + (String) operand.right); + } else { + return Restrictions.ge((String) operand.left, operand.right); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion lessThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + + if (operand.sql) { + return SQLParamRestriction.restriction((String) operand.left + + " <= " + (String) operand.right); + } else { + return Restrictions.le((String) operand.left, operand.right); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isLike(net.opengis.filter + * .v_1_1_0.PropertyIsLikeType, java.lang.Object) + */ + @Override + public Criterion isLike(PropertyIsLikeType op, Object obj) + throws Exception { + List> expressions = op.getExpression(); + ExpressionProcessor left = new ExpressionProcessor(expressions.get(0)); + ExpressionProcessor right = new ExpressionProcessor(expressions.get(1)); + + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + + Character wild = checkChar(op.getWildCard(), op.isSetWildCard(), + SQL_WILD); + Character esc = checkChar(op.getEscapeChar(), op.isSetEscapeChar(), '!'); + Character single = checkChar(op.getSingleChar(), op.isSetSingleChar(), + SQL_SINGLE); + String likeStr = toSqlLike((String) operand.right, wild, esc, single); + + if (operand.sql) { + return SQLParamRestriction.restriction((String) operand.left + + " ~~ " + likeStr); + } else { + return new EscapingLikeExpression((String) operand.left, likeStr, + MatchMode.ANYWHERE, esc, false); + } + } + + /** + * Ensure that character string is of length 1 + * + * @param charStr + * character string + * @param isSet + * if false, return fallback + * @param fallback + * default return value + * @return + * @throws Exception + * if character string is not of length 1 + */ + private Character checkChar(String charStr, boolean isSet, + Character fallback) throws Exception { + if (!isSet) { + return fallback; + } + if (charStr.length() != 1) { + throw new Exception( + "Wild, single and escape strings must be 1 character each"); + } + return charStr.charAt(0); + } + + /** + * Convert orig to SQL 'like' operand + * + * @param orig + * @param wild + * glob wildcard character used in orig + * @param esc + * escape character used + * @param single + * single wildcard character used in orig + * @return + */ + protected static String toSqlLike(String orig, Character wild, + Character esc, + Character single) { + String rval = orig; + if (!wild.equals(SQL_WILD)) { + rval = switchSpecial(rval, wild, SQL_WILD, esc); + } + if (!single.equals(SQL_SINGLE)) { + rval = switchSpecial(rval, single, SQL_SINGLE, esc); + } + return rval; + } + + /** + * Replace special character in orig with replacement. (Un)escapes + * characters as needed. + * + * @param orig + * @param special + * @param replacement + * @param escape + * @return + */ + protected static String switchSpecial(String orig, Character special, + Character replacement, Character escape) { + StringBuilder sb = new StringBuilder(); + char[] arr = orig.toCharArray(); + for (int i = 0; i < arr.length; ++i) { + Character c = Character.valueOf(arr[i]); + if (c.equals(escape)) { + Character next = Character.valueOf(arr[++i]); + // preserve escapes on other special characters + if (!next.equals(special)) { + sb.append(escape); + } + sb.append(next); + } else if (c.equals(replacement)) { + // escape literal instances of the new special char + sb.append(escape).append(c); + } else if (c.equals(special)) { + // one for one switch + sb.append(replacement); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isNull(net.opengis.filter + * .v_1_1_0.PropertyIsNullType, java.lang.Object) + */ + @Override + public Criterion isNull(PropertyIsNullType op, Object obj) + throws Exception { + ExpressionProcessor eproc = new ExpressionProcessor(op.getExpression()); + String field = getRef(eproc, (VisitorBag) obj).value; + return Restrictions.isNull(field); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#between(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public Criterion between(ExpressionProcessor lower, + ExpressionProcessor exp, + ExpressionProcessor upper, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + + Operand lowerPart = getBinaryProps(exp, lower, bag); + Operand upperPart = getBinaryProps(exp, upper, bag); + + return Restrictions.between((String) lowerPart.left, lowerPart.right, + upperPart.right); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#and(java.util.List, + * java.lang.Object) + */ + @Override + public Criterion and(List filters, Object obj) + throws Exception { + Conjunction rval = Restrictions.conjunction(); + acceptAll(filters, obj, rval); + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#or(java.util.List, + * java.lang.Object) + */ + @Override + public Criterion or(List filters, Object obj) + throws Exception { + Disjunction rval = Restrictions.disjunction(); + acceptAll(filters, obj, rval); + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#not(com.raytheon.uf.edex + * .filter.FilterProcessor, java.lang.Object) + */ + @Override + public Criterion not(Filter2Processor filter, Object obj) throws Exception { + return Restrictions.not((Criterion) filter.accept(this, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#spatialEquals(net.opengis + * .filter.v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion spatialEquals(BinarySpatialOpType op, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinarySpatial(op, bag); + return SpatialRestrictions.eq(bag.filterField(e.getKey()), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#disjoint(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion disjoint(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.disjoint(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#touches(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion touches(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.touches(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#within(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion within(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.within(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#overlaps(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion overlaps(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.overlaps(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#crosses(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion crosses(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.crosses(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#intersects(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion intersects(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.intersects(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#contains(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion contains(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.contains(e.getKey(), e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#dWithin(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public Object dWithin(DistanceBufferType op, Object obj) + throws Exception { + throw new Exception("dWithin queries not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#beyond(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public Object beyond(DistanceBufferType op, Object obj) + throws Exception { + throw new Exception("Beyond queries not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#bbox(net.opengis.filter. + * v_1_1_0.BBOXType, java.lang.Object) + */ + @Override + public Criterion bbox(BBOXType op, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + String prop; + if (!op.isSetExpression()) { + prop = bag.getSpatialField(); + } else { + ExpressionProcessor eproc = new ExpressionProcessor( + op.getExpression()); + prop = getRef(eproc, bag).value; + } + Object any = op.getAny(); + if (any instanceof JAXBElement) { + any = ((JAXBElement) any).getValue(); + } + if (!(any instanceof EnvelopeType)) { + throw new Exception("Unsupported bbox type: " + any.getClass()); + } + EnvelopeType value = (EnvelopeType) any; + int dims = EnvelopeConverter.getDims(value); + Envelope env; + if (dims == 2) { + env = envConverter.convert(value); + SpatialRelateExpression disjoint = SpatialRestrictions.disjoint( + bag.filterField(prop), JTS.toGeometry(env)); + return Restrictions.not(disjoint); + } else if (dims == 3) { + String verticalField = bag.getVerticalField(); + if (verticalField == null) { + throw new WfsException(Code.InvalidParameterValue, + "Feature does not have vertical information"); + } + Composite3DBoundingBox composite = BoundingBoxUtil + .separate3DEnvelope(value); + env = composite.getHorizontal().transform( + MapUtil.LATLON_PROJECTION, true); + Conjunction and = Restrictions.conjunction(); + // horiz + SpatialRelateExpression disjoint = SpatialRestrictions.disjoint( + bag.filterField(prop), JTS.toGeometry(env)); + and.add(Restrictions.not(disjoint)); + // vert + VerticalCoordinate vert = composite.getVertical(); + // TODO convert units + String min = Integer.toString((int) Math.floor(vert.getMin())); + String max = Integer.toString((int) Math.ceil(vert.getMax())); + String[] path = verticalField.split("\\."); + Object minObj = ConvertService.get().convertAsType(min, + bag.getRootEntity(), + path); + Object maxObj = ConvertService.get().convertAsType(max, + bag.getRootEntity(), + path); + and.add(Restrictions.between(verticalField, minObj, maxObj)); + return and; + } else { + throw new Exception("Unsupported number of dimensions: " + dims); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#isNil(net.opengis + * .filter.v_2_0_0.PropertyIsNilType, java.lang.Object) + */ + @Override + public Object isNil(PropertyIsNilType op, Object obj) throws Exception { + ExpressionProcessor eproc = new ExpressionProcessor(op.getExpression()); + String field = getRef(eproc, (VisitorBag) obj).value; + return Restrictions.isNull(field); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#after(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Criterion after(BinaryTemporalOpType op, Object obj) + throws Exception { + Entry> ref = getRef(op, (VisitorBag)obj); + TimeOperand operand = getOperand(op, ref.getValue(), obj); + Object rhs = operand.instance ? operand.start : operand.end; + + if (operand.sql) { + return SQLParamRestriction.restriction("{" + ref.getKey() + "} > " + + (String) rhs); + } else { + return Restrictions.gt(ref.getKey(), rhs); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#before(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Criterion before(BinaryTemporalOpType op, Object obj) + throws Exception { + Entry> ref = getRef(op, (VisitorBag) obj); + TimeOperand operand = getOperand(op, ref.getValue(), obj); + // both instance and period operands have value in start + + if (operand.sql) { + return SQLParamRestriction.restriction("{" + ref.getKey() + "} < " + + (String) operand.start); + } else { + return Restrictions.lt(ref.getKey(), operand.start); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#begins(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Criterion begins(BinaryTemporalOpType op, Object obj) + throws Exception { + Entry> ref = getRef(op, (VisitorBag) obj); + TimeOperand operand = getOperand(op, ref.getValue(), obj); + if (!operand.sql && operand.instance) { + throw new Exception("Left operand for begins filter must be period"); + } + + if (operand.sql) { + return SQLParamRestriction.restriction("{" + ref.getKey() + "} = " + + (String) operand.start); + } else { + return Restrictions.eq(ref.getKey(), operand.start); + } + + } + + @Override + public Criterion ends(BinaryTemporalOpType op, Object obj) throws Exception { + Entry> ref = getRef(op, (VisitorBag) obj); + TimeOperand operand = getOperand(op, ref.getValue(), obj); + if (!operand.sql && operand.instance) { + throw new Exception("Left operand for ends filter must be period"); + } + + if (operand.sql) { + // sql value stored in start regardless of operation + return SQLParamRestriction.restriction("{" + ref.getKey() + "} = " + + (String) operand.start); + } else { + return Restrictions.eq(ref.getKey(), operand.end); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#begunBy(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object begunBy(BinaryTemporalOpType op, Object obj) throws Exception { + // TODO + throw new Exception("Begun By filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#tContains(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object tContains(BinaryTemporalOpType op, Object obj) + throws Exception { + // TODO + throw new Exception("TContains filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#during(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Criterion during(BinaryTemporalOpType op, Object obj) + throws Exception { + Entry> ref = getRef(op, (VisitorBag) obj); + TimeOperand operand = getOperand(op, ref.getValue(), obj); + if (!operand.sql && operand.instance) { + throw new Exception("Left operand for during filter must be period"); + } + Conjunction and = Restrictions.conjunction(); + + if (operand.sql) { + and.add(SQLParamRestriction.restriction("{" + ref.getKey() + "} > " + + (String) operand.start)); + and.add(SQLParamRestriction.restriction("{" + ref.getKey() + "} < " + + (String) operand.end)); + } else { + and.add(Restrictions.gt(ref.getKey(), operand.start)); + and.add(Restrictions.lt(ref.getKey(), operand.end)); + } + + return and; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#tEquals(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Criterion tEquals(BinaryTemporalOpType op, Object obj) + throws Exception { + Entry> ref = getRef(op, (VisitorBag) obj); + TimeOperand operand = getOperand(op, ref.getValue(), obj); + if (!operand.sql && !operand.instance) { + throw new Exception( + "Left operand for TEquals filter must be instance"); + } + if (operand.sql) { + return SQLParamRestriction.restriction("{" + ref.getKey() + "} = " + + (String) operand.start); + } else { + return Restrictions.eq(ref.getKey(), operand.start); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#tOverlaps(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object tOverlaps(BinaryTemporalOpType op, Object obj) + throws Exception { + // TODO + throw new Exception("TOverlaps filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#meets(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object meets(BinaryTemporalOpType op, Object obj) throws Exception { + // TODO + throw new Exception("Meets filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#overlappedBy(net + * .opengis.filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object overlappedBy(BinaryTemporalOpType op, Object obj) + throws Exception { + // TODO + throw new Exception("Overlapped By filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#metBy(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object metBy(BinaryTemporalOpType op, Object obj) throws Exception { + // TODO + throw new Exception("Met By filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#endedBy(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object endedBy(BinaryTemporalOpType op, Object obj) throws Exception { + // TODO + throw new Exception("Ended By filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#anyInteracts(net + * .opengis.filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public Object anyInteracts(BinaryTemporalOpType op, Object obj) + throws Exception { + // TODO + throw new Exception("Any Interacts filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#id(java.util.List, + * java.lang.Object) + */ + @Override + public Criterion id(List ids, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Disjunction dis = Restrictions.disjunction(); + for (AbstractIdType id : ids) { + if (id instanceof ResourceIdType) { + ResourceIdType rid = (ResourceIdType) id; + Criterion crit = Restrictions + .eq(bag.getIdField(), rid.getRid()); + dis.add(crit); + } + } + return dis; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/SubFilterVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/SubFilterVisitor.java new file mode 100644 index 0000000000..a64d7c7c01 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/SubFilterVisitor.java @@ -0,0 +1,751 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.AbstractIdType; +import net.opengis.filter.v_2_0_0.BBOXType; +import net.opengis.filter.v_2_0_0.BinarySpatialOpType; +import net.opengis.filter.v_2_0_0.BinaryTemporalOpType; +import net.opengis.filter.v_2_0_0.DistanceBufferType; +import net.opengis.filter.v_2_0_0.PropertyIsLikeType; +import net.opengis.filter.v_2_0_0.PropertyIsNilType; +import net.opengis.filter.v_2_0_0.PropertyIsNullType; +import net.opengis.filter.v_2_0_0.ResourceIdType; +import net.opengis.gml.v_3_2_1.EnvelopeType; + +import org.geotools.geometry.jts.JTS; + +import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.TimeRange; +import com.raytheon.uf.edex.ogc.common.filter.AbstractPdoFilter; +import com.raytheon.uf.edex.ogc.common.filter.ComparisonFilter; +import com.raytheon.uf.edex.ogc.common.filter.ComparisonFilter.CompOp; +import com.raytheon.uf.edex.ogc.common.filter.LogicFilter; +import com.raytheon.uf.edex.ogc.common.filter.SpatialFilter; +import com.raytheon.uf.edex.ogc.common.filter.SpatialFilter.SpatialOp; +import com.raytheon.uf.edex.ogc.common.filter.TemporalFilter; +import com.raytheon.uf.edex.ogc.common.filter.TemporalFilter.TimeOp; +import com.raytheon.uf.edex.ogc.common.filter.VerticalFilter; +import com.raytheon.uf.edex.ogc.common.filter.VerticalFilter.VerticalOp; +import com.raytheon.uf.edex.ogc.common.gml3_2_1.EnvelopeConverter; +import com.raytheon.uf.edex.ogc.common.spatial.BoundingBoxUtil; +import com.raytheon.uf.edex.ogc.common.spatial.Composite3DBoundingBox; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsException.Code; +import com.raytheon.uf.edex.wfs.provider.VisitorBag; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 15, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class SubFilterVisitor extends AbstractQueryFilterVisitor { + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#equal(com.raytheon.uf.edex + * .filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public ComparisonFilter equal(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + if (operand.sql) { + // subscriptions do not go to the DB, if we need sql, likely from a + // function, throw exception + throw new Exception( + "SQL filtering such as functions not supported for subscriptions."); + } + return new ComparisonFilter((String) operand.left, CompOp.EQ, + operand.right); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#notEqual(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public ComparisonFilter notEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + if (operand.sql) { + // subscriptions do not go to the DB, if we need sql, likely from a + // function, throw exception + throw new Exception( + "SQL filtering such as functions not supported for subscriptions."); + } + return new ComparisonFilter((String) operand.left, CompOp.NEQ, + operand.right); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThan(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public ComparisonFilter lessThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + if (operand.sql) { + // subscriptions do not go to the DB, if we need sql, likely from a + // function, throw exception + throw new Exception( + "SQL filtering such as functions not supported for subscriptions."); + } + return new ComparisonFilter((String) operand.left, CompOp.LT, + operand.right); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThan(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public ComparisonFilter greaterThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + if (operand.sql) { + // subscriptions do not go to the DB, if we need sql, likely from a + // function, throw exception + throw new Exception( + "SQL filtering such as functions not supported for subscriptions."); + } + return new ComparisonFilter((String) operand.left, CompOp.GT, + operand.right); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public ComparisonFilter greaterThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + if (operand.sql) { + // subscriptions do not go to the DB, if we need sql, likely from a + // function, throw exception + throw new Exception( + "SQL filtering such as functions not supported for subscriptions."); + } + return new ComparisonFilter((String) operand.left, CompOp.GTE, + operand.right); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public ComparisonFilter lessThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Operand operand = getBinaryProps(left, right, bag); + if (operand.sql) { + // subscriptions do not go to the DB, if we need sql, likely from a + // function, throw exception + throw new Exception( + "SQL filtering such as functions not supported for subscriptions."); + } + return new ComparisonFilter((String) operand.left, CompOp.LTE, + operand.right); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isLike(net.opengis.filter + * .v_1_1_0.PropertyIsLikeType, java.lang.Object) + */ + @Override + public ComparisonFilter isLike(PropertyIsLikeType op, Object obj) + throws Exception { + // TODO + throw new Exception("isLike filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isNull(net.opengis.filter + * .v_1_1_0.PropertyIsNullType, java.lang.Object) + */ + @Override + public ComparisonFilter isNull(PropertyIsNullType op, Object obj) + throws Exception { + ExpressionProcessor eproc = new ExpressionProcessor(op.getExpression()); + String field = getRef(eproc, (VisitorBag) obj).value; + return ComparisonFilter.isNull(field); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#between(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public AbstractPdoFilter between(ExpressionProcessor lower, + ExpressionProcessor exp, ExpressionProcessor upper, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + + Operand lowerPart = getBinaryProps(exp, lower, bag); + Operand upperPart = getBinaryProps(exp, upper, bag); + + if (lowerPart.sql || upperPart.sql) { + // subscriptions do not go to the DB, if we need sql, likely from a + // function, throw exception + throw new Exception( + "SQL filtering such as functions not supported for subscriptions."); + } + + ComparisonFilter lowerFilter = new ComparisonFilter( + (String) lowerPart.left, CompOp.GT, lowerPart.right); + ComparisonFilter upperFilter = new ComparisonFilter( + (String) upperPart.left, CompOp.LT, upperPart.right); + return LogicFilter.and(lowerFilter, upperFilter); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#and(java.util.List, + * java.lang.Object) + */ + @Override + public LogicFilter and(List filters, Object obj) + throws Exception { + return LogicFilter.and(acceptAll(filters, obj)); + } + + protected AbstractPdoFilter[] acceptAll(List filters, + Object obj) throws Exception { + AbstractPdoFilter[] rval = new AbstractPdoFilter[filters.size()]; + Iterator iter = filters.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + rval[i] = (AbstractPdoFilter) iter.next().accept(this, obj); + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#or(java.util.List, + * java.lang.Object) + */ + @Override + public LogicFilter or(List filters, Object obj) + throws Exception { + return LogicFilter.or(acceptAll(filters, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#not(com.raytheon.uf.edex + * .filter.FilterProcessor, java.lang.Object) + */ + @Override + public LogicFilter not(Filter2Processor filter, Object obj) + throws Exception { + return LogicFilter.not((AbstractPdoFilter) filter.accept(this, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#spatialEquals(net.opengis + * .filter.v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter spatialEquals(BinarySpatialOpType op, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinarySpatial(op, bag); + return new SpatialFilter(SpatialOp.EQUALS, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#disjoint(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter disjoint(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return new SpatialFilter(SpatialOp.DISJOINT, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#touches(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter touches(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return new SpatialFilter(SpatialOp.TOUCHES, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#within(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter within(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return new SpatialFilter(SpatialOp.WITHIN, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#overlaps(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter overlaps(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return new SpatialFilter(SpatialOp.OVERLAPS, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#crosses(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter crosses(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return new SpatialFilter(SpatialOp.CROSSES, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#intersects(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter intersects(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return new SpatialFilter(SpatialOp.INTERSECTS, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#contains(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public SpatialFilter contains(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return new SpatialFilter(SpatialOp.CONTAINS, e.getValue()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#dWithin(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public SpatialFilter dWithin(DistanceBufferType op, Object obj) + throws Exception { + throw new Exception("dWithin queries not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#beyond(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public SpatialFilter beyond(DistanceBufferType op, Object obj) + throws Exception { + throw new Exception("Beyond queries not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#bbox(net.opengis.filter. + * v_1_1_0.BBOXType, java.lang.Object) + */ + @Override + public LogicFilter bbox(BBOXType op, Object obj) throws Exception { + if (!(obj instanceof VisitorBag)) { + log.error("Mismatched visitor and helper object", new Exception()); + throw new WfsException(Code.OperationProcessingFailed); + } + VisitorBag bag = (VisitorBag) obj; + Object any = op.getAny(); + if (any instanceof JAXBElement) { + any = ((JAXBElement) any).getValue(); + } + if (!(any instanceof EnvelopeType)) { + throw new Exception("Unsupported bbox type: " + any.getClass()); + } + EnvelopeType value = (EnvelopeType) any; + int dims = EnvelopeConverter.getDims(value); + Envelope env; + if (dims == 2) { + env = envConverter.convert(value); + SpatialFilter disjoint = new SpatialFilter(SpatialOp.DISJOINT, + JTS.toGeometry(env)); + return LogicFilter.not(disjoint); + } else if (dims == 3) { + String verticalField = bag.getVerticalField(); + if (verticalField == null) { + throw new WfsException(Code.InvalidParameterValue, + "Feature does not have vertical information"); + } + Composite3DBoundingBox composite = BoundingBoxUtil + .separate3DEnvelope(value); + env = composite.getHorizontal().transform( + MapUtil.LATLON_PROJECTION, true); + + // horiz + SpatialFilter disjoint = new SpatialFilter(SpatialOp.DISJOINT, + JTS.toGeometry(env)); + LogicFilter horiz = LogicFilter.not(disjoint); + // vert + VerticalFilter vert = new VerticalFilter(VerticalOp.BETWEEN, + composite.getVertical()); + return LogicFilter.and(horiz, vert); + } else { + throw new Exception("Unsupported number of dimensions: " + dims); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#isNil(net.opengis + * .filter.v_2_0_0.PropertyIsNilType, java.lang.Object) + */ + @Override + public Object isNil(PropertyIsNilType op, Object obj) throws Exception { + ExpressionProcessor eproc = new ExpressionProcessor(op.getExpression()); + String field = getRef(eproc, (VisitorBag) obj).value; + return ComparisonFilter.isNull(field); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#after(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter after(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.After, parseTimeOp(op, obj)); + } + + protected DataTime parseTimeOp(BinaryTemporalOpType op, Object obj) + throws Exception { + TimeOperand operand = getOperand(op, Date.class, obj); + DataTime dt; + if (operand.instance) { + dt = new DataTime((Date) operand.start); + } else { + Date start = (Date) operand.start; + TimeRange range = new TimeRange(start, (Date) operand.end); + dt = new DataTime(start.getTime(), range); + } + return dt; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#before(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter before(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.Before, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#begins(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter begins(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.Begins, parseTimeOp(op, obj)); + } + + @Override + public TemporalFilter ends(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.Ends, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#begunBy(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter begunBy(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.BegunBy, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#tContains(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter tContains(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.TContains, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#during(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter during(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.During, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#tEquals(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter tEquals(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.TEquals, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#tOverlaps(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter tOverlaps(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.TOverlaps, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#meets(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter meets(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.Meets, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#overlappedBy(net + * .opengis.filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter overlappedBy(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.OverlappedBy, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#metBy(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter metBy(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.MetBy, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#endedBy(net.opengis + * .filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter endedBy(BinaryTemporalOpType op, Object obj) + throws Exception { + return new TemporalFilter(TimeOp.EndedBy, parseTimeOp(op, obj)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#anyInteracts(net + * .opengis.filter.v_2_0_0.BinaryTemporalOpType, java.lang.Object) + */ + @Override + public TemporalFilter anyInteracts(BinaryTemporalOpType op, Object obj) + throws Exception { + // TODO + throw new Exception("Any Interacts filter not supported"); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Visitor#id(java.util.List, + * java.lang.Object) + */ + @Override + public AbstractPdoFilter id(List ids, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + ArrayList filters = new ArrayList( + ids.size()); + for (AbstractIdType id : ids) { + if (id instanceof ResourceIdType) { + ResourceIdType rid = (ResourceIdType) id; + ComparisonFilter comp = new ComparisonFilter(bag.getIdField(), + rid.getRid()); + filters.add(comp); + } + } + return LogicFilter.or(filters.toArray(new AbstractPdoFilter[filters + .size()])); + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/TimeFunction.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/TimeFunction.java new file mode 100644 index 0000000000..9ed260bea3 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/filter/v2_0_0/TimeFunction.java @@ -0,0 +1,163 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.filter.v2_0_0; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 20, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class TimeFunction extends FilterFunction { + + public static class TimeStampAdd extends TimeFunction { + + protected String fieldName; + + protected String units; + + protected int interval; + + /** + * @param args + * @throws Exception + */ + public TimeStampAdd(String[] args) throws Exception { + super(args); + if (args.length != 3) { + throw new Exception("Invalid argument list: " + args); + } + fieldName = args[0]; + units = checkUnit(args[1]); + interval = checkInt(args[2]); + + // TODO set literal based on fieldName + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.filter.v2_0_0.FilterFunction#toSql() + */ + @Override + public String toSql() { + return String.format("{%s} + interval '%d %s'", fieldName, + interval, units); + } + } + + public static class TimeStampDiff extends TimeFunction { + + protected String field0; + + protected String field1; + + protected String units; + + private static Map intMap = new HashMap(); + + static { + // since we don't know specifics, we use average year and month + intMap.put("YEAR", 31557600); + intMap.put("MONTH", 31557600 / 12); + intMap.put("DAY", 86400); + intMap.put("HOUR", 3600); + intMap.put("MINUTE", 60); + intMap.put("SECOND", 1); + } + + /** + * @param args + * @throws Exception + */ + public TimeStampDiff(String[] args) throws Exception { + super(args); + if (args.length != 3) { + throw new Exception("Invalid argument list: " + args); + } + field0 = args[0]; + field1 = args[1]; + units = checkUnit(args[2]); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.filter.v2_0_0.FilterFunction#toSql() + */ + @Override + public String toSql() { + int seconds = intMap.get(units.toUpperCase()); + return String.format("extract(epoch from {%s} - {%s})/%d", field0, + field1, seconds); + } + } + + protected final String[] args; + + protected static final String[] UNITS = { "YEAR", "MONTH", "DAY", "HOUR", + "MINUTE", "SECOND" }; + + protected static final Set UNIT_SET = new HashSet( + Arrays.asList(UNITS)); + + public TimeFunction(String[] args) { + this.args = args; + } + + protected String checkUnit(String units) throws Exception { + if (!UNIT_SET.contains(units.toUpperCase())) { + throw new Exception("Unsupported time function units: " + units); + } + return units; + } + + protected int checkInt(String intVal) throws Exception { + try { + return Integer.parseInt(intVal); + } catch (Throwable t) { + throw new Exception("Invalid integer argument to function: " + + intVal); + } + } + + /** + * @param name + * @param args + * @return null if name doesn't match any supported functions + * @throws Exception + */ + public static TimeFunction create(String name, String[] args) + throws Exception { + if ("TIMESTAMPADD".equalsIgnoreCase(name)) { + return new TimeStampAdd(args); + } else if ("TIMESTAMPDIFF".equalsIgnoreCase(name)) { + return new TimeStampDiff(args); + } + return null; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/AbstractWfsProvider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/AbstractWfsProvider.java new file mode 100644 index 0000000000..aece70f579 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/AbstractWfsProvider.java @@ -0,0 +1,253 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.provider; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcNamespace; +import com.raytheon.uf.edex.ogc.common.OgcPrefix; +import com.raytheon.uf.edex.ogc.common.OgcTimeRange; +import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; +import com.raytheon.uf.edex.wfs.IWfsProvider; +import com.raytheon.uf.edex.wfs.request.QualifiedName; +import com.raytheon.uf.edex.wfs.request.SortBy; +import com.raytheon.uf.edex.wfs.request.SortBy.Order; + +/** + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 25, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public abstract class AbstractWfsProvider implements IWfsProvider { + + public static final String REQUEST_HEADER = "request"; + + public static final String CAP_PARAM = "getcapabilities"; + + public static final String DESC_PARAM = "describefeaturetype"; + + public static final String GET_PARAM = "getfeature"; + + public static final String RESTYPE_HEADER = "resulttype"; + + public static final String PROPNAME_HEADER = "propertyname"; + + public static final String MAXFEAT_HEADER = "maxfeatures"; + + public static final String SRSNAME_HEADER = "srsname"; + + public static final String TYPENAME_HEADER = "typename"; + + public static final String FEATID_HEADER = "featureid"; + + public static final String FILTER_HEADER = "filter"; + + public static final String BBOX_HEADER = "bbox"; + + public static final String SORTBY_HEADER = "sortby"; + + public static final String NS_HEADER = "namespace"; + + public static final String OUTFORMAT_HEADER = "outputformat"; + + public static final String EXCEP_FORMAT_HEADER = "exceptions"; + + public static final String LIST_QUERY_PARAM = "liststoredqueries"; + + public static final String DESC_QUERY_PARAM = "describestoredqueries"; + + public static final String QUERY_IDS_HEADER = "storedquery_id"; + + public static final String TIME_HEADER = "time"; + + protected static final Pattern nspattern = Pattern + .compile("xmlns\\((\\S+)=(\\S+)\\)"); + + protected final String slashes = "\\\\,"; + + protected final String lamdas = "λλλ"; + + protected final Pattern sortBys = Pattern.compile("\\s+"); + + protected final Pattern slash = Pattern.compile("\\\\"); + + protected final Pattern comma = Pattern.compile(","); + + protected final IUFStatusHandler statusHandler = UFStatus.getHandler(this + .getClass()); + + private static ThreadLocal ogcDateFormat = new ThreadLocal() { + + @Override + protected SimpleDateFormat initialValue() { + + SimpleDateFormat sdf = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + return sdf; + } + + }; + + /** + * @param nsmap + * @param string + * @return + */ + protected List getTypeNames(String typename, + Map nsmap) { + String[] parts = typename.split(":", 2); + List rval = new LinkedList(); + if (parts.length == 1) { + // default names to the edex namespace + rval.add(new QualifiedName(OgcNamespace.EDEX, parts[0], null)); + } else if (parts.length == 2) { + rval.add(new QualifiedName(nsmap.get(parts[0]), parts[1], parts[0])); + } + return rval; + } + + /** + * @param headers + * @return + */ + protected List getSortBys(String sortby) { + List rval = new LinkedList(); + String[] sorts = splitOnComma(sortby); + for (String s : sorts) { + String[] parts = sortBys.split(s); + SortBy.Order order = Order.Ascending; + if (parts.length == 2) { + if (parts[1].trim().equalsIgnoreCase("D")) { + order = Order.Descending; + } + } + rval.add(new SortBy(parts[0].trim(), order)); + } + return rval; + } + + /** + * @param bboxes + * @return + */ + protected OgcBoundingBox getBoundingBox(String bbox) { + String[] parts = splitOnComma(bbox); + OgcBoundingBox rval = null; + if (parts.length == 4) { + rval = new OgcBoundingBox(); + try { + rval.setMinx(Double.parseDouble(parts[0])); + rval.setMiny(Double.parseDouble(parts[1])); + rval.setMaxx(Double.parseDouble(parts[2])); + rval.setMaxy(Double.parseDouble(parts[3])); + } catch (NumberFormatException e) { + statusHandler.error("couldn't parse Bounding Box!", e); + } + }// else TODO handle non 2d WGS84 + return rval; + } + + protected Map getNameSpaceMap(Map headers) + throws OgcException { + Map nsmap = new HashMap(); + String ns = OgcHttpHandler.getString(headers, NS_HEADER); + if (ns != null) { + for (String s : splitOnComma(ns)) { + Matcher matcher = nspattern.matcher(s); + if (matcher.matches()) { + nsmap.put(matcher.group(1), matcher.group(2)); + } + } + } else { + nsmap.put(OgcPrefix.EDEX, OgcNamespace.EDEX); + } + return nsmap; + } + + protected String[] splitOnComma(String str) { + // TODO Use pattern for replace + String val = str.replaceAll(slashes, lamdas); + String[] rval = comma.split(val); + for (int i = 0; i < rval.length; ++i) { + rval[i] = rval[i].replaceAll(lamdas, comma.pattern()); + } + return rval; + } + + protected String[] splitOnSlash(String str) { + String[] times = slash.split(str); + return times; + } + + protected String[] splitOnParens(String name, Map headers) + throws OgcException { + String val = OgcHttpHandler.getString(headers, name); + String[] rval; + if (val != null) { + val = val.replaceAll("\\s*\\(", ""); + rval = val.split("\\)"); + } else { + rval = new String[0]; + } + return rval; + } + + protected OgcTimeRange getTimeRange(String stimes) { + OgcTimeRange otr = null; + // we assume it is a start time going up to present + try { + + String[] times = splitOnSlash(stimes); + + if (times.length > 0) { + Date endDate = null; + Date startDate = null; + if (times.length == 1) { + endDate = new Date(System.currentTimeMillis()); + startDate = ogcDateFormat.get().parse(times[0]); + + } else { + endDate = ogcDateFormat.get().parse(times[1]); + startDate = ogcDateFormat.get().parse(times[0]); + } + + otr = new OgcTimeRange(startDate, endDate); + } + } catch (ParseException pe) { + statusHandler.error("couldn't parse times!", pe); + } + + return otr; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Capabilities.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Capabilities.java index 85187d40ed..97bf802cfb 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Capabilities.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Capabilities.java @@ -70,7 +70,7 @@ import com.raytheon.uf.edex.ogc.common.OgcNamespace; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.wfs.WfsException; -import com.raytheon.uf.edex.wfs.WfsProvider.WfsOpType; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; import com.raytheon.uf.edex.wfs.request.GetCapReq; @@ -81,300 +81,300 @@ import com.raytheon.uf.edex.wfs.request.GetCapReq; */ public class Capabilities { - protected String SERV_TYPE = "WFS"; + protected String SERV_TYPE = "WFS"; - protected String SERV_TITLE = "EDEX WFS"; + protected String SERV_TITLE = "EDEX WFS"; - protected String OWS_NS = OgcNamespace.OWS; + protected String OWS_NS = OgcNamespace.OWS; - protected String GML_NS = OgcNamespace.GML; + protected String GML_NS = OgcNamespace.GML; - protected String OGC_NS = OgcNamespace.OGC; + protected String OGC_NS = OgcNamespace.OGC; - protected String WFS_NS = OgcNamespace.WFS; + protected String WFS_NS = OgcNamespace.WFS; - protected String GML_MIME = "text/xml; subtype=gml/3.1.1"; + protected String GML_MIME = "text/xml; subtype=gml/3.1.1"; - protected String[] gmlObjects = { "AbstractFeatureType", "PointType", - "LineStringType", "PolygonType", "MultiPointType" }; + protected String[] gmlObjects = { "AbstractFeatureType", "PointType", + "LineStringType", "PolygonType", "MultiPointType" }; - protected String[] geometryOperands = { "Envelope", "Point", "LineString", - "Polygon" }; + protected String[] geometryOperands = { "Envelope", "Point", "LineString", + "Polygon" }; - protected SpatialOperatorNameType[] spatialOperators = { - SpatialOperatorNameType.BBOX, SpatialOperatorNameType.EQUALS }; + protected SpatialOperatorNameType[] spatialOperators = { + SpatialOperatorNameType.BBOX, SpatialOperatorNameType.EQUALS }; - protected ComparisonOperatorType[] comparisonOperators = { - ComparisonOperatorType.LESS_THAN, - ComparisonOperatorType.GREATER_THAN, - ComparisonOperatorType.LESS_THAN_EQUAL_TO, - ComparisonOperatorType.GREATER_THAN_EQUAL_TO, - ComparisonOperatorType.EQUAL_TO, - ComparisonOperatorType.NOT_EQUAL_TO }; + protected ComparisonOperatorType[] comparisonOperators = { + ComparisonOperatorType.LESS_THAN, + ComparisonOperatorType.GREATER_THAN, + ComparisonOperatorType.LESS_THAN_EQUAL_TO, + ComparisonOperatorType.GREATER_THAN_EQUAL_TO, + ComparisonOperatorType.EQUAL_TO, + ComparisonOperatorType.NOT_EQUAL_TO }; - protected String[] logicOperators = { "And" }; + protected String[] logicOperators = { "And" }; - protected FeatureTranslator translator = new FeatureTranslator(); + protected FeatureTranslator translator = new FeatureTranslator(); - protected WfsRegistryImpl registry; + protected WfsRegistryImpl registry; - public Capabilities(WfsRegistryImpl registry) { - this.registry = registry; - } + public Capabilities(WfsRegistryImpl registry) { + this.registry = registry; + } - public WFSCapabilitiesType getCapabilities(GetCapReq request, - OgcServiceInfo serviceinfo) throws WfsException { - WFSCapabilitiesType cap = new WFSCapabilitiesType(); - cap.setServiceIdentification(getServiceId(serviceinfo)); - cap.setOperationsMetadata(getOpData(serviceinfo)); - cap.setFeatureTypeList(getFeatureTypes(request, serviceinfo)); - cap.setServesGMLObjectTypeList(getServesGML()); - cap.setSupportsGMLObjectTypeList(getSupportsGML()); - cap.setFilterCapabilities(getFilterCap()); - return cap; - } + public WFSCapabilitiesType getCapabilities(GetCapReq request, + OgcServiceInfo serviceinfo) throws WfsException { + WFSCapabilitiesType cap = new WFSCapabilitiesType(); + cap.setServiceIdentification(getServiceId(serviceinfo)); + cap.setOperationsMetadata(getOpData(serviceinfo)); + cap.setFeatureTypeList(getFeatureTypes(request, serviceinfo)); + cap.setServesGMLObjectTypeList(getServesGML()); + cap.setSupportsGMLObjectTypeList(getSupportsGML()); + cap.setFilterCapabilities(getFilterCap()); + return cap; + } - /** - * @param serviceinfo - * @return - */ - protected OperationsMetadata getOpData(OgcServiceInfo serviceinfo) { - OperationsMetadata rval = new OperationsMetadata(); - List operations = new LinkedList(); - for (OgcOperationInfo op : serviceinfo.getOperations()) { - Operation to = new Operation(); - to.setName(op.getType().toString()); - to.setDCP(getDcpList(op)); - to.setParameter(getOpParams(op)); - operations.add(to); - } - rval.setOperation(operations); - rval.setParameter(getParams(serviceinfo)); - // may want to do constraints as well - return rval; - } + /** + * @param serviceinfo + * @return + */ + protected OperationsMetadata getOpData(OgcServiceInfo serviceinfo) { + OperationsMetadata rval = new OperationsMetadata(); + List operations = new LinkedList(); + for (OgcOperationInfo op : serviceinfo.getOperations()) { + Operation to = new Operation(); + to.setName(op.getType().toString()); + to.setDCP(getDcpList(op)); + to.setParameter(getOpParams(op)); + operations.add(to); + } + rval.setOperation(operations); + rval.setParameter(getParams(serviceinfo)); + // may want to do constraints as well + return rval; + } - /** - * @param op - * @return - */ - private List getOpParams(OgcOperationInfo op) { - return Arrays.asList( - getAsDomainType("AcceptVersions", op.getVersions()), - getAsDomainType("AcceptFormats", op.getFormats())); - } + /** + * @param op + * @return + */ + private List getOpParams(OgcOperationInfo op) { + return Arrays.asList( + getAsDomainType("AcceptVersions", op.getVersions()), + getAsDomainType("AcceptFormats", op.getFormats())); + } - /** - * @param op - * @return - */ - protected List getDcpList(OgcOperationInfo op) { - List rval = new LinkedList(); - DCP dcp = new DCP(); - HTTP http = new HTTP(); - List> value = new LinkedList>(); - if (op.hasHttpGet()) { - value.add(getRequestType("Get", op.getHttpGetRes())); - } - if (op.hasHttpPost()) { - value.add(getRequestType("Post", op.getHttpPostRes())); - } - http.setGetOrPost(value); - dcp.setHTTP(http); - rval.add(dcp); - return rval; - } + /** + * @param op + * @return + */ + protected List getDcpList(OgcOperationInfo op) { + List rval = new LinkedList(); + DCP dcp = new DCP(); + HTTP http = new HTTP(); + List> value = new LinkedList>(); + if (op.hasHttpGet()) { + value.add(getRequestType("Get", op.getHttpGetRes())); + } + if (op.hasHttpPost()) { + value.add(getRequestType("Post", op.getHttpPostRes())); + } + http.setGetOrPost(value); + dcp.setHTTP(http); + rval.add(dcp); + return rval; + } - protected JAXBElement getRequestType(String name, - String value) { - JAXBElement rval = new JAXBElement( - new QName(OWS_NS, name), RequestMethodType.class, - new RequestMethodType()); - rval.getValue().setHref(value); - return rval; - } + protected JAXBElement getRequestType(String name, + String value) { + JAXBElement rval = new JAXBElement( + new QName(OWS_NS, name), RequestMethodType.class, + new RequestMethodType()); + rval.getValue().setHref(value); + return rval; + } - protected DomainType getAsDomainType(String name, Collection values) { - DomainType rval = new DomainType(); - rval.setName(name); - List toVals = new ArrayList(values.size()); - for (String val : values) { - toVals.add(val); - } - rval.setValue(toVals); - return rval; - } + protected DomainType getAsDomainType(String name, Collection values) { + DomainType rval = new DomainType(); + rval.setName(name); + List toVals = new ArrayList(values.size()); + for (String val : values) { + toVals.add(val); + } + rval.setValue(toVals); + return rval; + } - /** - * @param serviceinfo - * @return - */ - protected List getParams(OgcServiceInfo serviceinfo) { - // TODO this info should be passed in from somewhere - return Arrays.asList(getAsDomainType("srsName", - Arrays.asList("EPSG:4326"))); - } + /** + * @param serviceinfo + * @return + */ + protected List getParams(OgcServiceInfo serviceinfo) { + // TODO this info should be passed in from somewhere + return Arrays.asList(getAsDomainType("srsName", + Arrays.asList("EPSG:4326"))); + } - /** - * @return - */ - protected FilterCapabilities getFilterCap() { - FilterCapabilities rval = new FilterCapabilities(); - rval.setScalarCapabilities(getScalarCapabilities()); - rval.setSpatialCapabilities(getSpatialCapabilities()); - rval.setIdCapabilities(getIdCapabilities()); - return rval; - } + /** + * @return + */ + protected FilterCapabilities getFilterCap() { + FilterCapabilities rval = new FilterCapabilities(); + rval.setScalarCapabilities(getScalarCapabilities()); + rval.setSpatialCapabilities(getSpatialCapabilities()); + rval.setIdCapabilities(getIdCapabilities()); + return rval; + } - /** - * @return - */ - protected IdCapabilitiesType getIdCapabilities() { - // TODO Auto-generated method stub - return null; - } + /** + * @return + */ + protected IdCapabilitiesType getIdCapabilities() { + // TODO Auto-generated method stub + return null; + } - /** - * @return - */ - protected SpatialCapabilitiesType getSpatialCapabilities() { - SpatialCapabilitiesType rval = new SpatialCapabilitiesType(); - rval.setGeometryOperands(getGeometryOperands()); - rval.setSpatialOperators(getSpatialOperators()); - return rval; - } + /** + * @return + */ + protected SpatialCapabilitiesType getSpatialCapabilities() { + SpatialCapabilitiesType rval = new SpatialCapabilitiesType(); + rval.setGeometryOperands(getGeometryOperands()); + rval.setSpatialOperators(getSpatialOperators()); + return rval; + } - /** - * @return - */ - protected SpatialOperatorsType getSpatialOperators() { - SpatialOperatorsType rval = new SpatialOperatorsType(); - List ops = new ArrayList( - spatialOperators.length); - for (SpatialOperatorNameType name : spatialOperators) { - SpatialOperatorType op = new SpatialOperatorType(); - op.setName(name); - ops.add(op); - } - rval.setSpatialOperator(ops); - return rval; - } + /** + * @return + */ + protected SpatialOperatorsType getSpatialOperators() { + SpatialOperatorsType rval = new SpatialOperatorsType(); + List ops = new ArrayList( + spatialOperators.length); + for (SpatialOperatorNameType name : spatialOperators) { + SpatialOperatorType op = new SpatialOperatorType(); + op.setName(name); + ops.add(op); + } + rval.setSpatialOperator(ops); + return rval; + } - /** - * @return - */ - protected GeometryOperandsType getGeometryOperands() { - GeometryOperandsType rval = new GeometryOperandsType(); - List ops = new ArrayList(geometryOperands.length); - for (String op : geometryOperands) { - QName name = new QName(OgcNamespace.GML, op); - ops.add(name); - } - rval.setGeometryOperand(ops); - return rval; - } + /** + * @return + */ + protected GeometryOperandsType getGeometryOperands() { + GeometryOperandsType rval = new GeometryOperandsType(); + List ops = new ArrayList(geometryOperands.length); + for (String op : geometryOperands) { + QName name = new QName(OgcNamespace.GML, op); + ops.add(name); + } + rval.setGeometryOperand(ops); + return rval; + } - /** - * @return - */ - protected ScalarCapabilitiesType getScalarCapabilities() { - ScalarCapabilitiesType rval = new ScalarCapabilitiesType(); - rval.setArithmeticOperators(getArithmeticOperators()); - rval.setComparisonOperators(getComparisonOperators()); - rval.setLogicalOperators(GetLogicalOperators()); - return rval; - } + /** + * @return + */ + protected ScalarCapabilitiesType getScalarCapabilities() { + ScalarCapabilitiesType rval = new ScalarCapabilitiesType(); + rval.setArithmeticOperators(getArithmeticOperators()); + rval.setComparisonOperators(getComparisonOperators()); + rval.setLogicalOperators(GetLogicalOperators()); + return rval; + } - /** - * @return - */ - protected LogicalOperators GetLogicalOperators() { - return null; - } + /** + * @return + */ + protected LogicalOperators GetLogicalOperators() { + return null; + } - /** - * @return - */ - protected ComparisonOperatorsType getComparisonOperators() { - ComparisonOperatorsType rval = new ComparisonOperatorsType(); - List ops = new ArrayList( - comparisonOperators.length); - for (ComparisonOperatorType op : comparisonOperators) { - ops.add(op); - } - rval.setComparisonOperator(ops); - return rval; - } + /** + * @return + */ + protected ComparisonOperatorsType getComparisonOperators() { + ComparisonOperatorsType rval = new ComparisonOperatorsType(); + List ops = new ArrayList( + comparisonOperators.length); + for (ComparisonOperatorType op : comparisonOperators) { + ops.add(op); + } + rval.setComparisonOperator(ops); + return rval; + } - /** - * @return - */ - protected ArithmeticOperatorsType getArithmeticOperators() { - // TODO Auto-generated method stub - return null; - } + /** + * @return + */ + protected ArithmeticOperatorsType getArithmeticOperators() { + // TODO Auto-generated method stub + return null; + } - /** - * @return - */ - protected GMLObjectTypeListType getSupportsGML() { - GMLObjectTypeListType rval = new GMLObjectTypeListType(); - List gmlObs = new ArrayList( - gmlObjects.length); - for (String type : gmlObjects) { - gmlObs.add(getGMLObjType(type)); - } - rval.setGMLObjectType(gmlObs); - return rval; - } + /** + * @return + */ + protected GMLObjectTypeListType getSupportsGML() { + GMLObjectTypeListType rval = new GMLObjectTypeListType(); + List gmlObs = new ArrayList( + gmlObjects.length); + for (String type : gmlObjects) { + gmlObs.add(getGMLObjType(type)); + } + rval.setGMLObjectType(gmlObs); + return rval; + } - protected GMLObjectTypeType getGMLObjType(String name) { - GMLObjectTypeType rval = new GMLObjectTypeType(); - rval.setName(new QName(GML_NS, name)); - OutputFormatListType outFormats = new OutputFormatListType(); - outFormats.setFormat(Arrays.asList(GML_MIME)); - rval.setOutputFormats(outFormats); - return rval; - } + protected GMLObjectTypeType getGMLObjType(String name) { + GMLObjectTypeType rval = new GMLObjectTypeType(); + rval.setName(new QName(GML_NS, name)); + OutputFormatListType outFormats = new OutputFormatListType(); + outFormats.setFormat(Arrays.asList(GML_MIME)); + rval.setOutputFormats(outFormats); + return rval; + } - /** - * @return - */ - protected GMLObjectTypeListType getServesGML() { - // TODO Auto-generated method stub - return null; - } + /** + * @return + */ + protected GMLObjectTypeListType getServesGML() { + // TODO Auto-generated method stub + return null; + } - /** - * @param request - * @param serviceinfo - * @return - * @throws WfsException - */ - protected FeatureTypeListType getFeatureTypes(GetCapReq request, - OgcServiceInfo serviceinfo) throws WfsException { - FeatureTypeListType rval = new FeatureTypeListType(); - // rval.setOperations(getOperations(serviceinfo)); - rval.setFeatureType(getFeatureTypes(request)); - return rval; - } + /** + * @param request + * @param serviceinfo + * @return + * @throws WfsException + */ + protected FeatureTypeListType getFeatureTypes(GetCapReq request, + OgcServiceInfo serviceinfo) throws WfsException { + FeatureTypeListType rval = new FeatureTypeListType(); + // rval.setOperations(getOperations(serviceinfo)); + rval.setFeatureType(getFeatureTypes(request)); + return rval; + } - protected List getFeatureTypes(GetCapReq request) - throws WfsException { - return translator.transform(registry.getFeatures()); - } + protected List getFeatureTypes(GetCapReq request) + throws WfsException { + return translator.transform(registry.getFeatures()); + } - /** - * @param serviceinfo - * @return - */ - protected ServiceIdentification getServiceId( - OgcServiceInfo serviceinfo) { - ServiceIdentification rval = new ServiceIdentification(); - CodeType ct = new CodeType(); - ct.setValue(SERV_TYPE); - rval.setServiceType(ct); - rval.setTitle(SERV_TITLE); - return rval; - } + /** + * @param serviceinfo + * @return + */ + protected ServiceIdentification getServiceId( + OgcServiceInfo serviceinfo) { + ServiceIdentification rval = new ServiceIdentification(); + CodeType ct = new CodeType(); + ct.setValue(SERV_TYPE); + rval.setServiceType(ct); + rval.setTitle(SERV_TITLE); + return rval; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/FeatureDescriber.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/FeatureDescriber.java new file mode 100644 index 0000000000..86f83d1877 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/FeatureDescriber.java @@ -0,0 +1,156 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.provider; + +import java.util.ArrayList; +import java.util.List; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.reg.IWfsSource; +import com.raytheon.uf.edex.wfs.request.DescFeatureTypeReq; +import com.raytheon.uf.edex.wfs.request.QualifiedName; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 25, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class FeatureDescriber { + + protected WfsRegistryImpl registry; + + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + /** + * + */ + public FeatureDescriber(WfsRegistryImpl registry) { + this.registry = registry; + } + + public String describe(DescFeatureTypeReq request, + OgcServiceInfo serviceInfo) throws WfsException { + List typenames = request.getTypenames(); + String xml; + if (typenames == null || !typenames.isEmpty()) { + xml = getAllSchemas(serviceInfo); + } else if (typenames.size() == 1) { + xml = getOneSchema(typenames.get(0)); + } else { + xml = getMergedSchemas(typenames, serviceInfo); + } + return xml; + } + + /** + * @param roles + * @param username + * @param typenames + * @return + * @throws WfsException + */ + protected String getMergedSchemas(List typenames, + OgcServiceInfo serviceInfo) throws WfsException { + int count = 0; + boolean success = false; + StringBuilder rval = new StringBuilder("\n"); + rval.append("\n"); + String base = getBaseDescUrl(serviceInfo) + + "&request=describefeaturetype"; + // TODO better encoding + base = base.replaceAll("&", "&"); + for (QualifiedName name : typenames) { + if (registry.getSource(name) == null) { + continue; + } + success = true; + if (name.getPrefix() == null) { + name.setPrefix("ns" + count++); + } + rval.append("\n"); + } + rval.append(""); + return success ? rval.toString() : null; + } + + protected String getBaseDescUrl(OgcServiceInfo serviceInfo) { + for (OgcOperationInfo opinfo : serviceInfo.getOperations()) { + if (opinfo.getType().equals(WfsOpType.DescribeFeatureType)) { + return opinfo.getHttpGetRes(); + } + } + log.error("Unable to construct describe feature URL"); + return "http://localhost:8085/wfs?service=wfs"; + } + + /** + * @param roles + * @param username + * @param qualifiedName + * @return + * @throws WfsException + */ + protected String getOneSchema(QualifiedName feature) throws WfsException { + IWfsSource source = registry.getSource(feature); + return source == null ? null : source.describeFeatureType(feature); + } + + /** + * @param roles + * @param username + * @return + * @throws WfsException + */ + protected String getAllSchemas(OgcServiceInfo serviceInfo) + throws WfsException { + return getMergedSchemas(getFeatureNames(), serviceInfo); + } + + public List getFeatureNames() { + List features = registry.getFeatures(); + List rval = new ArrayList(features.size()); + for (WfsFeatureType f : features) { + rval.add(f.getName()); + } + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/FeatureFetcher.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/FeatureFetcher.java index 584c69f79e..efb438b33e 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/FeatureFetcher.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/FeatureFetcher.java @@ -30,37 +30,35 @@ */ package com.raytheon.uf.edex.wfs.provider; -import java.math.BigInteger; import java.util.ArrayList; +import java.util.Date; import java.util.List; -import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import net.opengis.filter.v_1_1_0.FilterType; -import net.opengis.gml.v_3_1_1.AbstractFeatureType; -import net.opengis.gml.v_3_1_1.FeaturePropertyType; -import net.opengis.wfs.v_1_1_0.FeatureCollectionType; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.geotools.geometry.jts.JTS; import org.hibernate.criterion.Criterion; import org.hibernatespatial.criterion.SpatialRestrictions; import org.opengis.feature.simple.SimpleFeature; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; +import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.wfs.WfsException; import com.raytheon.uf.edex.wfs.WfsException.Code; -import com.raytheon.uf.edex.wfs.WfsProvider.WfsOpType; -import com.raytheon.uf.edex.wfs.filter.FilterProcessor; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; import com.raytheon.uf.edex.wfs.reg.WfsQuery; +import com.raytheon.uf.edex.wfs.reg.WfsQueryOptions; +import com.raytheon.uf.edex.wfs.reg.WfsQueryResults; +import com.raytheon.uf.edex.wfs.reg.WfsQueryResults.ResultType; import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; -import com.raytheon.uf.edex.wfs.reg.WfsSource; +import com.raytheon.uf.edex.wfs.reg.IWfsSource; import com.raytheon.uf.edex.wfs.request.FeatureQuery; import com.raytheon.uf.edex.wfs.request.GetFeatureReq; -import com.raytheon.uf.edex.wfs.request.GetFeatureReq.ResultType; import com.raytheon.uf.edex.wfs.request.QualifiedName; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Polygon; @@ -70,161 +68,175 @@ import com.vividsolutions.jts.geom.Polygon; * @author bclement * @version 1.0 */ -public class FeatureFetcher { +public abstract class FeatureFetcher { - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected WfsRegistryImpl registry; + protected WfsRegistryImpl registry; - /** - * @param registry - */ - public FeatureFetcher(WfsRegistryImpl registry) { - this.registry = registry; - } + public static class CountedFeatures { + public List features; - public List> getSimpleFeatures(GetFeatureReq request, - OgcServiceInfo serviceinfo) throws WfsException { - List> rval = new ArrayList>(); - for (FeatureQuery q : request.getQueries()) { - for (QualifiedName type : q.getTypeNames()) { - WfsSource source = registry.getSource(type); - if (source != null) { - String spatial = source.getFeatureSpatialField(type); - VisitorBag bag = new VisitorBag( - source.getFeatureEntity(type), spatial); - bag.setFieldMap(source.getFieldMap()); - WfsQuery wfsq; - try { - wfsq = new WfsQuery(getQuery(q, bag), - request.getMaxFeatures(), q.getSortBys(), - q.getPropertyNames(), q.getTimeRange()); - } catch (Exception e) { - log.error("Problem parsing wfs query", e); - throw new WfsException(Code.INVALID_REQUEST, - "Invalid filter"); - } - rval.add(source.querySimple(type, wfsq)); - } else { - throw new WfsException(Code.INVALID_REQUEST, - "Unkown feature type: " + type); - } - } - } - return rval; - } + public long count = 0; - public FeatureCollectionType getFeatures(GetFeatureReq request, - OgcServiceInfo serviceinfo) throws WfsException { - FeatureCollectionType featColl = new FeatureCollectionType(); - List members = featColl.getFeatureMember(); - long count = 0; - for (FeatureQuery q : request.getQueries()) { - for (QualifiedName type : q.getTypeNames()) { - WfsSource source = registry.getSource(type); - if (source != null) { - String spatial = source.getFeatureSpatialField(type); - VisitorBag bag = new VisitorBag( - source.getFeatureEntity(type), spatial); - bag.setFieldMap(source.getFieldMap()); - WfsQuery wfsq; - try { - wfsq = new WfsQuery(getQuery(q, bag), - request.getMaxFeatures(), q.getSortBys(), - q.getPropertyNames(), q.getTimeRange()); - } catch (Exception e) { - log.error("Problem parsing wfs query", e); - throw new WfsException(Code.INVALID_REQUEST, - "Invalid filter"); - } - if (request.getResulttype() == ResultType.hits) { - count += source.count(type, wfsq); - } else { - List> result = source - .query(type, wfsq); - count += populateFeatures(members, result); - } - } else { - throw new WfsException(Code.INVALID_REQUEST, - "Unkown feature type: " + type); - } - } - } - featColl.setNumberOfFeatures(new BigInteger("" + count)); - return featColl; - } + public Date latest; - protected long populateFeatures(List members, - List> results) { - if (results == null || results.isEmpty()) { - return 0; - } - for (JAXBElement feature : results) { - FeaturePropertyType propType = new FeaturePropertyType(); - propType.setFeature(feature); - members.add(propType); - } - return results.size(); - } + public CountedFeatures(List features) { + this(features, features.size()); + } - /** - * @param q - * @param spatial - * @return - * @throws Exception - */ - protected Criterion getQuery(FeatureQuery q, VisitorBag bag) - throws Exception { - Criterion rval = null; - switch (q.getFilterType()) { - case BBOX: - OgcBoundingBox bbox = (OgcBoundingBox) q.getFilter(); - rval = getBbox(bbox.getMiny(), bbox.getMinx(), bbox.getMaxy(), - bbox.getMaxx(), bag); - break; - case FIDS: - // TODO - rval = getDefault(bag); - break; - case XML: - FilterType f = parseFilterXml((String) q.getFilter()); - rval = getFromFilter(f, bag); - break; - case XMLOBJ: - FilterType filter = (FilterType) q.getFilter(); - rval = getFromFilter(filter, bag); - break; - default: - rval = getDefault(bag); - } - return rval; - } + public CountedFeatures(long count) { + this(new ArrayList(0), count); + } - protected Criterion getDefault(VisitorBag bag) { - return null; - } + public CountedFeatures(List features, long count) { + this.features = features; + this.count = count; + } + } - protected FilterType parseFilterXml(String xml) throws JAXBException { - return (FilterType) registry.unmarshal(xml); - } + protected static abstract class FeatureCallback { + public abstract long addResults(WfsQueryResults results); + } - protected Criterion getFromFilter(FilterType filter, VisitorBag bag) - throws Exception { - if (filter != null) { - FilterProcessor proc = new FilterProcessor(filter); - return (Criterion) proc.accept(new QueryFilterVisitor(), bag); - } else { - // FIXME - return null; - } + /** + * @param registry + */ + public FeatureFetcher(WfsRegistryImpl registry) { + this.registry = registry; + } - } + @SuppressWarnings("unchecked") + public List> getSimpleFeatures(GetFeatureReq request, + OgcServiceInfo serviceinfo) throws WfsException { + List> rval = new ArrayList>(); + for (FeatureQuery q : request.getQueries()) { + for (QualifiedName type : q.getTypeNames()) { + IWfsSource source = registry.getSource(type); + if (source != null) { + String spatial = source.getFeatureSpatialField(type); + String vert = source.getFeatureVerticalField(type); + String id = source.getFeatureIdField(type); + VisitorBag bag = new VisitorBag( + source.getFeatureEntity(type), spatial, vert, id); + bag.setFieldMap(source.getFieldMap()); + WfsQuery wfsq; + try { + wfsq = new WfsQuery(getQuery(q, bag), + request.getMaxFeatures(), q.getSortBys(), + q.getPropertyNames(), q.getTimeRange()); + } catch (OgcException e) { + throw new WfsException(e); + } catch (WfsException e) { + throw e; + } catch (Exception e) { + log.error("Problem parsing wfs query", e); + throw new WfsException(Code.INVALID_REQUEST, + "Invalid filter"); + } + WfsQueryResults results = source.query(type, wfsq, + new WfsQueryOptions(ResultType.SIMPLE)); + rval.add((List) results.getResults()); + } else { + throw new WfsException(Code.INVALID_REQUEST, + "Unkown feature type: " + type); + } + } + } + return rval; + } - protected Criterion getBbox(double lowerLat, double lowerLon, - double upperLat, double upperLon, VisitorBag bag) { - Polygon geom = JTS.toGeometry(new Envelope(lowerLon, upperLon, - lowerLat, upperLat)); - return SpatialRestrictions.within(bag.getSpatialField(), geom); - } + protected long getFeatures(GetFeatureReq request, WfsQueryOptions options, + FeatureCallback callback) throws WfsException { + long count = 0; + for (FeatureQuery q : request.getQueries()) { + for (QualifiedName type : q.getTypeNames()) { + IWfsSource source = registry.getSource(type); + if (source != null) { + String spatial = source.getFeatureSpatialField(type); + String vert = source.getFeatureVerticalField(type); + String id = source.getFeatureIdField(type); + VisitorBag bag = new VisitorBag( + source.getFeatureEntity(type), spatial, vert, id); + bag.setFieldMap(source.getFieldMap()); + WfsQuery wfsq; + try { + wfsq = new WfsQuery(getQuery(q, bag), + request.getMaxFeatures(), q.getSortBys(), + q.getPropertyNames(), q.getTimeRange()); + } catch (OgcException e) { + throw new WfsException(e); + } catch (WfsException e) { + throw e; + } catch (Exception e) { + log.error("Problem parsing wfs query", e); + throw new WfsException(Code.INVALID_REQUEST, + "Invalid filter"); + } + if (request.getResulttype() == GetFeatureReq.ResultType.hits) { + count += source.count(type, wfsq); + } else { + WfsQueryResults result = source.query(type, wfsq, + options); + count += callback.addResults(result); + } + } else { + throw new WfsException(Code.INVALID_REQUEST, + "Unkown feature type: " + type); + } + } + } + return count; + } + + /** + * @param q + * @param spatial + * @return + * @throws Exception + */ + protected Criterion getQuery(FeatureQuery q, VisitorBag bag) + throws Exception { + Criterion rval = null; + switch (q.getFilterType()) { + case BBOX: + OgcBoundingBox bbox = (OgcBoundingBox) q.getFilter(); + rval = getBbox(bbox.getMiny(), bbox.getMinx(), bbox.getMaxy(), + bbox.getMaxx(), bag); + break; + case FIDS: + // TODO + rval = getDefault(bag); + break; + case XML: + FilterType f = parseFilterXml((String) q.getFilter()); + rval = getFromFilter(f, bag); + break; + case XMLOBJ: + rval = getFromFilter(q.getFilter(), bag); + break; + default: + rval = getDefault(bag); + } + return rval; + } + + protected Criterion getDefault(VisitorBag bag) { + return null; + } + + protected FilterType parseFilterXml(String xml) throws JAXBException { + return (FilterType) registry.unmarshal(xml); + } + + protected abstract Criterion getFromFilter(Object filter, VisitorBag bag) + throws Exception; + + protected Criterion getBbox(double lowerLat, double lowerLon, + double upperLat, double upperLon, VisitorBag bag) { + Polygon geom = JTS.toGeometry(new Envelope(lowerLon, upperLon, + lowerLat, upperLat)); + return SpatialRestrictions.within(bag.getSpatialField(), geom); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Gml31FeatureFetcher.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Gml31FeatureFetcher.java new file mode 100644 index 0000000000..30da55bed1 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Gml31FeatureFetcher.java @@ -0,0 +1,121 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.provider; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_1_1_0.FilterType; +import net.opengis.gml.v_3_1_1.AbstractFeatureType; +import net.opengis.gml.v_3_1_1.FeaturePropertyType; + +import org.hibernate.criterion.Criterion; + +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; +import com.raytheon.uf.edex.wfs.filter.v1_1_0.FilterProcessor; +import com.raytheon.uf.edex.wfs.filter.v1_1_0.QueryFilterVisitor; +import com.raytheon.uf.edex.wfs.reg.WfsQueryOptions; +import com.raytheon.uf.edex.wfs.reg.WfsQueryResults; +import com.raytheon.uf.edex.wfs.reg.WfsQueryResults.ResultType; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.request.GetFeatureReq; + +/** + * Feature fetcher for gml version 3.1.1 + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 16, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class Gml31FeatureFetcher extends FeatureFetcher { + + public static final String GML_VERSION = "3.1.1"; + + /** + * @param registry + */ + public Gml31FeatureFetcher(WfsRegistryImpl registry) { + super(registry); + } + + /** + * @param request + * @param options + * @return + * @throws WfsException + */ + public CountedFeatures getFeatures( + GetFeatureReq request, OgcServiceInfo serviceinfo) + throws WfsException { + final List members = new ArrayList(); + FeatureCallback callback = new FeatureCallback() { + @Override + public long addResults(WfsQueryResults results) { + return populateFeatures(members, results); + } + }; + WfsQueryOptions options = new WfsQueryOptions(ResultType.JAXB); + options.setGmlVersion(GML_VERSION); + long count = getFeatures(request, options, callback); + return new CountedFeatures(members, count); + } + + /** + * @param members + * @param results + * @return + */ + @SuppressWarnings("unchecked") + protected long populateFeatures(List members, + WfsQueryResults results) { + List> list = (List>) results.getResults(); + if (list == null || list.isEmpty()) { + return 0; + } + for (JAXBElement feature : list) { + FeaturePropertyType propType = new FeaturePropertyType(); + propType.setFeature((JAXBElement) feature); + members.add(propType); + } + return list.size(); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.provider.FeatureFetcher#getFromFilter(java.lang + * .Object, com.raytheon.uf.edex.wfs.provider.VisitorBag) + */ + protected Criterion getFromFilter(Object filter, VisitorBag bag) + throws Exception { + if (filter != null) { + FilterProcessor proc = new FilterProcessor((FilterType) filter); + return (Criterion) proc.accept(new QueryFilterVisitor(), bag); + } else { + // FIXME + return null; + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Gml32FeatureFetcher.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Gml32FeatureFetcher.java new file mode 100644 index 0000000000..e146ec8075 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Gml32FeatureFetcher.java @@ -0,0 +1,131 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.provider; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.filter.v_2_0_0.FilterType; +import net.opengis.gml.v_3_2_1.AbstractFeatureType; +import net.opengis.gml.v_3_2_1.FeaturePropertyType; + +import org.hibernate.criterion.Criterion; + +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; +import com.raytheon.uf.edex.wfs.filter.v2_0_0.Filter2Processor; +import com.raytheon.uf.edex.wfs.filter.v2_0_0.QueryFilterVisitor; +import com.raytheon.uf.edex.wfs.reg.WfsQueryOptions; +import com.raytheon.uf.edex.wfs.reg.WfsQueryResults; +import com.raytheon.uf.edex.wfs.reg.WfsQueryResults.ResultType; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.request.GetFeatureReq; + +/** + * Feature fetcher for GML 3.2.1 + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 16, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class Gml32FeatureFetcher extends FeatureFetcher { + + public static final String GML_VERSION = "3.2.1"; + + /** + * @param registry + */ + public Gml32FeatureFetcher(WfsRegistryImpl registry) { + super(registry); + } + + /** + * @param request + * @param options + * @return + * @throws WfsException + */ + public CountedFeatures getFeatures( + GetFeatureReq request, OgcServiceInfo serviceinfo, + boolean gatherMetadata) throws WfsException { + final List members = new ArrayList(); + final Date[] holder = new Date[1]; + FeatureCallback callback = new FeatureCallback() { + @Override + public long addResults(WfsQueryResults results) { + Date latest = results.getLatestResult(); + if (holder[0] == null || latest.after(holder[0])) { + holder[0] = latest; + } + return populateFeatures(members, results); + } + }; + WfsQueryOptions options = new WfsQueryOptions(ResultType.JAXB); + options.setGmlVersion(GML_VERSION); + options.setGatherMetadata(gatherMetadata); + long count = getFeatures(request, options, callback); + CountedFeatures rval = new CountedFeatures( + members, count); + rval.latest = holder[0]; + return rval; + } + + /** + * @param members + * @param results + * @return + */ + @SuppressWarnings("unchecked") + protected long populateFeatures(List members, + WfsQueryResults results) { + List> list = (List>) results.getResults(); + if (list == null || list.isEmpty()) { + return 0; + } + for (JAXBElement feature : list) { + FeaturePropertyType propType = new FeaturePropertyType(); + propType.setAbstractFeature((JAXBElement) feature); + members.add(propType); + } + return list.size(); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.provider.FeatureFetcher#getFromFilter(java.lang + * .Object, com.raytheon.uf.edex.wfs.provider.VisitorBag) + */ + protected Criterion getFromFilter(Object filter, VisitorBag bag) + throws Exception { + if (filter != null) { + QueryFilterVisitor visitor = new QueryFilterVisitor(); + Filter2Processor proc = new Filter2Processor((FilterType) filter); + return (Criterion) proc.accept(visitor, bag); + } else { + // FIXME + return null; + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/OgcWfsProvider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/OgcWfsProvider.java deleted file mode 100644 index ef9383569a..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/OgcWfsProvider.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * Apr 22, 2011 bclement Initial creation - * - */ -package com.raytheon.uf.edex.wfs.provider; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.xml.bind.JAXBException; - -import net.opengis.ows.v_1_0_0.ExceptionReport; -import net.opengis.ows.v_1_0_0.ExceptionType; -import net.opengis.wfs.v_1_1_0.DescribeFeatureTypeType; -import net.opengis.wfs.v_1_1_0.FeatureCollectionType; -import net.opengis.wfs.v_1_1_0.GetCapabilitiesType; -import net.opengis.wfs.v_1_1_0.GetFeatureType; -import net.opengis.wfs.v_1_1_0.ObjectFactory; -import net.opengis.wfs.v_1_1_0.TransactionResponseType; -import net.opengis.wfs.v_1_1_0.TransactionType; -import net.opengis.wfs.v_1_1_0.WFSCapabilitiesType; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.opengis.feature.simple.SimpleFeature; -import org.springframework.context.ApplicationContext; - -import com.raytheon.uf.edex.core.EDEXUtil; -import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; -import com.raytheon.uf.edex.ogc.common.OgcResponse; -import com.raytheon.uf.edex.ogc.common.OgcResponse.ErrorType; -import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; -import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; -import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; -import com.raytheon.uf.edex.wfs.WfsException; -import com.raytheon.uf.edex.wfs.WfsException.Code; -import com.raytheon.uf.edex.wfs.WfsFeatureType; -import com.raytheon.uf.edex.wfs.WfsProvider; -import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; -import com.raytheon.uf.edex.wfs.reg.WfsSource; -import com.raytheon.uf.edex.wfs.request.DescFeatureTypeReq; -import com.raytheon.uf.edex.wfs.request.GetCapReq; -import com.raytheon.uf.edex.wfs.request.GetFeatureReq; -import com.raytheon.uf.edex.wfs.request.GetFeatureReq.ResultType; -import com.raytheon.uf.edex.wfs.request.QualifiedName; -import com.raytheon.uf.edex.wfs.request.TransReq; -import com.raytheon.uf.edex.wfs.request.WfsRequest; -import com.raytheon.uf.edex.wfs.request.WfsRequest.Type; - -public class OgcWfsProvider implements WfsProvider { - - protected String describeFeatureUrl; - - protected Log log = LogFactory.getLog(this.getClass()); - - protected WfsRegistryImpl registry; - - protected Capabilities capabilities; - - protected FeatureFetcher features; - - protected Transactor transactor; - - protected ObjectFactory wfsFactory = new ObjectFactory(); - - public OgcWfsProvider(WfsRegistryImpl registry) { - this.capabilities = new Capabilities(registry); - this.features = new FeatureFetcher(registry); - this.registry = registry; - this.transactor = new Transactor(); - } - - protected OgcWfsProvider() { - // unit tests - } - - @Override - public OgcResponse getError(WfsException e, String exceptionFormat) { - ExceptionType et = new ExceptionType(); - et.setExceptionCode(e.getCode().toString()); - et.setExceptionText(Arrays.asList(e.getMessage())); - ExceptionReport report = new ExceptionReport(); - report.setException(Arrays.asList(et)); - String rval = ""; - String mimeType = OgcResponse.TEXT_XML_MIME; - if (exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_XML_MIME)) { - try { - rval = registry.marshal(report); - mimeType = OgcResponse.TEXT_XML_MIME; - } catch (JAXBException e1) { - log.error("Unable to marshal WFS response", e1); - rval = ""; - rval += ""; - rval += "" + e.getMessage() - + ""; - rval += ""; - mimeType = OgcResponse.TEXT_XML_MIME; - } - } else if (exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_HTML_MIME)) { - rval = ""; - rval += "
An error occurred performing the request:
"; - rval += "
Error Code: " + e.getCode().toString(); - rval += "
Message: " + e.getMessage() + ""; - mimeType = OgcResponse.TEXT_HTML_MIME; - } - OgcResponse resp = new OgcResponse(rval, mimeType, TYPE.TEXT); - switch (e.getCode()) { - case INTERNAL_SERVER_ERROR: - resp.setError(ErrorType.INT_ERR); - break; - default: - resp.setError(ErrorType.BAD_REQ); - } - return resp; - } - - protected String getXml(InputStream in) throws IOException { - return new java.util.Scanner(in).useDelimiter("\\A").next(); - } - - @Override - public WfsRequest getRequest(InputStream in) { - Object obj; - WfsRequest rval; - String xml; - try { - xml = getXml(in); - obj = registry.unmarshal(xml); - } catch (Exception e) { - log.error("Unable to decode request", e); - return getDecodeError(OgcResponse.TEXT_XML_MIME); - } - if (obj instanceof GetCapabilitiesType) { - rval = new GetCapReq((GetCapabilitiesType) obj); - } else if (obj instanceof GetFeatureType) { - rval = new GetFeatureReq((GetFeatureType) obj); - } else if (obj instanceof DescribeFeatureTypeType) { - rval = new DescFeatureTypeReq((DescribeFeatureTypeType) obj); - } else if (obj instanceof TransactionType) { - rval = TransReq.buildTransReq((TransactionType) obj); - if (rval == null) { - rval = getDecodeError(OgcResponse.TEXT_XML_MIME); - } - } else { - rval = getDecodeError(OgcResponse.TEXT_XML_MIME); - } - if (rval.getType() != Type.ERROR) { - rval.setRawrequest(obj); - } - return rval; - } - - public WfsRequest getDecodeError(String exceptionFormat) { - OgcResponse error = getError(new WfsException(Code.INVALID_REQUEST, - "Unable to decode request"), exceptionFormat); - WfsRequest rval = new WfsRequest(Type.ERROR); - rval.setRawrequest(error); - return rval; - } - - @Override - public OgcResponse getCapabilities(GetCapReq request, - OgcServiceInfo serviceinfo) { - OgcResponse rval; - try { - WFSCapabilitiesType cap = capabilities.getCapabilities(request, - serviceinfo); - rval = marshalResponse(wfsFactory.createWFSCapabilities(cap)); - } catch (WfsException e) { - rval = getError(e, request.getExceptionFormat()); - } - return rval; - } - - protected OgcResponse marshalResponse(Object jaxbobject) { - OgcResponse rval; - try { - String xml = registry.marshal(jaxbobject); - rval = new OgcResponse(xml, "text/gml; subtype=gml/3.1.1", - TYPE.TEXT); - } catch (JAXBException e) { - log.error("Unable to marshal WFS response", e); - // TODO: real error code - rval = getError(new WfsException(Code.INVALID_REQUEST), - OgcResponse.TEXT_XML_MIME); - } - return rval; - } - - @Override - public OgcResponse getFeature(GetFeatureReq request, - OgcServiceInfo serviceinfo) { - OgcResponse rval; - FeatureCollectionType featColl; - String format = request.getOutputformat(); - try { - if (format.toLowerCase().contains("gml") - || format.toLowerCase().contains("xml")) { - // use JAXB instead of gml simple feature formatter - featColl = features.getFeatures(request, serviceinfo); - rval = marshalResponse(wfsFactory - .createFeatureCollection(featColl)); - } else { - if (request.getResulttype() == ResultType.hits) { - throw new WfsException(Code.INVALID_PARAMETER_VALUE, - "Hits result not supported in format: " + format); - } - SimpleFeatureFormatter formatter = getFormatter(format); - List> res = features.getSimpleFeatures( - request, serviceinfo); - try { - rval = formatter.format(res); - } catch (Exception e) { - log.error("Problem formatting features", e); - throw new WfsException(Code.INTERNAL_SERVER_ERROR); - } - } - } catch (WfsException e) { - rval = getError(e, request.getExceptionFormat()); - } - return rval; - } - - protected SimpleFeatureFormatter getFormatter(String format) - throws WfsException { - ApplicationContext ctx = EDEXUtil.getSpringContext(); - String[] beans = ctx.getBeanNamesForType(SimpleFeatureFormatter.class); - for (String bean : beans) { - SimpleFeatureFormatter sff = (SimpleFeatureFormatter) ctx - .getBean(bean); - if (sff.matchesFormat(format)) { - return sff; - } - } - throw new WfsException(Code.INVALID_PARAMETER_VALUE, - "Unsupported format: " + format); - } - - @Override - public OgcResponse transaction(TransReq request) { - TransactionResponseType rval = transactor.transaction(request); - return marshalResponse(wfsFactory.createTransactionResponse(rval)); - } - - @Override - public OgcResponse describeFeatureType(DescFeatureTypeReq request, - OgcServiceInfo serviceInfo) { - OgcResponse rval; - try { - String xml = descFeatureInternal(request, serviceInfo); - if (xml == null) { - throw new WfsException(Code.INVALID_REQUEST, - "Unknown type name(s)"); - } - rval = new OgcResponse(xml, "text/xml; subtype=gml/3.1.1", - TYPE.TEXT); - } catch (WfsException e) { - rval = getError(e, request.getExceptionFormat()); - } - return rval; - } - - public String descFeatureInternal(DescFeatureTypeReq request, - OgcServiceInfo serviceInfo) throws WfsException { - List typenames = request.getTypenames(); - String xml; - if (typenames == null || typenames.size() == 0) { - xml = getAllSchemas(serviceInfo); - } else if (typenames.size() == 1) { - xml = getOneSchema(typenames.get(0)); - } else { - xml = getMergedSchemas(typenames, serviceInfo); - } - return xml; - } - - // the following are desc feature type specific TODO move to separate object - - /** - * @param roles - * @param username - * @param typenames - * @return - * @throws WfsException - */ - protected String getMergedSchemas(List typenames, - OgcServiceInfo serviceInfo) throws WfsException { - int count = 0; - boolean success = false; - StringBuilder rval = new StringBuilder("\n"); - rval.append("\n"); - for (QualifiedName name : typenames) { - if (registry.getSource(name) == null) { - continue; - } - success = true; - if (name.getPrefix() == null) { - name.setPrefix("ns" + count++); - } - rval.append("\n"); - } - rval.append(""); - return success ? rval.toString() : null; - } - - protected String getDescUrl(OgcServiceInfo serviceInfo) { - if (describeFeatureUrl == null) { - for (OgcOperationInfo opinfo : serviceInfo - .getOperations()) { - String res = parse(opinfo.getHttpGetRes()); - if (res != null) { - describeFeatureUrl = res; - break; - } - } - if (describeFeatureUrl == null) { - log.error("Unable to construct describe feature URL"); - describeFeatureUrl = "http://localhost:8085/wfs?request=describefeaturetype"; - } - } - return describeFeatureUrl; - } - - /** - * @param httpGetRes - * @return - */ - private String parse(String target) { - if (target == null) { - return null; - } - if (target.toLowerCase().contains("describefeaturetype")) { - return target; - } - return null; - } - - /** - * @param roles - * @param username - * @param qualifiedName - * @return - * @throws WfsException - */ - protected String getOneSchema(QualifiedName feature) throws WfsException { - WfsSource source = registry.getSource(feature); - return source == null ? null : source.describeFeatureType(feature); - } - - /** - * @param roles - * @param username - * @return - * @throws WfsException - */ - protected String getAllSchemas(OgcServiceInfo serviceInfo) - throws WfsException { - return getMergedSchemas(getFeatureNames(), serviceInfo); - } - - public List getFeatureNames() { - // no authorization since the results of this will be authorized - // individually - List features = registry.getFeatures(); - List rval = new ArrayList(features.size()); - for (WfsFeatureType f : features) { - rval.add(f.getName()); - } - return rval; - } - -} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryExpressionVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryExpressionVisitor.java index 00d7b8ee53..39a2b43921 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryExpressionVisitor.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryExpressionVisitor.java @@ -34,9 +34,8 @@ import java.util.List; import net.opengis.filter.v_1_1_0.PropertyNameType; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.wfs.filter.ExpressionProcessor; import com.raytheon.uf.edex.wfs.filter.OgcExpressionVisitor; @@ -47,7 +46,7 @@ import com.raytheon.uf.edex.wfs.filter.OgcExpressionVisitor; */ public class QueryExpressionVisitor implements OgcExpressionVisitor { - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); /* * (non-Javadoc) diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryFilterVisitor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryFilterVisitor.java index a2ed8f0028..38b0d3105c 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryFilterVisitor.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/QueryFilterVisitor.java @@ -47,8 +47,6 @@ import net.opengis.gml.v_3_1_1.AbstractGeometryType; import net.opengis.gml.v_3_1_1.EnvelopeType; import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.geotools.geometry.jts.JTS; import org.hibernate.criterion.Conjunction; import org.hibernate.criterion.Criterion; @@ -58,7 +56,9 @@ import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Restrictions; import org.hibernatespatial.criterion.SpatialRestrictions; -import com.raytheon.uf.common.util.ConvertUtil; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.util.ConvertService; import com.raytheon.uf.edex.wfs.filter.ExpressionProcessor; import com.raytheon.uf.edex.wfs.filter.FilterProcessor; import com.raytheon.uf.edex.wfs.filter.OgcFilterVisitor; @@ -74,469 +74,445 @@ import com.vividsolutions.jts.geom.Geometry; */ public class QueryFilterVisitor implements OgcFilterVisitor { - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected GeometryConverter geomConverter = new GeometryConverter(); + protected GeometryConverter geomConverter = new GeometryConverter(); - protected EnvelopeConverter envConverter = new EnvelopeConverter(); + protected EnvelopeConverter envConverter = new EnvelopeConverter(); - protected QueryExpressionVisitor exprVisitor = new QueryExpressionVisitor(); + protected QueryExpressionVisitor exprVisitor = new QueryExpressionVisitor(); - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#equal(com.raytheon.uf.edex - * .filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, - * java.lang.Object) - */ - @Override - public Criterion equal(ExpressionProcessor left, - ExpressionProcessor right, - boolean matchCase, Object obj) throws Exception { - VisitorBag bag = (VisitorBag) obj; - Entry e = getBinaryProps(left, right, bag); - return Restrictions.eq(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#equal(com.raytheon.uf.edex + * .filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion equal(ExpressionProcessor left, ExpressionProcessor right, + boolean matchCase, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.eq(e.getKey(), e.getValue()); + } - protected Entry getBinaryProps(ExpressionProcessor left, - ExpressionProcessor right, VisitorBag bag) throws Exception { - String prop = (String) left.accept(exprVisitor, bag); - String value = (String) right.accept(exprVisitor, bag); - Class ent = bag.getRootEntity(); - String[] path = parseProp(prop); - Object val = ConvertUtil.convertAsType(value, ent, path); - String field = StringUtils.join(path, "."); - return new SimpleEntry(bag.filterField(field), val); - } + protected Entry getBinaryProps(ExpressionProcessor left, + ExpressionProcessor right, VisitorBag bag) throws Exception { + String prop = (String) left.accept(exprVisitor, bag); + String value = (String) right.accept(exprVisitor, bag); + Class ent = bag.getRootEntity(); + String[] path = parseProp(prop); + Object val = ConvertService.get().convertAsType(value, ent, path); + String field = StringUtils.join(path, "."); + return new SimpleEntry(bag.filterField(field), val); + } - protected String[] parseProp(String prop) { - // TODO we may want to keep the namespaces - String[] rval = prop.trim().split("\\/"); - for (int i = 0; i < rval.length; ++i) { - int index = rval[i].lastIndexOf(':'); - if (index > -1) { - rval[i] = rval[i].substring(index + 1); - } - } - return rval; - } + protected String[] parseProp(String prop) { + // TODO we may want to keep the namespaces + String[] rval = prop.trim().split("\\/"); + for (int i = 0; i < rval.length; ++i) { + int index = rval[i].lastIndexOf(':'); + if (index > -1) { + rval[i] = rval[i].substring(index + 1); + } + } + return rval; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#notEqual(com.raytheon.uf - * .edex.filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, - * java.lang.Object) - */ - @Override - public Criterion notEqual(ExpressionProcessor left, - ExpressionProcessor right, - boolean matchCase, Object obj) throws Exception { - VisitorBag bag = (VisitorBag) obj; - Entry e = getBinaryProps(left, right, bag); - return Restrictions.ne(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#notEqual(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion notEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.ne(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThan(com.raytheon.uf - * .edex.filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, - * java.lang.Object) - */ - @Override - public Criterion lessThan(ExpressionProcessor left, - ExpressionProcessor right, - boolean matchCase, Object obj) throws Exception { - VisitorBag bag = (VisitorBag) obj; - Entry e = getBinaryProps(left, right, bag); - return Restrictions.lt(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThan(com.raytheon.uf + * .edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion lessThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.lt(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThan(com.raytheon - * .uf.edex.filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, - * java.lang.Object) - */ - @Override - public Criterion greaterThan(ExpressionProcessor left, - ExpressionProcessor right, boolean matchCase, Object obj) - throws Exception { - VisitorBag bag = (VisitorBag) obj; - Entry e = getBinaryProps(left, right, bag); - return Restrictions.gt(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThan(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion greaterThan(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.gt(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThanEqual(com.raytheon - * .uf.edex.filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, - * java.lang.Object) - */ - @Override - public Criterion greaterThanEqual(ExpressionProcessor left, - ExpressionProcessor right, boolean matchCase, Object obj) - throws Exception { - VisitorBag bag = (VisitorBag) obj; - Entry e = getBinaryProps(left, right, bag); - return Restrictions.ge(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#greaterThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion greaterThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.ge(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThanEqual(com.raytheon - * .uf.edex.filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, - * java.lang.Object) - */ - @Override - public Criterion lessThanEqual(ExpressionProcessor left, - ExpressionProcessor right, boolean matchCase, Object obj) - throws Exception { - VisitorBag bag = (VisitorBag) obj; - Entry e = getBinaryProps(left, right, bag); - return Restrictions.le(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#lessThanEqual(com.raytheon + * .uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, boolean, + * java.lang.Object) + */ + @Override + public Criterion lessThanEqual(ExpressionProcessor left, + ExpressionProcessor right, boolean matchCase, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinaryProps(left, right, bag); + return Restrictions.le(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#isLike(net.opengis.filter - * .v_1_1_0.PropertyIsLikeType, java.lang.Object) - */ - @Override - public Criterion isLike(PropertyIsLikeType op, Object obj) - throws Exception { - // FIXME this is not correct, needs to take wildcard, anychar and - // escapes into account - VisitorBag bag = (VisitorBag) obj; - String prop = (String) op.getPropertyName().getContent().get(0); - String value = (String) op.getLiteral().getContent().get(0); - return Restrictions.like(bag.filterField(prop), value, - MatchMode.ANYWHERE); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isLike(net.opengis.filter + * .v_1_1_0.PropertyIsLikeType, java.lang.Object) + */ + @Override + public Criterion isLike(PropertyIsLikeType op, Object obj) throws Exception { + // FIXME this is not correct, needs to take wildcard, anychar and + // escapes into account + VisitorBag bag = (VisitorBag) obj; + String prop = (String) op.getPropertyName().getContent().get(0); + String value = (String) op.getLiteral().getContent().get(0); + return Restrictions.like(bag.filterField(prop), value, + MatchMode.ANYWHERE); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#isNull(net.opengis.filter - * .v_1_1_0.PropertyIsNullType, java.lang.Object) - */ - @Override - public Criterion isNull(PropertyIsNullType op, Object obj) - throws Exception { - VisitorBag bag = (VisitorBag) obj; - String field = (String) op.getPropertyName().getContent().get(0); - return Restrictions.isNull(bag.filterField(field)); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#isNull(net.opengis.filter + * .v_1_1_0.PropertyIsNullType, java.lang.Object) + */ + @Override + public Criterion isNull(PropertyIsNullType op, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + String field = (String) op.getPropertyName().getContent().get(0); + return Restrictions.isNull(bag.filterField(field)); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#between(com.raytheon.uf. - * edex.filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, - * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) - */ - @Override - public Criterion between(ExpressionProcessor lower, - ExpressionProcessor exp, - ExpressionProcessor upper, Object obj) throws Exception { - VisitorBag bag = (VisitorBag) obj; + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#between(com.raytheon.uf. + * edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, + * com.raytheon.uf.edex.filter.ExpressionProcessor, java.lang.Object) + */ + @Override + public Criterion between(ExpressionProcessor lower, + ExpressionProcessor exp, ExpressionProcessor upper, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; - Entry lowerPart = getBinaryProps(exp, lower, bag); - Entry upperPart = getBinaryProps(exp, upper, bag); + Entry lowerPart = getBinaryProps(exp, lower, bag); + Entry upperPart = getBinaryProps(exp, upper, bag); - return Restrictions.between(lowerPart.getKey(), lowerPart.getValue(), - upperPart.getValue()); - } + return Restrictions.between(lowerPart.getKey(), lowerPart.getValue(), + upperPart.getValue()); + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#and(java.util.List, - * java.lang.Object) - */ - @Override - public Criterion and(List filters, Object obj) - throws Exception { - Conjunction rval = Restrictions.conjunction(); - acceptAll(filters, obj, rval); - return rval; - } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#and(java.util.List, + * java.lang.Object) + */ + @Override + public Criterion and(List filters, Object obj) + throws Exception { + Conjunction rval = Restrictions.conjunction(); + acceptAll(filters, obj, rval); + return rval; + } - protected void acceptAll(List filters, Object obj, - Junction junc) throws Exception { - Iterator i = filters.iterator(); - while (i.hasNext()) { - junc.add((Criterion) i.next().accept(this, obj)); - } - } + protected void acceptAll(List filters, Object obj, + Junction junc) throws Exception { + Iterator i = filters.iterator(); + while (i.hasNext()) { + junc.add((Criterion) i.next().accept(this, obj)); + } + } - protected List addAll(List l1, List l2) { - if (l1 == null) { - return l2; - } - if (l2 == null) { - return l1; - } - ArrayList rval = new ArrayList(l1.size() + l2.size()); - rval.addAll(l1); - rval.addAll(l2); - return rval; - } + protected List addAll(List l1, List l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + ArrayList rval = new ArrayList(l1.size() + l2.size()); + rval.addAll(l1); + rval.addAll(l2); + return rval; + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#or(java.util.List, - * java.lang.Object) - */ - @Override - public Criterion or(List filters, Object obj) - throws Exception { - Disjunction rval = Restrictions.disjunction(); - acceptAll(filters, obj, rval); - return rval; - } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.filter.OgcFilterVisitor#or(java.util.List, + * java.lang.Object) + */ + @Override + public Criterion or(List filters, Object obj) + throws Exception { + Disjunction rval = Restrictions.disjunction(); + acceptAll(filters, obj, rval); + return rval; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#not(com.raytheon.uf.edex - * .filter.FilterProcessor, java.lang.Object) - */ - @Override - public Criterion not(FilterProcessor filter, Object obj) throws Exception { - return Restrictions.not((Criterion) filter.accept(this, obj)); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#not(com.raytheon.uf.edex + * .filter.FilterProcessor, java.lang.Object) + */ + @Override + public Criterion not(FilterProcessor filter, Object obj) throws Exception { + return Restrictions.not((Criterion) filter.accept(this, obj)); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#spatialEquals(net.opengis - * .filter.v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion spatialEquals(BinarySpatialOpType op, Object obj) - throws Exception { - VisitorBag bag = (VisitorBag) obj; - Entry e = getBinarySpatial(op, bag); - return SpatialRestrictions.eq(bag.filterField(e.getKey()), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#spatialEquals(net.opengis + * .filter.v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion spatialEquals(BinarySpatialOpType op, Object obj) + throws Exception { + VisitorBag bag = (VisitorBag) obj; + Entry e = getBinarySpatial(op, bag); + return SpatialRestrictions + .eq(bag.filterField(e.getKey()), e.getValue()); + } + protected Entry getBinarySpatial( + BinarySpatialOpType binary, VisitorBag bag) throws Exception { + List lst = binary.getPropertyName().getContent(); + String str = getStringWarn(lst, "Unsupported property name type"); + String prop = StringUtils.join(parseProp(str), '.'); + Geometry shape = getGeometry(binary); + return new SimpleEntry(bag.filterField(prop), shape); + } - protected Entry getBinarySpatial( - BinarySpatialOpType binary, VisitorBag bag) throws Exception { - List lst = binary.getPropertyName().getContent(); - String str = getStringWarn(lst, "Unsupported property name type"); - String prop = StringUtils.join(parseProp(str), '.'); - Geometry shape = getGeometry(binary); - return new SimpleEntry(bag.filterField(prop), shape); - } + protected Geometry getGeometry(BinarySpatialOpType binary) throws Exception { + JAXBElement env = binary.getEnvelope(); + JAXBElement geom = binary.getGeometry(); + Geometry shape; + if (env != null && !env.isNil()) { + Envelope envelope = envConverter.convert(env.getValue()); + shape = geomConverter.convert(envelope); + } else if (geom != null && !geom.isNil()) { + shape = geomConverter.convert(geom.getValue()); + } else { + throw new Exception("Unsupported geometry format"); + } + return shape; + } - protected Geometry getGeometry(BinarySpatialOpType binary) throws Exception { - JAXBElement env = binary.getEnvelope(); - JAXBElement geom = binary.getGeometry(); - Geometry shape; - if (env != null && !env.isNil()) { - Envelope envelope = envConverter.convert(env.getValue()); - shape = geomConverter.convert(envelope); - } else if (geom != null && !geom.isNil()) { - shape = geomConverter.convert(geom.getValue()); - } else { - throw new Exception("Unsupported geometry format"); - } - return shape; - } + protected String getStringWarn(List lst, String msg) { + if (lst.size() != 1) { + log.warn(msg); + } + return (String) lst.get(0); + } - protected String getStringWarn(List lst, String msg) { - if (lst.size() != 1) { - log.warn(msg); - } - return (String) lst.get(0); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#disjoint(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion disjoint(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.disjoint(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#disjoint(net.opengis.filter - * .v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion disjoint(BinarySpatialOpType op, Object obj) - throws Exception { - Entry e = getBinarySpatial(op, (VisitorBag) obj); - return SpatialRestrictions.disjoint(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#touches(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion touches(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.touches(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#touches(net.opengis.filter - * .v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion touches(BinarySpatialOpType op, Object obj) - throws Exception { - Entry e = getBinarySpatial(op, (VisitorBag) obj); - return SpatialRestrictions.touches(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#within(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion within(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.within(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#within(net.opengis.filter - * .v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion within(BinarySpatialOpType op, Object obj) - throws Exception { - Entry e = getBinarySpatial(op, (VisitorBag) obj); - return SpatialRestrictions.within(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#overlaps(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion overlaps(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.overlaps(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#overlaps(net.opengis.filter - * .v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion overlaps(BinarySpatialOpType op, Object obj) - throws Exception { - Entry e = getBinarySpatial(op, (VisitorBag) obj); - return SpatialRestrictions.overlaps(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#crosses(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion crosses(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.crosses(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#crosses(net.opengis.filter - * .v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion crosses(BinarySpatialOpType op, Object obj) - throws Exception { - Entry e = getBinarySpatial(op, (VisitorBag) obj); - return SpatialRestrictions.crosses(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#intersects(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion intersects(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.intersects(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#intersects(net.opengis.filter - * .v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion intersects(BinarySpatialOpType op, Object obj) - throws Exception { - Entry e = getBinarySpatial(op, (VisitorBag) obj); - return SpatialRestrictions.intersects(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#contains(net.opengis.filter + * .v_1_1_0.BinarySpatialOpType, java.lang.Object) + */ + @Override + public Criterion contains(BinarySpatialOpType op, Object obj) + throws Exception { + Entry e = getBinarySpatial(op, (VisitorBag) obj); + return SpatialRestrictions.contains(e.getKey(), e.getValue()); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#contains(net.opengis.filter - * .v_1_1_0.BinarySpatialOpType, java.lang.Object) - */ - @Override - public Criterion contains(BinarySpatialOpType op, Object obj) - throws Exception { - Entry e = getBinarySpatial(op, (VisitorBag) obj); - return SpatialRestrictions.contains(e.getKey(), e.getValue()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#dWithin(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public Object dWithin(DistanceBufferType op, Object obj) throws Exception { + throw new Exception("dWithin queries not supported"); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#dWithin(net.opengis.filter - * .v_1_1_0.DistanceBufferType, java.lang.Object) - */ - @Override - public Object dWithin(DistanceBufferType op, Object obj) - throws Exception { - throw new Exception("dWithin queries not supported"); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#beyond(net.opengis.filter + * .v_1_1_0.DistanceBufferType, java.lang.Object) + */ + @Override + public Object beyond(DistanceBufferType op, Object obj) throws Exception { + throw new Exception("Beyond queries not supported"); + } - // public RangeParameter getDistance(DistanceBufferType dist, RangeOperand - // op, - // VisitorBag bag) throws Exception { - // List lst = dist.getPropertyName().getContent(); - // String str = getStringWarn(lst, "Unsupported property name type"); - // String prop = StringUtils.join(parseProp(str), '.'); - // AbstractGeometryType geom = dist.getGeometry().getValue(); - // Geometry res = geomConverter.convert(geom); - // if (!(res instanceof Point)) { - // throw new Exception("Unsupported distance geometry" - // + res.getClass()); - // } - // double distance = 0;// FIXME jaxb classes do not contain distance value - // RangeParameter param = new RangeParameter(prop, (Point) res, distance, - // op); - // throw new Exception("Distance types not supported"); - // // return rval; - // } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#beyond(net.opengis.filter - * .v_1_1_0.DistanceBufferType, java.lang.Object) - */ - @Override - public Object beyond(DistanceBufferType op, Object obj) - throws Exception { - throw new Exception("Beyond queries not supported"); - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.filter.OgcFilterVisitor#bbox(net.opengis.filter. - * v_1_1_0.BBOXType, java.lang.Object) - */ - @Override - public Criterion bbox(BBOXType op, Object obj) throws Exception { - VisitorBag bag = (VisitorBag) obj; - List lst = op.getPropertyName().getContent(); - String str = getStringWarn(lst, "Unsupported property name type"); - String prop = StringUtils.join(parseProp(str), '.'); - EnvelopeType value = op.getEnvelope().getValue(); - Envelope env = envConverter.convert(value); - return SpatialRestrictions.within(bag.filterField(prop), - JTS.toGeometry(env)); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.filter.OgcFilterVisitor#bbox(net.opengis.filter. + * v_1_1_0.BBOXType, java.lang.Object) + */ + @Override + public Criterion bbox(BBOXType op, Object obj) throws Exception { + VisitorBag bag = (VisitorBag) obj; + List lst = op.getPropertyName().getContent(); + String str = getStringWarn(lst, "Unsupported property name type"); + String prop = StringUtils.join(parseProp(str), '.'); + EnvelopeType value = op.getEnvelope().getValue(); + Envelope env = envConverter.convert(value); + return SpatialRestrictions.within(bag.filterField(prop), + JTS.toGeometry(env)); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/SqlQueryParts.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/SqlQueryParts.java index 28ec6a3952..d094667d4e 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/SqlQueryParts.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/SqlQueryParts.java @@ -1,3 +1,13 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + package com.raytheon.uf.edex.wfs.provider; public class SqlQueryParts { diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Transactor.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Transactor.java index 66d49ff9fd..b7464bd287 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Transactor.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/Transactor.java @@ -70,12 +70,12 @@ public class Transactor { TransactionResultsType rval = new TransactionResultsType(); switch (request.getTransType()) { case Native: - String[] parts = request.getParameter().replaceAll("\\w+:", "") - .split("/"); - String param = (parts.length > 1 ? parts[1] : parts[0]); - for (int i = 2; i < parts.length; ++i) { - param += "." + parts[i]; - } + // String[] parts = request.getParameter().replaceAll("\\w+:", "") + // .split("/"); + // String param = (parts.length > 1 ? parts[1] : parts[0]); + // for (int i = 2; i < parts.length; ++i) { + // param += "." + parts[i]; + // } // String plugname = featureManager.getFeaturePlugName(parts[0]); // MorphiaStrategy strat = new MorphiaStrategy(); // try { @@ -88,6 +88,8 @@ public class Transactor { // } catch (PluginException e) { // log.error("Problem querying for plugin: " + plugname, e); // } + default: + break; } return rval; } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/VisitorBag.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/VisitorBag.java index b7bdad56cb..06dd5144bf 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/VisitorBag.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/VisitorBag.java @@ -44,18 +44,24 @@ public class VisitorBag { protected String spatialField; + protected String verticalField; + protected Map fieldMap; + protected String idField; + /** * @param converter * @param rootEntity * @param spatialField */ - public VisitorBag(Class rootEntity, - String spatialField) { + public VisitorBag(Class rootEntity, String spatialField, + String verticalField, String idField) { super(); this.rootEntity = rootEntity; this.spatialField = spatialField; + this.verticalField = verticalField; + this.idField = idField; } public String filterField(String field) { @@ -90,4 +96,34 @@ public class VisitorBag { this.fieldMap = fieldMap; } + /** + * @return the idField + */ + public String getIdField() { + return idField; + } + + /** + * @param idField + * the idField to set + */ + public void setIdField(String idField) { + this.idField = idField; + } + + /** + * @return the verticalField + */ + public String getVerticalField() { + return verticalField; + } + + /** + * @param verticalField + * the verticalField to set + */ + public void setVerticalField(String verticalField) { + this.verticalField = verticalField; + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/FileSystemQueryStore.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/FileSystemQueryStore.java new file mode 100644 index 0000000000..636e2b3188 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/FileSystemQueryStore.java @@ -0,0 +1,169 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.querystore; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; + +import net.opengis.wfs.v_2_0_0.CreateStoredQueryType; +import net.opengis.wfs.v_2_0_0.ObjectFactory; +import net.opengis.wfs.v_2_0_0.QueryType; +import net.opengis.wfs.v_2_0_0.StoredQueryDescriptionType; + +import com.raytheon.uf.edex.ogc.common.AbstractFSQueryStore; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; + +/** + * Caching File System query store implementation + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 17, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class FileSystemQueryStore extends + AbstractFSQueryStore implements IQueryStore { + + private static final String STORE_NAME = "wfsquerystore"; + + protected final WfsRegistryImpl registry; + + protected final StoredQueryResolver resolver; + + private static final ObjectFactory wfsFactory = new ObjectFactory(); + + /** + * @param registry + * @param storeLocation + * @throws IllegalArgumentException + * if storage location cannot be created or is not a writable + * directory + */ + public FileSystemQueryStore(WfsRegistryImpl registry, File storeLocation) + throws IllegalArgumentException { + super(storeLocation); + this.registry = registry; + this.resolver = new StoredQueryResolver(registry); + } + + /** + * Create a store in a directory named storeName in the default location + * + * @param registry + * @param storeName + * @throws IllegalArgumentException + */ + public FileSystemQueryStore(WfsRegistryImpl registry, String storeName) + throws IllegalArgumentException { + this(registry, findStore(storeName)); + } + + /** + * @param registry + */ + public FileSystemQueryStore(WfsRegistryImpl registry) { + this(registry, STORE_NAME); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.querystore.QueryStore#resolve(java.lang.String, + * java.util.Map) + */ + public List resolve(String id, Map parameters) + throws OgcException { + String desc = retrieveString(id); + if (desc == null) { + return new ArrayList(0); + } + return resolver.resolve(desc, parameters); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.querystore.QueryStore#getResolver() + */ + @Override + public StoredQueryResolver getResolver() { + return resolver; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.AbstractFSQueryStore#marshal(java.lang + * .Object) + */ + @Override + protected String marshal(StoredQueryDescriptionType query) + throws OgcException { + CreateStoredQueryType holder = new CreateStoredQueryType(); + holder.setStoredQueryDefinition(Arrays.asList(query)); + JAXBElement elem = wfsFactory + .createCreateStoredQuery(holder); + try { + return registry.marshal(elem); + } catch (JAXBException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.querystore.QueryStore#store(net.opengis.wfs. + * v_2_0_0.StoredQueryDescriptionType) + */ + @Override + public void store(StoredQueryDescriptionType query) throws OgcException { + store(query.getId(), query); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.AbstractFSQueryStore#unmarshal(java.lang + * .String) + */ + @Override + protected StoredQueryDescriptionType unmarshal(String xml) + throws OgcException { + try { + CreateStoredQueryType holder = (CreateStoredQueryType) registry + .unmarshal(xml); + return holder.getStoredQueryDefinition().get(0); + } catch (JAXBException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/IQueryStore.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/IQueryStore.java new file mode 100644 index 0000000000..c612207191 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/IQueryStore.java @@ -0,0 +1,95 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.wfs.querystore; + +import java.util.List; +import java.util.Map; + +import net.opengis.wfs.v_2_0_0.QueryType; +import net.opengis.wfs.v_2_0_0.StoredQueryDescriptionType; + +import com.raytheon.uf.edex.ogc.common.OgcException; + +/** + * interface for parameterized query storage + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 17, 2012            bclement     Initial creation
+ * Aug 18, 2013  #2097     dhladky      renamed for standards
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface IQueryStore { + + /** + * @param query + * @throws Exception + */ + public void store(StoredQueryDescriptionType query) throws OgcException; + + /** + * @param id + * @return null if no stored query matches id + * @throws Exception + */ + public StoredQueryDescriptionType retrieve(String id) throws OgcException; + + /** + * Remove stored query. Does nothing if no query matches id + * + * @param id + * @throws Exception + */ + public void remove(String id) throws OgcException; + + /** + * List all IDs of stored queries + * + * @return empty list if no queries are found + * @throws Exception + */ + public List list() throws OgcException; + + /** + * Retrieve and resolve stored query + * + * @param id + * @param jaxbParameters + * map of parameter names to values + * @return + * @throws Exception + */ + public List resolve(String id, Map parameters) + throws OgcException; + + /** + * @return internal resolver for store + */ + public StoredQueryResolver getResolver(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerHolder.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/IStoredQueryCallback.java similarity index 55% rename from edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerHolder.java rename to edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/IStoredQueryCallback.java index dd3354b20d..a27b02e0fe 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/db/LayerHolder.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/IStoredQueryCallback.java @@ -17,40 +17,35 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.edex.ogc.common.db; +package com.raytheon.uf.edex.wfs.querystore; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; - /** +import net.opengis.wfs.v_2_0_0.StoredQueryType; + +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.request.FeatureQuery; + +/** + * Store a Query callback interface + * + *
  *
  * SOFTWARE HISTORY
  *
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Mar 29, 2011            bclement     Initial creation
+ * May 8, 2013            bclement     Initial creation
+ * Aug 18, 2013  #2097     dhladky      renamed for standards
  *
-**/
-@XmlRootElement
-@XmlAccessorType(XmlAccessType.NONE)
-public class LayerHolder {
-	@XmlElement
-	protected L value;
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface IStoredQueryCallback { - @SuppressWarnings("unchecked") - public static Class> getDefaultClass() { - return (Class>) new LayerHolder() - .getClass(); - } - - public L getValue() { - return value; - } - - public void setValue(L value) { - this.value = value; - } + public List getQueries(StoredQueryType sqt) + throws WfsException; } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/StoredQueryResolver.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/StoredQueryResolver.java new file mode 100644 index 0000000000..ef27d09834 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/querystore/StoredQueryResolver.java @@ -0,0 +1,399 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.querystore; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import net.opengis.wfs.v_2_0_0.CreateStoredQueryType; +import net.opengis.wfs.v_2_0_0.GetFeatureType; +import net.opengis.wfs.v_2_0_0.ObjectFactory; +import net.opengis.wfs.v_2_0_0.ParameterExpressionType; +import net.opengis.wfs.v_2_0_0.QueryExpressionTextType; +import net.opengis.wfs.v_2_0_0.QueryType; +import net.opengis.wfs.v_2_0_0.StoredQueryDescriptionType; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; +import com.raytheon.uf.edex.ogc.common.OgcNamespace; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; + +/** + * Convert stored queries to get feature requests + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 18, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class StoredQueryResolver { + + protected final WfsRegistryImpl registry; + + protected static final ObjectFactory wfsFactory = new ObjectFactory(); + + protected static final net.opengis.filter.v_2_0_0.ObjectFactory filtFactory = new net.opengis.filter.v_2_0_0.ObjectFactory(); + + protected final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + public static class ParameterNode { + public String name; + + public QName type; + + public Node node; + + public ParameterNode(String name, QName type, Node node) { + this.name = name; + this.type = type; + this.node = node; + } + } + + public StoredQueryResolver(WfsRegistryImpl registry) { + this.registry = registry; + } + + /** + * Merge parameters with stored query packaged in CreateStoredQuery xml + * document + * + * @param createStoredQueryStr + * @param parameters + * map of parameter name to xml string that replaces that name in + * the stored query + * @return + * @throws Exception + */ + public List resolve(String createStoredQueryStr, + Map parameters) throws OgcException { + String resolved = replaceAll(createStoredQueryStr, parameters); + try { + CreateStoredQueryType holder = (CreateStoredQueryType) registry + .unmarshal(resolved); + StoredQueryDescriptionType desc = holder.getStoredQueryDefinition() + .get(0); + return resolve(desc, parameters); + } catch (JAXBException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + + /** + * @param desc + * @param parameters + * @return + * @throws Exception + */ + public List resolve(StoredQueryDescriptionType desc, + Map parameters) throws OgcException { + List rval = new ArrayList(); + List texts = desc.getQueryExpressionText(); + for (QueryExpressionTextType text : texts) { + List content = text.getContent(); + for (Object obj : content) { + if (obj instanceof Node) { + try { + obj = registry.unmarshal((Node) obj); + } catch (JAXBException e) { + throw new OgcException(Code.InternalServerError, e); + } + } + if (obj instanceof JAXBElement) { + obj = ((JAXBElement) obj).getValue(); + } + if (obj instanceof QueryType) { + rval.add((QueryType) obj); + } else { + log.error("Unsupported query type: " + obj.getClass()); + } + } + } + return rval; + } + + /** + * Merge parameters with stored query packaged in CreateStoredQuery xml + * document + * + * @param createStoredQueryStr + * @param parameters + * map of parameter name to xml string that replaces that name in + * the stored query + * @return + */ + private String replaceAll(String createStoredQueryStr, + Map parameters){ + StringBuilder rval = new StringBuilder(createStoredQueryStr); + int index = 0; + while (true) { + index = rval.indexOf("${", index); + if (index == -1) { + break; + } + int end = rval.indexOf("}", index); + if (end == -1) { + break; + } + int nextOpen = rval.indexOf("${", index + 2); + if (nextOpen > 0 && end > nextOpen) { + index = index + 2; + continue; + } + String key = rval.substring(index + 2, end); + String value = parameters.get(key); + if (value != null) { + rval.replace(index, end + 1, value); + index = index + value.length(); + } else { + index = end + 1; + } + } + return rval.toString(); + } + + /** + * Create a template Node for stored query that is Filter 2.0 value + * referenced operator. + * + * @param operator + * name of Filter 2.0 operator + * @param valueRef + * feature field being referenced by operator + * @param parameter + * template placeholder for operand that will be replaced when + * stored query is resolved + * @return + * @throws ParserConfigurationException + */ + public Node createReferenceOpNode(String operator, String valueRef, + String parameter) throws ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + Element opNode = doc.createElementNS(OgcNamespace.FES20, "fes:" + + operator); + Element valRefNode = doc.createElementNS(OgcNamespace.FES20, + "fes:ValueReference"); + Text refText = doc.createTextNode(valueRef); + valRefNode.appendChild(refText); + opNode.appendChild(valRefNode); + Text paramNode = doc.createTextNode("${" + parameter + "}"); + opNode.appendChild(paramNode); + return opNode; + } + + /** + * Add parameters to stored query description filters. The parameters will + * be in a logical 'and' with each of the query's top level filter elements + * + * @param desc + * @param parameters + * @return + * @throws JAXBException + * @throws ParserConfigurationException + */ + public StoredQueryDescriptionType addAndParams( + StoredQueryDescriptionType desc, List parameters) + throws JAXBException, ParserConfigurationException { + List pexprs = desc.getParameter(); + List texts = desc.getQueryExpressionText(); + for (ParameterNode param : parameters) { + pexprs.add(createParamExpr(param.name, param.type)); + for (QueryExpressionTextType text : texts) { + addAndParam(text, param); + } + } + return desc; + } + + /** + * Add parameter to stored query expression text filters. The parameter will + * be in a logical 'and' with each of the query's top level filter elements + * + * @param text + * @param param + * @throws JAXBException + * @throws ParserConfigurationException + */ + public void addAndParam(QueryExpressionTextType text, ParameterNode param) + throws JAXBException, ParserConfigurationException { + List content = text.getContent(); + List newContents = new ArrayList(content.size()); + for (Object obj : content) { + if (obj instanceof JAXBElement) { + obj = ((JAXBElement) obj).getValue(); + } + if (obj instanceof QueryType) { + newContents.add(addAnd((QueryType) obj, param)); + } else if (obj instanceof Element) { + Element elem = (Element) obj; + newContents.addAll(addAndToElement(elem, param)); + } + } + text.unsetContent(); + text.setContent(newContents); + } + + /** + * @param elem + * @param param + * @return + * @throws ParserConfigurationException + */ + private List addAndToElement(Element elem, ParameterNode param) + throws ParserConfigurationException { + List rval = new ArrayList(); + String name = elem.getLocalName(); + if (name.equalsIgnoreCase("Query")) { + rval.add(addAnd(elem, param)); + } + return rval; + } + + /** + * Add parameter to stored query filters. The parameter will be in a logical + * 'and' with each of the query's top level filter elements + * + * @param qt + * @param param + * @return + * @throws JAXBException + * @throws ParserConfigurationException + */ + protected Object addAnd(QueryType qt, ParameterNode param) + throws JAXBException, + ParserConfigurationException { + Element qe = (Element) registry.marshalToNode(wfsFactory + .createQuery(qt)); + return addAnd(qe, param); + } + + /** + * Add parameter to stored query filters. The parameter will be in a logical + * 'and' with each of the query's top level filter elements + * + * @param queryElement + * Query node + * @param param + * @return + * @throws ParserConfigurationException + */ + protected Object addAnd(Element queryElement, ParameterNode param) + throws ParserConfigurationException { + Node clonedQuery = queryElement.cloneNode(false); + NodeList filters = queryElement.getElementsByTagNameNS( + OgcNamespace.FES20, "Filter"); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + Node importedClonedQuery = doc.importNode(clonedQuery, true); + if (filters.getLength() == 0) { + // no existing filter, skip creating 'and', just add parameter + Element filter = doc.createElementNS(OgcNamespace.FES20, + "fes:Filter"); + Node paramNode = doc.importNode(param.node, true); + filter.appendChild(paramNode); + importedClonedQuery.appendChild(filter); + return importedClonedQuery; + } + Node filter = filters.item(0); + Node clonedFilter = filter.cloneNode(false); + Node importedClonedFilter = doc.importNode(clonedFilter, true); + importedClonedQuery.appendChild(importedClonedFilter); + Element andElem = doc.createElementNS(OgcNamespace.FES20, "fes:And"); + importedClonedFilter.appendChild(andElem); + Node paramNode = doc.importNode(param.node, true); + andElem.appendChild(paramNode); + for (Node child = filter.getFirstChild(); child != null; child = child + .getNextSibling()) { + Node importNode = doc.importNode(child, true); + andElem.appendChild(importNode); + } + return importedClonedQuery; + } + + /** + * Create a new parameter expression type + * + * @param name + * @param type + * @return + */ + protected ParameterExpressionType createParamExpr(String name, + QName type) { + ParameterExpressionType rval = new ParameterExpressionType(); + rval.setName(name); + rval.setType(type); + return rval; + } + + /** + * Convert jaxb get feature request to stored query description object + * + * @param id + * @param featureRequest + * @return + */ + public StoredQueryDescriptionType convert(String id, + GetFeatureType featureRequest) { + StoredQueryDescriptionType desc = new StoredQueryDescriptionType(); + desc.setId(id); + QueryExpressionTextType textType = new QueryExpressionTextType(); + List> expElems = featureRequest + .getAbstractQueryExpression(); + List queries = extract(expElems); + textType.setContent(queries); + desc.setQueryExpressionText(Arrays.asList(textType)); + return desc; + } + + /** + * Extract jaxb element values to list + * + * @param expElems + * @return + */ + private List extract(List> expElems) { + ArrayList rval = new ArrayList(expElems.size()); + for (JAXBElement elem : expElems) { + rval.add(elem); + } + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/AbstractWfsSource.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/AbstractWfsSource.java index 03322fed61..7b9334778f 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/AbstractWfsSource.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/AbstractWfsSource.java @@ -47,6 +47,7 @@ import org.hibernate.criterion.Restrictions; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.database.dao.CoreDao; +import com.raytheon.uf.edex.ogc.common.AbstractOgcSource; import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; import com.raytheon.uf.edex.ogc.common.OgcTimeRange; import com.raytheon.uf.edex.wfs.WfsException; @@ -56,26 +57,34 @@ import com.raytheon.uf.edex.wfs.request.QualifiedName; import com.raytheon.uf.edex.wfs.request.SortBy; /** + * Abstract base class for WFS sources * * @author bclement * @version 1.0 */ -public abstract class AbstractWfsSource implements WfsSource { +public abstract class AbstractWfsSource extends AbstractOgcSource implements + IWfsSource { - protected String key; + protected final String key; - protected static String defaultCRS = "crs:84"; + public static final String defaultCRS = "crs:84"; - protected static OgcGeoBoundingBox fullBbox = new OgcGeoBoundingBox(180, + public static final OgcGeoBoundingBox fullBbox = new OgcGeoBoundingBox(180, -180, 90, -90); protected abstract CoreDao getDao() throws Exception; protected static final String temporalKey = "dataTime.refTime"; - - private static final IUFStatusHandler statusHandler = UFStatus + + protected static final IUFStatusHandler statusHandler = UFStatus .getHandler(AbstractWfsSource.class); + protected IFeatureTypeModifier typeModifier = null; + + /** + * @param key + * unique key for this source + */ public AbstractWfsSource(String key) { this.key = key; } @@ -86,7 +95,15 @@ public abstract class AbstractWfsSource implements WfsSource { * @see com.raytheon.uf.edex.wfs.reg.WfsSource#listFeatureTypes() */ @Override - public abstract List listFeatureTypes(); + public List listFeatureTypes() { + List featureTypes = getFeatureTypes(); + if (this.typeModifier == null) { + return featureTypes; + } + return this.typeModifier.modify(featureTypes); + } + + protected abstract List getFeatureTypes(); /* * (non-Javadoc) @@ -96,7 +113,8 @@ public abstract class AbstractWfsSource implements WfsSource { * .uf.edex.wfs.request.QualifiedName) */ @Override - public abstract String describeFeatureType(QualifiedName feature); + public abstract String describeFeatureType(QualifiedName feature) + throws WfsException; /** * Utility method for reading text files from the classpath @@ -123,11 +141,19 @@ public abstract class AbstractWfsSource implements WfsSource { return rval; } + /** + * Interacts with database to get features + * + * @param feature + * @param query + * @return + * @throws WfsException + */ protected List queryInternal(QualifiedName feature, WfsQuery query) throws WfsException { query = modQuery(query); List rval; - //TODO get rid of core DAO calls + // TODO get rid of core DAO calls Session sess = null; try { CoreDao dao = getDao(); @@ -144,7 +170,7 @@ public abstract class AbstractWfsSource implements WfsSource { } catch (Exception e) { statusHandler.error("Problem querying for feature", e); - throw new WfsException(Code.INTERNAL_SERVER_ERROR); + throw new WfsException(Code.OperationProcessingFailed); } finally { if (sess != null) { sess.close(); @@ -200,12 +226,17 @@ public abstract class AbstractWfsSource implements WfsSource { OgcTimeRange otr = query.timeRange; if (otr != null) { - crit.add(Restrictions.between(temporalKey, otr.getStartTime(), otr.getEndTime())); + crit.add(Restrictions.between(temporalKey, otr.getStartTime(), + otr.getEndTime())); } return crit; } + /** + * @param criteria + * @param sortBys + */ protected void addOrder(Criteria criteria, List sortBys) { if (sortBys == null || sortBys.isEmpty()) { return; @@ -224,6 +255,10 @@ public abstract class AbstractWfsSource implements WfsSource { } } + /** + * @param criteria + * @param query + */ protected void populateCriteria(Criteria criteria, WfsQuery query) { query = modQuery(query); Criterion criterion = query.getCriterion(); @@ -293,7 +328,7 @@ public abstract class AbstractWfsSource implements WfsSource { } } catch (Exception e) { statusHandler.error("Unable to get count!", e); - throw new WfsException(Code.INTERNAL_SERVER_ERROR); + throw new WfsException(Code.OperationProcessingFailed); } finally { if (sess != null) { sess.close(); @@ -320,9 +355,29 @@ public abstract class AbstractWfsSource implements WfsSource { @Override public abstract Class[] getJaxbClasses(); + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.WfsSource#getFieldMap() + */ @Override public Map getFieldMap() { return null; } + /** + * @return the typeModifier + */ + public IFeatureTypeModifier getTypeModifier() { + return typeModifier; + } + + /** + * @param typeModifier + * the typeModifier to set + */ + public void setTypeModifier(IFeatureTypeModifier typeModifier) { + this.typeModifier = typeModifier; + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/DefaultWfsSource.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/DefaultWfsSource.java deleted file mode 100644 index 1be1660d59..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/DefaultWfsSource.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * Jul 26, 2011 bclement Initial creation - * - */ -package com.raytheon.uf.edex.wfs.reg; - -import java.util.List; - -import javax.xml.bind.JAXBElement; - -import net.opengis.gml.v_3_1_1.AbstractFeatureType; - -import org.opengis.feature.simple.SimpleFeature; - -import com.raytheon.uf.common.datadelivery.harvester.ConfigLayer; -import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfig; -import com.raytheon.uf.common.datadelivery.harvester.HarvesterConfigurationManager; -import com.raytheon.uf.common.datadelivery.harvester.OGCAgent; -import com.raytheon.uf.common.dataplugin.PluginDataObject; -import com.raytheon.uf.common.dataplugin.PluginException; -import com.raytheon.uf.common.dataplugin.PluginProperties; -import com.raytheon.uf.common.status.IUFStatusHandler; -import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; -import com.raytheon.uf.edex.database.dao.CoreDao; -import com.raytheon.uf.edex.database.plugin.PluginFactory; -import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; -import com.raytheon.uf.edex.ogc.common.feature.FeatureFactory; -import com.raytheon.uf.edex.wfs.WfsException; -import com.raytheon.uf.edex.wfs.WfsException.Code; -import com.raytheon.uf.edex.wfs.request.QualifiedName; - - -/** - * - * Default WFS Source - * - *
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * 04/22/2013   1746       dhladky      initial creation, based on B Clements original
- * 
- * - * @author dhladky - * @version 1.0 - */ - - -public abstract class DefaultWfsSource extends - AbstractWfsSource { - - protected CoreDao _dao; - - protected PluginProperties props; - - protected WfsTranslator translator; - - protected FeatureFactory featFactory; - - protected HarvesterConfig config = null; - - protected ConfigLayer layer = null; - - private static final IUFStatusHandler statusHandler = UFStatus - .getHandler(DefaultWfsSource.class); - - - public DefaultWfsSource(PluginProperties props, String key, - WfsTranslator translator, FeatureFactory featFactory) { - super(key); - this.props = props; - this.translator = translator; - this.featFactory = featFactory; - this.config = HarvesterConfigurationManager.getOGCConfiguration(); - } - - @Override - protected CoreDao getDao() throws PluginException { - if (_dao == null) { - _dao = PluginFactory.getInstance().getPluginDao( - props.getPluginName()); - } - return _dao; - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wfs.reg.WfsSource#query(com.raytheon.uf.edex.wfs - * .request.QualifiedName, com.raytheon.uf.edex.db.api.DatabaseQuery) - */ - @Override - public List> query( - QualifiedName feature, WfsQuery query) throws WfsException { - List pdos = queryInternal(feature, query); - PluginDataObject[] arr = pdos - .toArray(new PluginDataObject[pdos.size()]); - try { - return translator.translate(arr); - } catch (Exception e) { - statusHandler.handle(Priority.ERROR, "Problem translating pdos to jaxb features", e); - throw new WfsException(Code.INTERNAL_SERVER_ERROR); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wfs.reg.WfsSource#querySimple(com.raytheon.uf.edex - * .wfs.request.QualifiedName, com.raytheon.uf.edex.wfs.reg.WfsQuery) - */ - @Override - public List querySimple(QualifiedName feature, WfsQuery q) - throws WfsException { - List pdos = queryInternal(feature, q); - PluginDataObject[] arr = pdos - .toArray(new PluginDataObject[pdos.size()]); - return featFactory.convert(arr); - } - - /** - * Get the configuration for the layer (feature) - * - * @param name - * @return - */ - public ConfigLayer getConfigLayer(String name) { - ConfigLayer layer = null; - if (config.getAgent() != null) { - if (config.getAgent() instanceof OGCAgent) { - layer = ((OGCAgent) config.getAgent()).getLayer(name); - } - } - return layer; - } - - /** - * Gets the configured bounded box - * - * @param layer - * @return - */ - public OgcGeoBoundingBox getBoundingBox(String name) { - - OgcGeoBoundingBox bbox = null; - - try { - ConfigLayer layer = getConfigLayer(name); - double upperLeftLon = layer.getMinx(); - double lowerRightLon = layer.getMaxx(); - double upperLeftLat = layer.getMaxy(); - double lowerRightLat = layer.getMiny(); - bbox = new OgcGeoBoundingBox(lowerRightLon, upperLeftLon, - upperLeftLat, lowerRightLat); - - } catch (Exception e) { - statusHandler.handle(Priority.ERROR, "Couldn't create Bounding Box for feature: "+name+", Using default"); - bbox = fullBbox; - } - - return bbox; - } - - /** - * Override this if you want a different CRS from you config - * @param name - * @return - */ - public String getCRS(String name) { - - String crs = null; - - try { - ConfigLayer layer = getConfigLayer(name); - crs = layer.getCrs(); - } catch (Exception e) { - statusHandler.handle(Priority.ERROR, "Couldn't retrieve CRS for feature: "+name+", Using default"); - crs = defaultCRS; - } - - return crs; - } - -} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IFeatureTypeModifier.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IFeatureTypeModifier.java new file mode 100644 index 0000000000..8bd9c24a8e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IFeatureTypeModifier.java @@ -0,0 +1,36 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.reg; + +import java.util.List; + +import com.raytheon.uf.edex.wfs.WfsFeatureType; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 26, 2013            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface IFeatureTypeModifier { + + public List modify(List list); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsTranslator.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IPdoGmlTranslator.java similarity index 83% rename from edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsTranslator.java rename to edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IPdoGmlTranslator.java index b5fe4dce67..0d32f49b0a 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsTranslator.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IPdoGmlTranslator.java @@ -30,12 +30,10 @@ */ package com.raytheon.uf.edex.wfs.reg; -import java.util.List; +import java.util.ArrayList; import javax.xml.bind.JAXBElement; -import net.opengis.gml.v_3_1_1.AbstractFeatureType; - import com.raytheon.uf.common.dataplugin.PluginDataObject; /** @@ -43,8 +41,11 @@ import com.raytheon.uf.common.dataplugin.PluginDataObject; * @author bclement * @version 1.0 */ -public interface WfsTranslator { +public interface IPdoGmlTranslator { + + public ArrayList> translate(PluginDataObject[] pdos) + throws Exception; + + public String getVersion(); - public List> translate( - PluginDataObject[] pdos) throws Exception; } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsRegistry.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsRegistry.java new file mode 100644 index 0000000000..596c31216c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsRegistry.java @@ -0,0 +1,51 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Aug 18, 2013 #2097 dhladky renamed for standards + * + */ +package com.raytheon.uf.edex.wfs.reg; + +import com.raytheon.uf.common.util.registry.RegistryException; + +/** + * @author bclement + * + */ +public interface IWfsRegistry { + + /** + * @param source + * @return + * @throws RegistryException + */ + IWfsRegistry register(IWfsSource source) throws RegistryException; + + /** + * @param source + * @return + */ + IWfsRegistry unregister(IWfsSource source); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsSource.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsSource.java new file mode 100644 index 0000000000..c8e1e2ad97 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsSource.java @@ -0,0 +1,140 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Aug 18, 2013 #2097 dhladky renamed for standards + */ +package com.raytheon.uf.edex.wfs.reg; + +import java.util.List; +import java.util.Map; + +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.request.QualifiedName; + +/** + * Source interface for WFS data adapters + * + * @author bclement + */ +public interface IWfsSource { + + /** + * @return list of all feature types provided by source + */ + public List listFeatureTypes(); + + /** + * @param feature + * name of feature to describe + * @return XSD describing feature + * @throws WfsException + */ + public String describeFeatureType(QualifiedName feature) + throws WfsException; + + /** + * @param feature + * @return field name of spatial geometry relative to root entity + */ + public String getFeatureSpatialField(QualifiedName feature); + + /** + * @param feature + * @return field name of vertical height relative to root entity or null for + * surface + */ + public String getFeatureVerticalField(QualifiedName feature); + + /** + * @param feature + * @return field name of unique ID field for feature + */ + public String getFeatureIdField(QualifiedName feature); + + /** + * @param feature + * @return root entity of feature record object + */ + public Class getFeatureEntity(QualifiedName feature); + + /** + * The XML schema returned from describe feature can be independent from the + * layout of the feature entity class. This method returns a mapping of + * dotted field paths in the XSD to dotted field paths in the feature + * entity. + * + * @return + */ + public Map getFieldMap(); + + /** + * Query for features + * + * @param feature + * @param q + * @param options + * @return + * @throws WfsException + */ + public WfsQueryResults query(QualifiedName feature, WfsQuery q, + WfsQueryOptions options) throws WfsException; + + /** + * Performs a distinct query for an entity field + * + * @param feature + * @param q + * @return + * @throws WfsException + */ + public List distinct(QualifiedName feature, WfsQuery q) + throws WfsException; + + /** + * @param feature + * @param q + * @return number of features that the query matches + * @throws WfsException + */ + public long count(QualifiedName feature, WfsQuery q) throws WfsException; + + /** + * @return unique key for this source + */ + public String getKey(); + + /** + * @return additional class for JAXB context + */ + public Class[] getJaxbClasses(); + + /** + * @param c + * extension class + * @return extension object for class, null if none registered + */ + public T getExtension(Class c); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsTranslator.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsTranslator.java new file mode 100644 index 0000000000..a773c8cfc9 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/IWfsTranslator.java @@ -0,0 +1,48 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Aug 18, 2013 #2097 dhladky renamed for standards + * Jul 26, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.reg; + +import java.util.List; + +import javax.xml.bind.JAXBElement; + +import net.opengis.gml.v_3_1_1.AbstractFeatureType; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; + +/** + * + * @author bclement + * @version 1.0 + */ +public interface IWfsTranslator { + + public List> translate( + PluginDataObject[] pdos) throws Exception; +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/PluginWfsSource.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/PluginWfsSource.java new file mode 100644 index 0000000000..1c89ecabf9 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/PluginWfsSource.java @@ -0,0 +1,224 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Jul 26, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.reg; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.dataplugin.PluginException; +import com.raytheon.uf.common.dataplugin.PluginProperties; +import com.raytheon.uf.edex.database.dao.CoreDao; +import com.raytheon.uf.edex.database.plugin.PluginFactory; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector; +import com.raytheon.uf.edex.ogc.common.feature.FeatureFactory; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsException.Code; +import com.raytheon.uf.edex.wfs.reg.WfsQueryResults.ResultType; +import com.raytheon.uf.edex.wfs.request.QualifiedName; + +/** + * Abstract implementation for sources backed by plugin data objects + * + * @author bclement + * @version 1.0 + */ +public abstract class PluginWfsSource extends + AbstractWfsSource { + + protected CoreDao _dao; + + protected PluginProperties props; + + protected Map translatorMap; + + protected FeatureFactory featFactory; + + protected final SingleLayerCollector, PluginDataObject> collector; + + /** + * @param props + * @param key + * unique key for this source + * @param translators + * @param featFactory + */ + public PluginWfsSource(PluginProperties props, String key, + List translators, FeatureFactory featFactory, + SingleLayerCollector, PluginDataObject> collector) { + super(key); + this.props = props; + this.translatorMap = new HashMap( + translators.size()); + for (IPdoGmlTranslator trans : translators) { + this.translatorMap.put(trans.getVersion(), trans); + } + this.featFactory = featFactory; + this.collector = collector; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.AbstractWfsSource#getDao() + */ + @Override + protected CoreDao getDao() throws PluginException { + if (_dao == null) { + _dao = PluginFactory.getInstance().getPluginDao( + props.getPluginName()); + } + return _dao; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsSource#query(com.raytheon.uf.edex.wfs + * .request.QualifiedName, com.raytheon.uf.edex.wfs.reg.WfsQuery, + * com.raytheon.uf.edex.wfs.reg.WfsQueryOptions) + */ + @Override + public WfsQueryResults query(QualifiedName feature, WfsQuery query, + WfsQueryOptions options) throws WfsException { + WfsQueryResults rval; + switch (options.getType()) { + case JAXB: + rval = jaxbQuery(feature, query, options); + break; + case SIMPLE: + rval = querySimple(feature, query, options); + break; + default: + statusHandler.error("Unsupported query results type: " + + options.getType()); + throw new WfsException(Code.OperationProcessingFailed); + } + return rval; + } + + /** + * @param feature + * @param query + * @param options + * @return + * @throws WfsException + */ + protected WfsQueryResults jaxbQuery(QualifiedName feature, WfsQuery query, + WfsQueryOptions options) throws WfsException { + String gmlVersion = options.getGmlVersion(); + IPdoGmlTranslator translator = translatorMap.get(gmlVersion); + if (translator == null) { + String msg = String.format( + "Feature type '%s' does not support GML version %s", + feature.getName(), gmlVersion); + throw new WfsException(Code.InvalidParameterValue, msg); + } + WfsQueryResults rval = new WfsQueryResults(ResultType.JAXB); + List pdos = queryInternal(feature, query); + PluginDataObject[] arr = extractData(pdos, rval, options); + try { + ArrayList> results = translator.translate(arr); + rval.setResults(results); + return rval; + } catch (Exception e) { + statusHandler.error("Problem translating pdos to jaxb features", e); + throw new WfsException(Code.OperationProcessingFailed); + } + } + + /** + * Convert pdo list to array and populate query results with metadata + * information + * + * @param pdos + * @param results + * @return + */ + protected PluginDataObject[] extractData( + List pdos, WfsQueryResults results, + WfsQueryOptions options) { + if (!options.gatherMetadata || pdos.isEmpty()) { + return pdos.toArray(new PluginDataObject[pdos.size()]); + } + PluginDataObject[] rval = new PluginDataObject[pdos.size()]; + long oldest = Long.MAX_VALUE; + long latest = Long.MIN_VALUE; + Iterator iter = pdos.iterator(); + for (int i = 0; iter.hasNext(); ++i) { + PluginDataObject pdo = iter.next(); + long insert = pdo.getInsertTime().getTimeInMillis(); + oldest = Math.min(oldest, insert); + latest = Math.max(latest, insert); + rval[i] = pdo; + } + results.setLatestResult(new Date(latest)); + results.setOldestResult(new Date(oldest)); + return rval; + } + + /** + * @param feature + * @param q + * @param options + * @return + * @throws WfsException + */ + public WfsQueryResults querySimple(QualifiedName feature, WfsQuery q, + WfsQueryOptions options) throws WfsException { + List pdos = queryInternal(feature, q); + WfsQueryResults rval = new WfsQueryResults(ResultType.SIMPLE); + PluginDataObject[] arr = extractData(pdos, rval, options); + rval.setResults(featFactory.convert(arr)); + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsSource#getFeatureIdField(com.raytheon + * .uf.edex.wfs.request.QualifiedName) + */ + @Override + public String getFeatureIdField(QualifiedName feature) { + return "dataURI"; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/Unique.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/Unique.java index d40414d55d..fb09c1c300 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/Unique.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/Unique.java @@ -1,3 +1,13 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 // See http://java.sun.com/xml/jaxb diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQuery.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQuery.java index fc25b18398..e5ec7e8dd9 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQuery.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQuery.java @@ -1,3 +1,12 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ package com.raytheon.uf.edex.wfs.reg; import java.util.LinkedList; @@ -5,13 +14,32 @@ import java.util.List; import org.hibernate.criterion.Criterion; +import com.raytheon.uf.edex.wfs.request.QualifiedName; import com.raytheon.uf.edex.ogc.common.OgcTimeRange; import com.raytheon.uf.edex.wfs.request.SortBy; +/** + * Holds query information for WFS + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 13, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ public class WfsQuery { protected Criterion criterion; + protected List typeNames = new LinkedList(); + protected int maxResults; protected List sortBys = new LinkedList(); @@ -20,10 +48,18 @@ public class WfsQuery { protected OgcTimeRange timeRange; + /** + * + */ public WfsQuery() { - // TODO Auto-generated constructor stub } + /** + * @param criterion + * @param maxResults + * @param sortBys + * @param propertyNames + */ public WfsQuery(Criterion criterion, int maxResults, List sortBys, List propertyNames, OgcTimeRange timeRange) { this.criterion = criterion; @@ -33,36 +69,75 @@ public class WfsQuery { this.timeRange = timeRange; } + /** + * @return + */ public Criterion getCriterion() { return criterion; } + /** + * @param criterion + */ public void setCriterion(Criterion criterion) { this.criterion = criterion; } + /** + * @return + */ public int getMaxResults() { return maxResults; } + /** + * @param maxResults + */ public void setMaxResults(int maxResults) { this.maxResults = maxResults; } + /** + * @return + */ public List getSortBys() { return sortBys; } + /** + * @param sortBys + */ public void setSortBys(List sortBys) { this.sortBys = sortBys; } + /** + * @return + */ public List getPropertyNames() { return propertyNames; } + /** + * @param propertyNames + */ public void setPropertyNames(List propertyNames) { this.propertyNames = propertyNames; } + /** + * @return the typeNames + */ + public List getTypeNames() { + return typeNames; + } + + /** + * @param typeNames + * the typeNames to set + */ + public void setTypeNames(List typeNames) { + this.typeNames = typeNames; + } + } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQueryOptions.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQueryOptions.java new file mode 100644 index 0000000000..d7314634ed --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQueryOptions.java @@ -0,0 +1,89 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.reg; + +/** + * options for wfs query + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 13, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class WfsQueryOptions { + + protected WfsQueryResults.ResultType type; + + protected boolean gatherMetadata = false; + + protected String gmlVersion = "3.2.1"; + + /** + * + */ + public WfsQueryOptions(WfsQueryResults.ResultType type) { + this.type = type; + } + + /** + * @return the type + */ + public WfsQueryResults.ResultType getType() { + return type; + } + + /** + * @param type + * the type to set + */ + public void setType(WfsQueryResults.ResultType type) { + this.type = type; + } + + /** + * @return the gatherMetadata + */ + public boolean isGatherMetadata() { + return gatherMetadata; + } + + /** + * @param gatherMetadata + * the gatherMetadata to set + */ + public void setGatherMetadata(boolean gatherMetadata) { + this.gatherMetadata = gatherMetadata; + } + + /** + * @return the gmlVersion + */ + public String getGmlVersion() { + return gmlVersion; + } + + /** + * @param gmlVersion + * the gmlVersion to set + */ + public void setGmlVersion(String gmlVersion) { + this.gmlVersion = gmlVersion; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQueryResults.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQueryResults.java new file mode 100644 index 0000000000..697a2cf090 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsQueryResults.java @@ -0,0 +1,110 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.reg; + +import java.util.Date; +import java.util.List; + +/** + * Results wrapper for wfs queries + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 13, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class WfsQueryResults { + + public static enum ResultType { + JAXB, SIMPLE + }; + + protected final ResultType type; + + protected List results; + + protected Date oldestResult; + + protected Date latestResult; + + /** + * + */ + public WfsQueryResults(List results, ResultType type) { + this.type = type; + this.results = results; + } + + public WfsQueryResults(ResultType type) { + this.type = type; + } + + /** + * @return the oldestResult + */ + public Date getOldestResult() { + return oldestResult; + } + + /** + * @param oldestResult + * the oldestResult to set + */ + public void setOldestResult(Date oldestResult) { + this.oldestResult = oldestResult; + } + + /** + * @return the latestResult + */ + public Date getLatestResult() { + return latestResult; + } + + /** + * @param latestResult + * the latestResult to set + */ + public void setLatestResult(Date latestResult) { + this.latestResult = latestResult; + } + + /** + * @return the type + */ + public ResultType getType() { + return type; + } + + /** + * @return the results + */ + public List getResults() { + return results; + } + + /** + * @param results + * the results to set + */ + public void setResults(List results) { + this.results = results; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsRegistry.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsRegistry.java deleted file mode 100644 index e360b1c35f..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsRegistry.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * - */ -package com.raytheon.uf.edex.wfs.reg; - -import com.raytheon.uf.common.util.registry.RegistryException; - -/** - * @author bclement - * - */ -public interface WfsRegistry { - - /** - * @param source - * @return - * @throws RegistryException - */ - WfsRegistry register(WfsSource source) - throws RegistryException; - - /** - * @param source - * @return - */ - WfsRegistry unregister(WfsSource source); - -} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsRegistryImpl.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsRegistryImpl.java index 1cd7b9dfd9..fd3b12377c 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsRegistryImpl.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsRegistryImpl.java @@ -31,18 +31,27 @@ */ package com.raytheon.uf.edex.wfs.reg; +import java.io.InputStream; +import java.io.OutputStream; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.xml.bind.JAXBException; +import javax.xml.parsers.ParserConfigurationException; import net.opengis.gml.v_3_1_1.ObjectFactory; import org.apache.commons.lang.ArrayUtils; +import org.w3c.dom.Node; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.util.registry.RegistryException; import com.raytheon.uf.edex.ogc.common.OgcNamespace; import com.raytheon.uf.edex.ogc.common.OgcPrefix; @@ -52,29 +61,47 @@ import com.raytheon.uf.edex.wfs.WfsFeatureType; import com.raytheon.uf.edex.wfs.request.QualifiedName; /** + * Wfs registry implementation. Handles wfs sources and the JAXB context * * @author bclement * @version 1.0 */ -public class WfsRegistryImpl implements WfsRegistry { +public class WfsRegistryImpl implements IWfsRegistry { - protected Map byKey = new HashMap(); + protected final Map byKey = new HashMap(); - protected Map byFeature = new HashMap(); + protected final Map byFeature = new HashMap(); protected Class[] jaxbClasses = new Class[] { ObjectFactory.class, net.opengis.wfs.v_1_1_0.ObjectFactory.class, - net.opengis.filter.v_1_1_0.ObjectFactory.class, Unique.class }; + net.opengis.filter.v_1_1_0.ObjectFactory.class, + org.w3.xmlschema.ObjectFactory.class, Unique.class, + net.opengis.wfs.v_2_0_0.ObjectFactory.class, + net.opengis.filter.v_2_0_0.ObjectFactory.class, + net.opengis.gml.v_3_2_1.ObjectFactory.class, + com.eurocontrol.avwx.v_1_1_1.ObjectFactory.class, + com.eurocontrol.wx.v_1_1_1.ObjectFactory.class, + net.opengis.sensorml.v_1_0_1_gml32.ObjectFactory.class, + net.oasis.wsn.b2.ObjectFactory.class, + net.oasis.wsn.bf2.ObjectFactory.class, + net.oasis.wsn.br2.ObjectFactory.class, + net.oasis.wsn.t1.ObjectFactory.class, + net.opengis.owsnt.v1.ObjectFactory.class, + org.w3c.ws_addressing.ObjectFactory.class }; - protected OgcJaxbManager jaxbManager; + protected volatile OgcJaxbManager jaxbManager; - protected long currentVersion = 0; + protected final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected long jaxbContextVersion = 0; + protected volatile long currentVersion = 0; + + protected volatile long jaxbContextVersion = 0; protected String prefix = "wfs"; - protected static final Map NS_MAP = new ConcurrentHashMap(); + protected final ReadWriteLock lock = new ReentrantReadWriteLock(); + + public static final Map NS_MAP = new ConcurrentHashMap(); static { NS_MAP.put(OgcNamespace.EDEX, OgcPrefix.EDEX); @@ -84,42 +111,130 @@ public class WfsRegistryImpl implements WfsRegistry { NS_MAP.put(OgcNamespace.WFS, OgcPrefix.WFS); NS_MAP.put(OgcNamespace.XSI, OgcPrefix.XSI); NS_MAP.put(OgcNamespace.XLINK, OgcPrefix.XLINK); + NS_MAP.put(OgcNamespace.SMIL, OgcPrefix.SMIL); + NS_MAP.put(OgcNamespace.OWS110, OgcPrefix.OWS + "11"); + NS_MAP.put(OgcNamespace.WFS20, OgcPrefix.WFS + "2"); + NS_MAP.put(OgcNamespace.FES20, OgcPrefix.FES); + NS_MAP.put(OgcNamespace.GML32, OgcPrefix.GML + "32"); + NS_MAP.put(OgcNamespace.SWE_GML32, OgcPrefix.SWE); + NS_MAP.put(OgcNamespace.AVWX11, OgcPrefix.AVWX); + NS_MAP.put(OgcNamespace.WX, OgcPrefix.WX); + NS_MAP.put(OgcNamespace.OM_GML32, OgcPrefix.OM); + NS_MAP.put(OgcNamespace.SML_GML32, OgcPrefix.SensorML); + NS_MAP.put(OgcNamespace.ISM, OgcPrefix.ISM); + NS_MAP.put(OgcNamespace.WSNT, OgcPrefix.WSNT); + NS_MAP.put(OgcNamespace.WSA, OgcPrefix.WSA); + NS_MAP.put(OgcNamespace.OWSNT, OgcPrefix.OWSNT); } public WfsRegistryImpl() { } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsRegistry#register(com.raytheon.uf.edex + * .wfs.reg.WfsSource) + */ @Override - public synchronized WfsRegistry register(final WfsSource source) + public IWfsRegistry register(final IWfsSource source) throws RegistryException { - addByKey(source); - addByFeature(source); - jaxbClasses = (Class[]) ArrayUtils.addAll(jaxbClasses, - source.getJaxbClasses()); - currentVersion++; - + Lock write = lock.writeLock(); + write.lock(); + try { + addByKey(source); + addByFeature(source); + jaxbClasses = (Class[]) ArrayUtils.addAll(jaxbClasses, + source.getJaxbClasses()); + currentVersion++; + } finally { + write.unlock(); + } return this; } - protected OgcJaxbManager getManager() throws JAXBException { - if (jaxbManager == null || jaxbContextVersion < currentVersion) { - jaxbContextVersion = currentVersion; - jaxbManager = new OgcJaxbManager(jaxbClasses); - jaxbManager.setPrefixMap(NS_MAP); - } + /** + * @return + * @throws JAXBException + */ + public OgcJaxbManager getManager() throws JAXBException { + if (jaxbManager == null || jaxbContextVersion < currentVersion) { + Lock write = lock.writeLock(); + write.lock(); + try { + jaxbContextVersion = currentVersion; + jaxbManager = new OgcJaxbManager(jaxbClasses); + jaxbManager.setPrefixMap(NS_MAP); + } finally { + write.unlock(); + } + } return jaxbManager; } + /** + * @param xml + * @return + * @throws JAXBException + */ public Object unmarshal(String xml) throws JAXBException { return getManager().unmarshal(xml); } + public Object unmarshal(Node node) throws JAXBException { + return getManager().unmarshal(node); + } + + /** + * @param in + * @return + * @throws JAXBException + */ + public Object unmarshal(InputStream in) throws JAXBException { + return getManager().unmarshal(in); + } + + /** + * @param obj + * @return + * @throws JAXBException + */ public String marshal(Object obj) throws JAXBException { - return getManager().marshal(obj); + return getManager().marshal(obj, false); } - protected void addByKey(WfsSource source) throws RegistryException { + public Node marshalToNode(Object obj) throws JAXBException, + ParserConfigurationException { + return getManager().marshalToNode(obj); + } + + public String marshal(Object obj, boolean fragment) throws JAXBException { + return getManager().marshal(obj, false, fragment); + } + + /** + * @param obj + * @param out + * @throws JAXBException + */ + public void marshal(Object obj, OutputStream out) throws JAXBException { + getManager().marshal(obj, out, null, false, false); + } + + public void marshal(Object obj, OutputStream out, boolean fragment) + throws JAXBException { + getManager().marshal(obj, out, null, false, fragment); + } + + /** + * Catalog source by key + * + * @param source + * @throws RegistryException + */ + protected void addByKey(IWfsSource source) throws RegistryException { String key = source.getKey(); if (byKey.containsKey(key)) { throw new RegistryException("WFS Source already exists with key: " @@ -128,22 +243,38 @@ public class WfsRegistryImpl implements WfsRegistry { byKey.put(source.getKey(), source); } - protected void addByFeature(WfsSource source) throws RegistryException { + /** + * Catalog source by provided feature types + * + * @param source + * @throws RegistryException + */ + protected void addByFeature(IWfsSource source) throws RegistryException { for (WfsFeatureType f : source.listFeatureTypes()) { QualifiedName feature = f.getName(); if (byFeature.containsKey(feature)) { throw new RegistryException( "Already providing a feature with name: " + feature); } - String prefix = (feature.getPrefix() != null ? feature.getPrefix() - : feature.getName()); - NS_MAP.put(feature.getNamespace(), prefix); + String prefix = NS_MAP.get(feature.getNamespace()); + if (prefix == null) { + prefix = (feature.getPrefix() != null + && !feature.getPrefix().isEmpty() ? feature.getPrefix() + : feature.getName()); + NS_MAP.put(feature.getNamespace(), prefix); + } + byFeature.put(f.getName(), source); } } - protected void removeAll(WfsSource source) { - WfsSource removed = byKey.remove(source.getKey()); + /** + * Remove source from all maps + * + * @param source + */ + protected void removeAll(IWfsSource source) { + IWfsSource removed = byKey.remove(source.getKey()); if (removed != null) { for (WfsFeatureType f : removed.listFeatureTypes()) { byFeature.remove(f.getName()); @@ -151,23 +282,59 @@ public class WfsRegistryImpl implements WfsRegistry { } } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.WfsRegistry#unregister(com.raytheon.uf.edex + * .wfs.reg.WfsSource) + */ @Override - public synchronized WfsRegistry unregister(WfsSource source) { - removeAll(source); - return this; + public synchronized IWfsRegistry unregister(IWfsSource source) { + Lock write = lock.writeLock(); + write.lock(); + try { + removeAll(source); + } finally { + write.unlock(); + } + return this; } - public WfsSource getSource(QualifiedName feature) throws WfsException { - WfsSource rval = byFeature.get(feature); - return rval; + /** + * Look up source by feature type + * + * @param feature + * @return + * @throws WfsException + */ + public IWfsSource getSource(QualifiedName feature) throws WfsException { + Lock read = lock.readLock(); + read.lock(); + try { + return byFeature.get(feature); + } finally { + read.unlock(); + } } + /** + * Get a list of all available feature types + * + * @return + */ public List getFeatures() { List rval = new LinkedList(); - for (WfsSource source : byKey.values()) { - rval.addAll(source.listFeatureTypes()); - } - return rval; + Lock read = lock.readLock(); + read.lock(); + try { + for (IWfsSource source : byKey.values()) { + rval.addAll(source.listFeatureTypes()); + } + } finally { + read.unlock(); + } + return rval; } /** @@ -185,5 +352,4 @@ public class WfsRegistryImpl implements WfsRegistry { this.prefix = prefix; } - } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsSource.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsSource.java deleted file mode 100644 index b0f4ba422d..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/reg/WfsSource.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * - * SOFTWARE HISTORY - * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * - */ -package com.raytheon.uf.edex.wfs.reg; - -import java.util.List; -import java.util.Map; - -import javax.xml.bind.JAXBElement; - -import net.opengis.gml.v_3_1_1.AbstractFeatureType; - -import org.opengis.feature.simple.SimpleFeature; - -import com.raytheon.uf.edex.wfs.WfsException; -import com.raytheon.uf.edex.wfs.WfsFeatureType; -import com.raytheon.uf.edex.wfs.request.QualifiedName; - -/** - * @author bclement - * - */ -public interface WfsSource { - - public List listFeatureTypes(); - - public String describeFeatureType(QualifiedName feature) - throws WfsException; - - public String getFeatureSpatialField(QualifiedName feature); - - public Class getFeatureEntity(QualifiedName feature); - - public Map getFieldMap(); - - public List> query( - QualifiedName feature, WfsQuery q) throws WfsException; - - public List querySimple(QualifiedName feature, WfsQuery q) - throws WfsException; - - public List distinct(QualifiedName feature, WfsQuery q) - throws WfsException; - - public long count(QualifiedName feature, WfsQuery q) throws WfsException; - - public String getKey(); - - public Class[] getJaxbClasses(); -} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/DescFeatureTypeReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/DescFeatureTypeReq.java index 9292724226..750b107033 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/DescFeatureTypeReq.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/DescFeatureTypeReq.java @@ -81,7 +81,28 @@ public class DescFeatureTypeReq extends WfsRequest { } } - public void addTypename(QualifiedName typename) { + /** + * @param obj + */ + public DescFeatureTypeReq( + net.opengis.wfs.v_2_0_0.DescribeFeatureTypeType req) { + super(Type.DescribeFeature); + setRawrequest(req); + String outputFormat = req.getOutputFormat(); + if (outputFormat != null && !outputFormat.isEmpty()) { + setOutputformat(outputFormat); + } + List typeName = req.getTypeName(); + if (typeName != null) { + for (QName n : typeName) { + QualifiedName qname = new QualifiedName(n.getNamespaceURI(), + n.getLocalPart(), n.getPrefix()); + addTypename(qname); + } + } + } + + public void addTypename(QualifiedName typename) { if (this.typenames == null) { this.typenames = new ArrayList(); } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/DescQueryReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/DescQueryReq.java new file mode 100644 index 0000000000..fb38e0fd75 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/DescQueryReq.java @@ -0,0 +1,61 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.request; + +import java.util.ArrayList; +import java.util.List; + +import net.opengis.wfs.v_2_0_0.DescribeStoredQueriesType; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 8, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class DescQueryReq extends WfsRequest { + + private final List ids; + + /** + * @param type + */ + public DescQueryReq(List ids) { + super(Type.DescribeStoredQueries); + this.ids = ids; + } + + public DescQueryReq(DescribeStoredQueriesType req) { + super(Type.DescribeStoredQueries); + if (req.isSetStoredQueryId()) { + this.ids = req.getStoredQueryId(); + } else { + this.ids = new ArrayList(0); + } + } + + /** + * @return the ids + */ + public List getIds() { + return ids; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/FeatureQuery.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/FeatureQuery.java index bea98a1f97..9cf088ed63 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/FeatureQuery.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/FeatureQuery.java @@ -32,6 +32,13 @@ package com.raytheon.uf.edex.wfs.request; import java.util.LinkedList; import java.util.List; +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; + +import net.opengis.filter.v_2_0_0.FilterType; +import net.opengis.wfs.v_2_0_0.QueryType; + +import com.raytheon.uf.edex.wfs.request.SortBy.Order; import com.raytheon.uf.edex.ogc.common.OgcTimeRange; /** @@ -58,6 +65,43 @@ public class FeatureQuery { protected OgcTimeRange timeRange; + /** + * + */ + public FeatureQuery() { + } + + /** + * @param qt + */ + public FeatureQuery(QueryType qt) { + if (qt.isSetAbstractSelectionClause()) { + JAXBElement elem = qt.getAbstractSelectionClause(); + FilterType filter = (FilterType) elem.getValue(); + this.setFilter(filter, QFilterType.XMLOBJ); + } + if (qt.isSetAbstractSortingClause()) { + net.opengis.filter.v_2_0_0.SortByType sortBy = (net.opengis.filter.v_2_0_0.SortByType) qt + .getAbstractSortingClause().getValue(); + for (net.opengis.filter.v_2_0_0.SortPropertyType prop : sortBy + .getSortProperty()) { + String name = prop.getValueReference(); + Order o = (prop.getSortOrder() == net.opengis.filter.v_2_0_0.SortOrderType.DESC ? Order.Descending + : Order.Ascending); + this.addSortBy(new SortBy(name, o)); + } + } + String srsName = qt.getSrsName(); + if (srsName != null) { + this.setSrsName(srsName); + } + if (qt.isSetTypeNames()) { + for (QName q : qt.getTypeNames()) { + this.addTypeName(new QualifiedName(q)); + } + } + } + public void addPropertyName(String propertyName) { this.propertyNames.add(propertyName); } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetCapReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetCapReq.java index 023d780db7..b53a4249cd 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetCapReq.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetCapReq.java @@ -47,6 +47,14 @@ public class GetCapReq extends WfsRequest { public GetCapReq(GetCapabilitiesType getCap) { super(Type.GetCapabilities); setRawrequest(getCap); - } + } + + /** + * @param obj + */ + public GetCapReq(net.opengis.wfs.v_2_0_0.GetCapabilitiesType getCap) { + super(Type.GetCapabilities); + setRawrequest(getCap); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java index 4463d52706..c58869eb1a 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java @@ -30,9 +30,11 @@ package com.raytheon.uf.edex.wfs.request; import java.math.BigInteger; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; import net.opengis.filter.v_1_1_0.SortByType; @@ -41,7 +43,13 @@ import net.opengis.filter.v_1_1_0.SortPropertyType; import net.opengis.wfs.v_1_1_0.GetFeatureType; import net.opengis.wfs.v_1_1_0.QueryType; import net.opengis.wfs.v_1_1_0.ResultTypeType; +import net.opengis.wfs.v_2_0_0.GetPropertyValueType; +import net.opengis.wfs.v_2_0_0.StoredQueryType; +import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsException.Code; +import com.raytheon.uf.edex.wfs.querystore.IStoredQueryCallback; import com.raytheon.uf.edex.wfs.request.FeatureQuery.QFilterType; import com.raytheon.uf.edex.wfs.request.SortBy.Order; @@ -51,139 +59,228 @@ import com.raytheon.uf.edex.wfs.request.SortBy.Order; */ public class GetFeatureReq extends WfsRequest { - public enum ResultType { - results, hits - } + public enum ResultType { + results, hits + } - protected List queries = new LinkedList(); + protected List queries = new LinkedList(); - protected String outputformat = "text/xml; subtype=gml/3.1.1"; + protected MimeType outputformat = new MimeType( + "text/xml; subtype=\"gml/3.1.1\""); - protected ResultType resulttype = ResultType.results; + protected ResultType resulttype = ResultType.results; - // may want to set default - protected int maxFeatures = Integer.MAX_VALUE; + // may want to set default + protected int maxFeatures = Integer.MAX_VALUE; - /** - * @param type - */ - public GetFeatureReq() { - super(Type.GetFeature); - } + /** + * @param type + */ + public GetFeatureReq() { + super(Type.GetFeature); + } - public GetFeatureReq(GetFeatureType req) { - super(Type.GetFeature); - setRawrequest(req); - ResultTypeType resultType = req.getResultType(); - if (resultType == ResultTypeType.HITS) { - setResulttype(ResultType.hits); - } - String outputFormat = req.getOutputFormat(); - if (outputFormat != null) { - setOutputformat(outputFormat); - } - BigInteger maxFeatures = req.getMaxFeatures(); - if (maxFeatures != null) { - setMaxFeatures(maxFeatures.intValue()); - } - List query = req.getQuery(); - if (query != null) { - for (QueryType qt : query) { - addQuery(getQuery(qt)); - } - } - } + public GetFeatureReq(GetFeatureType req) { + super(Type.GetFeature); + setRawrequest(req); + ResultTypeType resultType = req.getResultType(); + if (resultType == ResultTypeType.HITS) { + setResulttype(ResultType.hits); + } + String outputFormat = req.getOutputFormat(); + if (outputFormat != null) { + setOutputformat(new MimeType(outputFormat)); + } + BigInteger maxFeatures = req.getMaxFeatures(); + if (maxFeatures != null) { + setMaxFeatures(maxFeatures.intValue()); + } + List query = req.getQuery(); + if (query != null) { + for (QueryType qt : query) { + addQuery(getQuery(qt)); + } + } + } - /** - * @param qt - * @return - */ - protected FeatureQuery getQuery(QueryType qt) { - FeatureQuery rval = new FeatureQuery(); - rval.setFilter(qt.getFilter(), QFilterType.XMLOBJ); - SortByType sortBy = qt.getSortBy(); - if (sortBy != null) { - for (SortPropertyType prop : sortBy.getSortProperty()) { - String name = prop.getPropertyName().getContent().get(0) - .toString(); - Order o = (prop.getSortOrder() == SortOrderType.DESC ? Order.Descending - : Order.Ascending); - rval.addSortBy(new SortBy(name, o)); - } - } - String srsName = qt.getSrsName(); - if (srsName != null) { - rval.setSrsName(srsName); - } - for (QName q : qt.getTypeName()) { - rval.addTypeName(new QualifiedName(q.getNamespaceURI(), q - .getLocalPart(), q.getPrefix())); - } - return rval; - } + /** + * @param obj + * @throws WfsException + */ + public GetFeatureReq(net.opengis.wfs.v_2_0_0.GetFeatureType req, + IStoredQueryCallback callback) throws WfsException { + super(Type.GetFeature); + setRawrequest(req); + net.opengis.wfs.v_2_0_0.ResultTypeType resultType = req.getResultType(); + String outputFormat = req.getOutputFormat(); + BigInteger maxFeatures = req.getCount(); + List> querys = req.getAbstractQueryExpression(); + init(resultType, outputFormat, maxFeatures, querys, callback); + } - public void addQuery(FeatureQuery query) { - this.queries.add(query); - } + /** + * @param req + * @param callback + * @throws WfsException + */ + public GetFeatureReq(GetPropertyValueType req, IStoredQueryCallback callback) + throws WfsException { + super(Type.GetFeature); + setRawrequest(req); + net.opengis.wfs.v_2_0_0.ResultTypeType resultType = req.getResultType(); + String outputFormat = req.getOutputFormat(); + BigInteger maxFeatures = req.getCount(); + List> querys = new ArrayList>(1); + querys.add(req.getAbstractQueryExpression()); + init(resultType, outputFormat, maxFeatures, querys, callback); + } - /** - * @return the queries - */ - public List getQueries() { - return queries; - } + /** + * Initialize with common WFS 2.0 query parameters + * + * @param resultType + * @param outputFormat + * @param maxFeatures + * @param querys + * @param callback + * @throws WfsException + */ + private void init(net.opengis.wfs.v_2_0_0.ResultTypeType resultType, + String outputFormat, BigInteger maxFeatures, + List> querys, IStoredQueryCallback callback) + throws WfsException { + if (resultType == net.opengis.wfs.v_2_0_0.ResultTypeType.HITS) { + setResulttype(ResultType.hits); + } + if (outputFormat != null) { + setOutputformat(new MimeType(outputFormat)); + } + if (maxFeatures != null) { + setMaxFeatures(maxFeatures.intValue()); + } + if (queries != null) { + for (JAXBElement e : querys) { + Object value = e.getValue(); + if (value instanceof net.opengis.wfs.v_2_0_0.QueryType) { + addQuery(getQuery((net.opengis.wfs.v_2_0_0.QueryType) value)); + } else if (value instanceof StoredQueryType) { + addAllQueries(callback.getQueries((StoredQueryType) value)); + } else { + throw new WfsException(Code.OptionNotSupported, + "Unsupported query type"); + } + } + } + } - /** - * @param queries - * the queries to set - */ - public void setQueries(List queries) { - this.queries = queries; - } + public void addQueries(List queries) { + for (net.opengis.wfs.v_2_0_0.QueryType q : queries) { + addQuery(getQuery(q)); + } + } - /** - * @return the outputformat - */ - public String getOutputformat() { - return outputformat; - } + /** + * @param qt + * @return + */ + protected FeatureQuery getQuery(net.opengis.wfs.v_2_0_0.QueryType qt) { + return new FeatureQuery(qt); + } - /** - * @param outputformat - * the outputformat to set - */ - public void setOutputformat(String outputformat) { - this.outputformat = outputformat; - } + /** + * @param qt + * @return + */ + protected FeatureQuery getQuery(QueryType qt) { + FeatureQuery rval = new FeatureQuery(); + rval.setFilter(qt.getFilter(), QFilterType.XMLOBJ); + SortByType sortBy = qt.getSortBy(); + if (sortBy != null) { + for (SortPropertyType prop : sortBy.getSortProperty()) { + String name = prop.getPropertyName().getContent().get(0) + .toString(); + Order o = (prop.getSortOrder() == SortOrderType.DESC ? Order.Descending + : Order.Ascending); + rval.addSortBy(new SortBy(name, o)); + } + } + String srsName = qt.getSrsName(); + if (srsName != null) { + rval.setSrsName(srsName); + } + for (QName q : qt.getTypeName()) { + rval.addTypeName(new QualifiedName(q.getNamespaceURI(), q + .getLocalPart(), q.getPrefix())); + } + return rval; + } - /** - * @return the resulttype - */ - public ResultType getResulttype() { - return resulttype; - } + public void addQuery(FeatureQuery query) { + this.queries.add(query); + } - /** - * @param resulttype - * the resulttype to set - */ - public void setResulttype(ResultType resulttype) { - this.resulttype = resulttype; - } + public void addAllQueries(List queries) { + this.queries.addAll(queries); + } - /** - * @return the maxFeatures - */ - public int getMaxFeatures() { - return maxFeatures; - } + /** + * @return the queries + */ + public List getQueries() { + return queries; + } - /** - * @param maxFeatures - * the maxFeatures to set - */ - public void setMaxFeatures(int maxFeatures) { - this.maxFeatures = maxFeatures; - } + /** + * @param queries + * the queries to set + */ + public void setQueries(List queries) { + this.queries = queries; + } + + /** + * @return the outputformat + */ + public MimeType getOutputformat() { + return outputformat; + } + + /** + * @param outputformat + * the outputformat to set + */ + public void setOutputformat(MimeType outputformat) { + this.outputformat = outputformat; + } + + /** + * @return the resulttype + */ + public ResultType getResulttype() { + return resulttype; + } + + /** + * @param resulttype + * the resulttype to set + */ + public void setResulttype(ResultType resulttype) { + this.resulttype = resulttype; + } + + /** + * @return the maxFeatures + */ + public int getMaxFeatures() { + return maxFeatures; + } + + /** + * @param maxFeatures + * the maxFeatures to set + */ + public void setMaxFeatures(int maxFeatures) { + this.maxFeatures = maxFeatures; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetPropValueReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetPropValueReq.java new file mode 100644 index 0000000000..c69292be1a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetPropValueReq.java @@ -0,0 +1,37 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.request; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 21, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class GetPropValueReq extends WfsRequest { + + /** + * @param type + */ + public GetPropValueReq() { + super(Type.GetPropertyValue); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/ListQueriesReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/ListQueriesReq.java new file mode 100644 index 0000000000..7732e0271d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/ListQueriesReq.java @@ -0,0 +1,38 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.request; + + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 8, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class ListQueriesReq extends WfsRequest { + + /** + * @param type + */ + public ListQueriesReq() { + super(WfsRequest.Type.ListStoredQueries); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/QualifiedName.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/QualifiedName.java index 13ea44d0fe..58b4cdac86 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/QualifiedName.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/QualifiedName.java @@ -29,6 +29,8 @@ */ package com.raytheon.uf.edex.wfs.request; +import javax.xml.namespace.QName; + /** * @author bclement * @@ -51,6 +53,12 @@ public class QualifiedName { this(namespace, name, null); } + public QualifiedName(QName name) { + this.namespace = name.getNamespaceURI(); + this.name = name.getLocalPart(); + this.prefix = name.getPrefix(); + } + @Override public int hashCode() { final int prime = 31; diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/TransReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/TransReq.java index c5b966f166..fbc0ee864c 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/TransReq.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/TransReq.java @@ -64,8 +64,9 @@ public class TransReq extends WfsRequest { * @param obj * @return */ - public static WfsRequest buildTransReq(TransactionType transaction) { - WfsRequest rval = null; + public static WfsRequest buildTransReq( + TransactionType transaction) { + WfsRequest rval = null; for (Object obj : transaction.getInsertOrUpdateOrDelete()) { if (obj instanceof Unique) { TransReq ret = new TransReq(TransType.Native); @@ -76,6 +77,7 @@ public class TransReq extends WfsRequest { rval = ret; } } + rval.setRawrequest(transaction); return rval; } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java index 92dfe6cc73..ddd1183581 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java @@ -31,14 +31,15 @@ package com.raytheon.uf.edex.wfs.request; import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.http.MimeType; public class WfsRequest { public enum Type { - GetFeature, DescribeFeature, GetCapabilities, Transaction, ERROR + GetFeature, DescribeFeature, GetCapabilities, Transaction, ERROR, ListStoredQueries, DescribeStoredQueries, GetPropertyValue } - protected Object rawrequest; + protected Object rawrequest; protected Type type; @@ -46,7 +47,7 @@ public class WfsRequest { protected String[] roles; - private String exceptionFormat = OgcResponse.TEXT_XML_MIME; + private MimeType exceptionFormat = OgcResponse.TEXT_XML_MIME; public WfsRequest(Type type) { super(); @@ -72,7 +73,7 @@ public class WfsRequest { * @param rawrequest * the rawrequest to set */ - public void setRawrequest(Object rawrequest) { + public void setRawrequest(Object rawrequest) { this.rawrequest = rawrequest; } @@ -109,14 +110,14 @@ public class WfsRequest { /** * @param exceptionFormat the exceptionFormat to set */ - public void setExceptionFormat(String exceptionFormat) { + public void setExceptionFormat(MimeType exceptionFormat) { this.exceptionFormat = exceptionFormat; } /** * @return the exceptionFormat */ - public String getExceptionFormat() { + public MimeType getExceptionFormat() { return exceptionFormat; } diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/Wfs.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/Wfs.java new file mode 100644 index 0000000000..e6685fde50 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/Wfs.java @@ -0,0 +1,189 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ + +package com.raytheon.uf.edex.wfs.soap2_0_0; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.BindingType; + +import net.opengis.wfs.v_2_0_0.CreateStoredQueryResponseType; +import net.opengis.wfs.v_2_0_0.CreateStoredQueryType; +import net.opengis.wfs.v_2_0_0.DescribeFeatureTypeType; +import net.opengis.wfs.v_2_0_0.DescribeStoredQueriesResponseType; +import net.opengis.wfs.v_2_0_0.DescribeStoredQueriesType; +import net.opengis.wfs.v_2_0_0.DropStoredQuery; +import net.opengis.wfs.v_2_0_0.ExecutionStatusType; +import net.opengis.wfs.v_2_0_0.FeatureCollectionType; +import net.opengis.wfs.v_2_0_0.GetCapabilitiesType; +import net.opengis.wfs.v_2_0_0.GetFeatureType; +import net.opengis.wfs.v_2_0_0.GetFeatureWithLockType; +import net.opengis.wfs.v_2_0_0.GetPropertyValueType; +import net.opengis.wfs.v_2_0_0.ListStoredQueriesResponseType; +import net.opengis.wfs.v_2_0_0.ListStoredQueriesType; +import net.opengis.wfs.v_2_0_0.LockFeatureResponseType; +import net.opengis.wfs.v_2_0_0.LockFeatureType; +import net.opengis.wfs.v_2_0_0.TransactionResponseType; +import net.opengis.wfs.v_2_0_0.TransactionType; +import net.opengis.wfs.v_2_0_0.ValueCollectionType; +import net.opengis.wfs.v_2_0_0.WFSCapabilitiesType; + +import com.raytheon.uf.edex.ogc.common.soap.ServiceExceptionReport; +import com.raytheon.uf.edex.wfs.soap2_0_0.util.DescribeFeatureTypeResponseType; + +@WebService(name = "wfs", targetNamespace = "http://www.opengis.net/wfs/requests/2.0") +@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) +@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING) +@XmlSeeAlso({ org.w3.xmlschema.ObjectFactory.class, + net.opengis.wfs.v_2_0_0.ObjectFactory.class, + net.opengis.filter.v_2_0_0.ObjectFactory.class, + net.opengis.gml.v_3_2_1.ObjectFactory.class, + com.eurocontrol.avwx.v_1_1_1.ObjectFactory.class, + com.eurocontrol.wx.v_1_1_1.ObjectFactory.class, + net.opengis.sensorml.v_1_0_1_gml32.ObjectFactory.class }) +public interface Wfs { + + /** + * + * @param body + * @return returns net.opengis.wfs._2.WFSCapabilitiesType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.getCapabilities", action = "http://www.opengis.net/wfs/requests#GetCapabilities") + @WebResult(name = "WFS_Capabilities", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public WFSCapabilitiesType wfsGetCapabilities( + @WebParam(name = "GetCapabilities", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") GetCapabilitiesType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns java.lang.String + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.describeFeatureType", action = "http://www.opengis.net/wfs/requests#DescribeFeatureType") + @WebResult(name = "DescribeFeatureTypeResponse", targetNamespace = "http://www.opengis.net/wfs-util/2.0", partName = "Body") + public DescribeFeatureTypeResponseType wfsDescribeFeatureType( + @WebParam(name = "DescribeFeatureType", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") DescribeFeatureTypeType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.ValueCollectionType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.getPropertyValue", action = "http://www.opengis.net/wfs/requests#GetPropertyValue") + @WebResult(name = "ValueCollection", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public ValueCollectionType wfsGetPropertyValue( + @WebParam(name = "GetPropertyValue", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") GetPropertyValueType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.FeatureCollectionType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.getFeature", action = "http://www.opengis.net/wfs/requests#GetFeature") + @WebResult(name = "FeatureCollection", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public FeatureCollectionType wfsGetFeature( + @WebParam(name = "GetFeature", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") GetFeatureType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.FeatureCollectionType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.getFeatureWithLock", action = "http://www.opengis.net/wfs/requests#GetFeatureWithLock") + @WebResult(name = "FeatureCollection", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public FeatureCollectionType wfsGetFeatureWithLock( + @WebParam(name = "GetFeatureWithLock", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") GetFeatureWithLockType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.LockFeatureResponseType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.lockFeature", action = "http://www.opengis.net/wfs/requests#LockFeature") + @WebResult(name = "LockFeatureResponse", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public LockFeatureResponseType wfsLockFeature( + @WebParam(name = "LockFeature", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") LockFeatureType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.TransactionResponseType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.transaction", action = "http://www.opengis.net/wfs/requests#Transaction") + @WebResult(name = "TransactionResponse", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public TransactionResponseType wfsTransaction( + @WebParam(name = "Transaction", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") TransactionType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.ListStoredQueriesResponseType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.listStoredQueries", action = "http://www.opengis.net/wfs/requests#ListStoredQueries") + @WebResult(name = "ListStoredQueriesResponse", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public ListStoredQueriesResponseType wfsListStoredQueries( + @WebParam(name = "ListStoredQueries", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") ListStoredQueriesType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.DescribeStoredQueriesResponseType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.describeStoredQueries", action = "http://www.opengis.net/wfs/requests#DescribeStoredQueries") + @WebResult(name = "DescribeStoredQueriesResponse", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public DescribeStoredQueriesResponseType wfsDescribeStoredQueries( + @WebParam(name = "DescribeStoredQueries", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") DescribeStoredQueriesType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.CreateStoredQueryResponseType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.createStoredQuery", action = "http://www.opengis.net/wfs/requests#CreateStoredQuery") + @WebResult(name = "CreateStoredQueryResponse", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public CreateStoredQueryResponseType wfsCreateStoredQuery( + @WebParam(name = "CreateStoredQuery", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") CreateStoredQueryType body) + throws ServiceExceptionReport; + + /** + * + * @param body + * @return returns net.opengis.wfs._2.ExecutionStatusType + * @throws ServiceExceptionReport + */ + @WebMethod(operationName = "wfs.dropStoredQuery", action = "http://www.opengis.net/wfs/requests#DropStoredQuery") + @WebResult(name = "DropStoredQueryResponse", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") + public ExecutionStatusType wfsDropStoredQuery( + @WebParam(name = "DropStoredQuery", targetNamespace = "http://www.opengis.net/wfs/2.0", partName = "Body") DropStoredQuery body) + throws ServiceExceptionReport; + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/WfsImpl.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/WfsImpl.java new file mode 100644 index 0000000000..12a9e9ebb8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/WfsImpl.java @@ -0,0 +1,312 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.soap2_0_0; + +import javax.annotation.Resource; +import javax.xml.ws.WebServiceContext; + +import net.opengis.wfs.v_2_0_0.CreateStoredQueryResponseType; +import net.opengis.wfs.v_2_0_0.CreateStoredQueryType; +import net.opengis.wfs.v_2_0_0.DescribeFeatureTypeType; +import net.opengis.wfs.v_2_0_0.DescribeStoredQueriesResponseType; +import net.opengis.wfs.v_2_0_0.DescribeStoredQueriesType; +import net.opengis.wfs.v_2_0_0.DropStoredQuery; +import net.opengis.wfs.v_2_0_0.ExecutionStatusType; +import net.opengis.wfs.v_2_0_0.FeatureCollectionType; +import net.opengis.wfs.v_2_0_0.GetCapabilitiesType; +import net.opengis.wfs.v_2_0_0.GetFeatureType; +import net.opengis.wfs.v_2_0_0.GetFeatureWithLockType; +import net.opengis.wfs.v_2_0_0.GetPropertyValueType; +import net.opengis.wfs.v_2_0_0.ListStoredQueriesResponseType; +import net.opengis.wfs.v_2_0_0.ListStoredQueriesType; +import net.opengis.wfs.v_2_0_0.LockFeatureResponseType; +import net.opengis.wfs.v_2_0_0.LockFeatureType; +import net.opengis.wfs.v_2_0_0.TransactionResponseType; +import net.opengis.wfs.v_2_0_0.TransactionType; +import net.opengis.wfs.v_2_0_0.ValueCollectionType; +import net.opengis.wfs.v_2_0_0.WFSCapabilitiesType; + +import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; +import com.raytheon.uf.edex.ogc.common.soap.AbstractOwsService; +import com.raytheon.uf.edex.ogc.common.soap.ServiceExceptionReport; +import com.raytheon.uf.edex.ogc.common.stats.OgcStatsRecorder; +import com.raytheon.uf.edex.ogc.common.stats.StatsRecorderFinder; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsException.Code; +import com.raytheon.uf.edex.wfs.request.DescFeatureTypeReq; +import com.raytheon.uf.edex.wfs.request.DescQueryReq; +import com.raytheon.uf.edex.wfs.request.GetCapReq; +import com.raytheon.uf.edex.wfs.request.GetFeatureReq; +import com.raytheon.uf.edex.wfs.soap2_0_0.util.DescribeFeatureTypeResponseType; +import com.raytheon.uf.edex.wfs.v2_0_0.Wfs2_0_0Provider; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 9, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class WfsImpl extends AbstractOwsService implements Wfs { + + protected Wfs2_0_0Provider provider; + + private static final String VERSION = "2.0.0"; + + @Resource + protected WebServiceContext context; + + public WfsImpl(Wfs2_0_0Provider provider) { + this.provider = provider; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsGetCapabilities(net.opengis + * .wfs.v_2_0_0.GetCapabilitiesType) + */ + @Override + public WFSCapabilitiesType wfsGetCapabilities(GetCapabilitiesType body) + throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + EndpointInfo info = getInfo(); + return provider.getCapabilities(new GetCapReq(body), info); + } catch (WfsException e) { + success = false; + throw getReport(e); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WFS", success); + } + } + + private ServiceExceptionReport getReport(WfsException e) { + return getReport(e.getCode().toString(), e.getMessage(), VERSION); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsDescribeFeatureType(net.opengis + * .wfs.v_2_0_0.DescribeFeatureTypeType) + */ + @Override + public DescribeFeatureTypeResponseType wfsDescribeFeatureType( + DescribeFeatureTypeType body) throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + EndpointInfo info = getInfo(); + return provider.describeFeatureType( + new DescFeatureTypeReq(body), + info); + } catch (WfsException e) { + success = false; + throw getReport(e); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WFS", success); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsGetPropertyValue(net.opengis + * .wfs.v_2_0_0.GetPropertyValueType) + */ + @Override + public ValueCollectionType wfsGetPropertyValue(GetPropertyValueType body) + throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + EndpointInfo info = getInfo(); + return provider.getPropertyValues(body, info); + } catch (WfsException e) { + success = false; + throw getReport(e); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WFS", success); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsGetFeature(net.opengis.wfs. + * v_2_0_0.GetFeatureType) + */ + @Override + public FeatureCollectionType wfsGetFeature(GetFeatureType body) + throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + EndpointInfo info = getInfo(); + return provider.getFeatureGML(new GetFeatureReq(body, provider), + info); + } catch (WfsException e) { + success = false; + throw getReport(e); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WFS", success); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsGetFeatureWithLock(net.opengis + * .wfs.v_2_0_0.GetFeatureWithLockType) + */ + @Override + public FeatureCollectionType wfsGetFeatureWithLock( + GetFeatureWithLockType body) throws ServiceExceptionReport { + throw getReport(new WfsException(Code.OperationNotSupported)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsLockFeature(net.opengis.wfs + * .v_2_0_0.LockFeatureType) + */ + @Override + public LockFeatureResponseType wfsLockFeature(LockFeatureType body) + throws ServiceExceptionReport { + throw getReport(new WfsException(Code.OperationNotSupported)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsTransaction(net.opengis.wfs + * .v_2_0_0.TransactionType) + */ + @Override + public TransactionResponseType wfsTransaction(TransactionType body) + throws ServiceExceptionReport { + throw getReport(new WfsException(Code.OperationNotSupported)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsListStoredQueries(net.opengis + * .wfs.v_2_0_0.ListStoredQueriesType) + */ + @Override + public ListStoredQueriesResponseType wfsListStoredQueries( + ListStoredQueriesType body) throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + EndpointInfo info = getInfo(); + return provider.listQueries(info); + } catch (WfsException e) { + success = false; + throw getReport(e); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WFS", success); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsDescribeStoredQueries(net.opengis + * .wfs.v_2_0_0.DescribeStoredQueriesType) + */ + @Override + public DescribeStoredQueriesResponseType wfsDescribeStoredQueries( + DescribeStoredQueriesType body) throws ServiceExceptionReport { + long start = System.nanoTime(); + boolean success = true; + try { + EndpointInfo info = getInfo(); + return provider.describeQueries(new DescQueryReq(body), info); + } catch (WfsException e) { + success = false; + throw getReport(e); + } finally { + OgcStatsRecorder statRecorder = StatsRecorderFinder.find(); + statRecorder.recordRequest(System.currentTimeMillis(), + System.nanoTime() - start, "WFS", success); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsCreateStoredQuery(net.opengis + * .wfs.v_2_0_0.CreateStoredQueryType) + */ + @Override + public CreateStoredQueryResponseType wfsCreateStoredQuery( + CreateStoredQueryType body) throws ServiceExceptionReport { + throw getReport(new WfsException(Code.OperationNotSupported)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.soap2_0_0.Wfs#wfsDropStoredQuery(net.opengis + * .wfs.v_2_0_0.DropStoredQuery) + */ + @Override + public ExecutionStatusType wfsDropStoredQuery(DropStoredQuery body) + throws ServiceExceptionReport { + throw getReport(new WfsException(Code.OperationNotSupported)); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.ogc.common.soap.AbstractOwsService#getContext() + */ + @Override + protected WebServiceContext getContext() { + return context; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/WfsTransientAnnotationReader.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/WfsTransientAnnotationReader.java new file mode 100644 index 0000000000..97324c8660 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/WfsTransientAnnotationReader.java @@ -0,0 +1,49 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.soap2_0_0; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.ogc.common.jaxb.TransientAnnotationReader; + +/** + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 21, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public class WfsTransientAnnotationReader extends TransientAnnotationReader { + + private IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + /** + * + */ + public WfsTransientAnnotationReader() { + try { + addTransientField(Throwable.class.getDeclaredField("stackTrace")); + addTransientMethod(Throwable.class + .getDeclaredMethod("getStackTrace")); + } catch (Exception e) { + log.error("Unable to add transients for wfs JAXB", e); + throw new RuntimeException(e); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/util/DescribeFeatureTypeResponseType.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/util/DescribeFeatureTypeResponseType.java new file mode 100644 index 0000000000..7779b7baf3 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/util/DescribeFeatureTypeResponseType.java @@ -0,0 +1,70 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.soap2_0_0.util; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.w3.xmlschema.Schema; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 10, 2012            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class DescribeFeatureTypeResponseType { + + @XmlElement + protected Schema schema; + + /** + * + */ + public DescribeFeatureTypeResponseType() { + } + + /** + * @param schema + */ + public DescribeFeatureTypeResponseType(Schema schema) { + this.schema = schema; + } + + /** + * @return the schema + */ + public Schema getSchema() { + return schema; + } + + /** + * @param schema + * the schema to set + */ + public void setSchema(Schema schema) { + this.schema = schema; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/util/package-info.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/util/package-info.java new file mode 100644 index 0000000000..25c3e1db5c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/soap2_0_0/util/package-info.java @@ -0,0 +1,12 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.soap2_0_0.util; + + diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Capabilities.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Capabilities.java new file mode 100644 index 0000000000..19f787c544 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Capabilities.java @@ -0,0 +1,388 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 29, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.v1_1_0; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; + +import net.opengis.filter.v_1_1_0.ArithmeticOperatorsType; +import net.opengis.filter.v_1_1_0.ComparisonOperatorType; +import net.opengis.filter.v_1_1_0.ComparisonOperatorsType; +import net.opengis.filter.v_1_1_0.FID; +import net.opengis.filter.v_1_1_0.FilterCapabilities; +import net.opengis.filter.v_1_1_0.GeometryOperandsType; +import net.opengis.filter.v_1_1_0.IdCapabilitiesType; +import net.opengis.filter.v_1_1_0.LogicalOperators; +import net.opengis.filter.v_1_1_0.ScalarCapabilitiesType; +import net.opengis.filter.v_1_1_0.SpatialCapabilitiesType; +import net.opengis.filter.v_1_1_0.SpatialOperatorNameType; +import net.opengis.filter.v_1_1_0.SpatialOperatorType; +import net.opengis.filter.v_1_1_0.SpatialOperatorsType; +import net.opengis.ows.v_1_0_0.CodeType; +import net.opengis.ows.v_1_0_0.DCP; +import net.opengis.ows.v_1_0_0.DomainType; +import net.opengis.ows.v_1_0_0.HTTP; +import net.opengis.ows.v_1_0_0.Operation; +import net.opengis.ows.v_1_0_0.OperationsMetadata; +import net.opengis.ows.v_1_0_0.RequestMethodType; +import net.opengis.ows.v_1_0_0.ServiceIdentification; +import net.opengis.wfs.v_1_1_0.FeatureTypeListType; +import net.opengis.wfs.v_1_1_0.FeatureTypeType; +import net.opengis.wfs.v_1_1_0.GMLObjectTypeListType; +import net.opengis.wfs.v_1_1_0.GMLObjectTypeType; +import net.opengis.wfs.v_1_1_0.OutputFormatListType; +import net.opengis.wfs.v_1_1_0.WFSCapabilitiesType; + +import com.raytheon.uf.edex.ogc.common.OgcNamespace; +import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; +import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.request.GetCapReq; + +/** + * + * @author bclement + * @version 1.0 + */ +public class Capabilities { + + public static final String SERV_TYPE = "WFS"; + + public static final String SERV_TITLE = "EDEX WFS"; + + protected static final String OWS_NS = OgcNamespace.OWS; + + protected static final String GML_NS = OgcNamespace.GML; + + protected static final String OGC_NS = OgcNamespace.OGC; + + protected static final String WFS_NS = OgcNamespace.WFS; + + protected static final MimeType GML_MIME = GmlUtils.GML311_OLD_TYPE; + + protected static final String[] gmlObjects = { "AbstractFeatureType", + "PointType", + "LineStringType", "PolygonType", "MultiPointType" }; + + protected static final String[] geometryOperands = { "Envelope", "Point", + "LineString", + "Polygon" }; + + protected static final SpatialOperatorNameType[] spatialOperators = { + SpatialOperatorNameType.BBOX, SpatialOperatorNameType.EQUALS }; + + protected static final ComparisonOperatorType[] comparisonOperators = { + ComparisonOperatorType.LESS_THAN, + ComparisonOperatorType.GREATER_THAN, + ComparisonOperatorType.LESS_THAN_EQUAL_TO, + ComparisonOperatorType.GREATER_THAN_EQUAL_TO, + ComparisonOperatorType.EQUAL_TO, + ComparisonOperatorType.NOT_EQUAL_TO }; + + protected static final String[] logicOperators = { "And" }; + + protected final FeatureTranslator translator = new FeatureTranslator(); + + protected final WfsRegistryImpl registry; + + public Capabilities(WfsRegistryImpl registry) { + this.registry = registry; + } + + public WFSCapabilitiesType getCapabilities(GetCapReq request, + OgcServiceInfo serviceinfo) throws WfsException { + WFSCapabilitiesType cap = new WFSCapabilitiesType(); + cap.setServiceIdentification(getServiceId(serviceinfo)); + cap.setOperationsMetadata(getOpData(serviceinfo)); + cap.setFeatureTypeList(getFeatureTypes(request, serviceinfo)); + cap.setServesGMLObjectTypeList(getServesGML()); + cap.setSupportsGMLObjectTypeList(getSupportsGML()); + cap.setFilterCapabilities(getFilterCap()); + return cap; + } + + /** + * @param serviceinfo + * @return + */ + protected OperationsMetadata getOpData(OgcServiceInfo serviceinfo) { + OperationsMetadata rval = new OperationsMetadata(); + List operations = new LinkedList(); + for (OgcOperationInfo op : serviceinfo.getOperations()) { + Operation to = new Operation(); + to.setName(op.getType().toString()); + to.setDCP(getDcpList(op)); + to.setParameter(getOpParams(op)); + operations.add(to); + } + rval.setOperation(operations); + rval.setParameter(getParams(serviceinfo)); + // may want to do constraints as well + return rval; + } + + /** + * @param op + * @return + */ + private List getOpParams(OgcOperationInfo op) { + return Arrays.asList( + getAsDomainType("AcceptVersions", op.getVersions()), + getAsDomainType("AcceptFormats", op.getFormats())); + } + + /** + * @param op + * @return + */ + protected List getDcpList(OgcOperationInfo op) { + List rval = new LinkedList(); + DCP dcp = new DCP(); + HTTP http = new HTTP(); + List> value = new LinkedList>(); + if (op.hasHttpGet()) { + value.add(getRequestType("Get", op.getHttpGetRes())); + } + if (op.hasHttpPost()) { + value.add(getRequestType("Post", op.getHttpPostRes())); + } + http.setGetOrPost(value); + dcp.setHTTP(http); + rval.add(dcp); + return rval; + } + + protected JAXBElement getRequestType(String name, + String value) { + JAXBElement rval = new JAXBElement( + new QName(OWS_NS, name), RequestMethodType.class, + new RequestMethodType()); + rval.getValue().setHref(value); + return rval; + } + + protected DomainType getAsDomainType(String name, Collection values) { + DomainType rval = new DomainType(); + rval.setName(name); + List toVals = new ArrayList(values.size()); + for (String val : values) { + toVals.add(val); + } + rval.setValue(toVals); + return rval; + } + + /** + * @param serviceinfo + * @return + */ + protected List getParams(OgcServiceInfo serviceinfo) { + // TODO this info should be passed in from somewhere + return Arrays.asList(getAsDomainType("srsName", + Arrays.asList("EPSG:4326"))); + } + + /** + * @return + */ + protected FilterCapabilities getFilterCap() { + FilterCapabilities rval = new FilterCapabilities(); + rval.setScalarCapabilities(getScalarCapabilities()); + rval.setSpatialCapabilities(getSpatialCapabilities()); + rval.setIdCapabilities(getIdCapabilities()); + return rval; + } + + /** + * @return + */ + protected IdCapabilitiesType getIdCapabilities() { + IdCapabilitiesType rval = new IdCapabilitiesType(); + rval.setEIDOrFID(Arrays.asList((Object) new FID())); + return rval; + } + + /** + * @return + */ + protected SpatialCapabilitiesType getSpatialCapabilities() { + SpatialCapabilitiesType rval = new SpatialCapabilitiesType(); + rval.setGeometryOperands(getGeometryOperands()); + rval.setSpatialOperators(getSpatialOperators()); + return rval; + } + + /** + * @return + */ + protected SpatialOperatorsType getSpatialOperators() { + SpatialOperatorsType rval = new SpatialOperatorsType(); + List ops = new ArrayList( + spatialOperators.length); + for (SpatialOperatorNameType name : spatialOperators) { + SpatialOperatorType op = new SpatialOperatorType(); + op.setName(name); + ops.add(op); + } + rval.setSpatialOperator(ops); + return rval; + } + + /** + * @return + */ + protected GeometryOperandsType getGeometryOperands() { + GeometryOperandsType rval = new GeometryOperandsType(); + List ops = new ArrayList(geometryOperands.length); + for (String op : geometryOperands) { + QName name = new QName(OgcNamespace.GML, op); + ops.add(name); + } + rval.setGeometryOperand(ops); + return rval; + } + + /** + * @return + */ + protected ScalarCapabilitiesType getScalarCapabilities() { + ScalarCapabilitiesType rval = new ScalarCapabilitiesType(); + rval.setArithmeticOperators(getArithmeticOperators()); + rval.setComparisonOperators(getComparisonOperators()); + rval.setLogicalOperators(GetLogicalOperators()); + return rval; + } + + /** + * @return + */ + protected LogicalOperators GetLogicalOperators() { + return null; + } + + /** + * @return + */ + protected ComparisonOperatorsType getComparisonOperators() { + ComparisonOperatorsType rval = new ComparisonOperatorsType(); + List ops = new ArrayList( + comparisonOperators.length); + for (ComparisonOperatorType op : comparisonOperators) { + ops.add(op); + } + rval.setComparisonOperator(ops); + return rval; + } + + /** + * @return + */ + protected ArithmeticOperatorsType getArithmeticOperators() { + // TODO Auto-generated method stub + return null; + } + + /** + * @return + */ + protected GMLObjectTypeListType getSupportsGML() { + GMLObjectTypeListType rval = new GMLObjectTypeListType(); + List gmlObs = new ArrayList( + gmlObjects.length); + for (String type : gmlObjects) { + gmlObs.add(getGMLObjType(type)); + } + rval.setGMLObjectType(gmlObs); + return rval; + } + + protected GMLObjectTypeType getGMLObjType(String name) { + GMLObjectTypeType rval = new GMLObjectTypeType(); + rval.setName(new QName(GML_NS, name)); + OutputFormatListType outFormats = new OutputFormatListType(); + outFormats.setFormat(Arrays.asList(GML_MIME.toString())); + rval.setOutputFormats(outFormats); + return rval; + } + + /** + * @return + */ + protected GMLObjectTypeListType getServesGML() { + // TODO Auto-generated method stub + return null; + } + + /** + * @param request + * @param serviceinfo + * @return + * @throws WfsException + */ + protected FeatureTypeListType getFeatureTypes(GetCapReq request, + OgcServiceInfo serviceinfo) throws WfsException { + FeatureTypeListType rval = new FeatureTypeListType(); + // rval.setOperations(getOperations(serviceinfo)); + rval.setFeatureType(getFeatureTypes(request)); + return rval; + } + + protected List getFeatureTypes(GetCapReq request) + throws WfsException { + return translator.transform(registry.getFeatures()); + } + + /** + * @param serviceinfo + * @return + */ + protected ServiceIdentification getServiceId( + OgcServiceInfo serviceinfo) { + ServiceIdentification rval = new ServiceIdentification(); + CodeType ct = new CodeType(); + ct.setValue(SERV_TYPE); + rval.setServiceType(ct); + rval.setTitle(SERV_TITLE); + rval.setServiceTypeVersion(Arrays.asList(Wfs1_1_0Provider.version)); + return rval; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/FeatureTranslator.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/FeatureTranslator.java new file mode 100644 index 0000000000..4982e16948 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/FeatureTranslator.java @@ -0,0 +1,112 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 27, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.v1_1_0; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.namespace.QName; + +import net.opengis.ows.v_1_0_0.KeywordsType; +import net.opengis.ows.v_1_0_0.WGS84BoundingBoxType; +import net.opengis.wfs.v_1_1_0.FeatureTypeType; + +import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.request.QualifiedName; + +/** + * + * @author bclement + * @version 1.0 + */ +public class FeatureTranslator { + + public List transform(List features) { + List rval = new ArrayList( + features.size()); + for (WfsFeatureType f : features) { + rval.add(transform(f)); + } + return rval; + } + + /** + * @param source + * @return + */ + public FeatureTypeType transform(WfsFeatureType from) { + FeatureTypeType fType = new FeatureTypeType(); + QName name = transform(from.getName()); + fType.setName(name); + fType.setTitle(from.getTitle()); + fType.setAbstract(from.getAbs()); + fType.setKeywords(getAsKeywordList(from.getKeywords())); + fType.setDefaultSRS(from.getDefaultSRS()); + fType.setOtherSRS(from.getOtherSRS()); + fType.setWGS84BoundingBox(getBBox(from.getBbox())); + return fType; + } + + protected QName transform(QualifiedName from) { + return new QName(from.getNamespace(), from.getName()); + } + + /** + * @param bbox + * @return + */ + private List getBBox(OgcGeoBoundingBox bbox) { + List rval = new LinkedList(); + WGS84BoundingBoxType to = new WGS84BoundingBoxType(); + List ur = new LinkedList(); + List ll = new LinkedList(); + ur.add(bbox.getMaxx()); + ur.add(bbox.getMaxy()); + ll.add(bbox.getMinx()); + ll.add(bbox.getMiny()); + to.setUpperCorner(ur); + to.setLowerCorner(ll); + rval.add(to); + return rval; + } + + protected List getAsKeywordList(List keywords) { + List rval = new LinkedList(); + if (keywords != null && !keywords.isEmpty()) { + KeywordsType kwType = new KeywordsType(); + kwType.setKeyword(keywords); + rval.add(kwType); + } + return rval; + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java new file mode 100644 index 0000000000..257a22b672 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java @@ -0,0 +1,801 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.v1_1_0; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; + +import net.opengis.gml.v_3_1_1.FeaturePropertyType; +import net.opengis.ows.v_1_0_0.ExceptionReport; +import net.opengis.ows.v_1_0_0.ExceptionType; +import net.opengis.wfs.v_1_1_0.DescribeFeatureTypeType; +import net.opengis.wfs.v_1_1_0.FeatureCollectionType; +import net.opengis.wfs.v_1_1_0.GetCapabilitiesType; +import net.opengis.wfs.v_1_1_0.GetFeatureType; +import net.opengis.wfs.v_1_1_0.ObjectFactory; +import net.opengis.wfs.v_1_1_0.TransactionResponseType; +import net.opengis.wfs.v_1_1_0.TransactionType; +import net.opengis.wfs.v_1_1_0.WFSCapabilitiesType; + +import org.opengis.feature.simple.SimpleFeature; +import org.springframework.context.ApplicationContext; +import org.w3.xmlschema.Schema; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.core.EDEXUtil; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; +import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.OgcResponse.ErrorType; +import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; +import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; +import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; +import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; +import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsException.Code; +import com.raytheon.uf.edex.wfs.provider.AbstractWfsProvider; +import com.raytheon.uf.edex.wfs.provider.FeatureDescriber; +import com.raytheon.uf.edex.wfs.provider.FeatureFetcher.CountedFeatures; +import com.raytheon.uf.edex.wfs.provider.Gml31FeatureFetcher; +import com.raytheon.uf.edex.wfs.provider.Transactor; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.request.DescFeatureTypeReq; +import com.raytheon.uf.edex.wfs.request.FeatureQuery; +import com.raytheon.uf.edex.wfs.request.FeatureQuery.QFilterType; +import com.raytheon.uf.edex.wfs.request.GetCapReq; +import com.raytheon.uf.edex.wfs.request.GetFeatureReq; +import com.raytheon.uf.edex.wfs.request.GetFeatureReq.ResultType; +import com.raytheon.uf.edex.wfs.request.TransReq; +import com.raytheon.uf.edex.wfs.request.WfsRequest; +import com.raytheon.uf.edex.wfs.request.WfsRequest.Type; +import com.raytheon.uf.edex.wfs.soap2_0_0.util.DescribeFeatureTypeResponseType; + +public class Wfs1_1_0Provider extends AbstractWfsProvider { + + protected final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + public static final String version = "1.1.0"; + + public static final MimeType GML_MIME = GmlUtils.GML311_OLD_TYPE; + + protected final WfsRegistryImpl registry; + + protected final Capabilities capabilities; + + protected final Gml31FeatureFetcher features; + + protected final Transactor transactor; + + protected final FeatureDescriber describer; + + protected final ObjectFactory wfsFactory = new ObjectFactory(); + + public Wfs1_1_0Provider(WfsRegistryImpl registry) { + this.capabilities = new Capabilities(registry); + this.features = new Gml31FeatureFetcher(registry); + this.describer = new FeatureDescriber(registry); + this.registry = registry; + this.transactor = new Transactor(); + } + + protected Wfs1_1_0Provider() { + this.capabilities = null; + this.features = null; + this.describer = null; + this.registry = null; + this.transactor = null; + } + + /** + * Create an error response + * + * @param e + * @param exceptionFormat + * @return + */ + public OgcResponse getError(WfsException e, MimeType exceptionFormat) { + ExceptionType et = new ExceptionType(); + et.setExceptionCode(e.getCode().toString()); + et.setExceptionText(Arrays.asList(e.getMessage())); + ExceptionReport report = new ExceptionReport(); + report.setException(Arrays.asList(et)); + String rval = ""; + if (exceptionFormat == null) { + exceptionFormat = OgcResponse.TEXT_XML_MIME; + } + if (exceptionFormat.equalsIgnoreParams(OgcResponse.TEXT_XML_MIME)) { + try { + rval = registry.marshal(report); + } catch (JAXBException e1) { + log.error("Unable to marshal WFS response", e1); + rval = ""; + rval += ""; + rval += "" + e.getMessage() + + ""; + rval += ""; + } + } else if (exceptionFormat + .equalsIgnoreParams(OgcResponse.TEXT_HTML_MIME)) { + rval = ""; + rval += "
An error occurred performing the request:
"; + rval += "
Error Code: " + e.getCode().toString(); + rval += "
Message: " + e.getMessage() + ""; + } + OgcResponse resp = new OgcResponse(rval, exceptionFormat, TYPE.TEXT); + switch (e.getCode()) { + case OperationProcessingFailed: + resp.setError(ErrorType.INT_ERR); + break; + default: + resp.setError(ErrorType.BAD_REQ); + } + return resp; + } + + /** + * Read input stream to string + * + * @param in + * @return + * @throws IOException + */ + protected String getXml(InputStream in) throws IOException { + return new java.util.Scanner(in).useDelimiter("\\A").next(); + } + + /** + * Decode post request from input stream + * + * @param in + * @return Error-type request object if unable to decode request + */ + public WfsRequest getRequest(InputStream in) { + Object obj; + WfsRequest rval; + try { + obj = registry.unmarshal(in); + } catch (Exception e) { + log.error("Unable to decode request", e); + return getDecodeError(OgcResponse.TEXT_XML_MIME); + } + if (obj instanceof GetCapabilitiesType) { + rval = new GetCapReq((GetCapabilitiesType) obj); + } else if (obj instanceof GetFeatureType) { + rval = new GetFeatureReq((GetFeatureType) obj); + } else if (obj instanceof DescribeFeatureTypeType) { + rval = new DescFeatureTypeReq((DescribeFeatureTypeType) obj); + } else if (obj instanceof TransactionType) { + rval = TransReq.buildTransReq((TransactionType) obj); + if (rval == null) { + rval = getDecodeError(OgcResponse.TEXT_XML_MIME); + } + } else { + rval = getDecodeError(OgcResponse.TEXT_XML_MIME); + } + if (rval.getType() != Type.ERROR) { + rval.setRawrequest(obj); + } + return rval; + } + + /** + * Create an error-type request for decoding problems + * + * @param exceptionFormat + * @return invalid request error + */ + public WfsRequest getDecodeError(MimeType exceptionFormat) { + return getRequestError(new WfsException(Code.INVALID_REQUEST, + "Unable to decode request"), exceptionFormat); + } + + /** + * Create an error-type request. + * + * @param e + * @param exceptionFormat + * @return + */ + public WfsRequest getRequestError(WfsException e, MimeType exceptionFormat) { + OgcResponse error = getError(e, exceptionFormat); + WfsRequest rval = new WfsRequest(Type.ERROR); + rval.setRawrequest(error); + return rval; + } + + /** + * Get capabilities as object + * + * @param request + * @param serviceInfo + * @return + * @throws WfsException + */ + public WFSCapabilitiesType getCapabilities(GetCapReq request, + OgcServiceInfo serviceInfo) throws WfsException { + return capabilities.getCapabilities(request, serviceInfo); + } + + /** + * Get capabilities as object + * + * @param request + * @param info + * @return + * @throws WfsException + */ + public WFSCapabilitiesType getCapabilities(GetCapReq request, + EndpointInfo info) throws WfsException { + return capabilities.getCapabilities(request, getServiceInfo(info)); + } + + /** + * Handle get capabilities request for http servlet + * + * @param request + * @param serviceInfo + * @param resp + * @throws Exception + * on unrecoverable error that was unable to be sent via + * response + */ + public void handleCapabilities(GetCapReq request, + OgcServiceInfo serviceInfo, IOgcHttpResponse resp) + throws Exception { + try { + WFSCapabilitiesType cap = getCapabilities(request, serviceInfo); + JAXBElement rval = wfsFactory + .createWFSCapabilities(cap); + marshalResponse(rval, OgcResponse.TEXT_XML_MIME, resp); + } catch (WfsException e) { + OgcResponse response = getError(e, null); + OgcResponseOutput.sendText(response, resp); + } + } + + /** + * Build service info based on endpoint. The results of this method are not + * cache-able since it uses the hostname that the client used to reach the + * service. + * + * @param info + * @return + */ + public OgcServiceInfo getServiceInfo(EndpointInfo info) { + String base = info.getProtocol() + "://" + info.getHost(); + int port = info.getPort(); + if (port != 80) { + base += ":" + port; + } + base += "/" + info.getPath() + "?service=" + Capabilities.SERV_TYPE + + "&version=" + version; + OgcServiceInfo rval = new OgcServiceInfo(base); + String getCapGet = base; + String getFeatureGet = base; + String descFeatureGet = base; + rval.addOperationInfo(getOp(getCapGet, base, WfsOpType.GetCapabilities)); + rval.addOperationInfo(getOp(descFeatureGet, base, + WfsOpType.DescribeFeatureType)); + rval.addOperationInfo(getOp(getFeatureGet, base, WfsOpType.GetFeature)); + return rval; + } + + /** + * Get operation info for op type + * + * @param get + * @param post + * @param type + * @return + */ + protected OgcOperationInfo getOp(String get, String post, + WfsOpType type) { + OgcOperationInfo rval = new OgcOperationInfo(type); + rval.setHttpGetRes(get); + rval.setHttpPostRes(post); + rval.addVersion(version); + rval.addFormat(OgcResponse.TEXT_XML_MIME.toString()); + return rval; + } + + /** + * Marshal object through response. Response cannot be reused after this + * method is called. + * + * @param jaxbobject + * @param mimeType + * @param response + * @throws Exception + * on unrecoverable error attempting to send response + */ + protected void marshalResponse(Object jaxbobject, MimeType mimeType, + IOgcHttpResponse response) throws Exception { + OutputStream out = null; + try { + out = response.getOutputStream(); + response.setContentType(mimeType.toString()); + registry.marshal(jaxbobject, response.getOutputStream()); + } catch (Exception e) { + log.error("Unable to marshal WFS response", e); + OgcResponse err = getError(new WfsException( + Code.OperationProcessingFailed), null); + OgcResponseOutput.sendText(err, response, out); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * Get features as JAXB object + * + * @param request + * @param serviceinfo + * @return + * @throws WfsException + * if return format isn't a supported GML version + */ + public FeatureCollectionType getFeatureGML(GetFeatureReq request, + OgcServiceInfo serviceinfo) throws WfsException { + FeatureCollectionType featColl; + MimeType format = request.getOutputformat(); + + if (GmlUtils.isGml(format)) { + if (!GmlUtils.areCompatible(format, GML_MIME)) { + throw new WfsException(Code.InvalidParameterValue, + "Unsupported GML Version: " + format); + } + featColl = wrap(features.getFeatures(request, serviceinfo)); + } else { + String msg = String.format( + "Output format '%s' not supported for protocol", + format); + throw new WfsException(Code.InvalidParameterValue, msg); + } + return featColl; + } + + /** + * Wrap counted features in JAXB feature collection type + * + * @param features + * @return + */ + protected FeatureCollectionType wrap( + CountedFeatures features) { + FeatureCollectionType rval = new FeatureCollectionType(); + List members = rval.getFeatureMember(); + members.addAll(features.features); + rval.setNumberOfFeatures(new BigInteger("" + features.count)); + return rval; + } + + /** + * Handle get feature request for http servlet. Response cannot be reused + * after this method is called. + * + * @param request + * @param serviceinfo + * @param response + * @throws Exception + * if unable to send response + */ + public void handleGetFeature(GetFeatureReq request, + OgcServiceInfo serviceinfo, IOgcHttpResponse response) + throws Exception { + FeatureCollectionType featColl; + MimeType format = request.getOutputformat(); + try { + if (GmlUtils.isGml(format)) { + if (!GmlUtils.areCompatible(format, GML_MIME)) { + throw new WfsException(Code.InvalidParameterValue, + "Unsupported GML Version: " + format); + } + // use JAXB instead of gml simple feature formatter + featColl = wrap(features.getFeatures(request, serviceinfo)); + marshalResponse(wfsFactory.createFeatureCollection(featColl), + GML_MIME, response); + } else { + if (request.getResulttype() == ResultType.hits) { + throw new WfsException(Code.InvalidParameterValue, + "Hits result not supported in format: " + format); + } + SimpleFeatureFormatter formatter = getFormatter(format); + List> res = features.getSimpleFeatures( + request, serviceinfo); + sendFormatted(formatter, res, response); + } + } catch (WfsException e) { + // this will only succeed if stream/writer haven't been extracted + // from response + OgcResponse err = getError(e, request.getExceptionFormat()); + OgcResponseOutput.output(err, response); + } + } + + /** + * Marshal simple features through response using formatter. Response cannot + * be reused after this method is called. + * + * @param formatter + * @param res + * @param response + * @throws Exception + * if unable to send response + */ + protected void sendFormatted(SimpleFeatureFormatter formatter, + List> res, IOgcHttpResponse response) + throws Exception { + OutputStream out = null; + try { + out = response.getOutputStream(); + formatter.format(res, out); + out.flush(); + } catch (Exception e) { + log.error("Problem formatting features", e); + OgcResponse err = getError(new WfsException( + Code.OperationProcessingFailed), null); + OgcResponseOutput.sendText(err, response, out); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * Find formatter for mime type + * + * @param format + * @return + * @throws WfsException + * if no matching formatter is found + */ + protected SimpleFeatureFormatter getFormatter(MimeType format) + throws WfsException { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx.getBeanNamesForType(SimpleFeatureFormatter.class); + for (String bean : beans) { + SimpleFeatureFormatter sff = (SimpleFeatureFormatter) ctx + .getBean(bean); + if (sff.matchesFormat(format)) { + return sff; + } + } + throw new WfsException(Code.InvalidParameterValue, + "Unsupported format: " + format); + } + + /** + * Handle transaction request. + * + * @deprecated unmaintained + * @param request + * @return + */ + @Deprecated + public TransactionResponseType transaction(TransReq request) { + return transactor.transaction(request); + } + + /** + * @param request + * @param info + * @return + * @throws WfsException + */ + public DescribeFeatureTypeResponseType describeFeatureType( + DescFeatureTypeReq request, EndpointInfo info) throws WfsException { + return describeFeatureType(request, getServiceInfo(info)); + } + + /** + * @param request + * @param serviceInfo + * @return + * @throws WfsException + */ + public DescribeFeatureTypeResponseType describeFeatureType( + DescFeatureTypeReq request, OgcServiceInfo serviceInfo) + throws WfsException { + String xml = describer.describe(request, serviceInfo); + if (xml == null) { + throw new WfsException(Code.INVALID_REQUEST, "Unknown type name(s)"); + } + try { + Schema s = (Schema) registry.unmarshal(xml); + return new DescribeFeatureTypeResponseType(s); + } catch (JAXBException e) { + throw new WfsException(Code.OperationProcessingFailed); + } + } + + /** + * Handle describe feature type request for http servlet. Response cannot be + * used after this method is called. + * + * @param request + * @param serviceInfo + * @param response + * @throws Exception + * if unable to send response + */ + public void handleDescribeFeatureType(DescFeatureTypeReq request, + OgcServiceInfo serviceInfo, IOgcHttpResponse response) + throws Exception { + try { + String xml = describer.describe(request, serviceInfo); + if (xml == null) { + throw new WfsException(Code.INVALID_REQUEST, + "Unknown type name(s)"); + } + OgcResponse ogcResp = new OgcResponse(xml, GML_MIME, TYPE.TEXT); + OgcResponseOutput.output(ogcResp, response); + } catch (WfsException e) { + OgcResponse ogcResp = getError(e, null); + OgcResponseOutput.sendText(ogcResp, response); + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.WfsProvider#getVersion() + */ + @Override + public String getVersion() { + return version; + } + + /** + * @param headers + * @return + * @throws OgcException + * if unable to decode request + */ + protected WfsRequest getRequestFromHeaders(Map headers) + throws OgcException { + WfsRequest rval = null; + getExceptionFormat(headers); + String req = OgcHttpHandler.getString(headers, REQUEST_HEADER); + if (req.equalsIgnoreCase(CAP_PARAM)) { + rval = new GetCapReq(); + } else if (req.equalsIgnoreCase(DESC_PARAM)) { + rval = buildDescFeatureReq(headers); + } else if (req.equalsIgnoreCase(GET_PARAM)) { + rval = buildGetFeatureReq(headers); + } + + if (rval == null) { + throw new OgcException(OgcException.Code.InvalidRequest, + "Unable to decode request"); + } + + return rval; + } + + /** + * Get and validate exception format + * + * @param headers + * @return XML format if no exception format is specified + * @throws OgcException + * if format is invalid + */ + protected MimeType getExceptionFormat(Map headers) + throws OgcException { + String exFormatStr = OgcHttpHandler.getString(headers, + EXCEP_FORMAT_HEADER); + MimeType rval; + if (exFormatStr == null || exFormatStr.isEmpty()) { + rval = OgcResponse.TEXT_XML_MIME; + } else { + try { + rval = new MimeType(exFormatStr); + } catch (IllegalArgumentException e) { + throw new OgcException(OgcException.Code.InvalidParameterValue, + e.getMessage()); + } + } + if (!rval.equalsIgnoreParams(OgcResponse.TEXT_HTML_MIME) + && !rval.equalsIgnoreParams(OgcResponse.TEXT_XML_MIME)) { + throw new OgcException(OgcException.Code.InvalidParameterValue, + "exceptions parameter invalid"); + } + return rval; + } + + /** + * @param headers + * @return + * @throws OgcException + */ + protected GetFeatureReq buildGetFeatureReq(Map headers) + throws OgcException { + GetFeatureReq rval = new GetFeatureReq(); + String resType = OgcHttpHandler.getString(headers, RESTYPE_HEADER); + if (resType != null) { + ResultType valueOf = GetFeatureReq.ResultType.valueOf(resType); + if (valueOf != null) { + rval.setResulttype(valueOf); + } + } + Integer max = OgcHttpHandler.getInt(headers, MAXFEAT_HEADER); + if (max != null) { + rval.setMaxFeatures(max); + } + MimeType outputformat = OgcHttpHandler.getMimeType(headers, + OUTFORMAT_HEADER); + if (outputformat != null) { + rval.setOutputformat(outputformat); + } + Map nsmap = getNameSpaceMap(headers); + String[] bboxes = splitOnParens(BBOX_HEADER, headers); + String[] times = splitOnParens(TIME_HEADER, headers); + String[] filters = splitOnParens(FILTER_HEADER, headers); + String[] sorts = splitOnParens(SORTBY_HEADER, headers); + String[] props = splitOnParens(PROPNAME_HEADER, headers); + String[] srsnames = splitOnParens(SRSNAME_HEADER, headers); + String[] types = OgcHttpHandler.getStringArr(headers, TYPENAME_HEADER); + if (types == null) { + types = new String[0]; + } + for (int i = 0; i < types.length; ++i) { + FeatureQuery fq = new FeatureQuery(); + if (bboxes.length > 0) { + fq.setFilter(getBoundingBox(bboxes[i]), QFilterType.BBOX); + } else if (filters.length > 0) { + fq.setFilter(filters[i], QFilterType.XML); + } + fq.setTypeNames(getTypeNames(types[i], nsmap)); + if (i < sorts.length) { + fq.setSortBys(getSortBys(sorts[i])); + } + if (i < props.length) { + fq.setPropertyNames(Arrays.asList(splitOnComma(props[i]))); + } + if (i < srsnames.length) { + fq.setSrsName(srsnames[i]); + } + if (i < times.length) { + fq.setTimeRange(getTimeRange(times[i])); + } + rval.addQuery(fq); + } + return rval; + } + + /** + * @param headers + * @return + * @throws OgcException + */ + protected DescFeatureTypeReq buildDescFeatureReq(Map headers) + throws OgcException { + DescFeatureTypeReq rval = new DescFeatureTypeReq(); + String outputformat = OgcHttpHandler.getString(headers, + OUTFORMAT_HEADER); + if (outputformat != null) { + rval.setOutputformat(outputformat); + } + String typename = OgcHttpHandler.getString(headers, TYPENAME_HEADER); + if (typename != null) { + Map nsmap = getNameSpaceMap(headers); + rval.setTypenames(getTypeNames(typename, nsmap)); + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.WfsProvider#handlePost(java.io.InputStream, + * com.raytheon.uf.edex.ogc.common.http.EndpointInfo, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void handlePost(InputStream body, EndpointInfo info, + IOgcHttpResponse response) throws Exception { + WfsRequest request = getRequest(body); + handleInternal(request, info, response); + } + + /** + * @param request + * @param info + * @param response + * @throws Exception + */ + protected void handleInternal(WfsRequest request, EndpointInfo info, + IOgcHttpResponse response) throws Exception { + OgcServiceInfo serviceInfo = getServiceInfo(info); + OgcResponse err = null; + switch (request.getType()) { + case GetCapabilities: + handleCapabilities((GetCapReq) request, serviceInfo, response); + break; + case DescribeFeature: + handleDescribeFeatureType((DescFeatureTypeReq) request, + serviceInfo, response); + break; + case GetFeature: + handleGetFeature((GetFeatureReq) request, serviceInfo, response); + break; + case ERROR: + err = (OgcResponse) request.getRawrequest(); + default: + if (err == null) { + err = getError(new WfsException(Code.INVALID_REQUEST, + "Unsupported request: " + request.getType()), null); + } + OgcResponseOutput.output(err, response); + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.WfsProvider#handleGet(java.util.Map, + * com.raytheon.uf.edex.ogc.common.http.EndpointInfo, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void handleGet(Map headers, EndpointInfo info, + IOgcHttpResponse response) throws Exception { + WfsRequest req; + try { + req = getRequestFromHeaders(headers); + } catch (OgcException e) { + req = getRequestError(new WfsException(e), + OgcResponse.TEXT_XML_MIME); + } + handleInternal(req, info, response); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Capabilities.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Capabilities.java new file mode 100644 index 0000000000..940c91a79b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Capabilities.java @@ -0,0 +1,316 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 29, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.v2_0_0; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; + +import net.opengis.filter.v_2_0_0.ComparisonOperatorType; +import net.opengis.filter.v_2_0_0.ComparisonOperatorsType; +import net.opengis.filter.v_2_0_0.FilterCapabilities; +import net.opengis.filter.v_2_0_0.GeometryOperandsType; +import net.opengis.filter.v_2_0_0.GeometryOperandsType.GeometryOperand; +import net.opengis.filter.v_2_0_0.IdCapabilitiesType; +import net.opengis.filter.v_2_0_0.LogicalOperators; +import net.opengis.filter.v_2_0_0.ScalarCapabilitiesType; +import net.opengis.filter.v_2_0_0.SpatialCapabilitiesType; +import net.opengis.filter.v_2_0_0.SpatialOperatorType; +import net.opengis.filter.v_2_0_0.SpatialOperatorsType; +import net.opengis.ows.v_1_1_0.AllowedValues; +import net.opengis.ows.v_1_1_0.CodeType; +import net.opengis.ows.v_1_1_0.DCP; +import net.opengis.ows.v_1_1_0.DomainType; +import net.opengis.ows.v_1_1_0.HTTP; +import net.opengis.ows.v_1_1_0.LanguageStringType; +import net.opengis.ows.v_1_1_0.OperationsMetadata; +import net.opengis.ows.v_1_1_0.RequestMethodType; +import net.opengis.ows.v_1_1_0.ServiceIdentification; +import net.opengis.wfs.v_2_0_0.FeatureTypeListType; +import net.opengis.wfs.v_2_0_0.FeatureTypeType; +import net.opengis.wfs.v_2_0_0.WFSCapabilitiesType; + +import com.raytheon.uf.edex.ogc.common.OgcNamespace; +import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; +import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.request.GetCapReq; + +/** + * + * @author bclement + * @version 1.0 + */ +public class Capabilities { + + protected static final String SERV_TYPE = "WFS"; + + protected static final String SERV_TITLE = "EDEX WFS"; + + protected static final String OWS_NS = OgcNamespace.OWS; + + protected static final String GML_NS = OgcNamespace.GML; + + protected static final String OGC_NS = OgcNamespace.OGC; + + protected static final String WFS_NS = OgcNamespace.WFS; + + protected static final String VERSION = "2.0.0"; + + protected static final MimeType GML_MIME = GmlUtils.GML32_TYPE; + + protected String[] gmlObjects = { "AbstractFeatureType", "PointType", + "LineStringType", "PolygonType", "MultiPointType" }; + + protected String[] geometryOperands = { "Envelope", "Point", "LineString", + "Polygon" }; + + protected String[] spatialOperators = { "BBOX", "Equals", "Within", + "Disjoint", "Contains", "Crosses", "Intersects", "Overlaps", + "Touches" }; + + protected String[] comparisonOperators = { "PropertyIsLessThan", + "PropertyIsGreaterThan", "PropertyIsLessThanEqualTo", + "PropertyIsGreaterThenEqualTo", "PropertyIsEqualTo", + "PropertyIsNotEqualTo" }; + + protected String[] logicOperators = { "And", "Or", "Not" }; + + protected FeatureTranslator translator = new FeatureTranslator(); + + protected WfsRegistryImpl registry; + + private final WfsOperationsDescriber opDescriber = new WfsOperationsDescriber(); + + public Capabilities(WfsRegistryImpl registry) { + this.registry = registry; + } + + public WFSCapabilitiesType getCapabilities(GetCapReq request, + OgcServiceInfo serviceinfo) throws WfsException { + WFSCapabilitiesType cap = new WFSCapabilitiesType(); + cap.setServiceIdentification(getServiceId(serviceinfo)); + cap.setOperationsMetadata(getOpData(serviceinfo)); + cap.setFeatureTypeList(getFeatureTypes(request, serviceinfo)); + cap.setVersion(VERSION); + cap.setFilterCapabilities(getFilterCap()); + return cap; + } + + /** + * @param serviceinfo + * @return + */ + protected OperationsMetadata getOpData(OgcServiceInfo serviceinfo) { + return opDescriber.getOpData(serviceinfo); + } + + /** + * @param op + * @return + */ + protected List getDcpList(OgcOperationInfo op) { + List rval = new LinkedList(); + DCP dcp = new DCP(); + HTTP http = new HTTP(); + List> value = new LinkedList>(); + if (op.hasHttpGet()) { + value.add(getRequestType("Get", op.getHttpGetRes())); + } + if (op.hasHttpPost()) { + value.add(getRequestType("Post", op.getHttpPostRes())); + } + http.setGetOrPost(value); + dcp.setHTTP(http); + rval.add(dcp); + return rval; + } + + protected JAXBElement getRequestType(String name, + String value) { + JAXBElement rval = new JAXBElement( + new QName(OWS_NS, name), RequestMethodType.class, + new RequestMethodType()); + rval.getValue().setHref(value); + return rval; + } + + protected DomainType getAsDomainType(String name, Collection values) { + DomainType rval = new DomainType(); + rval.setName(name); + List toVals = new ArrayList(values.size()); + for (String val : values) { + toVals.add(val); + } + AllowedValues value = new AllowedValues(); + value.setValueOrRange(toVals); + rval.setAllowedValues(value); + return rval; + } + + /** + * @return + */ + protected FilterCapabilities getFilterCap() { + FilterCapabilities rval = new FilterCapabilities(); + rval.setScalarCapabilities(getScalarCapabilities()); + rval.setSpatialCapabilities(getSpatialCapabilities()); + rval.setIdCapabilities(getIdCapabilities()); + return rval; + } + + /** + * @return + */ + protected IdCapabilitiesType getIdCapabilities() { + // TODO Auto-generated method stub + return null; + } + + /** + * @return + */ + protected SpatialCapabilitiesType getSpatialCapabilities() { + SpatialCapabilitiesType rval = new SpatialCapabilitiesType(); + rval.setGeometryOperands(getGeometryOperands()); + rval.setSpatialOperators(getSpatialOperators()); + return rval; + } + + /** + * @return + */ + protected SpatialOperatorsType getSpatialOperators() { + SpatialOperatorsType rval = new SpatialOperatorsType(); + List ops = new ArrayList( + spatialOperators.length); + for (String name : spatialOperators) { + SpatialOperatorType op = new SpatialOperatorType(); + op.setName(name); + ops.add(op); + } + rval.setSpatialOperator(ops); + return rval; + } + + /** + * @return + */ + protected GeometryOperandsType getGeometryOperands() { + GeometryOperandsType rval = new GeometryOperandsType(); + List ops = new ArrayList( + geometryOperands.length); + for (String op : geometryOperands) { + QName name = new QName(OgcNamespace.GML, op); + GeometryOperand gop = new GeometryOperand(); + gop.setName(name); + } + rval.setGeometryOperand(ops); + return rval; + } + + /** + * @return + */ + protected ScalarCapabilitiesType getScalarCapabilities() { + ScalarCapabilitiesType rval = new ScalarCapabilitiesType(); + rval.setComparisonOperators(getComparisonOperators()); + rval.setLogicalOperators(GetLogicalOperators()); + return rval; + } + + /** + * @return + */ + protected LogicalOperators GetLogicalOperators() { + return null; + } + + /** + * @return + */ + protected ComparisonOperatorsType getComparisonOperators() { + ComparisonOperatorsType rval = new ComparisonOperatorsType(); + List ops = new ArrayList( + comparisonOperators.length); + for (String name : comparisonOperators) { + ComparisonOperatorType op = new ComparisonOperatorType(); + op.setName(name); + ops.add(op); + } + rval.setComparisonOperator(ops); + return rval; + } + + /** + * @param request + * @param serviceinfo + * @return + * @throws WfsException + */ + protected FeatureTypeListType getFeatureTypes(GetCapReq request, + OgcServiceInfo serviceinfo) throws WfsException { + FeatureTypeListType rval = new FeatureTypeListType(); + // rval.setOperations(getOperations(serviceinfo)); + rval.setFeatureType(getFeatureTypes(request)); + return rval; + } + + protected List getFeatureTypes(GetCapReq request) + throws WfsException { + return translator.transform(registry.getFeatures()); + } + + /** + * @param serviceinfo + * @return + */ + protected ServiceIdentification getServiceId( + OgcServiceInfo serviceinfo) { + ServiceIdentification rval = new ServiceIdentification(); + CodeType ct = new CodeType(); + ct.setValue(SERV_TYPE); + rval.setServiceType(ct); + LanguageStringType lst = new LanguageStringType(); + lst.setValue(SERV_TITLE); + rval.setTitle(Arrays.asList(lst)); + return rval; + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/FeatureTranslator.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/FeatureTranslator.java new file mode 100644 index 0000000000..a3d7f91403 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/FeatureTranslator.java @@ -0,0 +1,145 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 27, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.v2_0_0; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.namespace.QName; + +import net.opengis.ows.v_1_1_0.KeywordsType; +import net.opengis.ows.v_1_1_0.LanguageStringType; +import net.opengis.ows.v_1_1_0.WGS84BoundingBoxType; +import net.opengis.wfs.v_2_0_0.Abstract; +import net.opengis.wfs.v_2_0_0.FeatureTypeType; +import net.opengis.wfs.v_2_0_0.Title; + +import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.request.QualifiedName; + +/** + * + * @author bclement + * @version 1.0 + */ +public class FeatureTranslator { + + public List transform(List features) { + List rval = new ArrayList( + features.size()); + for (WfsFeatureType f : features) { + rval.add(transform(f)); + } + return rval; + } + + /** + * @param source + * @return + */ + public FeatureTypeType transform(WfsFeatureType from) { + FeatureTypeType fType = new FeatureTypeType(); + QName name = transform(from.getName()); + fType.setName(name); + setTitle(fType, from); + setAbstract(fType, from); + fType.setKeywords(getAsKeywordList(from.getKeywords())); + fType.setDefaultCRS(from.getDefaultSRS()); + fType.setOtherCRS(from.getOtherSRS()); + fType.setWGS84BoundingBox(getBBox(from.getBbox())); + return fType; + } + + protected void setTitle(FeatureTypeType fType, WfsFeatureType from) { + if (from.getTitle() == null || from.getTitle().isEmpty()) { + return; + } + Title title = new Title(); + title.setValue(from.getTitle()); + fType.setTitle(Arrays.asList(title)); + } + + protected void setAbstract(FeatureTypeType fType, WfsFeatureType from) { + if (from.getAbs() == null || from.getAbs().isEmpty()) { + return; + } + Abstract abs = new Abstract(); + abs.setValue(from.getAbs()); + fType.setAbstract(Arrays.asList(abs)); + } + + protected QName transform(QualifiedName from) { + return new QName(from.getNamespace(), from.getName()); + } + + /** + * @param bbox + * @return + */ + private List getBBox(OgcGeoBoundingBox bbox) { + List rval = new LinkedList(); + WGS84BoundingBoxType to = new WGS84BoundingBoxType(); + List ur = new LinkedList(); + List ll = new LinkedList(); + ur.add(bbox.getMaxx()); + ur.add(bbox.getMaxy()); + ll.add(bbox.getMinx()); + ll.add(bbox.getMiny()); + to.setUpperCorner(ur); + to.setLowerCorner(ll); + rval.add(to); + return rval; + } + + protected List getAsKeywordList(List keywords) { + List rval = new LinkedList(); + if (keywords != null && !keywords.isEmpty()) { + KeywordsType kwType = new KeywordsType(); + kwType.setKeyword(asLangStr(keywords)); + rval.add(kwType); + } + return rval; + } + + protected List asLangStr(List strs) { + List rval = new ArrayList( + strs.size()); + for (String s : strs) { + LanguageStringType lst = new LanguageStringType(); + lst.setValue(s); + rval.add(lst); + } + return rval; + } +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java new file mode 100644 index 0000000000..f66085acfa --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java @@ -0,0 +1,1189 @@ +/* + * The following software products were developed by Raytheon: + * + * ADE (AWIPS Development Environment) software + * CAVE (Common AWIPS Visualization Environment) software + * EDEX (Environmental Data Exchange) software + * uFrame™ (Universal Framework) software + * + * Copyright (c) 2010 Raytheon Co. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/epl-v10.php + * + * + * Contractor Name: Raytheon Company + * Contractor Address: + * 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * + */ +package com.raytheon.uf.edex.wfs.v2_0_0; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import net.opengis.gml.v_3_2_1.FeaturePropertyType; +import net.opengis.ows.v_1_1_0.ExceptionReport; +import net.opengis.ows.v_1_1_0.ExceptionType; +import net.opengis.wfs.v_2_0_0.DescribeFeatureTypeType; +import net.opengis.wfs.v_2_0_0.DescribeStoredQueriesResponseType; +import net.opengis.wfs.v_2_0_0.FeatureCollectionType; +import net.opengis.wfs.v_2_0_0.GetCapabilitiesType; +import net.opengis.wfs.v_2_0_0.GetFeatureType; +import net.opengis.wfs.v_2_0_0.GetPropertyValueType; +import net.opengis.wfs.v_2_0_0.ListStoredQueriesResponseType; +import net.opengis.wfs.v_2_0_0.ListStoredQueriesType; +import net.opengis.wfs.v_2_0_0.MemberPropertyType; +import net.opengis.wfs.v_2_0_0.ObjectFactory; +import net.opengis.wfs.v_2_0_0.ParameterType; +import net.opengis.wfs.v_2_0_0.QueryType; +import net.opengis.wfs.v_2_0_0.StoredQueryDescriptionType; +import net.opengis.wfs.v_2_0_0.StoredQueryListItemType; +import net.opengis.wfs.v_2_0_0.StoredQueryType; +import net.opengis.wfs.v_2_0_0.ValueCollectionType; +import net.opengis.wfs.v_2_0_0.WFSCapabilitiesType; + +import org.apache.commons.collections.map.CaseInsensitiveMap; +import org.apache.ws.commons.schema.utils.NamespaceMap; +import org.opengis.feature.simple.SimpleFeature; +import org.springframework.context.ApplicationContext; +import org.w3.xmlschema.Schema; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.edex.core.EDEXUtil; +import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; +import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.OgcResponse.ErrorType; +import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; +import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; +import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; +import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; +import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; +import com.raytheon.uf.edex.wfs.WfsException; +import com.raytheon.uf.edex.wfs.WfsException.Code; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.provider.AbstractWfsProvider; +import com.raytheon.uf.edex.wfs.provider.FeatureDescriber; +import com.raytheon.uf.edex.wfs.provider.FeatureFetcher.CountedFeatures; +import com.raytheon.uf.edex.wfs.provider.Gml32FeatureFetcher; +import com.raytheon.uf.edex.wfs.querystore.FileSystemQueryStore; +import com.raytheon.uf.edex.wfs.querystore.IQueryStore; +import com.raytheon.uf.edex.wfs.querystore.IStoredQueryCallback; +import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; +import com.raytheon.uf.edex.wfs.request.DescFeatureTypeReq; +import com.raytheon.uf.edex.wfs.request.DescQueryReq; +import com.raytheon.uf.edex.wfs.request.FeatureQuery; +import com.raytheon.uf.edex.wfs.request.FeatureQuery.QFilterType; +import com.raytheon.uf.edex.wfs.request.GetCapReq; +import com.raytheon.uf.edex.wfs.request.GetFeatureReq; +import com.raytheon.uf.edex.wfs.request.GetFeatureReq.ResultType; +import com.raytheon.uf.edex.wfs.request.ListQueriesReq; +import com.raytheon.uf.edex.wfs.request.QualifiedName; +import com.raytheon.uf.edex.wfs.request.WfsRequest; +import com.raytheon.uf.edex.wfs.request.WfsRequest.Type; +import com.raytheon.uf.edex.wfs.soap2_0_0.util.DescribeFeatureTypeResponseType; + +public class Wfs2_0_0Provider extends AbstractWfsProvider implements + IStoredQueryCallback { + + protected final IUFStatusHandler log = UFStatus.getHandler(this.getClass()); + + public static final String version = "2.0.0"; + + public static final MimeType GML_MIME = GmlUtils.GML32_TYPE; + + protected WfsRegistryImpl registry; + + protected final Capabilities capabilities; + + protected final Gml32FeatureFetcher features; + + protected final FeatureDescriber describer; + + protected final ObjectFactory wfsFactory = new ObjectFactory(); + + protected final net.opengis.gml.v_3_2_1.ObjectFactory gmlFactory = new net.opengis.gml.v_3_2_1.ObjectFactory(); + + protected final IQueryStore queryStore; + + protected final NamespaceContext nsContext; + + public Wfs2_0_0Provider(WfsRegistryImpl registry) { + this.capabilities = new Capabilities(registry); + this.features = new Gml32FeatureFetcher(registry); + this.describer = new FeatureDescriber(registry); + this.registry = registry; + // this name must match preloaded store in utility directory + this.queryStore = new FileSystemQueryStore(registry, "wfsQueryStore"); + Map reverseNsMap = new HashMap( + WfsRegistryImpl.NS_MAP.size()); + for (Entry e : WfsRegistryImpl.NS_MAP.entrySet()) { + reverseNsMap.put(e.getValue(), e.getKey()); + } + nsContext = new NamespaceMap(reverseNsMap); + } + + /** + * Unit tests + */ + protected Wfs2_0_0Provider() { + this.capabilities = null; + this.features = null; + this.describer = null; + this.registry = null; + this.queryStore = null; + this.nsContext = null; + } + + /** + * Create an error response + * + * @param e + * @param exceptionFormat + * @return + */ + public OgcResponse getError(WfsException e, MimeType exceptionFormat) { + ExceptionType et = new ExceptionType(); + et.setExceptionCode(e.getCode().toString()); + et.setExceptionText(Arrays.asList(e.getMessage())); + ExceptionReport report = new ExceptionReport(); + report.setException(Arrays.asList(et)); + String rval = ""; + if (exceptionFormat == null) { + exceptionFormat = OgcResponse.TEXT_XML_MIME; + } + if (exceptionFormat.equalsIgnoreParams(OgcResponse.TEXT_XML_MIME)) { + try { + rval = registry.marshal(report); + } catch (JAXBException e1) { + log.error("Unable to marshal WFS response", e1); + rval = "\n"; + rval += "\n"; + rval += "" + e.getMessage() + + "\n"; + rval += "\n"; + } + } else if (exceptionFormat + .equalsIgnoreParams(OgcResponse.TEXT_HTML_MIME)) { + rval = ""; + rval += "
An error occurred performing the request:
"; + rval += "
Error Code: " + e.getCode().toString(); + rval += "
Message: " + e.getMessage() + ""; + } + OgcResponse resp = new OgcResponse(rval, exceptionFormat, TYPE.TEXT); + switch (e.getCode()) { + case OperationProcessingFailed: + resp.setError(ErrorType.INT_ERR); + break; + default: + resp.setError(ErrorType.BAD_REQ); + } + return resp; + } + + /** + * Read input stream to string + * + * @param in + * @return + * @throws IOException + */ + protected String getXml(InputStream in) throws IOException { + return new java.util.Scanner(in).useDelimiter("\\A").next(); + } + + /** + * Decode post request from input stream + * + * @param in + * @return Error-type request object if unable to decode request + */ + public WfsRequest getRequest(InputStream in) { + Object obj; + WfsRequest rval; + try { + obj = registry.unmarshal(in); + } catch (Exception e) { + log.error("Unable to decode request", e); + return getDecodeError(OgcResponse.TEXT_XML_MIME); + } + if (obj instanceof GetCapabilitiesType) { + rval = new GetCapReq((GetCapabilitiesType) obj); + } else if (obj instanceof GetFeatureType) { + try { + rval = new GetFeatureReq((GetFeatureType) obj, this); + } catch (WfsException e) { + rval = new WfsRequest(Type.ERROR); + rval.setRawrequest(e); + } + } else if (obj instanceof DescribeFeatureTypeType) { + rval = new DescFeatureTypeReq((DescribeFeatureTypeType) obj); + } else if (obj instanceof ListStoredQueriesType) { + rval = new ListQueriesReq(); + } else { + rval = getDecodeError(OgcResponse.TEXT_XML_MIME); + } + if (rval.getType() != Type.ERROR) { + rval.setRawrequest(obj); + } + return rval; + } + + /** + * Create an error-type request for decoding problems + * + * @param exceptionFormat + * @return invalid request error + */ + public WfsRequest getDecodeError(MimeType exceptionFormat) { + return getRequestError(new WfsException(Code.INVALID_REQUEST, + "Unable to decode request"), exceptionFormat); + } + + /** + * Create an error-type request. + * + * @param e + * @param exceptionFormat + * @return + */ + public WfsRequest getRequestError(WfsException e, MimeType exceptionFormat) { + OgcResponse error = getError(e, exceptionFormat); + WfsRequest rval = new WfsRequest(Type.ERROR); + rval.setRawrequest(error); + return rval; + } + + /** + * Get capabilities as object + * + * @param request + * @param serviceInfo + * @return + * @throws WfsException + */ + public WFSCapabilitiesType getCapabilities(GetCapReq request, + OgcServiceInfo serviceInfo) throws WfsException { + return capabilities.getCapabilities(request, serviceInfo); + } + + /** + * Get capabilities as object + * + * @param request + * @param info + * @return + * @throws WfsException + */ + public WFSCapabilitiesType getCapabilities(GetCapReq request, + EndpointInfo info) throws WfsException { + return capabilities.getCapabilities(request, getServiceInfo(info)); + } + + /** + * Handle get capabilities request for http servlet + * + * @param request + * @param serviceInfo + * @param resp + * @throws Exception + * on unrecoverable error that was unable to be sent via + * response + */ + public void handleCapabilities(GetCapReq request, + OgcServiceInfo serviceInfo, IOgcHttpResponse resp) + throws Exception { + try { + WFSCapabilitiesType cap = getCapabilities(request, serviceInfo); + JAXBElement rval = wfsFactory + .createWFSCapabilities(cap); + marshalResponse(rval, OgcResponse.TEXT_XML_MIME, resp); + } catch (WfsException e) { + OgcResponse response = getError(e, null); + OgcResponseOutput.sendText(response, resp); + } + } + + /** + * Build service info based on endpoint. The results of this method are not + * cache-able since it uses the hostname that the client used to reach the + * service. + * + * @param info + * @return + */ + public OgcServiceInfo getServiceInfo(EndpointInfo info) { + String base = info.getProtocol() + "://" + info.getHost(); + int port = info.getPort(); + if (port != 80) { + base += ":" + port; + } + base += info.getPath(); + OgcServiceInfo rval = new OgcServiceInfo(base); + for (WfsOpType val : WfsOpType.values()) { + rval.addOperationInfo(getOp(base, val, info)); + } + return rval; + } + + /** + * Get operation info for op type + * + * @param get + * @param post + * @param type + * @return + */ + protected OgcOperationInfo getOp(String base, WfsOpType type, + EndpointInfo info) { + OgcOperationInfo rval = new OgcOperationInfo(type); + if (!info.isPostOnly()) { + rval.setHttpGetRes(base); + } + rval.setHttpPostRes(base); + rval.addVersion(version); + rval.setPostEncoding(info.getEncoding()); + rval.addFormat(OgcResponse.TEXT_XML_MIME.toString()); + return rval; + } + + /** + * Marshal object through response. Response cannot be reused after this + * method is called. + * + * @param jaxbobject + * @param mimeType + * @param response + * @throws Exception + * on unrecoverable error attempting to send response + */ + protected void marshalResponse(Object jaxbobject, MimeType mimeType, + IOgcHttpResponse response) throws Exception { + OutputStream out = null; + try { + out = response.getOutputStream(); + response.setContentType(mimeType.toString()); + registry.marshal(jaxbobject, response.getOutputStream()); + } catch (Exception e) { + log.error("Unable to marshal WFS response", e); + OgcResponse err = getError(new WfsException( + Code.OperationProcessingFailed), null); + OgcResponseOutput.sendText(err, response, out); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * Get features as JAXB object + * + * @param request + * @param info + * @return + * @throws WfsException + * if return format isn't a supported GML version + */ + public FeatureCollectionType getFeatureGML(GetFeatureReq request, + EndpointInfo info) throws WfsException { + return getFeatureGML(request, getServiceInfo(info)); + } + + /** + * Get features as JAXB object + * + * @param request + * @param serviceinfo + * @return + * @throws WfsException + * if return format isn't a supported GML version + */ + public FeatureCollectionType getFeatureGML(GetFeatureReq request, + OgcServiceInfo serviceinfo) throws WfsException { + FeatureCollectionType featColl; + MimeType format = request.getOutputformat(); + ensureGML32(format); + featColl = wrap(features.getFeatures(request, serviceinfo, false)); + return featColl; + } + + /** + * @param format + * @throws WfsException + * if format isn't GML 3.2 + */ + public void ensureGML32(MimeType format) throws WfsException { + if (GmlUtils.isGml(format)) { + if (!GmlUtils.areCompatible(format, GML_MIME)) { + throw new WfsException(Code.InvalidParameterValue, + "Unsupported GML Version: " + format); + } + } else { + String msg = String.format( + "Output format '%s' not supported for protocol", format); + throw new WfsException(Code.InvalidParameterValue, msg); + } + } + + /** + * Wrap counted features in JAXB feature collection type + * + * @param features + * @return + */ + public FeatureCollectionType wrap( + CountedFeatures features) { + FeatureCollectionType rval = new FeatureCollectionType(); + List members = new ArrayList( + features.features.size()); + for (FeaturePropertyType feature : features.features) { + MemberPropertyType member = new MemberPropertyType(); + member.setContent(Arrays.asList((Object) feature + .getAbstractFeature())); + members.add(member); + } + rval.setMember(members); + rval.setNumberMatched(Long.toString(features.count)); + rval.setNumberReturned(new BigInteger(Integer + .toString(features.features.size()))); + return rval; + } + + /** + * Handle get feature request for http servlet. Response cannot be reused + * after this method is called. + * + * @param request + * @param serviceinfo + * @param response + * @throws Exception + * if unable to send response + */ + public void handleGetFeature(GetFeatureReq request, + OgcServiceInfo serviceinfo, IOgcHttpResponse response) + throws Exception { + FeatureCollectionType featColl; + MimeType format = request.getOutputformat(); + try { + if (GmlUtils.isGml(format)) { + if (!GmlUtils.areCompatible(format, GML_MIME)) { + throw new WfsException(Code.InvalidParameterValue, + "Unsupported GML Version: " + format); + } + // use JAXB instead of gml simple feature formatter + CountedFeatures counted = features + .getFeatures(request, serviceinfo, false); + featColl = wrap(counted); + marshalResponse(wfsFactory.createFeatureCollection(featColl), + GML_MIME, response); + } else { + if (request.getResulttype() == ResultType.hits) { + throw new WfsException(Code.InvalidParameterValue, + "Hits result not supported in format: " + format); + } + SimpleFeatureFormatter formatter = getFormatter(format); + List> res = features.getSimpleFeatures( + request, serviceinfo); + sendFormatted(formatter, res, response); + } + } catch (WfsException e) { + // this will only succeed if stream/writer haven't been extracted + // from response + OgcResponse err = getError(e, request.getExceptionFormat()); + OgcResponseOutput.output(err, response); + } + } + + /** + * Marshal simple features through response using formatter. Response cannot + * be reused after this method is called. + * + * @param formatter + * @param res + * @param response + * @throws Exception + * if unable to send response + */ + protected void sendFormatted(SimpleFeatureFormatter formatter, + List> res, IOgcHttpResponse response) + throws Exception { + OutputStream out = null; + try { + out = response.getOutputStream(); + formatter.format(res, out); + out.flush(); + } catch (Exception e) { + log.error("Problem formatting features", e); + OgcResponse err = getError(new WfsException( + Code.OperationProcessingFailed), null); + OgcResponseOutput.sendText(err, response, out); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * Find formatter for mime type + * + * @param format + * @return + * @throws WfsException + * if no matching formatter is found + */ + protected SimpleFeatureFormatter getFormatter(MimeType format) + throws WfsException { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx.getBeanNamesForType(SimpleFeatureFormatter.class); + for (String bean : beans) { + SimpleFeatureFormatter sff = (SimpleFeatureFormatter) ctx + .getBean(bean); + if (sff.matchesFormat(format)) { + return sff; + } + } + throw new WfsException(Code.InvalidParameterValue, + "Unsupported format: " + format); + } + + /** + * @param request + * @param info + * @return + * @throws WfsException + */ + public DescribeFeatureTypeResponseType describeFeatureType( + DescFeatureTypeReq request, EndpointInfo info) throws WfsException { + return describeFeatureType(request, getServiceInfo(info)); + } + + /** + * @param request + * @param serviceInfo + * @return + * @throws WfsException + */ + public DescribeFeatureTypeResponseType describeFeatureType( + DescFeatureTypeReq request, OgcServiceInfo serviceInfo) + throws WfsException { + String xml = describer.describe(request, serviceInfo); + if (xml == null) { + throw new WfsException(Code.InvalidParameterValue, + "Unknown type name(s)"); + } + try { + Schema s = (Schema) registry.unmarshal(xml); + return new DescribeFeatureTypeResponseType(s); + } catch (JAXBException e) { + throw new WfsException(Code.OperationProcessingFailed); + } + } + + /** + * Handle describe feature type request for http servlet. Response cannot be + * used after this method is called. + * + * @param request + * @param serviceInfo + * @param response + * @throws Exception + * if unable to send response + */ + public void handleDescribeFeatureType(DescFeatureTypeReq request, + OgcServiceInfo serviceInfo, IOgcHttpResponse response) + throws Exception { + try { + String xml = describer.describe(request, serviceInfo); + if (xml == null) { + throw new WfsException(Code.INVALID_REQUEST, + "Unknown type name(s)"); + } + OgcResponse ogcResp = new OgcResponse(xml, GML_MIME, TYPE.TEXT); + OgcResponseOutput.output(ogcResp, response); + } catch (WfsException e) { + OgcResponse ogcResp = getError(e, null); + OgcResponseOutput.sendText(ogcResp, response); + } + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.WfsProvider#getVersion() + */ + @Override + public String getVersion() { + return version; + } + + /** + * @param headers + * @return + * @throws OgcException + * if unable to decode request + */ + protected WfsRequest getRequestFromHeaders(Map headers) + throws OgcException { + WfsRequest rval = null; + getExceptionFormat(headers); + String req = OgcHttpHandler.getString(headers, REQUEST_HEADER); + if (req.equalsIgnoreCase(CAP_PARAM)) { + rval = new GetCapReq(); + } else if (req.equalsIgnoreCase(DESC_PARAM)) { + rval = buildDescFeatureReq(headers); + } else if (req.equalsIgnoreCase(GET_PARAM)) { + rval = buildGetFeatureReq(headers); + } else if (req.equalsIgnoreCase(LIST_QUERY_PARAM)) { + rval = new ListQueriesReq(); + } else if (req.equalsIgnoreCase(DESC_QUERY_PARAM)) { + String[] ids = OgcHttpHandler.getStringArr(headers, + QUERY_IDS_HEADER); + if (ids == null) { + ids = new String[0]; + } + rval = new DescQueryReq(Arrays.asList(ids)); + } + + if (rval == null) { + throw new OgcException(OgcException.Code.InvalidRequest, + "Unable to decode request"); + } + + return rval; + } + + /** + * Get and validate exception format + * + * @param headers + * @return XML format if no exception format is specified + * @throws OgcException + * if format is invalid + */ + protected MimeType getExceptionFormat(Map headers) + throws OgcException { + String exFormatStr = OgcHttpHandler.getString(headers, + EXCEP_FORMAT_HEADER); + MimeType rval; + if (exFormatStr == null || exFormatStr.isEmpty()) { + rval = OgcResponse.TEXT_XML_MIME; + } else { + try { + rval = new MimeType(exFormatStr); + } catch (IllegalArgumentException e) { + throw new OgcException(OgcException.Code.InvalidParameterValue, + e.getMessage()); + } + } + if (!rval.equalsIgnoreParams(OgcResponse.TEXT_HTML_MIME) + && !rval.equalsIgnoreParams(OgcResponse.TEXT_XML_MIME)) { + throw new OgcException(OgcException.Code.InvalidParameterValue, + "exceptions parameter invalid"); + } + return rval; + } + + /** + * @param headers + * @return + * @throws OgcException + */ + protected GetFeatureReq buildGetFeatureReq(Map headers) + throws OgcException { + GetFeatureReq rval = new GetFeatureReq(); + String resType = OgcHttpHandler.getString(headers, RESTYPE_HEADER); + if (resType != null) { + ResultType valueOf = GetFeatureReq.ResultType.valueOf(resType); + if (valueOf != null) { + rval.setResulttype(valueOf); + } + } + Integer max = OgcHttpHandler.getInt(headers, MAXFEAT_HEADER); + if (max != null) { + rval.setMaxFeatures(max); + } + MimeType outputformat = OgcHttpHandler.getMimeType(headers, + OUTFORMAT_HEADER); + if (outputformat != null) { + rval.setOutputformat(outputformat); + } + Map nsmap = getNameSpaceMap(headers); + String[] bboxes = splitOnParens(BBOX_HEADER, headers); + String[] filters = splitOnParens(FILTER_HEADER, headers); + String[] sorts = splitOnParens(SORTBY_HEADER, headers); + String[] props = splitOnParens(PROPNAME_HEADER, headers); + String[] srsnames = splitOnParens(SRSNAME_HEADER, headers); + String[] types = OgcHttpHandler.getStringArr(headers, TYPENAME_HEADER); + if (types == null) { + types = new String[0]; + } + for (int i = 0; i < types.length; ++i) { + FeatureQuery fq = new FeatureQuery(); + if (bboxes.length > 0) { + fq.setFilter(getBoundingBox(bboxes[i]), QFilterType.BBOX); + } else if (filters.length > 0) { + fq.setFilter(filters[i], QFilterType.XML); + } + fq.setTypeNames(getTypeNames(types[i], nsmap)); + if (i < sorts.length) { + fq.setSortBys(getSortBys(sorts[i])); + } + if (i < props.length) { + fq.setPropertyNames(Arrays.asList(splitOnComma(props[i]))); + } + if (i < srsnames.length) { + fq.setSrsName(srsnames[i]); + } + rval.addQuery(fq); + } + String storedQueryId = OgcHttpHandler.getString(headers, + QUERY_IDS_HEADER); + if (storedQueryId != null) { + throw new OgcException( + com.raytheon.uf.edex.ogc.common.OgcException.Code.InvalidRequest, + "Stored Query not supported for GET method"); + } + return rval; + } + + /** + * @param headers + * @return + * @throws OgcException + */ + protected DescFeatureTypeReq buildDescFeatureReq(Map headers) + throws OgcException { + DescFeatureTypeReq rval = new DescFeatureTypeReq(); + String outputformat = OgcHttpHandler.getString(headers, + OUTFORMAT_HEADER); + if (outputformat != null) { + rval.setOutputformat(outputformat); + } + String typename = OgcHttpHandler.getString(headers, TYPENAME_HEADER); + if (typename != null) { + Map nsmap = getNameSpaceMap(headers); + rval.setTypenames(getTypeNames(typename, nsmap)); + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.WfsProvider#handlePost(java.io.InputStream, + * com.raytheon.uf.edex.ogc.common.http.EndpointInfo, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void handlePost(InputStream body, EndpointInfo info, + IOgcHttpResponse response) throws Exception { + WfsRequest request = getRequest(body); + handleInternal(request, info, response); + } + + /** + * @param request + * @param info + * @param response + * @throws Exception + */ + protected void handleInternal(WfsRequest request, EndpointInfo info, + IOgcHttpResponse response) throws Exception { + OgcServiceInfo serviceInfo = getServiceInfo(info); + OgcResponse err = null; + switch (request.getType()) { + case GetCapabilities: + handleCapabilities((GetCapReq) request, serviceInfo, response); + break; + case DescribeFeature: + handleDescribeFeatureType((DescFeatureTypeReq) request, + serviceInfo, response); + break; + case GetFeature: + handleGetFeature((GetFeatureReq) request, serviceInfo, response); + break; + case ListStoredQueries: + handleListQueries((ListQueriesReq) request, serviceInfo, response); + break; + case DescribeStoredQueries: + handleDescQueries((DescQueryReq) request, serviceInfo, response); + case ERROR: + err = (OgcResponse) request.getRawrequest(); + break; + default: + if (err == null) { + err = getError(new WfsException(Code.INVALID_REQUEST, + "Unsupported request: " + request.getType()), null); + } + OgcResponseOutput.output(err, response); + } + } + + /** + * @param request + * @param serviceInfo + * @param response + * @throws Exception + */ + private void handleDescQueries(DescQueryReq request, + OgcServiceInfo serviceInfo, IOgcHttpResponse response) + throws Exception { + try { + DescribeStoredQueriesResponseType descriptions = describeQueries( + request, serviceInfo); + try { + marshalResponse(descriptions, GML_MIME, response); + } catch (Exception e) { + log.error("Unable to marshal response", e); + throw new WfsException(Code.OperationProcessingFailed); + } + } catch (WfsException e) { + OgcResponse ogcResp = getError(e, null); + OgcResponseOutput.sendText(ogcResp, response); + } + } + + /** + * Describe stored queries + * + * @param request + * @param info + * @return + * @throws WfsException + */ + public DescribeStoredQueriesResponseType describeQueries( + DescQueryReq request, EndpointInfo info) throws WfsException { + return describeQueries(request, getServiceInfo(info)); + } + + /** + * Describe stored queries + * + * @param request + * @param info + * @return + * @throws WfsException + */ + public DescribeStoredQueriesResponseType describeQueries( + DescQueryReq request, OgcServiceInfo info) + throws WfsException { + DescribeStoredQueriesResponseType rval = new DescribeStoredQueriesResponseType(); + List ids = request.getIds(); + if (ids.isEmpty()) { + try { + ids = queryStore.list(); + } catch (OgcException e) { + log.error("Problem getting queries", e); + throw new WfsException(Code.OperationProcessingFailed); + } + } + List descriptions = new ArrayList( + ids.size()); + for (String id : ids) { + try { + StoredQueryDescriptionType desc = queryStore.retrieve(id); + if (desc == null) { + throw new WfsException(Code.InvalidParameterValue, + "Unable to find query with id: " + id); + } + descriptions.add(desc); + } catch (OgcException e) { + log.error("problem retrieving query", e); + throw new WfsException(Code.OperationProcessingFailed); + } + } + rval.setStoredQueryDescription(descriptions); + return rval; + } + + /** + * List stored queries + * + * @param request + * @param serviceInfo + * @param response + * @throws Exception + */ + private void handleListQueries(ListQueriesReq request, + OgcServiceInfo serviceInfo, IOgcHttpResponse response) + throws Exception { + try { + ListStoredQueriesResponseType queries = listQueries(serviceInfo); + try { + marshalResponse(queries, GML_MIME, response); + } catch (Exception e) { + log.error("Unable to marshal response", e); + throw new WfsException(Code.OperationProcessingFailed); + } + } catch (WfsException e) { + OgcResponse ogcResp = getError(e, null); + OgcResponseOutput.sendText(ogcResp, response); + } + } + + /** + * List stored queries + * + * @param info + * @return + * @throws WfsException + */ + public ListStoredQueriesResponseType listQueries(EndpointInfo info) + throws WfsException { + return listQueries(getServiceInfo(info)); + } + + /** + * List stored queries + * + * @param serviceInfo + * @return + * @throws WfsException + */ + public ListStoredQueriesResponseType listQueries( + OgcServiceInfo serviceInfo) throws WfsException { + ListStoredQueriesResponseType rval = new ListStoredQueriesResponseType(); + List ids; + try { + ids = queryStore.list(); + } catch (OgcException e) { + log.error("Unable to list stored queries", e); + throw new WfsException(Code.OperationProcessingFailed); + } + List queries = new ArrayList( + ids.size()); + for (String id : ids) { + StoredQueryListItemType item = new StoredQueryListItemType(); + item.setId(id); + queries.add(item); + } + rval.setStoredQuery(queries); + return rval; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.WfsProvider#handleGet(java.util.Map, + * com.raytheon.uf.edex.ogc.common.http.EndpointInfo, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void handleGet(Map headers, EndpointInfo info, + IOgcHttpResponse response) throws Exception { + WfsRequest req; + try { + req = getRequestFromHeaders(headers); + } catch (OgcException e) { + req = getRequestError(new WfsException(e), + OgcResponse.TEXT_XML_MIME); + } + handleInternal(req, info, response); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.querystore.StoredQueryCallback#getQueries(net + * .opengis.wfs.v_2_0_0.StoredQueryType) + */ + @Override + public List getQueries(StoredQueryType sqt) + throws WfsException { + String id = sqt.getId(); + List params = sqt.getParameter(); + Map paramMap = getQueryParams(params); + try { + List res = queryStore.resolve(id, paramMap); + if (res.isEmpty()) { + throw new WfsException(Code.InvalidParameterValue, + "Unknown query id: " + id); + } + List rval = new ArrayList(res.size()); + for (QueryType qt : res) { + FeatureQuery fq = new FeatureQuery(qt); + List qnames = fq.getTypeNames(); + if (qnames.isEmpty()) { + fq.setTypeNames(getAllFeatureTypes()); + } + rval.add(fq); + } + return rval; + } catch (OgcException e) { + log.error("Problem resolving stored query", e); + // TODO this could be a problem with the input, return better error + throw new WfsException(Code.OperationProcessingFailed); + } + } + + /** + * @return a list of all feature type names + */ + private List getAllFeatureTypes() { + List features = registry.getFeatures(); + List rval = new ArrayList(features.size()); + for (WfsFeatureType feature : features) { + rval.add(feature.getName()); + } + return rval; + } + + /** + * Extract parameter types into string map + * + * @param params + * @return + * @throws WfsException + */ + @SuppressWarnings("unchecked") + private Map getQueryParams(List params) + throws WfsException { + Map rval = new CaseInsensitiveMap(params.size()); + for (ParameterType param : params) { + String key = param.getName(); + if (!param.isSetContent() || param.getContent().isEmpty()) { + throw new WfsException(Code.MissingParameterValue, + "Parameter content cannot be empty"); + } + Object object = param.getContent().get(0); + if (object instanceof JAXBElement) { + try { + String xml = registry.marshal(object, true); + rval.put(key, xml); + } catch (JAXBException e) { + log.error("Problem marshalling parameter value", e); + // is it possible that this isn't our fault? + throw new WfsException(Code.OperationProcessingFailed); + } + } else { + rval.put(key, object.toString()); + } + } + return rval; + } + + /** + * Get property values from features + * + * @param request + * @param info + * @return + * @throws Exception + */ + public ValueCollectionType getPropertyValues(GetPropertyValueType request, + EndpointInfo info) throws WfsException { + OgcServiceInfo serviceinfo = getServiceInfo(info); + GetFeatureReq featReq = new GetFeatureReq(request, this); + MimeType format = featReq.getOutputformat(); + ensureGML32(format); + CountedFeatures counted = features.getFeatures( + featReq, serviceinfo, false); + return getValues(counted, request); + } + + /** + * Extract property values form features using request + * + * @param counted + * @param request + * @return + * @throws WfsException + */ + private ValueCollectionType getValues( + CountedFeatures counted, + GetPropertyValueType request) throws WfsException { + ValueCollectionType rval = new ValueCollectionType(); + XPath xpath = XPathFactory.newInstance().newXPath(); + xpath.setNamespaceContext(nsContext); + List values = new ArrayList( + counted.features.size()); + for (FeaturePropertyType prop : counted.features) { + try { + Node node = registry.marshalToNode(prop.getAbstractFeature()); + NodeList nlist = (NodeList) xpath.evaluate( + request.getValueReference(), node, + XPathConstants.NODESET); + for (int i = 0; i < nlist.getLength(); ++i) { + MemberPropertyType member = new MemberPropertyType(); + member.setContent(Arrays.asList((Object) nlist.item(i))); + values.add(member); + } + } catch (JAXBException e) { + log.error("problem converting feature to Node", e); + throw new WfsException(Code.OperationProcessingFailed); + } catch (ParserConfigurationException e) { + log.error("problem converting feature to Node", e); + throw new WfsException(Code.OperationProcessingFailed); + } catch (XPathExpressionException e) { + String msg; + Throwable t = e; + do { + msg = t.getMessage(); + t = t.getCause(); + } while (msg == null); + throw new WfsException(Code.InvalidParameterValue, + "Invalid XPath expression: " + msg); + } + } + rval.setMember(values); + return rval; + } + + /** + * @return the registry + */ + public WfsRegistryImpl getRegistry() { + return registry; + } + + /** + * @return the features + */ + public Gml32FeatureFetcher getFeatures() { + return features; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/WfsOperationsDescriber.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/WfsOperationsDescriber.java new file mode 100644 index 0000000000..75dcb35d1e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/WfsOperationsDescriber.java @@ -0,0 +1,94 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.v2_0_0; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import net.opengis.ows.v_1_1_0.DomainType; + +import com.raytheon.uf.edex.ogc.common.AbstractOpDescriber; +import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; +import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; +import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; + +/** + * TODO Add Description + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * May 21, 2013            bclement     Initial creation
+ *
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class WfsOperationsDescriber extends AbstractOpDescriber { + + private final List constraints = new ArrayList(14); + + public WfsOperationsDescriber() { + constraints.add(getAsDomainType("ImplementsBasicWFS", "TRUE")); + constraints.add(getAsDomainType("ImplementsTransactionalWFS", "FALSE")); + constraints.add(getAsDomainType("ImplementsLockingWFS", "FALSE")); + constraints.add(getAsDomainType("KVPEncoding", "TRUE")); + constraints.add(getAsDomainType("XMLEncoding", "TRUE")); + constraints.add(getAsDomainType("SOAPEncoding", "TRUE")); + constraints.add(getAsDomainType("ImplementsInheritance", "FALSE")); + constraints.add(getAsDomainType("ImplementsRemoteResolve", "FALSE")); + constraints.add(getAsDomainType("ImplementsResultPaging", "FALSE")); + constraints.add(getAsDomainType("ImplementsStandardJoins", "FALSE")); + constraints.add(getAsDomainType("ImplementsSpatialJoins", "FALSE")); + constraints.add(getAsDomainType("ImplementsTemporalJoins", "FALSE")); + constraints + .add(getAsDomainType("ImplementsFeatureVersioning", "FALSE")); + constraints.add(getAsDomainType("ManageStoredQueries", "FALSE")); + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.AbstractOpDescriber#getParams(com.raytheon.uf.edex.ogc.common.OgcServiceInfo) + */ + @Override + protected List getParams(OgcServiceInfo serviceinfo) { + // TODO this info should be passed in from somewhere + return Arrays.asList(getAsDomainType("srsName", + Arrays.asList("EPSG:4326"))); + } + + /* (non-Javadoc) + * @see com.raytheon.uf.edex.ogc.common.AbstractOpDescriber#getOpParams(com.raytheon.uf.edex.ogc.common.OgcOperationInfo) + */ + @Override + protected List getOpParams(OgcOperationInfo op) { + return Arrays.asList( + getAsDomainType("AcceptVersions", op.getVersions()), + getAsDomainType("AcceptFormats", op.getFormats())); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.AbstractOpDescriber#getConstraints(com + * .raytheon.uf.edex.ogc.common.OgcServiceInfo) + */ + @Override + protected List getConstraints( + OgcServiceInfo serviceinfo) { + return constraints; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/AbstractWxxm32Translator.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/AbstractWxxm32Translator.java new file mode 100644 index 0000000000..44d13aba5b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/AbstractWxxm32Translator.java @@ -0,0 +1,624 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.wxxm; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.measure.converter.UnitConverter; +import javax.measure.unit.NonSI; +import javax.measure.unit.SI; +import javax.measure.unit.Unit; +import javax.xml.bind.JAXBElement; + +import net.opengis.gml.v_3_2_1.AbstractGeometryType; +import net.opengis.gml.v_3_2_1.AbstractTimeObjectType; +import net.opengis.gml.v_3_2_1.CodeWithAuthorityType; +import net.opengis.gml.v_3_2_1.DirectPositionType; +import net.opengis.gml.v_3_2_1.FeaturePropertyType; +import net.opengis.gml.v_3_2_1.LocationPropertyType; +import net.opengis.gml.v_3_2_1.PointType; +import net.opengis.gml.v_3_2_1.TimeInstantType; +import net.opengis.gml.v_3_2_1.TimePositionType; +import net.opengis.om.v_1_0_0_gml32.ProcessPropertyType; +import net.opengis.swe.v_1_0_1_gml32.PhenomenonPropertyType; +import net.opengis.swe.v_1_0_1_gml32.TimeObjectPropertyType; + +import com.eurocontrol.avwx.v_1_1_1.AirspaceType; +import com.eurocontrol.avwx.v_1_1_1.ObjectFactory; +import com.eurocontrol.wx.v_1_1_1.AirTemperatureType; +import com.eurocontrol.wx.v_1_1_1.ObservationType; +import com.eurocontrol.wx.v_1_1_1.PressureType; +import com.eurocontrol.wx.v_1_1_1.UomAngleType; +import com.eurocontrol.wx.v_1_1_1.UomDistanceType; +import com.eurocontrol.wx.v_1_1_1.UomPressureType; +import com.eurocontrol.wx.v_1_1_1.UomSpeedType; +import com.eurocontrol.wx.v_1_1_1.UomTemperatureType; +import com.eurocontrol.wx.v_1_1_1.VerticalDistanceType; +import com.eurocontrol.wx.v_1_1_1.WeatherIntensityType; +import com.eurocontrol.wx.v_1_1_1.WindDirectionType; +import com.eurocontrol.wx.v_1_1_1.WindSpeedType; +import com.raytheon.uf.common.dataplugin.IDecoderGettable.Amount; +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.PathManagerFactory; +import com.raytheon.uf.common.pointdata.spatial.AircraftObsLocation; +import com.raytheon.uf.common.pointdata.spatial.SurfaceObsLocation; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; +import com.raytheon.uf.edex.ogc.common.db.LayerTransformer; +import com.raytheon.uf.edex.ogc.common.gml3_2_1.GeometryConverter; +import com.raytheon.uf.edex.plugin.dataset.urn.URNLookup; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.reg.AbstractWfsSource; +import com.raytheon.uf.edex.wfs.request.QualifiedName; +import com.vividsolutions.jts.geom.Geometry; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 27, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public abstract class AbstractWxxm32Translator + implements IPdoWxxmTranslator { + + protected final Class pdoClass; + + public static final String version = "3.2.1"; + + protected static final ObjectFactory avFactory = new ObjectFactory(); + + protected static final com.eurocontrol.wx.v_1_1_1.ObjectFactory wxFactory = new com.eurocontrol.wx.v_1_1_1.ObjectFactory(); + + protected static final GeometryConverter geoConverter = new GeometryConverter(); + + protected static final net.opengis.gml.v_3_2_1.ObjectFactory gmlFactory = new net.opengis.gml.v_3_2_1.ObjectFactory(); + + protected static final net.opengis.om.v_1_0_0_gml32.ObjectFactory omFactory = new net.opengis.om.v_1_0_0_gml32.ObjectFactory(); + + protected static final net.opengis.swe.v_1_0_1_gml32.ObjectFactory sweFactory = new net.opengis.swe.v_1_0_1_gml32.ObjectFactory(); + + // FIXME + public static final String AIRCRAFT_URN = ""; + + // FIXME + public static final String AIRFRAME_URN = ""; + + // FIXME + public static final String FLIGHT_URN = ""; + + public static final double DEFAULT_NULL_VALUE = -9999; + + protected JAXBElement sample; + + protected static final String GEOM_KEY = "location"; + + protected static final String TIME_KEY = "time"; + + protected static final String TEMP_KEY = "temperature"; + + protected static final String WND_DIR_KEY = "windspeed"; + + protected static final String WND_SPD_KEY = "winddir"; + + protected static final String PRESS_KEY = "pressure"; + + protected static final String TURB_KEY = "turbulence"; + + protected static final String ICE_KEY = "icing"; + + protected static final String DPT_KEY = "dewpoint"; + + protected static final String TAIL_KEY = "tailnumber"; + + protected static final String STATION_KEY = "stationid"; + + protected static final String ALTITUDE_KEY = "altitude"; + + protected static final String FLIGHT_KEY = "flightnumber"; + + protected static final String DEFAULT_WXXM_TIME_FIELD = "airspaceWxObservation.observation.samplingTime"; + + protected static final String DEFAULT_PDO_TIME_FIELD = "dataTime.refTime"; + + protected static final Map intensityMap; + + static { + Map map = new HashMap(); + map.put("", WeatherIntensityType.NONE); + map.put("NEG", WeatherIntensityType.NONE); + map.put("SMOOTHLGT", WeatherIntensityType.LIGHT); + map.put("TRACE", WeatherIntensityType.LIGHT); + map.put("TRACELGT", WeatherIntensityType.LIGHT); + map.put("LGT", WeatherIntensityType.LIGHT); + map.put("LGTMOD", WeatherIntensityType.LIGHT_MODERATE); + map.put("MOD", WeatherIntensityType.MODERATE); + map.put("MODSEV", WeatherIntensityType.MODERATE_SEVERE); + map.put("SEV", WeatherIntensityType.SEVERE); + map.put("EXTRM", WeatherIntensityType.SEVERE); + intensityMap = Collections.unmodifiableMap(map); + } + + protected static final String AIRSPACE_OBSERVED_PROPERTY = "http://www.eurocontrol.int/ont/avwx/1.1/wx.owl#AirspaceWx"; + + protected static final String AERODROME_OBSERVED_PROPERTY = "http://www.eurocontrol.int/ont/avwx/1.1/wx.owl#AerodromeWx"; + + private static IUFStatusHandler statusHandler = UFStatus + .getHandler(AbstractWxxm32Translator.class); + + /** + * + */ + public AbstractWxxm32Translator(Class pdoClass, JAXBElement sample) { + this.pdoClass = pdoClass; + this.sample = sample; + } + + protected static Map loadFieldMap(String path) { + Map map = new HashMap(); + + // Always have the default time mapped + map.put(DEFAULT_WXXM_TIME_FIELD, DEFAULT_PDO_TIME_FIELD); + InputStream in = null; + try { + // read the rest from the file path param + IPathManager pathMgr = PathManagerFactory.getPathManager(); + LocalizationContext edexStaticBase = pathMgr.getContext( + LocalizationContext.LocalizationType.EDEX_STATIC, + LocalizationContext.LocalizationLevel.BASE); + + File fieldMapFile = pathMgr.getFile(edexStaticBase, path); + + Properties fieldprops = new Properties(); + in = new FileInputStream(fieldMapFile); + fieldprops.load(in); + + for (String xpath : fieldprops.stringPropertyNames()) { + map.put(xpath, fieldprops.getProperty(xpath)); + } + } catch (Exception e) { + statusHandler.error("Problem initializing field map", e); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + } + } + } + + return map; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.PdoGmlTranslator#translate(com.raytheon. + * uf.common.dataplugin.PluginDataObject[]) + */ + @SuppressWarnings("unchecked") + @Override + public ArrayList> translate(PluginDataObject[] pdos) + throws Exception { + if (pdos == null) { + return new ArrayList>(0); + } + ArrayList> rval = new ArrayList>( + pdos.length); + for (PluginDataObject pdo : pdos) { + if (pdoClass.isAssignableFrom(pdo.getClass())) { + rval.add(translate((T) pdo)); + } + } + return rval; + } + + /** + * Translate pdo into GML 3.2.1 WXXM Object + * + * @param pdo + * @return + * @throws Exception + */ + public abstract JAXBElement translate(T pdo) throws Exception; + + protected double getNullValue() { + return DEFAULT_NULL_VALUE; + } + + /** + * Create a new code from string and code space + * + * @param str + * @param codeSpace + * @return + */ + protected CodeWithAuthorityType asCode(String str, String codeSpace) { + CodeWithAuthorityType rval = new CodeWithAuthorityType(); + rval.setValue(str); + rval.setCodeSpace(codeSpace); + return rval; + } + + /** + * Converts to Pascals if needed + * + * @param amount + * @return null if amount is null + */ + protected PressureType getPressure(Amount amount) { + if (amount == null) { + return null; + } + double value = amount.getValue().doubleValue(); + Unit unit = amount.getUnit(); + UnitConverter converter = unit.getConverterTo(SI.PASCAL); + double paValue = converter.convert(value); + PressureType rval = new PressureType(); + rval.setValue(paValue); + rval.setUom(UomPressureType.PA); + return rval; + } + + /** + * @param value + * @param uom + * @return null if value is null + */ + protected Amount createAmount(Double value, Unit uom) { + if (value == null) { + return null; + } + return new Amount(value, uom); + } + + /** + * @param value + * @param uom + * @return null if value is null + */ + protected Amount createAmount(Integer value, Unit uom) { + if (value == null) { + return null; + } + return new Amount(value, uom); + } + + /** + * Assumes Celsius units + * + * @param value + * @return null if value equal to {@link #NULL_VALUE} + */ + protected AirTemperatureType getAirTemp(Double value) { + return getAirTemp(value, UomTemperatureType.C); + } + + /** + * @param value + * @param uom + * @return null if value equal to {@link #NULL_VALUE} + */ + protected AirTemperatureType getAirTemp(Double value, UomTemperatureType uom) { + if (value == null || value == getNullValue()) { + return null; + } + AirTemperatureType rval = new AirTemperatureType(); + rval.setUom(UomTemperatureType.C); + rval.setValue(value); + return rval; + } + + /** + * Converts amount to Celcius if needed + * + * @param amount + * @return null if amount is null + */ + protected AirTemperatureType getAirTemp(Amount amount) { + if (amount == null) { + return null; + } + double value = amount.getValue().doubleValue(); + Unit unit = amount.getUnit(); + UnitConverter converter = unit.getConverterTo(SI.CELSIUS); + double celValue = converter.convert(value); + return getAirTemp(celValue, UomTemperatureType.C); + } + + /** + * Converts amount to Knots if needed + * + * @param amount + * @return null if amount is null + */ + protected WindSpeedType getWindSpeed(Amount amount) { + if (amount == null) { + return null; + } + double value = amount.getValue().doubleValue(); + Unit unit = amount.getUnit(); + UnitConverter converter = unit.getConverterTo(NonSI.KNOT); + double knotVal = converter.convert(value); + WindSpeedType rval = new WindSpeedType(); + rval.setValue(knotVal); + rval.setUom(UomSpeedType.KT); + return rval; + } + + /** + * Converts to degrees if needed + * + * @param amount + * @return null if amount is null + */ + protected WindDirectionType getWindDir(Amount amount) { + if (amount == null) { + return null; + } + double value = amount.getValue().doubleValue(); + Unit unit = amount.getUnit(); + UnitConverter converter = unit.getConverterTo(NonSI.DEGREE_ANGLE); + double degValue = converter.convert(value); + WindDirectionType rval = new WindDirectionType(); + rval.setValue(degValue); + rval.setUom(UomAngleType.DEG); + return rval; + } + + /** + * Wrap reference time in time object property type + * + * @param pdo + * @return + */ + protected TimeObjectPropertyType getRefTime(PluginDataObject pdo) { + DataTime time = pdo.getDataTime(); + Date refTime = time.getRefTime(); + TimeObjectPropertyType rval = new TimeObjectPropertyType(); + TimeInstantType inst = new TimeInstantType(); + TimePositionType pos = new TimePositionType(); + String formatted = LayerTransformer.format(refTime); + pos.setValue(Arrays.asList(formatted)); + inst.setTimePosition(pos); + JAXBElement timeObj = gmlFactory + .createAbstractTimeObject(inst); + rval.setAbstractTimeObject(timeObj); + return rval; + } + + /** + * Get flight level as vertical distance + * + * @param value + * @return null if value is null + */ + protected VerticalDistanceType getFlightLevel(Integer value) { + if (value == null) { + return null; + } + VerticalDistanceType rval = new VerticalDistanceType(); + rval.setValue(value); + rval.setUom(UomDistanceType.FL); + return rval; + } + + /** + * Converts to feet if needed + * + * @param amount + * @return null if amount is null + */ + protected VerticalDistanceType getVertDist(Amount amount) { + if (amount == null) { + return null; + } + double value = amount.getValue().doubleValue(); + Unit unit = amount.getUnit(); + UnitConverter converter = unit.getConverterTo(NonSI.FOOT); + double ftValue = converter.convert(value); + VerticalDistanceType rval = new VerticalDistanceType(); + rval.setValue(ftValue); + rval.setUom(UomDistanceType.FT); + return rval; + } + + protected JAXBElement asLocation(Geometry geom) { + LocationPropertyType lpt = new LocationPropertyType(); + AbstractGeometryType geomType = geoConverter.convert(geom); + JAXBElement gElem = gmlFactory + .createAbstractGeometry(geomType); + lpt.setAbstractGeometry(gElem); + return gmlFactory.createLocation(lpt); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.PdoGmlTranslator#getVersion() + */ + @Override + public String getVersion() { + return version; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.wxxm.PdoWxxmTranslator#getFeatureType() + */ + @Override + public WfsFeatureType getFeatureType() { + QualifiedName name = new QualifiedName(sample.getName()); + String crs = AbstractWfsSource.defaultCRS; + OgcGeoBoundingBox bbox = AbstractWfsSource.fullBbox; + return new WfsFeatureType(name, name.getName(), crs, bbox); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.wxxm.PdoWxxmTranslator#getRecordClass() + */ + @Override + public Class getRecordClass() { + return pdoClass; + } + + /** + * Create a ProcessPropertyType referencing an external document/type + * + * @param urn + * the process urn to reference + * @return + */ + public ProcessPropertyType createProcedure(String href) { + ProcessPropertyType process = omFactory.createProcessPropertyType(); + process.setHref(href); + return process; + } + + /** + * Create a PhenomenonPropertyType referencing an external document/type + * + * @param href + * @return + */ + public PhenomenonPropertyType createObservedProperty(String href) { + PhenomenonPropertyType property = sweFactory + .createPhenomenonPropertyType(); + property.setHref(href); + return property; + } + + /** + * @param aircraftObsLocation + * @return + */ + protected FeaturePropertyType createFeatureOfInterest( + AircraftObsLocation aircraftLocation) { + return createFeatureOfInterest(aircraftLocation.getLatitude(), + aircraftLocation.getLongitude(), + aircraftLocation.getFlightLevel()); + } + + /** + * @param aircraftObsLocation + * @return + */ + protected FeaturePropertyType createFeatureOfInterest( + SurfaceObsLocation surfaceLocation) { + return createFeatureOfInterest(surfaceLocation.getLatitude(), + surfaceLocation.getLongitude(), surfaceLocation.getElevation()); + } + + /** + * @param aircraftObsLocation + * @return + */ + protected FeaturePropertyType createFeatureOfInterest(double latitude, + double longitude, Integer altitudeMSL) { + FeaturePropertyType feature = gmlFactory.createFeaturePropertyType(); + + // create gml location + DirectPositionType directPositionType = gmlFactory + .createDirectPositionType(); + + // determine number of dimensions + int dims = altitudeMSL == null ? 2 : 3; + + // TODO - Bad hard-coded srs, can we get this from the data itself? + if (dims == 2) { + directPositionType.setAxisLabels(Arrays.asList("Latitude", + "Longitude")); + directPositionType.setSrsName("urn:ogc:def:crs:EPSG::4326"); + directPositionType.setSrsDimension(new BigInteger("2")); + directPositionType.setValue(Arrays.asList(new Double(latitude), + new Double(longitude))); + } else { + directPositionType.setAxisLabels(Arrays.asList("Latitude", + "Longitude", "Altitude")); + directPositionType + .setSrsName("urn:ogc:def:crs:EPSG::4326_plus_z_in_m_AMSL"); + directPositionType.setSrsDimension(new BigInteger("3")); + + // TODO - convert from meters MSL to meters above ellipsoid + directPositionType.setValue(Arrays.asList(new Double(latitude), + new Double(longitude), new Double(altitudeMSL))); + } + + PointType pointType = gmlFactory.createPointType(); + pointType.setPos(directPositionType); + pointType.setSrsName(directPositionType.getSrsName()); + pointType.setSrsDimension(directPositionType.getSrsDimension()); + pointType.setAxisLabels(directPositionType.getAxisLabels()); + JAXBElement point = gmlFactory.createPoint(pointType); + + LocationPropertyType locationPropertyType = gmlFactory + .createLocationPropertyType(); + locationPropertyType.setAbstractGeometry(point); + JAXBElement location = gmlFactory + .createLocation(locationPropertyType); + + AirspaceType airspaceType = avFactory.createAirspaceType(); + airspaceType.setLocation(location); + JAXBElement airspace = avFactory + .createAirspace(airspaceType); + + feature.setAbstractFeature(airspace); + return feature; + } + + /** + * Add procedure, observed property, and feature of interest to observation + * + * @param obs + * @param location + */ + protected void addAircraftObsInformation(ObservationType obs, + AircraftObsLocation location) { + // Add procedure, this is currently the same in AIREP, PIREP and ACARS + String procedure = URNLookup.getAircraftReportURN(); + obs.setProcedure(createProcedure(procedure)); + // Add observed property + // This is potentially from the ontology, like + // http://www.eurocontrol.int/ont/avwx/1.1/wx.owl#AirspaceWx + obs.setObservedProperty(createObservedProperty(AIRSPACE_OBSERVED_PROPERTY)); + // add feature of interest, for pirep we are using aircraft location + obs.setFeatureOfInterest(createFeatureOfInterest(location)); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/IPdoWxxmTranslator.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/IPdoWxxmTranslator.java new file mode 100644 index 0000000000..59749ff713 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/IPdoWxxmTranslator.java @@ -0,0 +1,43 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.wxxm; + +import java.util.Map; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.reg.IPdoGmlTranslator; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 13, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public interface IPdoWxxmTranslator extends IPdoGmlTranslator { + + public WfsFeatureType getFeatureType(); + + public Class getRecordClass(); + + public Map getFieldMap(); + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/WxxmWfsSource.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/WxxmWfsSource.java new file mode 100644 index 0000000000..1aa65bba77 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/wxxm/WxxmWfsSource.java @@ -0,0 +1,128 @@ +/** + * Copyright 09/24/12 Raytheon Company. + * + * Unlimited Rights + * This software was developed pursuant to Contract Number + * DTFAWA-10-D-00028 with the US Government. The US Government’s rights + * in and to this copyrighted software are as specified in DFARS + * 252.227-7014 which was made part of the above contract. + */ +package com.raytheon.uf.edex.wfs.wxxm; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.map.CaseInsensitiveMap; + +import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.dataplugin.PluginProperties; +import com.raytheon.uf.edex.ogc.common.db.SimpleLayer; +import com.raytheon.uf.edex.ogc.common.db.SingleLayerCollector; +import com.raytheon.uf.edex.ogc.common.feature.FeatureFactory; +import com.raytheon.uf.edex.wfs.WfsFeatureType; +import com.raytheon.uf.edex.wfs.reg.IPdoGmlTranslator; +import com.raytheon.uf.edex.wfs.reg.PluginWfsSource; +import com.raytheon.uf.edex.wfs.request.QualifiedName; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 13, 2012            bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ + +public abstract class WxxmWfsSource extends PluginWfsSource { + + private final Map> classMap; + + private final Map fieldMap; + + /** + * @param props + * @param key + * @param translators + * @param featFactory + */ + @SuppressWarnings("unchecked") + public WxxmWfsSource(PluginProperties props, String key, + List translators, FeatureFactory featFactory, + SingleLayerCollector, PluginDataObject> collector) { + super(props, key, convert(translators), featFactory, collector); + classMap = new HashMap>(translators.size()); + fieldMap = new CaseInsensitiveMap(); + for (IPdoWxxmTranslator trans : translators) { + WfsFeatureType ft = trans.getFeatureType(); + classMap.put(ft.getName(), trans.getRecordClass()); + if (trans.getFieldMap() != null) { + fieldMap.putAll(trans.getFieldMap()); + } + } + } + + private static List convert(List list) { + return new ArrayList(list); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.AbstractWfsSource#getJaxbClasses() + */ + @Override + public Class[] getJaxbClasses() { + // we are using WXXM jaxb classes + return new Class[0]; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.AbstractWfsSource#listFeatureTypes() + */ + @Override + public List getFeatureTypes() { + Collection values = translatorMap.values(); + List rval = new ArrayList(values.size()); + for (IPdoGmlTranslator trans : values) { + IPdoWxxmTranslator wxTrans = (IPdoWxxmTranslator) trans; + rval.add(wxTrans.getFeatureType()); + } + return rval; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wfs.reg.AbstractWfsSource#getFeatureEntity(com.raytheon + * .uf.edex.wfs.request.QualifiedName) + */ + @Override + public Class getFeatureEntity(QualifiedName feature) { + return classMap.get(feature); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wfs.reg.AbstractWfsSource#getFieldMap() + */ + @Override + public Map getFieldMap() { + return fieldMap; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/utility/edex_static/base/wfsQueryStore/urn%3aogc%3adef%3aquery%3aOGC-WFS%3a%3aGetFeatureById b/edexOsgi/com.raytheon.uf.edex.wfs/utility/edex_static/base/wfsQueryStore/urn%3aogc%3adef%3aquery%3aOGC-WFS%3a%3aGetFeatureById new file mode 100644 index 0000000000..0dc04758e4 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wfs/utility/edex_static/base/wfsQueryStore/urn%3aogc%3adef%3aquery%3aOGC-WFS%3a%3aGetFeatureById @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wms/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.wms/META-INF/MANIFEST.MF index 8a3497590e..862ec68b5f 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.wms/META-INF/MANIFEST.MF @@ -21,7 +21,9 @@ Require-Bundle: com.raytheon.edex.common;bundle-version="1.12.1174", com.raytheon.uf.edex.database, org.apache.commons.codec;bundle-version="1.4.0", org.apache.commons.collections;bundle-version="3.2.0", - com.raytheon.uf.common.spatial;bundle-version="1.0.0" + com.raytheon.uf.common.spatial;bundle-version="1.0.0", + org.eclipse.jetty;bundle-version="7.6.9", + com.raytheon.uf.common.status;bundle-version="1.12.1174" Import-Package: com.raytheon.uf.common.colormap, com.raytheon.uf.common.time.util, com.raytheon.uf.edex.ogc.common, @@ -29,8 +31,7 @@ Import-Package: com.raytheon.uf.common.colormap, com.raytheon.uf.edex.ogc.common.db, com.raytheon.uf.edex.ogc.common.http, javax.servlet, - javax.servlet.http, - org.apache.commons.logging + javax.servlet.http Export-Package: com.raytheon.uf.edex.wms, com.raytheon.uf.edex.wms.format, com.raytheon.uf.edex.wms.provider, diff --git a/edexOsgi/com.raytheon.uf.edex.wms/overview.uml b/edexOsgi/com.raytheon.uf.edex.wms/overview.uml new file mode 100644 index 0000000000..160db458f7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wms/overview.uml @@ -0,0 +1,41 @@ +@startuml + +package "EDEX WMS Component" { + [WMS HTTP Endpoint] as wmshttp + + [WMS 1.3.0 Provider] as wms130 + + () "WMS Source" as isrc + + [WMS Source Accessor] as reg + + [Abstract Coverage WMS Source] as covsrc + [Abstract Feature WMS Source] as featsrc + + [Styled Layer Descriptor (SLD) Styler] as fstyle + [Colormap Data Styler] as cstyle +} + +node "EDEX Feature Data Plug-in Adapter" { + [Plug-in WMS Source] as fsrc +} + +node "EDEX Coverage Data Plug-in Adapter" { + [Plug-in WMS Source] as csrc +} + +wmshttp *-- wms130 + +reg o-- "*" isrc + +wms130 *-- reg + +isrc -- covsrc +isrc -- featsrc +csrc -left-|> covsrc +fsrc -left-|> featsrc + +cstyle *-left- covsrc +featsrc *-right- fstyle + +@enduml \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/BaseRequest.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/BaseRequest.java index d1d40b1e5e..deeefd3119 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/BaseRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/BaseRequest.java @@ -32,7 +32,8 @@ package com.raytheon.uf.edex.wms; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; -import com.raytheon.uf.edex.wms.WmsProvider.WmsOpType; +import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.edex.wms.IWmsProvider.WmsOpType; /** * @@ -43,13 +44,13 @@ public class BaseRequest { protected String version; - protected String format; + protected MimeType format; protected String userName; protected String[] roles; - protected String exceptionFormat = "text/xml"; + protected MimeType exceptionFormat = OgcResponse.TEXT_XML_MIME; protected String updateSequence; @@ -62,7 +63,7 @@ public class BaseRequest { // TODO Auto-generated constructor stub } - public BaseRequest(String version, String format, String userName, + public BaseRequest(String version, MimeType format, String userName, String[] roles) { super(); this.version = version; @@ -72,7 +73,7 @@ public class BaseRequest { } @SuppressWarnings("unchecked") - public OgcResponse execute(WmsProvider provider) { + public OgcResponse execute(IWmsProvider provider) { return provider.getCapabilities((BaseRequest) this); } @@ -94,7 +95,7 @@ public class BaseRequest { /** * @return the format */ - public String getFormat() { + public MimeType getFormat() { return format; } @@ -102,14 +103,14 @@ public class BaseRequest { * @param format * the format to set */ - public void setFormat(String format) { + public void setFormat(MimeType format) { this.format = format; } /** * @return the exceptionFormat */ - public String getExceptionFormat() { + public MimeType getExceptionFormat() { return exceptionFormat; } @@ -117,7 +118,7 @@ public class BaseRequest { * @param exceptionFormat * the exceptionFormat to set */ - public void setExceptionFormat(String exceptionFormat) { + public void setExceptionFormat(MimeType exceptionFormat) { this.exceptionFormat = exceptionFormat; } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetFeatureInfoRequest.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetFeatureInfoRequest.java index 9be259626b..fa16b21946 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetFeatureInfoRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetFeatureInfoRequest.java @@ -31,6 +31,7 @@ package com.raytheon.uf.edex.wms; import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * @@ -39,89 +40,89 @@ import com.raytheon.uf.edex.ogc.common.OgcResponse; */ public class GetFeatureInfoRequest extends GetMapRequest { - protected String[] reqLayers; + protected String[] reqLayers; - protected int featureCount = 1; + protected int featureCount = 1; - protected Integer i; + protected Integer i; - protected Integer j; + protected Integer j; - protected String infoFormat; + protected MimeType infoFormat; - public GetFeatureInfoRequest() { - } + public GetFeatureInfoRequest() { + } - public GetFeatureInfoRequest(GetMapRequest mapRequest, String[] reqLayers, - Integer i, Integer j, String infoFormat) { - super(mapRequest); - this.reqLayers = reqLayers; - this.i = i; - this.j = j; - this.infoFormat = infoFormat; - } + public GetFeatureInfoRequest(GetMapRequest mapRequest, String[] reqLayers, + Integer i, Integer j, MimeType infoFormat) { + super(mapRequest); + this.reqLayers = reqLayers; + this.i = i; + this.j = j; + this.infoFormat = infoFormat; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.BaseRequest#execute(com.raytheon.uf.edex.wms - * .WmsProvider) - */ - @Override - public OgcResponse execute(WmsProvider provider) { - return provider.getFeatureInfo(this); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.BaseRequest#execute(com.raytheon.uf.edex.wms + * .WmsProvider) + */ + @Override + public OgcResponse execute(IWmsProvider provider) { + return provider.getFeatureInfo(this); + } - public GetMapRequest getMapRequest() { - return this; - } + public GetMapRequest getMapRequest() { + return this; + } - public int getFeatureCount() { - return featureCount; - } + public int getFeatureCount() { + return featureCount; + } - public void setFeatureCount(int featureCount) { - this.featureCount = featureCount; - } + public void setFeatureCount(int featureCount) { + this.featureCount = featureCount; + } - public Integer getI() { - return i; - } + public Integer getI() { + return i; + } - public void setI(Integer i) { - this.i = i; - } + public void setI(Integer i) { + this.i = i; + } - public Integer getJ() { - return j; - } + public Integer getJ() { + return j; + } - public void setJ(Integer j) { - this.j = j; - } + public void setJ(Integer j) { + this.j = j; + } - /** - * @return the reqLayers - */ - public String[] getReqLayers() { - return reqLayers; - } + /** + * @return the reqLayers + */ + public String[] getReqLayers() { + return reqLayers; + } - /** - * @param reqLayers - * the reqLayers to set - */ - public void setReqLayers(String[] reqLayers) { - this.reqLayers = reqLayers; - } + /** + * @param reqLayers + * the reqLayers to set + */ + public void setReqLayers(String[] reqLayers) { + this.reqLayers = reqLayers; + } - public String getInfoFormat() { - return infoFormat; - } + public MimeType getInfoFormat() { + return infoFormat; + } - public void setInfoFormat(String infoFormat) { - this.infoFormat = infoFormat; - } + public void setInfoFormat(MimeType infoFormat) { + this.infoFormat = infoFormat; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetLegendGraphicRequest.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetLegendGraphicRequest.java index 1ebac5b186..09488a36ee 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetLegendGraphicRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetLegendGraphicRequest.java @@ -27,250 +27,250 @@ import java.util.Map; import org.geotools.styling.StyledLayerDescriptor; import com.raytheon.uf.edex.ogc.common.OgcResponse; -import com.raytheon.uf.edex.wms.WmsProvider.WmsOpType; +import com.raytheon.uf.edex.wms.IWmsProvider.WmsOpType; public class GetLegendGraphicRequest extends BaseRequest { - protected String layer; + protected String layer; - protected String style; + protected String style; - protected Integer width; + protected Integer width; - protected Integer height; + protected Integer height; - protected String time; + protected String time; - protected String elevation; + protected String elevation; - protected Map dimensions; + protected Map dimensions; - protected StyledLayerDescriptor sld; + protected StyledLayerDescriptor sld; - protected String rule; + protected String rule; - protected String scale; + protected String scale; - protected String featureType; + protected String featureType; - protected Boolean transparent; + protected Boolean transparent; - protected String bgcolor; + protected String bgcolor; - public GetLegendGraphicRequest(GetLegendGraphicRequest req) { - this.layer = req.getLayer(); - this.style = req.getStyle(); - this.width = req.getWidth(); - this.height = req.getHeight(); - this.time = req.time; - this.elevation = req.elevation; - this.dimensions = req.dimensions; - this.sld = req.getSld(); - this.rule = req.getRule(); - this.scale = req.getScale(); - this.featureType = req.getFeatureType(); - } + public GetLegendGraphicRequest(GetLegendGraphicRequest req) { + this.layer = req.getLayer(); + this.style = req.getStyle(); + this.width = req.getWidth(); + this.height = req.getHeight(); + this.time = req.time; + this.elevation = req.elevation; + this.dimensions = req.dimensions; + this.sld = req.getSld(); + this.rule = req.getRule(); + this.scale = req.getScale(); + this.featureType = req.getFeatureType(); + } - public GetLegendGraphicRequest(String layer, String style, Integer width, - Integer height, String time, String elevation, - Map dimensions, StyledLayerDescriptor sld, - String rule, String scale, String featureType) { - this.layer = layer; - this.style = style; - this.width = width; - this.height = height; - this.time = time; - this.elevation = elevation; - this.dimensions = dimensions; - this.sld = sld; - this.rule = rule; - this.scale = scale; - this.featureType = featureType; - } + public GetLegendGraphicRequest(String layer, String style, Integer width, + Integer height, String time, String elevation, + Map dimensions, StyledLayerDescriptor sld, + String rule, String scale, String featureType) { + this.layer = layer; + this.style = style; + this.width = width; + this.height = height; + this.time = time; + this.elevation = elevation; + this.dimensions = dimensions; + this.sld = sld; + this.rule = rule; + this.scale = scale; + this.featureType = featureType; + } - /** - * @return the layers - */ - public String getLayer() { - return layer; - } + /** + * @return the layers + */ + public String getLayer() { + return layer; + } - /** - * @param layers - * the layers to set - */ - public void setLayer(String layer) { - this.layer = layer; - } + /** + * @param layers + * the layers to set + */ + public void setLayer(String layer) { + this.layer = layer; + } - /** - * @return the styles - */ - public String getStyle() { - return style; - } + /** + * @return the styles + */ + public String getStyle() { + return style; + } - /** - * @param styles - * the styles to set - */ - public void setStyle(String style) { - this.style = style; - } + /** + * @param styles + * the styles to set + */ + public void setStyle(String style) { + this.style = style; + } - /** - * @return the width - */ - public Integer getWidth() { - return width; - } + /** + * @return the width + */ + public Integer getWidth() { + return width; + } - /** - * @param width - * the width to set - */ - public void setWidth(Integer width) { - this.width = width; - } + /** + * @param width + * the width to set + */ + public void setWidth(Integer width) { + this.width = width; + } - /** - * @return the height - */ - public Integer getHeight() { - return height; - } + /** + * @return the height + */ + public Integer getHeight() { + return height; + } - /** - * @param height - * the height to set - */ - public void setHeight(Integer height) { - this.height = height; - } + /** + * @param height + * the height to set + */ + public void setHeight(Integer height) { + this.height = height; + } - /** - * @return the time - */ - public String getTime() { - return time; - } + /** + * @return the time + */ + public String getTime() { + return time; + } - /** - * @param time - * the time to set - */ - public void setTime(String time) { - this.time = time; - } + /** + * @param time + * the time to set + */ + public void setTime(String time) { + this.time = time; + } - /** - * @return the elevation - */ - public String getElevation() { - return elevation; - } + /** + * @return the elevation + */ + public String getElevation() { + return elevation; + } - /** - * @param elevation - * the elevation to set - */ - public void setElevation(String elevation) { - this.elevation = elevation; - } + /** + * @param elevation + * the elevation to set + */ + public void setElevation(String elevation) { + this.elevation = elevation; + } - /** - * @return the dimensions - */ - public Map getDimensions() { - return dimensions; - } + /** + * @return the dimensions + */ + public Map getDimensions() { + return dimensions; + } - /** - * @param dimensions - * the dimensions to set - */ - public void setDimensions(Map dimensions) { - this.dimensions = dimensions; - } + /** + * @param dimensions + * the dimensions to set + */ + public void setDimensions(Map dimensions) { + this.dimensions = dimensions; + } - /** - * @return the sld - */ - public StyledLayerDescriptor getSld() { - return sld; - } + /** + * @return the sld + */ + public StyledLayerDescriptor getSld() { + return sld; + } - /** - * @param sld - * the sld to set - */ - public void setSld(StyledLayerDescriptor sld) { - this.sld = sld; - } + /** + * @param sld + * the sld to set + */ + public void setSld(StyledLayerDescriptor sld) { + this.sld = sld; + } - public String getRule() { - return rule; - } + public String getRule() { + return rule; + } - public void setRule(String rule) { - this.rule = rule; - } + public void setRule(String rule) { + this.rule = rule; + } - public String getScale() { - return scale; - } + public String getScale() { + return scale; + } - public void setScale(String scale) { - this.scale = scale; - } + public void setScale(String scale) { + this.scale = scale; + } - public String getFeatureType() { - return featureType; - } + public String getFeatureType() { + return featureType; + } - public void setFeatureType(String featureType) { - this.featureType = featureType; - } + public void setFeatureType(String featureType) { + this.featureType = featureType; + } - /** - * @return the transparent - */ - public Boolean getTransparent() { - return transparent; - } + /** + * @return the transparent + */ + public Boolean getTransparent() { + return transparent; + } - /** - * @param transparent - * the transparent to set - */ - public void setTransparent(Boolean transparent) { - this.transparent = transparent; - } + /** + * @param transparent + * the transparent to set + */ + public void setTransparent(Boolean transparent) { + this.transparent = transparent; + } - /** - * @return the bgcolor - */ - public String getBgcolor() { - return bgcolor; - } + /** + * @return the bgcolor + */ + public String getBgcolor() { + return bgcolor; + } - /** - * @param bgcolor - * the bgcolor to set - */ - public void setBgcolor(String bgcolor) { - this.bgcolor = bgcolor; - } + /** + * @param bgcolor + * the bgcolor to set + */ + public void setBgcolor(String bgcolor) { + this.bgcolor = bgcolor; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.BaseRequest#execute(com.raytheon.uf.edex.wms - * .WmsProvider) - */ - @Override - public OgcResponse execute(WmsProvider provider) { - return provider.getLegendGraphic(this); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.BaseRequest#execute(com.raytheon.uf.edex.wms + * .WmsProvider) + */ + @Override + public OgcResponse execute(IWmsProvider provider) { + return provider.getLegendGraphic(this); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetMapRequest.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetMapRequest.java index d6505dc3cb..0ca71562bb 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetMapRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/GetMapRequest.java @@ -29,7 +29,7 @@ import java.util.Map; import org.geotools.styling.StyledLayerDescriptor; import com.raytheon.uf.edex.ogc.common.OgcResponse; -import com.raytheon.uf.edex.wms.WmsProvider.WmsOpType; +import com.raytheon.uf.edex.wms.IWmsProvider.WmsOpType; /** * @@ -38,176 +38,176 @@ import com.raytheon.uf.edex.wms.WmsProvider.WmsOpType; */ public class GetMapRequest extends BaseRequest { - protected String[] layers; + protected String[] layers; - protected String[] styles; + protected String[] styles; - protected String crs; + protected String crs; - protected String bbox; + protected String bbox; - protected Integer width; + protected Integer width; - protected Integer height; + protected Integer height; - protected Boolean transparent; + protected Boolean transparent; - protected String bgcolor; + protected String bgcolor; - protected String time; + protected String[] times; - protected String elevation; + protected String elevation; - protected Map dimensions; + protected Map dimensions; - protected StyledLayerDescriptor sld; + protected StyledLayerDescriptor sld; - public GetMapRequest() { - } + public GetMapRequest() { + } - public GetMapRequest(GetMapRequest req) { - super(req.getVersion(), req.getFormat(), req.getUserName(), req - .getRoles()); - this.layers = req.getLayers(); - this.styles = req.getStyles(); - this.crs = req.getCrs(); - this.crs = req.crs; - this.bbox = req.bbox; - this.width = req.width; - this.height = req.height; - this.transparent = req.transparent; - this.bgcolor = req.bgcolor; - this.time = req.time; - this.elevation = req.elevation; - this.dimensions = req.dimensions; - this.sld = req.sld; - } + public GetMapRequest(GetMapRequest req) { + super(req.getVersion(), req.getFormat(), req.getUserName(), req + .getRoles()); + this.layers = req.getLayers(); + this.styles = req.getStyles(); + this.crs = req.getCrs(); + this.crs = req.crs; + this.bbox = req.bbox; + this.width = req.width; + this.height = req.height; + this.transparent = req.transparent; + this.bgcolor = req.bgcolor; + this.times = req.times; + this.elevation = req.elevation; + this.dimensions = req.dimensions; + this.sld = req.sld; + } - public GetMapRequest(String[] layers, String[] styles, String crs, - String bbox, Integer width, Integer height, Boolean transparent, - String bgcolor, String time, String elevation, - Map dimensions, StyledLayerDescriptor sld) { - super(); - this.layers = layers; - this.styles = styles; - this.crs = crs; - this.bbox = bbox; - this.width = width; - this.height = height; - this.transparent = transparent; - this.bgcolor = bgcolor; - this.time = time; - this.elevation = elevation; - this.dimensions = dimensions; - this.sld = sld; - } + public GetMapRequest(String[] layers, String[] styles, String crs, + String bbox, Integer width, Integer height, Boolean transparent, + String bgcolor, String[] times, String elevation, + Map dimensions, StyledLayerDescriptor sld) { + super(); + this.layers = layers; + this.styles = styles; + this.crs = crs; + this.bbox = bbox; + this.width = width; + this.height = height; + this.transparent = transparent; + this.bgcolor = bgcolor; + this.times = times; + this.elevation = elevation; + this.dimensions = dimensions; + this.sld = sld; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.BaseRequest#execute(com.raytheon.uf.edex.wms - * .WmsProvider) - */ - @Override - public OgcResponse execute(WmsProvider provider) { - return provider.getMap(this); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.BaseRequest#execute(com.raytheon.uf.edex.wms + * .WmsProvider) + */ + @Override + public OgcResponse execute(IWmsProvider provider) { + return provider.getMap(this); + } - public String[] getLayers() { - return layers; - } + public String[] getLayers() { + return layers; + } - public void setLayers(String[] layers) { - this.layers = layers; - } + public void setLayers(String[] layers) { + this.layers = layers; + } - public String[] getStyles() { - return styles; - } + public String[] getStyles() { + return styles; + } - public void setStyles(String[] styles) { - this.styles = styles; - } + public void setStyles(String[] styles) { + this.styles = styles; + } - public Integer getWidth() { - return width; - } + public Integer getWidth() { + return width; + } - public void setWidth(Integer width) { - this.width = width; - } + public void setWidth(Integer width) { + this.width = width; + } - public Integer getHeight() { - return height; - } + public Integer getHeight() { + return height; + } - public void setHeight(Integer height) { - this.height = height; - } + public void setHeight(Integer height) { + this.height = height; + } - public Boolean getTransparent() { - return transparent; - } + public Boolean getTransparent() { + return transparent; + } - public void setTransparent(Boolean transparent) { - this.transparent = transparent; - } + public void setTransparent(Boolean transparent) { + this.transparent = transparent; + } - public String getBgcolor() { - return bgcolor; - } + public String getBgcolor() { + return bgcolor; + } - public void setBgcolor(String bgcolor) { - this.bgcolor = bgcolor; - } + public void setBgcolor(String bgcolor) { + this.bgcolor = bgcolor; + } - public String getTime() { - return time; - } + public String[] getTimes() { + return times; + } - public void setTime(String time) { - this.time = time; - } + public void setTimes(String[] times) { + this.times = times; + } - public String getElevation() { - return elevation; - } + public String getElevation() { + return elevation; + } - public void setElevation(String elevation) { - this.elevation = elevation; - } + public void setElevation(String elevation) { + this.elevation = elevation; + } - public Map getDimensions() { - return dimensions; - } + public Map getDimensions() { + return dimensions; + } - public void setDimensions(Map dimensions) { - this.dimensions = dimensions; - } + public void setDimensions(Map dimensions) { + this.dimensions = dimensions; + } - public StyledLayerDescriptor getSld() { - return sld; - } + public StyledLayerDescriptor getSld() { + return sld; + } - public void setSld(StyledLayerDescriptor sld) { - this.sld = sld; - } + public void setSld(StyledLayerDescriptor sld) { + this.sld = sld; + } - public String getCrs() { - return crs; - } + public String getCrs() { + return crs; + } - public void setCrs(String crs) { - this.crs = crs; - } + public void setCrs(String crs) { + this.crs = crs; + } - public String getBbox() { - return bbox; - } + public String getBbox() { + return bbox; + } - public void setBbox(String bbox) { - this.bbox = bbox; - } + public void setBbox(String bbox) { + this.bbox = bbox; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/IWmsProvider.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/IWmsProvider.java new file mode 100644 index 0000000000..9cb0758d91 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/IWmsProvider.java @@ -0,0 +1,58 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + * + * + **********************************************************************/ +package com.raytheon.uf.edex.wms; + +import java.io.InputStream; + +import com.raytheon.uf.edex.ogc.common.OgcResponse; +import com.raytheon.uf.edex.ogc.common.http.MimeType; + +/** + * Interface for WMS provider + * + * SOFTWARE HISTORY + * + * Date Ticket# Engineer Description + * ------------ ---------- ----------- -------------------------- + * Apr 22, 2011 bclement Initial creation + * Aug 18, 2013 #2097 dhladky renamed for standards + */ +public interface IWmsProvider { + + public static final String WMS_NAME = "WMS"; + + public enum WmsOpType { + GetCapabilities, GetMap, GetFeatureInfo, GetLegendGraphic + } + + public OgcResponse getCapabilities(BaseRequest req); + + public OgcResponse getMap(GetMapRequest req); + + public OgcResponse getError(WmsException e, MimeType exceptionFormat); + + public OgcResponse handlePost(InputStream in); + + public OgcResponse getFeatureInfo(GetFeatureInfoRequest req); + + public OgcResponse getLegendGraphic(GetLegendGraphicRequest req); +} diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/WmsHttpHandler.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/WmsHttpHandler.java index 2a481d0435..b182870d88 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/WmsHttpHandler.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/WmsHttpHandler.java @@ -33,492 +33,462 @@ import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.map.CaseInsensitiveMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.geotools.styling.StyledLayerDescriptor; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.ogc.common.OgcException; +import com.raytheon.uf.edex.ogc.common.OgcException.Code; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.ogc.common.feature.JsonFeatureFormatter; +import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; import com.raytheon.uf.edex.ogc.common.http.OgcHttpRequest; -import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; -import com.raytheon.uf.edex.wms.WmsException.Code; -import com.raytheon.uf.edex.wms.WmsProvider.WmsOpType; +import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; +import com.raytheon.uf.edex.ogc.common.output.ServletOgcResponse; +import com.raytheon.uf.edex.wms.IWmsProvider.WmsOpType; import com.raytheon.uf.edex.wms.format.GmlFeatureFormatter; import com.raytheon.uf.edex.wms.format.HtmlFeatureFormatter; import com.raytheon.uf.edex.wms.sld.SldParser; import com.raytheon.uf.edex.wms.sld.SldParserRegistry; import com.vividsolutions.jts.geom.Envelope; -public class WmsHttpHandler implements OgcHttpHandler { +public class WmsHttpHandler extends OgcHttpHandler { - public static final String REQUEST_HEADER = "request"; + public static final String REQUEST_HEADER = "request"; - public static final String SLD_HEADER = "sld"; + public static final String SLD_HEADER = "sld"; - public static final String SLD_VERSION_HEADER = "sld_version"; + public static final String SLD_VERSION_HEADER = "sld_version"; - public static final String SLD_BODY_HEADER = "sld_body"; + public static final String SLD_BODY_HEADER = "sld_body"; - public static final String VERSION_HEADER = "version"; + public static final String VERSION_HEADER = "version"; - public static final String FORMAT_HEADER = "format"; + public static final String FORMAT_HEADER = "format"; - public static final String UPDATESEQ_HEADER = "updatesequence"; + public static final String UPDATESEQ_HEADER = "updatesequence"; - public static final String LAYERS_HEADER = "layers"; + public static final String LAYERS_HEADER = "layers"; - public static final String STYLES_HEADER = "styles"; + public static final String STYLES_HEADER = "styles"; - public static final String CRS_HEADER = "crs"; + public static final String CRS_HEADER = "crs"; - public static final String BBOX_HEADER = "bbox"; + public static final String BBOX_HEADER = "bbox"; - public static final String WIDTH_HEADER = "width"; + public static final String WIDTH_HEADER = "width"; - public static final String HEIGHT_HEADER = "height"; + public static final String HEIGHT_HEADER = "height"; - public static final String TRANSPARENT_HEADER = "transparent"; + public static final String TRANSPARENT_HEADER = "transparent"; - public static final String BGCOLOR_HEADER = "bgcolor"; + public static final String BGCOLOR_HEADER = "bgcolor"; - public static final String TIME_HEADER = "time"; + public static final String TIME_HEADER = "time"; - public static final String ELEVATION_HEADER = "elevation"; + public static final String ELEVATION_HEADER = "elevation"; - public static final String MIME_HEADER = "Content-Type"; + public static final String MIME_HEADER = "Content-Type"; - public static final String QLAYERS_HEADER = "query_layers"; + public static final String QLAYERS_HEADER = "query_layers"; - public static final String FCOUNT_HEADER = "feature_count"; + public static final String FCOUNT_HEADER = "feature_count"; - public static final String IFORMAT_HEADER = "info_format"; + public static final String IFORMAT_HEADER = "info_format"; - public static final String I_HEADER = "i"; + public static final String I_HEADER = "i"; - public static final String J_HEADER = "j"; + public static final String J_HEADER = "j"; - public static final String LAYER_HEADER = "layer"; + public static final String LAYER_HEADER = "layer"; - public static final String STYLE_HEADER = "style"; + public static final String STYLE_HEADER = "style"; - public static final String RULE_HEADER = "rule"; + public static final String RULE_HEADER = "rule"; - public static final String SCALE_HEADER = "scale"; + public static final String SCALE_HEADER = "scale"; - public static final String FEATURE_TYPE_HEADER = "feature_type"; + public static final String FEATURE_TYPE_HEADER = "feature_type"; - protected static final String CAP_PARAM = "getcapabilities"; + public static final String CAP_PARAM = "getcapabilities"; - protected static final String MAP_PARAM = "getmap"; + public static final String MAP_PARAM = "getmap"; - protected static final String FEAT_PARAM = "getfeatureinfo"; + public static final String FEAT_PARAM = "getfeatureinfo"; - protected static final String LEG_PARAM = "getlegendgraphic"; + public static final String LEG_PARAM = "getlegendgraphic"; - protected WmsProvider provider; + protected IWmsProvider provider; - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected SldParserRegistry sldRegistry; + protected SldParserRegistry sldRegistry; - public WmsHttpHandler(WmsProvider provider, SldParserRegistry sldRegistry) { - this.provider = provider; - this.sldRegistry = sldRegistry; - } + public WmsHttpHandler(IWmsProvider provider, SldParserRegistry sldRegistry) { + this.provider = provider; + this.sldRegistry = sldRegistry; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler#handle(javax.servlet - * .http.HttpServletRequest, javax.servlet.http.HttpServletResponse, - * java.util.Map) - */ - @Override - public void handle(OgcHttpRequest request) { - try { - handleInternal(request); - } catch (Exception e) { - log.error("Unable to handle request", e); - } - } - - protected void handleInternal(OgcHttpRequest ogcRequest) throws Exception { - HttpServletResponse response = ogcRequest.getResponse(); - if (ogcRequest.isPost()) { - InputStream is = ogcRequest.getInputStream(); - sendResponse(response, provider.handlePost(is)); - return; - } - Map headers = ogcRequest.getHeaders(); - String exceptionFormat = getString(headers.get(EXCEP_FORMAT_HEADER)); - if (exceptionFormat == null || exceptionFormat.isEmpty()) { - exceptionFormat = OgcResponse.TEXT_XML_MIME; - } - OgcResponse rval; - - rval = validateExceptionFormat(exceptionFormat); - if (rval != null) { - sendResponse(response, rval); - } - - Object obj = headers.get(REQUEST_HEADER); - if (obj instanceof String) { - String reqName = (String) obj; - rval = getResponse(reqName, ogcRequest.getRequest(), headers); - } else { - rval = handleError(new WmsException(Code.MissingParameterValue, - "Missing parameter: " + REQUEST_HEADER), exceptionFormat); - } - sendResponse(response, rval); - } - - /** - * @param exceptionFormat - * @return - */ - private OgcResponse validateExceptionFormat(String exceptionFormat) { - WmsException ex = validateExceptionFormatAsException(exceptionFormat); - if (ex != null) { - return provider.getError(ex, OgcResponse.TEXT_XML_MIME); - } - return null; - } - - private WmsException validateExceptionFormatAsException( - String exceptionFormat) { - if (!exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_HTML_MIME) - && !exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_XML_MIME) - && !exceptionFormat - .equalsIgnoreCase(OgcResponse.APP_VND_OGC_SE_XML)) { - new WmsException(Code.InvalidParameterValue, - "exceptions parameter invalid"); - } - return null; - } - - protected OgcResponse getResponse(String reqName, - HttpServletRequest request, Map headers) { - BaseRequest req; - OgcResponse rval; - String exceptionFormat = getString(headers.get(EXCEP_FORMAT_HEADER)); - if (exceptionFormat == null || exceptionFormat.isEmpty()) { - exceptionFormat = OgcResponse.TEXT_XML_MIME; - } - try { - req = getRequest(reqName, request, headers); - if (req != null) { - req.setVersion(getString(headers.get(VERSION_HEADER))); - req.setFormat(getString(headers.get(FORMAT_HEADER))); - req.setUpdateSequence(getString(headers.get(UPDATESEQ_HEADER))); - req.setUserName(getString(headers.get(USER_HEADER))); - req.setRoles(getStringArr(headers.get(ROLES_HEADER))); - req.setExceptionFormat(exceptionFormat); - rval = req.execute(provider); - } else { - throw new WmsException(Code.OperationNotSupported, - "No such operation: " + reqName); - } - } catch (WmsException e) { - rval = handleError(e, exceptionFormat); - } - return rval; - } - - protected BaseRequest getRequest(String reqName, - HttpServletRequest request, Map headers) - throws WmsException { - BaseRequest req = null; - if (reqName.equalsIgnoreCase(CAP_PARAM)) { - req = getBaseRequest(request, headers); - } else if (reqName.equalsIgnoreCase(MAP_PARAM)) { - req = parseMapRequest(headers); - } else if (reqName.equalsIgnoreCase(FEAT_PARAM)) { - req = getFeatureInfoReq(headers); - } else if (reqName.equalsIgnoreCase(LEG_PARAM)) { - req = getLegendGraphicReq(headers); - } - - return req; - } - - protected BaseRequest getBaseRequest(HttpServletRequest request, - Map headers) { - OgcServiceInfo serviceInfo = getServiceInfo(request); - BaseRequest req = new BaseRequest(); - req.setServiceinfo(serviceInfo); - return req; - } - - /** - * @param request - */ - private OgcServiceInfo getServiceInfo(HttpServletRequest request) { - int port = request.getServerPort(); - String base = "http://" + request.getServerName(); - if (port != 80) { - base += ":" + port; - } - base += "/wms"; - OgcServiceInfo rval = new OgcServiceInfo(base); - - OgcOperationInfo cap = new OgcOperationInfo( - WmsOpType.GetCapabilities); - cap.setHttpGetRes(base + "?request=" + CAP_PARAM); - cap.addFormat("text/xml"); - rval.addOperationInfo(cap); - - OgcOperationInfo map = new OgcOperationInfo( - WmsOpType.GetMap); - map.setHttpGetRes(base + "?request=" + MAP_PARAM); - map.addFormat("image/gif"); - map.addFormat("image/png"); - // map.addFormat("image/tiff"); - map.addFormat("image/jpeg"); - rval.addOperationInfo(map); - - OgcOperationInfo info = new OgcOperationInfo( - WmsOpType.GetFeatureInfo); - info.setHttpGetRes(base + "?request=" + FEAT_PARAM); - List formats = Arrays.asList(GmlFeatureFormatter.mimeType, - JsonFeatureFormatter.mimeType, HtmlFeatureFormatter.mimeType); - info.setFormats(formats); - rval.addOperationInfo(info); - - OgcOperationInfo legend = new OgcOperationInfo( - WmsOpType.GetLegendGraphic); - legend.setHttpGetRes(base + "?request=" + LEG_PARAM); - legend.addFormat("image/gif"); - legend.addFormat("image/png"); - legend.addFormat("image/jpeg"); - rval.addOperationInfo(legend); - - return rval; - } - - /** - * @param headers - * @return - * @throws WmsException - */ - protected GetFeatureInfoRequest getFeatureInfoReq( - Map headers) throws WmsException { - // TODO lookup provider based on version - // String version = getString(headers.get(VERSION_HEADER)); - GetMapRequest mapReq = parseMapRequest(headers); - - String[] layers = getStringArr(headers.get(QLAYERS_HEADER)); - String format = getString(headers.get(IFORMAT_HEADER)); - Integer i = getInt(headers.get(I_HEADER)); - Integer j = getInt(headers.get(J_HEADER)); - String exFormat = getString(headers.get(EXCEP_FORMAT_HEADER)); - GetFeatureInfoRequest req = new GetFeatureInfoRequest(mapReq, layers, - i, j, format); - Integer count = getInt(headers.get(FCOUNT_HEADER)); - if (count != null) { - req.setFeatureCount(count); - } - req.setExceptionFormat(exFormat); - return req; - } - - protected GetLegendGraphicRequest getLegendGraphicReq( - Map headers) throws WmsException { - String layer = getString(headers.get(LAYER_HEADER)); - String style = getString(headers.get(STYLE_HEADER)); - Integer width = getInt(headers.get(WIDTH_HEADER)); - Integer height = getInt(headers.get(HEIGHT_HEADER)); - String time = getString(headers.get(TIME_HEADER)); - String elevation = getString(headers.get(ELEVATION_HEADER)); - Map dimensions = getDimensions(headers); - StyledLayerDescriptor sld = getSLD(headers); - String rule = getString(headers.get(RULE_HEADER)); - String scale = getString(headers.get(SCALE_HEADER)); - String featureType = getString(headers.get(FEATURE_TYPE_HEADER)); - String bgcolor = getString(headers.get(BGCOLOR_HEADER)); - Boolean transparent = getBool(headers.get(TRANSPARENT_HEADER)); - GetLegendGraphicRequest req = new GetLegendGraphicRequest(layer, style, - width, height, time, elevation, dimensions, sld, rule, scale, - featureType); - req.setTransparent(transparent); - req.setBgcolor(bgcolor); - return req; - } - - protected GetMapRequest parseMapRequest(Map headers) - throws WmsException { - String[] layers = getStringArr(headers.get(LAYERS_HEADER)); - String[] styles = getStringArr(headers.get(STYLES_HEADER)); - if (styles == null) { - throw new WmsException(Code.MissingParameterValue, - "style parameter not in request."); - } - - String crs = getString(headers.get(CRS_HEADER)); - String bbox = getBbox(headers.get(BBOX_HEADER)); - Integer width = getInt(headers.get(WIDTH_HEADER)); - Integer height = getInt(headers.get(HEIGHT_HEADER)); - // String format = getString(headers.get(FORMAT_HEADER)); - Boolean transparent = getBool(headers.get(TRANSPARENT_HEADER)); - String bgcolor = getString(headers.get(BGCOLOR_HEADER)); - // String exceptionFormat = getString(headers.get(EXCEP_FORMAT_HEADER)); - String time = getString(headers.get(TIME_HEADER)); - String elevation = getString(headers.get(ELEVATION_HEADER)); - StyledLayerDescriptor sld = getSLD(headers); - Map dimensions = getDimensions(headers); - return new GetMapRequest(layers, styles, crs, bbox, width, height, - transparent, bgcolor, time, elevation, dimensions, sld); - } - - protected StyledLayerDescriptor getSLD(Map headers) - throws WmsException { - StyledLayerDescriptor rval = null; - String urlStr = getString(headers.get(SLD_HEADER)); - InputStream body = null; - if (urlStr != null) { - try { - URL url = new URL(urlStr); - body = url.openStream(); - } catch (Exception e) { - String msg = "Unable to open SLD at " + urlStr; - log.error(msg, e); - throw new WmsException(Code.InvalidParameterValue, msg); - } - } else if (headers.containsKey(SLD_BODY_HEADER)) { - String str = getString(headers.get(SLD_BODY_HEADER)); - body = new ByteArrayInputStream(str.getBytes(Charset - .forName("UTF-8"))); - } - if (body != null) { - String version = getString(headers.get(SLD_VERSION_HEADER)); - rval = parseSldXml(version, body); - } - return rval; - } - - protected StyledLayerDescriptor parseSldXml(String version, InputStream body) - throws WmsException { - SldParser parser = sldRegistry.getParser(version); - if (parser == null) { - throw new WmsException(Code.InvalidParameterValue, - "Missing or unknown SLD version"); - } - try { - return parser.parse(body); - } catch (Throwable t) { - String msg = "Unable to parse SLD"; - log.error(msg, t); - throw new WmsException(Code.InvalidParameterValue, msg); - } - } - - @SuppressWarnings("unchecked") - protected Map getDimensions(Map headers) { - Map rval = new CaseInsensitiveMap(); - for (String key : headers.keySet()) { - if (key.toLowerCase().startsWith("dim_")) { - String dim = key.substring(4); - rval.put(dim, (String) headers.get(key)); - } - } - return rval; - } - - /** - * @param object - * @return - */ - protected String getBbox(Object object) { - String rval = null; - if (object instanceof String) { - rval = (String) object; - } else if (object instanceof Envelope) { - Envelope env = (Envelope) object; - rval = String.format("%f,%f,%f,%f", env.getMinX(), env.getMinY(), - env.getMaxX(), env.getMinY()); - } - return rval; - } - - protected OgcResponse handleError(WmsException e, String exceptionFormat) { - return provider.getError(e, exceptionFormat); - } - - protected String getString(Object obj) { - String rval = null; - if (obj != null) { - if (obj instanceof String) { - rval = (String) obj; - } - } - return rval; - } - - protected String[] getStringArr(Object obj) { - String[] rval = null; - if (obj != null) { - if (obj instanceof String[]) { - rval = (String[]) obj; - } else if (obj instanceof String) { - rval = ((String) obj).split(","); - } - } - return rval; - } - - protected Integer getInt(Object obj) { - Integer rval = null; - if (obj != null) { - if (obj instanceof Integer) { - rval = (Integer) obj; - } else if (obj instanceof String) { - rval = getInt((String) obj); - } - } - return rval; - } - - protected Integer getInt(String str) { - Integer rval = null; - try { - rval = Integer.parseInt(str); - } catch (Exception e) { - // leave rval as null - } - return rval; - } - - protected Boolean getBool(Object obj) { - Boolean rval = null; - if (obj != null) { - if (obj instanceof Boolean) { - rval = (Boolean) obj; - } else if (obj instanceof String) { - try { - rval = Boolean.parseBoolean((String) obj); - } catch (Exception e) { - // leave rval as null - } - } - } - return rval; - } - - protected void sendResponse(HttpServletResponse httpRes, - OgcResponse response) throws Exception { - try { - OgcResponseOutput.output(response, httpRes); - } catch (OgcException e) { - OgcResponse error = handleError(new WmsException(e), null); - OgcResponseOutput.output(error, httpRes); - } - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler#handle(javax.servlet + * .http.HttpServletRequest, javax.servlet.http.HttpServletResponse, + * java.util.Map) + */ + @Override + public void handle(OgcHttpRequest request) { + try { + handleInternal(request); + } catch (Exception e) { + log.error("Unable to handle request", e); + } + } + + protected void handleInternal(OgcHttpRequest ogcRequest) throws Exception { + IOgcHttpResponse response = new ServletOgcResponse( + ogcRequest.getResponse()); + if (ogcRequest.isPost()) { + InputStream is = ogcRequest.getInputStream(); + sendResponse(response, provider.handlePost(is)); + return; + } + MimeType exceptionFormat = OgcResponse.TEXT_XML_MIME; + OgcResponse rval; + try { + Map headers = ogcRequest.getHeaders(); + String exFormatStr = getString(headers, EXCEP_FORMAT_HEADER); + if (exFormatStr != null && !exFormatStr.isEmpty()) { + exceptionFormat = new MimeType(exFormatStr); + } + + rval = validateExceptionFormat(exceptionFormat); + if (rval != null) { + sendResponse(response, rval); + } + + String reqName = getString(headers, REQUEST_HEADER); + if (reqName == null) { + throw new OgcException(Code.MissingParameterValue, + "Missing parameter: " + REQUEST_HEADER); + } + rval = getResponse(reqName, ogcRequest.getRequest(), headers); + } catch (OgcException e) { + rval = handleError(e, exceptionFormat); + } + + sendResponse(response, rval); + } + + /** + * @param exceptionFormat + * @return + */ + private OgcResponse validateExceptionFormat(MimeType exceptionFormat) { + WmsException ex = validateExceptionFormatAsException(exceptionFormat); + if (ex != null) { + return provider.getError(ex, OgcResponse.TEXT_XML_MIME); + } + return null; + } + + private WmsException validateExceptionFormatAsException( + MimeType exceptionFormat) { + if (!exceptionFormat.equalsIgnoreParams(OgcResponse.TEXT_HTML_MIME) + && !exceptionFormat + .equalsIgnoreParams(OgcResponse.TEXT_XML_MIME) + && !exceptionFormat + .equalsIgnoreParams(OgcResponse.APP_VND_OGC_SE_XML)) { + return new WmsException(WmsException.Code.InvalidParameterValue, + "exceptions parameter invalid"); + } + return null; + } + + protected OgcResponse getResponse(String reqName, + HttpServletRequest request, Map headers) { + BaseRequest req; + OgcResponse rval; + MimeType exceptionFormat = OgcResponse.TEXT_XML_MIME; + try { + exceptionFormat = getMimeType(headers, EXCEP_FORMAT_HEADER); + if (exceptionFormat == null) { + exceptionFormat = OgcResponse.TEXT_XML_MIME; + } + req = getRequest(reqName, request, headers); + if (req != null) { + req.setVersion(getString(headers, VERSION_HEADER)); + req.setFormat(getMimeType(headers, FORMAT_HEADER)); + req.setUpdateSequence(getString(headers, UPDATESEQ_HEADER)); + req.setUserName(getString(headers, USER_HEADER)); + req.setRoles(getStringArr(headers, ROLES_HEADER)); + req.setExceptionFormat(exceptionFormat); + rval = req.execute(provider); + } else { + throw new OgcException(Code.OperationNotSupported, + "No such operation: " + reqName); + } + } catch (OgcException e) { + rval = handleError(e, exceptionFormat); + } + return rval; + } + + protected BaseRequest getRequest(String reqName, + HttpServletRequest request, Map headers) + throws OgcException { + BaseRequest req = null; + if (reqName.equalsIgnoreCase(CAP_PARAM)) { + req = getBaseRequest(request, headers); + } else if (reqName.equalsIgnoreCase(MAP_PARAM)) { + req = parseMapRequest(headers); + } else if (reqName.equalsIgnoreCase(FEAT_PARAM)) { + req = getFeatureInfoReq(headers); + } else if (reqName.equalsIgnoreCase(LEG_PARAM)) { + req = getLegendGraphicReq(headers); + } + + return req; + } + + protected BaseRequest getBaseRequest(HttpServletRequest request, + Map headers) { + OgcServiceInfo serviceInfo = getServiceInfo(request); + BaseRequest req = new BaseRequest(); + req.setServiceinfo(serviceInfo); + return req; + } + + /** + * @param request + */ + private OgcServiceInfo getServiceInfo(HttpServletRequest request) { + int port = request.getServerPort(); + String base = "http://" + request.getServerName(); + if (port != 80) { + base += ":" + port; + } + base += "/wms?service=wms"; + OgcServiceInfo rval = new OgcServiceInfo(base); + + OgcOperationInfo cap = new OgcOperationInfo( + WmsOpType.GetCapabilities); + cap.setHttpGetRes(base); + cap.addFormat("text/xml"); + rval.addOperationInfo(cap); + + OgcOperationInfo map = new OgcOperationInfo( + WmsOpType.GetMap); + map.setHttpGetRes(base); + map.addFormat("image/gif"); + map.addFormat("image/png"); + // map.addFormat("image/tiff"); + map.addFormat("image/jpeg"); + rval.addOperationInfo(map); + + OgcOperationInfo info = new OgcOperationInfo( + WmsOpType.GetFeatureInfo); + info.setHttpGetRes(base); + List formats = Arrays.asList( + GmlFeatureFormatter.mimeType.toString(), + JsonFeatureFormatter.mimeType.toString(), + HtmlFeatureFormatter.mimeType.toString()); + info.setFormats(formats); + rval.addOperationInfo(info); + + OgcOperationInfo legend = new OgcOperationInfo( + WmsOpType.GetLegendGraphic); + legend.setHttpGetRes(base); + legend.addFormat("image/gif"); + legend.addFormat("image/png"); + legend.addFormat("image/jpeg"); + rval.addOperationInfo(legend); + + return rval; + } + + /** + * @param headers + * @return + * @throws OgcException + */ + protected GetFeatureInfoRequest getFeatureInfoReq( + Map headers) throws OgcException { + // TODO lookup provider based on version + // String version = getString(headers, VERSION_HEADER); + GetMapRequest mapReq = parseMapRequest(headers); + + String[] layers = getStringArr(headers, QLAYERS_HEADER); + MimeType format = getMimeType(headers, IFORMAT_HEADER); + Integer i = getInt(headers, I_HEADER); + Integer j = getInt(headers, J_HEADER); + MimeType exFormat = getMimeType(headers, EXCEP_FORMAT_HEADER); + GetFeatureInfoRequest req = new GetFeatureInfoRequest(mapReq, layers, + i, j, format); + Integer count = getInt(headers, FCOUNT_HEADER); + if (count != null) { + req.setFeatureCount(count); + } + req.setExceptionFormat(exFormat); + return req; + } + + protected GetLegendGraphicRequest getLegendGraphicReq( + Map headers) throws OgcException { + String layer = getString(headers, LAYER_HEADER); + String style = getString(headers, STYLE_HEADER); + Integer width = getInt(headers, WIDTH_HEADER); + Integer height = getInt(headers, HEIGHT_HEADER); + String time = getString(headers, TIME_HEADER); + String elevation = getString(headers, ELEVATION_HEADER); + Map dimensions = getDimensions(headers); + StyledLayerDescriptor sld = getSLD(headers); + String rule = getString(headers, RULE_HEADER); + String scale = getString(headers, SCALE_HEADER); + String featureType = getString(headers, FEATURE_TYPE_HEADER); + String bgcolor = getString(headers, BGCOLOR_HEADER); + Boolean transparent = getBool(headers, TRANSPARENT_HEADER); + GetLegendGraphicRequest req = new GetLegendGraphicRequest(layer, style, + width, height, time, elevation, dimensions, sld, rule, scale, + featureType); + req.setTransparent(transparent); + req.setBgcolor(bgcolor); + return req; + } + + protected GetMapRequest parseMapRequest(Map headers) + throws OgcException { + String[] layers = getStringArr(headers, LAYERS_HEADER); + String[] styles = getStringArr(headers, STYLES_HEADER); + if (styles == null) { + throw new OgcException(Code.MissingParameterValue, + "style parameter not in request."); + } + + String crs = getString(headers, CRS_HEADER); + String bbox = getBbox(headers, BBOX_HEADER); + Integer width = getInt(headers, WIDTH_HEADER); + Integer height = getInt(headers, HEIGHT_HEADER); + // String format = getString(headers, FORMAT_HEADER); + Boolean transparent = getBool(headers, TRANSPARENT_HEADER); + String bgcolor = getString(headers, BGCOLOR_HEADER); + // String exceptionFormat = getString(headers, EXCEP_FORMAT_HEADER); + String time = getString(headers, TIME_HEADER); + String[] times = parseTimes(time, layers.length); + String elevation = getString(headers, ELEVATION_HEADER); + StyledLayerDescriptor sld = getSLD(headers); + Map dimensions = getDimensions(headers); + return new GetMapRequest(layers, styles, crs, bbox, width, height, + transparent, bgcolor, times, elevation, dimensions, sld); + } + + protected String[] parseTimes(String timeStr, int layerNum) + throws OgcException { + if (timeStr == null || timeStr.isEmpty()) { + return new String[layerNum]; + } + String[] parts = timeStr.split(",", -1); + String[] rval; + if (parts.length == layerNum) { + rval = copyWithoutEmpties(parts); + } else if (parts.length == 1) { + rval = new String[layerNum]; + for (int i = 0; i < rval.length; ++i) { + rval[i] = parts[0]; + } + } else { + throw new OgcException(Code.InvalidParameterValue, + "invalid time string"); + } + return rval; + } + + /** + * @param arr + * @return copy of array where empty strings are replace with nulls + */ + protected String[] copyWithoutEmpties(String[] arr) { + String[] rval = new String[arr.length]; + for (int i = 0; i < arr.length; ++i) { + if (!arr[i].trim().isEmpty()) { + rval[i] = arr[i]; + } + } + return rval; + } + + protected StyledLayerDescriptor getSLD(Map headers) + throws OgcException { + StyledLayerDescriptor rval = null; + String urlStr = getString(headers, SLD_HEADER); + InputStream body = null; + if (urlStr != null) { + try { + URL url = new URL(urlStr); + body = url.openStream(); + } catch (Exception e) { + String msg = "Unable to open SLD at " + urlStr; + log.error(msg, e); + throw new OgcException(Code.InvalidParameterValue, msg); + } + } else if (headers.containsKey(SLD_BODY_HEADER)) { + String str = getString(headers, SLD_BODY_HEADER); + body = new ByteArrayInputStream(str.getBytes(Charset + .forName("UTF-8"))); + } + if (body != null) { + String version = getString(headers, SLD_VERSION_HEADER); + rval = parseSldXml(version, body); + } + return rval; + } + + protected StyledLayerDescriptor parseSldXml(String version, InputStream body) + throws OgcException { + SldParser parser = sldRegistry.getParser(version); + if (parser == null) { + throw new OgcException(Code.InvalidParameterValue, + "Missing or unknown SLD version"); + } + try { + return parser.parse(body); + } catch (Throwable t) { + String msg = "Unable to parse SLD"; + log.error(msg, t); + throw new OgcException(Code.InvalidParameterValue, msg); + } + } + + /** + * @param object + * @return + * @throws WmsException + */ + protected String getBbox(Map map, String key) + throws OgcException { + Object object = map.get(key); + String rval = null; + if (object instanceof String) { + rval = (String) object; + } else if (object instanceof Envelope) { + Envelope env = (Envelope) object; + rval = String.format("%f,%f,%f,%f", env.getMinX(), env.getMinY(), + env.getMaxX(), env.getMinY()); + } else if (object instanceof String[]) { + throw new OgcException(Code.InvalidParameterValue, + "Multiple values for parameter: " + key); + } + return rval; + } + + @Override + protected OgcResponse handleError(OgcException e, MimeType exceptionFormat) { + return provider.getError(new WmsException(e), exceptionFormat); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/WmsProvider.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/WmsProvider.java deleted file mode 100644 index 1e137e319f..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/WmsProvider.java +++ /dev/null @@ -1,54 +0,0 @@ -/********************************************************************** - * - * The following software products were developed by Raytheon: - * - * ADE (AWIPS Development Environment) software - * CAVE (Common AWIPS Visualization Environment) software - * EDEX (Environmental Data Exchange) software - * uFrame™ (Universal Framework) software - * - * Copyright (c) 2010 Raytheon Co. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/epl-v10.php - * - * - * Contractor Name: Raytheon Company - * Contractor Address: - * 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - **********************************************************************/ -package com.raytheon.uf.edex.wms; - -import java.io.InputStream; - -import com.raytheon.uf.edex.ogc.common.OgcResponse; - -/** - * @author bclement - * - */ -public interface WmsProvider { - - public static final String wmsName = "wms"; - - public enum WmsOpType { - GetCapabilities, GetMap, GetFeatureInfo, GetLegendGraphic - } - - public OgcResponse getCapabilities(BaseRequest req); - - public OgcResponse getMap(GetMapRequest req); - - public OgcResponse getError(WmsException e, String exceptionFormat); - - public OgcResponse handlePost(InputStream in); - - public OgcResponse getFeatureInfo(GetFeatureInfoRequest req); - - public OgcResponse getLegendGraphic(GetLegendGraphicRequest req); -} diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/GmlFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/GmlFeatureFormatter.java index 06ea49518d..7652f20aa1 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/GmlFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/GmlFeatureFormatter.java @@ -32,6 +32,8 @@ package com.raytheon.uf.edex.wms.format; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -54,6 +56,7 @@ import com.raytheon.uf.edex.ogc.common.OgcPrefix; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; +import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * @@ -62,161 +65,200 @@ import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; */ public class GmlFeatureFormatter implements SimpleFeatureFormatter { - public static final String mimeType = "text/xml; subtype=\"gml/3.1.1\""; + public static final MimeType mimeType = new MimeType( + "text/xml; subtype=\"gml/3.1.1\""); - public static final String empty = "\n" - + "\n" - + ""; + public static final String empty = "\n" + + "\n" + + ""; - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#format(java.util - * .List) - */ - @Override - public OgcResponse format(List> features) - throws Exception { + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#format + * (java.util.List, java.io.OutputStream) + */ + @Override + public void format(List> features, OutputStream out) + throws Exception { + if (features == null || features.isEmpty()) { + outputEmpty(out); + return; + } + List> colls = getAsCollections(features); + if (colls == null || colls.isEmpty()) { + outputEmpty(out); + return; + } + // TODO avoid having XML in memory + StringBuilder rval = new StringBuilder(); + populate(rval, colls); + OutputStreamWriter writer = new OutputStreamWriter(out); + writer.write(rval.toString()); + writer.flush(); + writer.close(); + } - if (features == null || features.isEmpty()) { - return new OgcResponse(empty, mimeType, TYPE.TEXT); - } - List> colls = getAsCollections(features); - StringBuilder rval = new StringBuilder(); - populate(rval, colls); - return new OgcResponse(rval.toString(), mimeType, TYPE.TEXT); - } + private void outputEmpty(OutputStream out) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(out); + writer.write(empty); + writer.flush(); + writer.close(); + } - protected void populate(StringBuilder sb, - List> colls) - throws IOException { - Configuration conf = new GMLConfiguration(); - Encoder encoder = new Encoder(conf); - Iterator> i = colls - .iterator(); - String xml = toXml(i.next(), encoder); - populate(sb, xml, true, !i.hasNext()); - while (i.hasNext()) { - xml = toXml(i.next(), encoder); - populate(sb, xml, false, !i.hasNext()); - } - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#format(java.util + * .List) + */ + @Override + public OgcResponse format(List> features) + throws Exception { + if (features == null || features.isEmpty()) { + return new OgcResponse(empty, mimeType, TYPE.TEXT); + } + List> colls = getAsCollections(features); + if (colls == null || colls.isEmpty()) { + return new OgcResponse(empty, mimeType, TYPE.TEXT); + } + StringBuilder rval = new StringBuilder(); + populate(rval, colls); + return new OgcResponse(rval.toString(), mimeType, TYPE.TEXT); + } - protected String toXml(FeatureCollection coll, Encoder encoder) - throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - FeatureTransformer trans = new FeatureTransformer(); - trans.setIndentation(4); - trans.setGmlPrefixing(true); - trans.getFeatureTypeNamespaces().declareDefaultNamespace(OgcPrefix.GML, - OgcNamespace.GML); - SimpleFeatureType schema = coll.getSchema(); - Name name = schema.getName(); - trans.getFeatureTypeNamespaces().declareNamespace(schema, - name.getLocalPart(), name.getNamespaceURI()); - trans.setCollectionNamespace(null); - trans.setCollectionPrefix(null); - trans.setCollectionBounding(true); - trans.getFeatureNamespaces(); - String srs = CRS.toSRS(schema.getCoordinateReferenceSystem()); - if (srs != null) { - trans.setSrsName(srs); - } - try { - trans.transform(coll, out); - } catch (TransformerException e) { - throw new IOException(e); - } - return new String(out.toByteArray(), encoder.getEncoding()); - } + protected void populate(StringBuilder sb, + List> colls) + throws IOException { + Configuration conf = new GMLConfiguration(); + Encoder encoder = new Encoder(conf); + Iterator> i = colls + .iterator(); + String xml = toXml(i.next(), encoder); + populate(sb, xml, true, !i.hasNext()); + while (i.hasNext()) { + xml = toXml(i.next(), encoder); + populate(sb, xml, false, !i.hasNext()); + } + } - protected void populate(StringBuilder sb, String xml, boolean header, - boolean footer) { - String[] parts = split(xml); - if (header) { - sb.append(parts[0]); - sb.append('\n'); - } - sb.append(parts[1]); - sb.append('\n'); - if (footer) { - sb.append(parts[2]); - sb.append('\n'); - } - } + protected String toXml( + FeatureCollection coll, + Encoder encoder) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + FeatureTransformer trans = new FeatureTransformer(); + trans.setIndentation(4); + trans.setGmlPrefixing(true); + trans.getFeatureTypeNamespaces().declareDefaultNamespace(OgcPrefix.GML, + OgcNamespace.GML); + SimpleFeatureType schema = coll.getSchema(); + Name name = schema.getName(); + trans.getFeatureTypeNamespaces().declareNamespace(schema, + name.getLocalPart(), name.getNamespaceURI()); + trans.setCollectionNamespace(null); + trans.setCollectionPrefix(null); + trans.setCollectionBounding(true); + trans.getFeatureNamespaces(); + String srs = CRS.toSRS(schema.getCoordinateReferenceSystem()); + if (srs != null) { + trans.setSrsName(srs); + } + try { + trans.transform(coll, out); + } catch (TransformerException e) { + throw new IOException(e); + } + return new String(out.toByteArray(), encoder.getEncoding()); + } - protected String[] split(String xml) { - String[] rval = new String[3]; - int endHeader; - int beginBody; - int endBody; - int beginFooter; - // FIXME xml should not be parsed like this - int i = xml.indexOf("FeatureCollection"); - endHeader = xml.indexOf('>', i) + 1; - i = xml.indexOf("featureMember"); - beginBody = xml.lastIndexOf('<', i); - i = xml.lastIndexOf("featureMember"); - endBody = xml.indexOf('>', i) + 1; - i = xml.lastIndexOf("FeatureCollection"); - beginFooter = xml.lastIndexOf('<', i); - rval[0] = xml.substring(0, endHeader); - rval[1] = xml.substring(beginBody, endBody); - rval[2] = xml.substring(beginFooter); - return rval; - } + protected void populate(StringBuilder sb, String xml, boolean header, + boolean footer) { + String[] parts = split(xml); + if (header) { + sb.append(parts[0]); + sb.append('\n'); + } + sb.append(parts[1]); + sb.append('\n'); + if (footer) { + sb.append(parts[2]); + sb.append('\n'); + } + } - protected List> getAsCollections( - List> features) { - List> colls = new ArrayList>( - features.size()); - SimpleFeature sample; - for (List l : features) { - if (l == null || l.isEmpty()) { - continue; - } - sample = l.get(0); - MemoryFeatureCollection coll = new MemoryFeatureCollection( - sample.getFeatureType()); - coll.addAll(l); - // ListFeatureCollection coll = new ListFeatureCollection( - // sample.getFeatureType(), l); - colls.add(coll); - } - return colls; - } + protected String[] split(String xml) { + String[] rval = new String[3]; + int endHeader; + int beginBody; + int endBody; + int beginFooter; + // FIXME xml should not be parsed like this + int i = xml.indexOf("FeatureCollection"); + endHeader = xml.indexOf('>', i) + 1; + i = xml.indexOf("featureMember"); + beginBody = xml.lastIndexOf('<', i); + i = xml.lastIndexOf("featureMember"); + endBody = xml.indexOf('>', i) + 1; + i = xml.lastIndexOf("FeatureCollection"); + beginFooter = xml.lastIndexOf('<', i); + rval[0] = xml.substring(0, endHeader); + rval[1] = xml.substring(beginBody, endBody); + rval[2] = xml.substring(beginFooter); + return rval; + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#getMimeType() - */ - @Override - public String getMimeType() { - return mimeType; - } + protected List> getAsCollections( + List> features) { + List> colls = new ArrayList>( + features.size()); + SimpleFeature sample; + for (List l : features) { + if (l == null || l.isEmpty()) { + continue; + } + sample = l.get(0); + MemoryFeatureCollection coll = new MemoryFeatureCollection( + sample.getFeatureType()); + coll.addAll(l); + // ListFeatureCollection coll = new ListFeatureCollection( + // sample.getFeatureType(), l); + colls.add(coll); + } + return colls; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#matchesFormat - * (java.lang.String) - */ - @Override - public boolean matchesFormat(String format) { - if ( mimeType.equalsIgnoreCase(format)){ - return true; - } - if (format.toLowerCase().contains("gml")) { - return true; - } - return false; - } + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#getMimeType() + */ + @Override + public MimeType getMimeType() { + return mimeType; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#matchesFormat + * (java.lang.String) + */ + @Override + public boolean matchesFormat(MimeType format) { + if (mimeType.equalsIgnoreParams(format)) { + return true; + } + if (format.toString().toLowerCase().contains("gml")) { + return true; + } + return false; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/HtmlFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/HtmlFeatureFormatter.java index fa506b6dbe..4315df895e 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/HtmlFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/format/HtmlFeatureFormatter.java @@ -32,7 +32,10 @@ package com.raytheon.uf.edex.wms.format; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.StringWriter; +import java.io.Writer; import java.util.List; import java.util.Scanner; @@ -47,6 +50,7 @@ import org.opengis.feature.simple.SimpleFeatureType; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; +import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * @@ -55,101 +59,129 @@ import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; */ public class HtmlFeatureFormatter implements SimpleFeatureFormatter { - public static final String mimeType = "text/html"; + public static final MimeType mimeType = new MimeType("text/html"); - private VelocityEngine _ve; + private VelocityEngine _ve; - private Template _bodyTemplate; + private Template _bodyTemplate; - private String _header; + private String _header; - protected String bodyLocation = "META-INF/templates/gfi-html-body.vm"; + protected String bodyLocation = "META-INF/templates/gfi-html-body.vm"; - protected String headerLocation = "META-INF/templates/gfi-html-header.txt"; + protected String headerLocation = "META-INF/templates/gfi-html-header.txt"; - protected Template getBodyTemplate() throws Exception { - if (_bodyTemplate == null) { - _ve = new VelocityEngine(); - _ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); - _ve.setProperty("classpath.resource.loader.class", - ClasspathResourceLoader.class.getName()); - _ve.init(); - _bodyTemplate = _ve.getTemplate(bodyLocation); - } - return _bodyTemplate; - } + protected Template getBodyTemplate() throws Exception { + if (_bodyTemplate == null) { + _ve = new VelocityEngine(); + _ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + _ve.setProperty("classpath.resource.loader.class", + ClasspathResourceLoader.class.getName()); + _ve.init(); + _bodyTemplate = _ve.getTemplate(bodyLocation); + } + return _bodyTemplate; + } - protected String getHeader() throws IOException { - if (_header == null) { - ClassLoader loader = this.getClass().getClassLoader(); - InputStream in = loader.getResourceAsStream(headerLocation); - if (in == null) { - throw new IOException("Unable to find classpath resource: " - + headerLocation); - } - _header = new Scanner(in).useDelimiter("\\A").next(); - } - return _header; - } + protected String getHeader() throws IOException { + if (_header == null) { + ClassLoader loader = this.getClass().getClassLoader(); + InputStream in = loader.getResourceAsStream(headerLocation); + if (in == null) { + throw new IOException("Unable to find classpath resource: " + + headerLocation); + } + _header = new Scanner(in).useDelimiter("\\A").next(); + } + return _header; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#format(java.util - * .List) - */ - @Override - public OgcResponse format(List> features) - throws Exception { - if (features == null || features.isEmpty()) { - return new OgcResponse("", mimeType, TYPE.TEXT); - } - StringBuilder rval = new StringBuilder(getHeader()); - for (List typeList : features) { - addFeatures(typeList, rval); - } - rval.append("\n"); - return new OgcResponse(rval.toString(), mimeType, TYPE.TEXT); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#format + * (java.util.List, java.io.OutputStream) + */ + @Override + public void format(List> features, OutputStream out) + throws Exception { + if (features == null || features.isEmpty()) { + return; + } + Writer writer = new OutputStreamWriter(out); + writer.write(getHeader()); + for (List typeList : features) { + addFeatures(typeList, writer); + } + writer.write("\n"); + writer.flush(); + writer.close(); + } - protected void addFeatures(List features, - StringBuilder builder) throws Exception { - if (features == null || features.isEmpty()) { - return; - } - SimpleFeature sample = features.get(0); - SimpleFeatureType type = sample.getType(); - Template t = getBodyTemplate(); - VelocityContext vc = new VelocityContext(); - vc.put("type", type); - vc.put("features", features); - StringWriter writer = new StringWriter(); - t.merge(vc, writer); - builder.append(writer.getBuffer()); - writer.close(); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#format(java.util + * .List) + */ + @Override + public OgcResponse format(List> features) + throws Exception { + if (features == null || features.isEmpty()) { + return new OgcResponse("", mimeType, TYPE.TEXT); + } + StringBuilder rval = new StringBuilder(getHeader()); + for (List typeList : features) { + addFeatures(typeList, rval); + } + rval.append("\n"); + return new OgcResponse(rval.toString(), mimeType, TYPE.TEXT); + } - /* - * (non-Javadoc) - * - * @see com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#getKey() - */ - @Override - public String getMimeType() { - return mimeType; - } + protected void addFeatures(List features, + StringBuilder builder) throws Exception { + StringWriter writer = new StringWriter(); + addFeatures(features, writer); + builder.append(writer.getBuffer()); + writer.close(); + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#matchesFormat - * (java.lang.String) - */ - @Override - public boolean matchesFormat(String format) { - return mimeType.equalsIgnoreCase(format); - } + protected void addFeatures(List features, Writer writer) + throws Exception { + if (features == null || features.isEmpty()) { + return; + } + SimpleFeature sample = features.get(0); + SimpleFeatureType type = sample.getType(); + Template t = getBodyTemplate(); + VelocityContext vc = new VelocityContext(); + vc.put("type", type); + vc.put("features", features); + t.merge(vc, writer); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.edex.wms.format.SimpleFeatureFormatter#getKey() + */ + @Override + public MimeType getMimeType() { + return mimeType; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter#matchesFormat + * (java.lang.String) + */ + @Override + public boolean matchesFormat(MimeType format) { + return mimeType.equalsIgnoreParams(format); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetLegendProcessor.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetLegendProcessor.java index 467e7fe77a..1b17a24879 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetLegendProcessor.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetLegendProcessor.java @@ -25,14 +25,13 @@ package com.raytheon.uf.edex.wms.provider; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; -import java.util.HashMap; import java.util.Map; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.geotools.styling.StyledLayerDescriptor; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.wms.WmsException; import com.raytheon.uf.edex.wms.reg.WmsSource; import com.raytheon.uf.edex.wms.styling.SldStyleProvider; @@ -56,7 +55,7 @@ public class GetLegendProcessor { protected WmsLayerManager layerManager; - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); public GetLegendProcessor(WmsLayerManager layerManager, String time, String elevation, Map dimensions, Integer width, @@ -94,12 +93,10 @@ public class GetLegendProcessor { * @return * @throws WmsException */ - public BufferedImage getLegendStyleLib(String layer, String style, - StyledLayerDescriptor sld) throws WmsException { + public BufferedImage getLegendStyleLib(String layer, String datauri, + String style, StyledLayerDescriptor sld) throws WmsException { SldStyleProvider styler = new SldStyleProvider(sld); - Map dims = new HashMap(0); - Map units = new HashMap(0); - return styler.getLegend(layer, style, dims, units, width, height); + return styler.getLegend(layer, null, style, width, height); } public static BufferedImage applyBackground(BufferedImage img, Color bgColor) { diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetMapProcessor.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetMapProcessor.java index e44eec6b73..4dd1599dce 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetMapProcessor.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/GetMapProcessor.java @@ -44,6 +44,7 @@ import org.geotools.styling.StyledLayerDescriptor; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.raytheon.uf.edex.wms.WmsException; +import com.raytheon.uf.edex.wms.WmsException.Code; import com.raytheon.uf.edex.wms.reg.WmsImage; import com.raytheon.uf.edex.wms.reg.WmsSource; import com.raytheon.uf.edex.wms.util.StyleLibrary; @@ -58,7 +59,6 @@ public class GetMapProcessor { protected CoordinateReferenceSystem crs; protected Envelope env; - protected String time; protected String elevation; protected Map dimensions; protected int width; @@ -69,24 +69,23 @@ public class GetMapProcessor { protected double scale; public GetMapProcessor(WmsLayerManager layerManager, - CoordinateReferenceSystem crs, Envelope env, String time, + CoordinateReferenceSystem crs, Envelope env, String elevation, Map dimensions, int width, int height, double scale, String username, String[] roles) { - this(layerManager, crs, env, time, elevation, dimensions, width, + this(layerManager, crs, env, elevation, dimensions, width, height, scale); this.username = username; this.roles = getAsSet(roles); } public GetMapProcessor(WmsLayerManager layerManager, - CoordinateReferenceSystem crs, Envelope env, String time, + CoordinateReferenceSystem crs, Envelope env, String elevation, Map dimensions, int width, int height, double scale) { super(); this.layerManager = layerManager; this.crs = crs; this.env = env; - this.time = time; this.elevation = elevation; this.dimensions = dimensions; this.width = width; @@ -94,10 +93,17 @@ public class GetMapProcessor { this.scale = scale; } - public List getMapSld(StyledLayerDescriptor sld) + public List getMapSld(StyledLayerDescriptor sld, String[] times) throws WmsException { StyledLayer[] layers = sld.getStyledLayers(); ArrayList rval = new ArrayList(layers.length); + String time; + if (times.length == 1) { + time = times[0]; + } else { + throw new WmsException(Code.InvalidParameterValue, + "times per layer not supported for sld"); + } for (StyledLayer sl : layers) { if (sl instanceof NamedLayer) { NamedLayer layer = (NamedLayer) sl; @@ -135,13 +141,14 @@ public class GetMapProcessor { } public List getMapStyleLib(String[] layers, String[] styles, - StyledLayerDescriptor sld) throws WmsException { + String[] times, StyledLayerDescriptor sld) throws WmsException { StyleLibrary lib = new StyleLibrary(sld); ArrayList rval = new ArrayList(layers.length); for (int i = 0; i < layers.length; ++i) { String layerName = layers[i]; WmsSource source = getSource(layerName); String styleName = styles[i]; + String time = times[i]; Style style = null; if (styleName != null && styleName.trim().isEmpty()) { // use default @@ -166,13 +173,15 @@ public class GetMapProcessor { return rval; } - public List getMap(String[] layers, String[] styles) + public List getMap(String[] layers, String[] styles, + String[] times) throws WmsException { ArrayList rval = new ArrayList(layers.length); for (int i = 0; i < layers.length; ++i) { String layerName = layers[i]; WmsSource source = getSource(layerName); String styleName = styles[i]; + String time = times[i]; boolean defaultStyle = (styleName == null || styleName.isEmpty()); WmsImage img = source.getImage(layerName, styleName, defaultStyle, crs, env, time, elevation, dimensions, scale); diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcGetMapTranslator.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcGetMapTranslator.java index 82a73b8d3c..40a290394c 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcGetMapTranslator.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcGetMapTranslator.java @@ -47,8 +47,6 @@ import net.opengis.sld.v_1_1_0.OutputType.Size; import net.opengis.sld.v_1_1_0.StyledLayerDescriptorElement; import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.dom4j.Element; import org.dom4j.Namespace; import org.dom4j.Node; @@ -57,9 +55,12 @@ import org.dom4j.io.DocumentSource; import org.geotools.styling.StyledLayerDescriptor; import org.w3c.dom.Document; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.edex.ogc.common.OgcNamespace; import com.raytheon.uf.edex.ogc.common.OgcPrefix; +import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.wms.GetMapRequest; import com.raytheon.uf.edex.wms.WmsException; import com.raytheon.uf.edex.wms.WmsException.Code; @@ -68,251 +69,263 @@ import com.raytheon.uf.edex.wms.sld.SldParserRegistry; public class OgcGetMapTranslator { - protected Log log = LogFactory.getLog(this.getClass()); + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected SldParserRegistry registry; + protected SldParserRegistry registry; - protected Namespace sldNS = new Namespace(OgcPrefix.SLD, OgcNamespace.SLD); + protected Namespace sldNS = new Namespace(OgcPrefix.SLD, OgcNamespace.SLD); - protected Namespace owsNS = new Namespace(OgcPrefix.OWS, OgcNamespace.OWS); + protected Namespace owsNS = new Namespace(OgcPrefix.OWS, OgcNamespace.OWS); - protected Namespace wmsNS = new Namespace(OgcPrefix.WMS, OgcNamespace.WMS); + protected Namespace wmsNS = new Namespace(OgcPrefix.WMS, OgcNamespace.WMS); - protected QName sldName = new QName("StyledLayerDescriptor", sldNS); + protected QName sldName = new QName("StyledLayerDescriptor", sldNS); - protected QName crsName = new QName("CRS", sldNS); + protected QName crsName = new QName("CRS", sldNS); - protected QName bboxName = new QName("BoundingBox", sldNS); + protected QName bboxName = new QName("BoundingBox", sldNS); - protected QName lcName = new QName("LowerCorner", owsNS); + protected QName lcName = new QName("LowerCorner", owsNS); - protected QName ucName = new QName("UpperCorner", owsNS); + protected QName ucName = new QName("UpperCorner", owsNS); - protected QName outputName = new QName("Output", sldNS); + protected QName outputName = new QName("Output", sldNS); - protected QName sizeName = new QName("Size", sldNS); + protected QName sizeName = new QName("Size", sldNS); - protected QName widthName = new QName("Width", sldNS); + protected QName widthName = new QName("Width", sldNS); - protected QName heightName = new QName("Height", sldNS); + protected QName heightName = new QName("Height", sldNS); - protected QName formatName = new QName("Format", wmsNS); + protected QName formatName = new QName("Format", wmsNS); - protected QName transparentName = new QName("Transparent", sldNS); + protected QName transparentName = new QName("Transparent", sldNS); - protected QName execptionsName = new QName("Exceptions", sldNS); + protected QName execptionsName = new QName("Exceptions", sldNS); - protected QName elevationName = new QName("Elevation", sldNS); + protected QName elevationName = new QName("Elevation", sldNS); - protected QName timeName = new QName("Time", sldNS); + protected QName timeName = new QName("Time", sldNS); - protected QName valueName = new QName("Value", sldNS); + protected QName valueName = new QName("Value", sldNS); - public OgcGetMapTranslator(SldParserRegistry registry) { - this.registry = registry; - } + public OgcGetMapTranslator(SldParserRegistry registry) { + this.registry = registry; + } - public GetMapRequest translate(Element root) throws WmsException { - GetMapRequest rval = new GetMapRequest(); - rval.setSld(parseSld(root.element(sldName))); - rval.setBbox(parseBbox(root.element(bboxName))); - rval.setCrs(getTextElement(root.element(crsName))); - rval.setElevation(parseElevation(root.element(elevationName))); - parseOutput(root.element(outputName), rval); - rval.setTime(getTextElement(root.element(timeName))); - rval.setExceptionFormat(root.elementTextTrim(execptionsName)); - return rval; - } + public GetMapRequest translate(Element root) throws WmsException { + GetMapRequest rval = new GetMapRequest(); + rval.setSld(parseSld(root.element(sldName))); + rval.setBbox(parseBbox(root.element(bboxName))); + rval.setCrs(getTextElement(root.element(crsName))); + rval.setElevation(parseElevation(root.element(elevationName))); + parseOutput(root.element(outputName), rval); + rval.setTimes(new String[] { getTextElement(root.element(timeName)) }); + rval.setExceptionFormat(getFormat(root.elementTextTrim(execptionsName))); + return rval; + } - /** - * @param element - * @param rval - */ - protected void parseOutput(Element output, GetMapRequest rval) { - if (output == null) { - return; - } - Element size = output.element(sizeName); - if (size != null) { - try { - String width = size.elementTextTrim(widthName); - rval.setWidth(Integer.valueOf(width)); - String height = size.elementTextTrim(heightName); - rval.setHeight(Integer.valueOf(height)); - } catch (NumberFormatException e) { - // leave sizes null - } - } - rval.setFormat(output.elementTextTrim(formatName)); - rval.setTransparent(getBoolElement(output.element(transparentName))); - } + protected MimeType getFormat(String format) throws WmsException { + try { + return new MimeType(format); + } catch (IllegalArgumentException e) { + throw new WmsException(Code.InvalidParameterValue, e.getMessage()); + } + } - protected Boolean getBoolElement(Element elem) { - if (elem == null) { - return null; - } - String txt = elem.getTextTrim(); - return txt != null && txt.equalsIgnoreCase("true"); - } + /** + * @param element + * @param rval + * @throws WmsException + */ + protected void parseOutput(Element output, GetMapRequest rval) + throws WmsException { + if (output == null) { + return; + } + Element size = output.element(sizeName); + if (size != null) { + try { + String width = size.elementTextTrim(widthName); + rval.setWidth(Integer.valueOf(width)); + String height = size.elementTextTrim(heightName); + rval.setHeight(Integer.valueOf(height)); + } catch (NumberFormatException e) { + // leave sizes null + } + } + rval.setFormat(getFormat(output.elementTextTrim(formatName))); + rval.setTransparent(getBoolElement(output.element(transparentName))); + } - protected String parseElevation(Element elev) { - if (elev == null) { - return null; - } - String rval = null; - // TODO handle intervals - Element val = elev.element(valueName); - if (val != null) { - rval = val.getTextTrim(); - } - return rval; - } + protected Boolean getBoolElement(Element elem) { + if (elem == null) { + return null; + } + String txt = elem.getTextTrim(); + return txt != null && txt.equalsIgnoreCase("true"); + } - /** - * @param element - * @return - */ - protected String getTextElement(Element elem) { - if (elem == null) { - return null; - } - return elem.getTextTrim(); - } + protected String parseElevation(Element elev) { + if (elev == null) { + return null; + } + String rval = null; + // TODO handle intervals + Element val = elev.element(valueName); + if (val != null) { + rval = val.getTextTrim(); + } + return rval; + } - /** - * @param element - * @return - */ - protected String parseBbox(Element bboxElem) { - if (bboxElem == null) { - return null; - } - String lcText = bboxElem.elementTextTrim(lcName); - String ucText = bboxElem.elementTextTrim(ucName); - String[] lc = StringUtils.split(lcText); - String[] uc = StringUtils.split(ucText); - List bounds = Arrays.asList(lc[0], lc[1], uc[0], uc[1]); - return StringUtils.join(bounds, ','); - } + /** + * @param element + * @return + */ + protected String getTextElement(Element elem) { + if (elem == null) { + return null; + } + return elem.getTextTrim(); + } - protected StyledLayerDescriptor parseSld(Element e) throws WmsException { - if (e == null) { - return null; - } - String version = e.attributeValue("version"); - SldParser parser = registry.getParser(version); - if (parser == null) { - throw new WmsException(Code.MissingParameterValue, - "SLD version must be specified"); - } - Document doc; - try { - doc = convert(e); - StyledLayerDescriptor rval = parser.parse(doc); - return rval; - } catch (Exception e1) { - log.error("Unable to parse SLD docuement", e1); - throw new WmsException(Code.InternalServerError); - } - } + /** + * @param element + * @return + */ + protected String parseBbox(Element bboxElem) { + if (bboxElem == null) { + return null; + } + String lcText = bboxElem.elementTextTrim(lcName); + String ucText = bboxElem.elementTextTrim(ucName); + String[] lc = StringUtils.split(lcText); + String[] uc = StringUtils.split(ucText); + List bounds = Arrays.asList(lc[0], lc[1], uc[0], uc[1]); + return StringUtils.join(bounds, ','); + } - protected Document convert(Node n) throws TransformerException { - TransformerFactory factory = TransformerFactory.newInstance(); - Transformer transformer = factory.newTransformer(); - DocumentSource source = new DocumentSource(n); - DOMResult result = new DOMResult(); - transformer.transform(source, result); - return (Document) result.getNode(); - } + protected StyledLayerDescriptor parseSld(Element e) throws WmsException { + if (e == null) { + return null; + } + String version = e.attributeValue("version"); + SldParser parser = registry.getParser(version); + if (parser == null) { + throw new WmsException(Code.MissingParameterValue, + "SLD version must be specified"); + } + Document doc; + try { + doc = convert(e); + StyledLayerDescriptor rval = parser.parse(doc); + return rval; + } catch (Exception e1) { + log.error("Unable to parse SLD docuement", e1); + throw new WmsException(Code.InternalServerError); + } + } - // below are JAXB utility methods (would need jaxb context) + protected Document convert(Node n) throws TransformerException { + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + DocumentSource source = new DocumentSource(n); + DOMResult result = new DOMResult(); + transformer.transform(source, result); + return (Document) result.getNode(); + } - /** - * @param req - * @return - * @throws Throwable - */ - @Deprecated - protected GetMapRequest translate(GetMapType req) throws Throwable { - GetMapRequest rval = new GetMapRequest(); - rval.setBbox(formatBbox(req.getBoundingBox())); - rval.setCrs(req.getCRS()); - rval.setElevation(formatElevation(req.getElevation())); - parseOutput(req.getOutput(), rval); - rval.setTime(formatTime(req.getTime())); - rval.setSld(translate(req.getStyledLayerDescriptor())); - return rval; - } + // below are JAXB utility methods (would need jaxb context) - protected String formatBbox(BoundingBoxType bbox) { - if (bbox == null) { - return null; - } - List lc = bbox.getLowerCorner(); - List uc = bbox.getUpperCorner(); + /** + * @param req + * @return + * @throws Throwable + */ + @Deprecated + protected GetMapRequest translate(GetMapType req) throws Throwable { + GetMapRequest rval = new GetMapRequest(); + rval.setBbox(formatBbox(req.getBoundingBox())); + rval.setCrs(req.getCRS()); + rval.setElevation(formatElevation(req.getElevation())); + parseOutput(req.getOutput(), rval); + rval.setTimes(new String[] { formatTime(req.getTime()) }); + rval.setSld(translate(req.getStyledLayerDescriptor())); + return rval; + } - return String.format("%f,%f,%f,%f", lc.get(0), lc.get(1), uc.get(0), - uc.get(1)); - } + protected String formatBbox(BoundingBoxType bbox) { + if (bbox == null) { + return null; + } + List lc = bbox.getLowerCorner(); + List uc = bbox.getUpperCorner(); - protected String formatElevation(ElevationType elev) { - if (elev == null) { - return null; - } - List value = elev.getValue(); - if (value != null && !value.isEmpty()) { - return StringUtils.join(value, ","); - } else { - return null; - } - } + return String.format("%f,%f,%f,%f", lc.get(0), lc.get(1), uc.get(0), + uc.get(1)); + } - protected void parseOutput(OutputType out, GetMapRequest req) { - if (out == null) { - return; - } - req.setBgcolor(out.getBGcolor()); - req.setFormat(out.getFormat()); - Size size = out.getSize(); - if (size != null) { - BigInteger width = size.getWidth(); - BigInteger height = size.getHeight(); - if (width != null) { - req.setWidth(width.intValue()); - } - if (height != null) { - req.setHeight(height.intValue()); - } - } - } + protected String formatElevation(ElevationType elev) { + if (elev == null) { + return null; + } + List value = elev.getValue(); + if (value != null && !value.isEmpty()) { + return StringUtils.join(value, ","); + } else { + return null; + } + } - protected String formatTime(XMLGregorianCalendar cal) { - if (cal == null) { - return null; - } - return TimeUtil.formatCalendar(cal.toGregorianCalendar()); - } + protected void parseOutput(OutputType out, GetMapRequest req) + throws WmsException { + if (out == null) { + return; + } + req.setBgcolor(out.getBGcolor()); + req.setFormat(getFormat(out.getFormat())); + Size size = out.getSize(); + if (size != null) { + BigInteger width = size.getWidth(); + BigInteger height = size.getHeight(); + if (width != null) { + req.setWidth(width.intValue()); + } + if (height != null) { + req.setHeight(height.intValue()); + } + } + } - protected StyledLayerDescriptor translate(StyledLayerDescriptorElement sld) - throws Throwable { - if (sld == null) { - return null; - } - // FIXME there must be a better way than this - // String xml = manager.marshal(sld); - // InputStream in = new StringInputStream(xml); - // SLDParser stylereader = new SLDParser( - // CommonFactoryFinder.getStyleFactory(null), in); - // return stylereader.parseSLD(); - return null; - } + protected String formatTime(XMLGregorianCalendar cal) { + if (cal == null) { + return null; + } + return TimeUtil.formatCalendar(cal.toGregorianCalendar()); + } - public SldParserRegistry getRegistry() { - return registry; - } + protected StyledLayerDescriptor translate(StyledLayerDescriptorElement sld) + throws Throwable { + if (sld == null) { + return null; + } + // FIXME there must be a better way than this + // TODO: Please do it the better way! + // String xml = manager.marshal(sld); + // InputStream in = new StringInputStream(xml); + // SLDParser stylereader = new SLDParser( + // CommonFactoryFinder.getStyleFactory(null), in); + // return stylereader.parseSLD(); + return null; + } - public void setRegistry(SldParserRegistry registry) { - this.registry = registry; - } + public SldParserRegistry getRegistry() { + return registry; + } + + public void setRegistry(SldParserRegistry registry) { + this.registry = registry; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcWmsProvider.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcWmsProvider.java index 3c570942ad..d731ec5fc3 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcWmsProvider.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/OgcWmsProvider.java @@ -59,8 +59,6 @@ import net.opengis.wms.v_1_3_0.ServiceExceptionReport; import net.opengis.wms.v_1_3_0.ServiceExceptionType; import net.opengis.wms.v_1_3_0.WMSCapabilities; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Namespace; @@ -87,10 +85,11 @@ import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.geometry.DirectPosition; import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.crs.GeographicCRS; import org.opengis.referencing.operation.MathTransform2D; import org.springframework.context.ApplicationContext; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.core.EDEXUtil; import com.raytheon.uf.edex.ogc.common.OgcNamespace; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; @@ -100,6 +99,7 @@ import com.raytheon.uf.edex.ogc.common.OgcResponse.ErrorType; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; +import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.jaxb.OgcJaxbManager; import com.raytheon.uf.edex.ogc.common.spatial.CrsLookup; import com.raytheon.uf.edex.wms.BaseRequest; @@ -109,809 +109,801 @@ import com.raytheon.uf.edex.wms.GetMapRequest; import com.raytheon.uf.edex.wms.WmsException; import com.raytheon.uf.edex.wms.WmsException.Code; import com.raytheon.uf.edex.wms.WmsHttpHandler; -import com.raytheon.uf.edex.wms.WmsProvider; +import com.raytheon.uf.edex.wms.IWmsProvider; import com.raytheon.uf.edex.wms.reg.WmsImage; import com.raytheon.uf.edex.wms.reg.WmsSource; import com.raytheon.uf.edex.wms.util.StyleUtility; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; -public class OgcWmsProvider implements WmsProvider { +public class OgcWmsProvider implements IWmsProvider { - protected static final String svcTitle = "EDEX Map Server"; + protected static final String svcTitle = "EDEX Map Server"; - protected WmsLayerManager layerManager; + protected WmsLayerManager layerManager; - protected OgcJaxbManager jaxbManager; + protected OgcJaxbManager jaxbManager; - private Log log = LogFactory.getLog(this.getClass()); + private IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected String resizeHint = "quality"; + protected String resizeHint = "quality"; - protected OgcGetMapTranslator getMapTranslator; + protected OgcGetMapTranslator getMapTranslator; - protected QName getMapName = new QName("GetMap", new Namespace( - OgcPrefix.SLD, OgcNamespace.SLD)); + protected QName getMapName = new QName("GetMap", new Namespace( + OgcPrefix.SLD, OgcNamespace.SLD)); - public OgcWmsProvider(WmsLayerManager layerManager, - OgcJaxbManager jaxbManager, OgcGetMapTranslator getMapTranslator) { - this.layerManager = layerManager; - this.jaxbManager = jaxbManager; - this.getMapTranslator = getMapTranslator; - } + public OgcWmsProvider(WmsLayerManager layerManager, + OgcJaxbManager jaxbManager, OgcGetMapTranslator getMapTranslator) { + this.layerManager = layerManager; + this.jaxbManager = jaxbManager; + this.getMapTranslator = getMapTranslator; + } - @Override - public OgcResponse getCapabilities(BaseRequest req) { - OgcResponse rval; - try { - WMSCapabilities capabilities = new WMSCapabilities(); - OgcServiceInfo serviceinfo = req.getServiceinfo(); - capabilities.setService(getServiceInfo(serviceinfo)); - capabilities.setCapability(getMainCapability(req)); - rval = marshalResponse(capabilities); - } catch (WmsException e) { - rval = getError(e, req.getExceptionFormat()); - } - return rval; - } + @Override + public OgcResponse getCapabilities(BaseRequest req) { + OgcResponse rval; + try { + WMSCapabilities capabilities = new WMSCapabilities(); + OgcServiceInfo serviceinfo = req.getServiceinfo(); + capabilities.setService(getServiceInfo(serviceinfo)); + capabilities.setCapability(getMainCapability(req)); + rval = marshalResponse(capabilities); + } catch (WmsException e) { + rval = getError(e, req.getExceptionFormat()); + } + return rval; + } - /** - * @return - */ - protected Service getServiceInfo(OgcServiceInfo serviceInfo) { - Service rval = new Service(); - rval.setName(wmsName); - rval.setTitle(svcTitle); - rval.setOnlineResource(getOLR(serviceInfo.getOnlineResource())); - return rval; - } + /** + * @return + */ + protected Service getServiceInfo(OgcServiceInfo serviceInfo) { + Service rval = new Service(); + rval.setName(WMS_NAME); + rval.setTitle(svcTitle); + rval.setOnlineResource(getOLR(serviceInfo.getOnlineResource())); + return rval; + } - protected OnlineResource getOLR(String href) { - OnlineResource rval = new OnlineResource(); - rval.setHref(href); - return rval; - } + protected OnlineResource getOLR(String href) { + OnlineResource rval = new OnlineResource(); + rval.setHref(href); + return rval; + } - protected Capability getMainCapability(BaseRequest req) - throws WmsException { - Capability rval = new Capability(); - OgcServiceInfo serviceinfo = req.getServiceinfo(); - rval.setRequest(getValidRequests(serviceinfo.getOperations())); - rval.setException(getExceptionInfo()); - rval.setLayer(getLayerInfo(req)); - return rval; - } + protected Capability getMainCapability(BaseRequest req) + throws WmsException { + Capability rval = new Capability(); + OgcServiceInfo serviceinfo = req.getServiceinfo(); + rval.setRequest(getValidRequests(serviceinfo.getOperations())); + rval.setException(getExceptionInfo()); + rval.setLayer(getLayerInfo(req)); + return rval; + } - /** - * @return - * @throws WmsException - */ - protected Layer getLayerInfo(BaseRequest req) - throws WmsException { - Layer rval = new Layer(); - rval.setTitle(svcTitle); - rval.setLayer(getAuthorizedLayers(req)); - return rval; - } + /** + * @return + * @throws WmsException + */ + protected Layer getLayerInfo(BaseRequest req) + throws WmsException { + Layer rval = new Layer(); + rval.setTitle(svcTitle); + rval.setLayer(getAuthorizedLayers(req)); + return rval; + } - protected List getAuthorizedLayers(BaseRequest req) - throws WmsException { - // List rval; - // if (req.getUserName() == null) { - // // we aren't doing authorization - // rval = layerManager.getLayers(); - // } else { - // Set userRoles = OgcAuthUtils.getAsSet(req.getRoles()); - // rval = layerManager.getAuthorizedLayers(userRoles); - // } - return layerManager.getLayers(req.getServiceinfo()); - } + protected List getAuthorizedLayers(BaseRequest req) + throws WmsException { - /** - * @return - */ - protected Exception getExceptionInfo() { - Exception rval = new Exception(); - rval.setFormat(Arrays.asList("XML")); - return rval; - } + return layerManager.getLayers(req.getServiceinfo()); + } - /** - * @param operations - * @return - */ - protected Request getValidRequests( - List> operations) { - Request rval = new Request(); - for (OgcOperationInfo op : operations) { - OperationType opType = new OperationType(); - populateOpType(opType, op); - switch (op.getType()) { - case GetCapabilities: - rval.setGetCapabilities(opType); - break; - case GetFeatureInfo: - rval.setGetFeatureInfo(opType); - break; - case GetMap: - rval.setGetMap(opType); - break; - } - } - return rval; - } + /** + * @return + */ + protected Exception getExceptionInfo() { + Exception rval = new Exception(); + rval.setFormat(Arrays.asList("XML")); + return rval; + } - protected void populateOpType(OperationType opType, - OgcOperationInfo info) { - opType.setFormat(info.getFormats()); - DCPType dcpt = new DCPType(); - HTTP http = new HTTP(); - if (info.hasHttpGet()) { - Get get = new Get(); - get.setOnlineResource(getOLR(info.getHttpGetRes())); - http.setGet(get); - } - if (info.hasHttpPost()) { - Post post = new Post(); - post.setOnlineResource(getOLR(info.getHttpPostRes())); - http.setPost(post); - } - dcpt.setHTTP(http); - opType.setDCPType(Arrays.asList(dcpt)); - } + /** + * @param operations + * @return + */ + protected Request getValidRequests( + List> operations) { + Request rval = new Request(); + for (OgcOperationInfo op : operations) { + OperationType opType = new OperationType(); + populateOpType(opType, op); + switch (op.getType()) { + case GetCapabilities: + rval.setGetCapabilities(opType); + break; + case GetFeatureInfo: + rval.setGetFeatureInfo(opType); + break; + case GetMap: + rval.setGetMap(opType); + break; + case GetLegendGraphic: + break; + } + } + return rval; + } - protected OgcResponse marshalResponse(Object jaxbobject) - throws WmsException { - OgcResponse rval; - try { - String xml = jaxbManager.marshal(jaxbobject); - rval = new OgcResponse(xml, OgcResponse.TEXT_XML_MIME, TYPE.TEXT); - } catch (JAXBException e) { - log.error("Unable to marshal WFS response", e); - throw new WmsException(Code.InternalServerError); - } - return rval; - } + protected void populateOpType(OperationType opType, + OgcOperationInfo info) { + opType.setFormat(info.getFormats()); + DCPType dcpt = new DCPType(); + HTTP http = new HTTP(); + if (info.hasHttpGet()) { + Get get = new Get(); + get.setOnlineResource(getOLR(info.getHttpGetRes())); + http.setGet(get); + } + if (info.hasHttpPost()) { + Post post = new Post(); + post.setOnlineResource(getOLR(info.getHttpPostRes())); + http.setPost(post); + } + dcpt.setHTTP(http); + opType.setDCPType(Arrays.asList(dcpt)); + } - @Override - public OgcResponse handlePost(InputStream in) { - Element root; - try { - SAXReader reader = new SAXReader(); - Document doc = reader.read(in); - root = doc.getRootElement(); - } catch (java.lang.Exception e) { - log.error("Unable to read post data", e); - return getError(new WmsException(Code.InternalServerError), - OgcResponse.TEXT_XML_MIME); - } - if (root.getQName().equals(getMapName)) { - return getMapPost(root); - } else { - return getError(new WmsException(Code.InvalidParameterValue, - "Post method only supported for GetMap operation"), - OgcResponse.TEXT_XML_MIME); - } - } + protected OgcResponse marshalResponse(Object jaxbobject) + throws WmsException { + OgcResponse rval; + try { + String xml = jaxbManager.marshal(jaxbobject, false); + rval = new OgcResponse(xml, OgcResponse.TEXT_XML_MIME, TYPE.TEXT); + } catch (JAXBException e) { + log.error("Unable to marshal WFS response", e); + throw new WmsException(Code.InternalServerError); + } + return rval; + } - protected OgcResponse getMapPost(Element root) { - GetMapRequest translated; - try { - translated = getMapTranslator.translate(root); - } catch (Throwable e) { - log.error("Unable to converted getmap request", e); - return getError(new WmsException(Code.InternalServerError), - OgcResponse.TEXT_XML_MIME); - } - return getMap(translated); - } + @Override + public OgcResponse handlePost(InputStream in) { + Element root; + try { + SAXReader reader = new SAXReader(); + Document doc = reader.read(in); + root = doc.getRootElement(); + } catch (java.lang.Exception e) { + log.error("Unable to read post data", e); + return getError(new WmsException(Code.InternalServerError), + OgcResponse.TEXT_XML_MIME); + } + if (root.getQName().equals(getMapName)) { + return getMapPost(root); + } else { + return getError(new WmsException(Code.InvalidParameterValue, + "Post method only supported for GetMap operation"), + OgcResponse.TEXT_XML_MIME); + } + } - @Override - public OgcResponse getMap(GetMapRequest req) { - OgcResponse rval = null; - StyledLayerDescriptor sld = req.getSld(); - String[] layers = req.getLayers(); - String[] styles = req.getStyles(); - String time = req.getTime(); - String elevation = req.getElevation(); - Map dimensions = req.getDimensions(); - Integer width = req.getWidth(); - Integer height = req.getHeight(); - boolean sldOnly = sld != null && layers == null; - if ((rval = checkGetMapArgs(req)) != null) { - // there was a problem, return the error - return rval; - } - boolean clear = parseTransparent(req.getTransparent()); - List images; - try { - Iterator it = ImageIO.getImageWritersByMIMEType(req.getFormat()); - if (!it.hasNext()) { - throw new WmsException(Code.InvalidFormat, - "Format not supported: " + req.getFormat()); - } - Color color = parseColor(req.getBgcolor()); - CoordinateReferenceSystem targetCrs = parseCrs(req.getCrs()); - Envelope env = parseEnvString(req.getBbox(), targetCrs); - if (req.getWidth() <= 0 || req.getHeight() <= 0) { - throw new WmsException(Code.InvalidParameterValue, - "Invalid resolution"); - } - String username = req.getUserName(); - String[] roles = req.getRoles(); - double scale = getScale(env, width, height); - GetMapProcessor proc = new GetMapProcessor(layerManager, targetCrs, - env, time, elevation, dimensions, width, height, scale, - username, roles); - if (sld == null) { - images = proc.getMap(layers, styles); - } else if (sldOnly) { - images = proc.getMapSld(sld); - } else { - images = proc.getMapStyleLib(layers, styles, sld); - } - BufferedImage map = mergeWmsImages(images, clear, color, width, - height, env, targetCrs); - rval = new OgcResponse(map, req.getFormat(), TYPE.IMAGE); - } catch (WmsException e) { - rval = getError(e, req.getExceptionFormat()); - } - return rval; - } + protected OgcResponse getMapPost(Element root) { + GetMapRequest translated; + try { + translated = getMapTranslator.translate(root); + } catch (Throwable e) { + log.error("Unable to converted getmap request", e); + return getError(new WmsException(Code.InternalServerError), + OgcResponse.TEXT_XML_MIME); + } + return getMap(translated); + } - protected Map getStyleMap(StyledLayerDescriptor sld) { - if (sld == null) { - return null; - } - StyledLayer[] layers = sld.getStyledLayers(); - Map rval = new HashMap(); - for (StyledLayer l : layers) { - if (l instanceof NamedLayer) { - NamedLayer nl = (NamedLayer) l; - Style[] styles = nl.getStyles(); - if (styles != null) { - for (Style s : styles) { - rval.put(s.getName(), s); - } - } - } - } - return rval; - } + @Override + public OgcResponse getMap(GetMapRequest req) { + OgcResponse rval = null; + StyledLayerDescriptor sld = req.getSld(); + String[] layers = req.getLayers(); + String[] styles = req.getStyles(); + String[] times = req.getTimes(); + String elevation = req.getElevation(); + Map dimensions = req.getDimensions(); + Integer width = req.getWidth(); + Integer height = req.getHeight(); + boolean sldOnly = sld != null && layers == null; + if ((rval = checkGetMapArgs(req)) != null) { + // there was a problem, return the error + return rval; + } + boolean clear = parseTransparent(req.getTransparent()); + List images; + try { + Iterator it = ImageIO.getImageWritersByMIMEType(req.getFormat() + .toString()); + if (!it.hasNext()) { + throw new WmsException(Code.InvalidFormat, + "Format not supported: " + req.getFormat()); + } + Color color = parseColor(req.getBgcolor()); + CoordinateReferenceSystem targetCrs = parseCrs(req.getCrs()); + Envelope env = parseEnvString(req.getBbox(), targetCrs); + if (req.getWidth() <= 0 || req.getHeight() <= 0) { + throw new WmsException(Code.InvalidParameterValue, + "Invalid resolution"); + } + String username = req.getUserName(); + String[] roles = req.getRoles(); + double scale = getScale(env, width, height); + GetMapProcessor proc = new GetMapProcessor(layerManager, targetCrs, + env, elevation, dimensions, width, height, scale, username, + roles); + if (sld == null) { + images = proc.getMap(layers, styles, times); + } else if (sldOnly) { + images = proc.getMapSld(sld, times); + } else { + images = proc.getMapStyleLib(layers, styles, times, sld); + } + BufferedImage map = mergeWmsImages(images, clear, color, width, + height, env, targetCrs); + rval = new OgcResponse(map, req.getFormat(), TYPE.IMAGE); + } catch (WmsException e) { + rval = getError(e, req.getExceptionFormat()); + } + return rval; + } - protected static boolean isEpsgGeoCrs(CoordinateReferenceSystem crs) { - try { - String auth = crs.getName().getCodeSpace(); - return "epsg".equalsIgnoreCase(auth) - && crs instanceof GeographicCRS; - } catch (NullPointerException e) { - return false; - } - } + protected Map getStyleMap(StyledLayerDescriptor sld) { + if (sld == null) { + return null; + } + StyledLayer[] layers = sld.getStyledLayers(); + Map rval = new HashMap(); + for (StyledLayer l : layers) { + if (l instanceof NamedLayer) { + NamedLayer nl = (NamedLayer) l; + Style[] styles = nl.getStyles(); + if (styles != null) { + for (Style s : styles) { + rval.put(s.getName(), s); + } + } + } + } + return rval; + } - protected Envelope parseEnvString(String str, CoordinateReferenceSystem crs) - throws WmsException { - Envelope rval = null; - try { - if (str != null) { - String[] parts = str.split(","); - if (parts.length >= 4) { - double minx = Double.parseDouble(parts[0]); - double miny = Double.parseDouble(parts[1]); - double maxx = Double.parseDouble(parts[2]); - double maxy = Double.parseDouble(parts[3]); - if (minx > maxx || miny > maxy) { - throw new java.lang.Exception(); - } - if (isEpsgGeoCrs(crs)) { - // EPSG GeoCRS uses lat/lon axis order. Switch to match - // framework order of lon/lat - rval = new Envelope(miny, maxy, minx, maxx); - } else { - rval = new Envelope(minx, maxx, miny, maxy); - } - } else { - throw new java.lang.Exception(); - } - } - } catch (Throwable e) { - throw new WmsException(Code.InvalidParameterValue, "Invalid bbox"); - } - return rval; - } + protected Envelope parseEnvString(String str, CoordinateReferenceSystem crs) + throws WmsException { + Envelope rval = null; + try { + if (str != null) { + String[] parts = str.split(","); + if (parts.length >= 4) { + double minx = Double.parseDouble(parts[0]); + double miny = Double.parseDouble(parts[1]); + double maxx = Double.parseDouble(parts[2]); + double maxy = Double.parseDouble(parts[3]); + if (minx > maxx || miny > maxy) { + throw new java.lang.Exception(); + } + if (CrsLookup.isEpsgGeoCrs(crs)) { + // EPSG GeoCRS uses lat/lon axis order. Switch to match + // framework order of lon/lat + rval = new Envelope(miny, maxy, minx, maxx); + } else { + rval = new Envelope(minx, maxx, miny, maxy); + } + } else { + throw new java.lang.Exception(); + } + } + } catch (Throwable e) { + throw new WmsException(Code.InvalidParameterValue, "Invalid bbox"); + } + return rval; + } - /** - * @param crs - * @return - * @throws WmsException - */ - protected CoordinateReferenceSystem parseCrs(String crs) - throws WmsException { - try { - return CrsLookup.lookup(crs); - } catch (Throwable e) { - throw new WmsException(Code.InvalidCRS); - } - } + /** + * @param crs + * @return + * @throws WmsException + */ + protected CoordinateReferenceSystem parseCrs(String crs) + throws WmsException { + try { + return CrsLookup.lookup(crs); + } catch (Throwable e) { + throw new WmsException(Code.InvalidCRS); + } + } - protected Color parseColor(String color) throws WmsException { - if (color == null) { - return Color.white; - } - try { - return Color.decode(color); - } catch (NumberFormatException e) { - throw new WmsException(Code.InvalidParameterValue, - "Invalid bgcolor: " + color); - } - } + protected Color parseColor(String color) throws WmsException { + if (color == null) { + return Color.white; + } + try { + return Color.decode(color); + } catch (NumberFormatException e) { + throw new WmsException(Code.InvalidParameterValue, + "Invalid bgcolor: " + color); + } + } - protected BufferedImage resize(BufferedImage input, int width, int height) { - BufferedImage rval = input; - // int type = transparent ? BufferedImage.TYPE_INT_ARGB - // : BufferedImage.TYPE_INT_RGB; - int type = BufferedImage.TYPE_INT_ARGB; - boolean quality = !resizeHint.equalsIgnoreCase("speed"); - Object hint = quality ? RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR - : RenderingHints.VALUE_INTERPOLATION_BILINEAR; - int h = quality ? input.getHeight() : height; - int w = quality ? input.getWidth() : width; + protected BufferedImage resize(BufferedImage input, int width, int height) { + BufferedImage rval = input; + // int type = transparent ? BufferedImage.TYPE_INT_ARGB + // : BufferedImage.TYPE_INT_RGB; + int type = BufferedImage.TYPE_INT_ARGB; + boolean quality = !resizeHint.equalsIgnoreCase("speed"); + Object hint = quality ? RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR + : RenderingHints.VALUE_INTERPOLATION_BILINEAR; + int h = quality ? input.getHeight() : height; + int w = quality ? input.getWidth() : width; - do { - if (quality && w > width) { - w /= 2; - if (w < width) { - w = width; - } - } else { - w = width; - } - if (quality && h > height) { - h /= 2; - if (h < height) { - h = height; - } - } else { - h = height; - } - BufferedImage tmp = new BufferedImage(w, h, type); - Graphics2D g = tmp.createGraphics(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint); - g.drawImage(rval, 0, 0, w, h, null); - g.dispose(); - rval = tmp; - } while (w != width || h != height); - return rval; - } + do { + if (quality && w > width) { + w /= 2; + if (w < width) { + w = width; + } + } else { + w = width; + } + if (quality && h > height) { + h /= 2; + if (h < height) { + h = height; + } + } else { + h = height; + } + BufferedImage tmp = new BufferedImage(w, h, type); + Graphics2D g = tmp.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint); + g.drawImage(rval, 0, 0, w, h, null); + g.dispose(); + rval = tmp; + } while (w != width || h != height); + return rval; + } - /** - * @param width - * @param height - * @return - */ - protected BufferedImage createBlank(Integer width, Integer height) { - return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - } + /** + * @param width + * @param height + * @return + */ + protected BufferedImage createBlank(Integer width, Integer height) { + return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + } - public static BufferedImage mergeWmsImages(List images, - boolean clear, Color bgcolor, int width, int height, Envelope env, - CoordinateReferenceSystem crs) throws WmsException { - GeneralEnvelope bounds = new GeneralEnvelope(crs); - bounds.setEnvelope(env.getMinX(), env.getMinY(), env.getMaxX(), - env.getMaxY()); - DefaultMapContext map = new DefaultMapContext(); - try { - populateMap(map, images, bounds); - Rectangle dims = new Rectangle(width, height); - ReferencedEnvelope re = new ReferencedEnvelope(env, crs); - if (clear) { - bgcolor = null; - } - return StyleUtility.mapToImage(map, dims, re, bgcolor); - } finally { - if (map != null) { - // map.dispose(); - } - } - } + public static BufferedImage mergeWmsImages(List images, + boolean clear, Color bgcolor, int width, int height, Envelope env, + CoordinateReferenceSystem crs) throws WmsException { + GeneralEnvelope bounds = new GeneralEnvelope(crs); + bounds.setEnvelope(env.getMinX(), env.getMinY(), env.getMaxX(), + env.getMaxY()); + DefaultMapContext map = new DefaultMapContext(); + try { + populateMap(map, images, bounds); + Rectangle dims = new Rectangle(width, height); + ReferencedEnvelope re = new ReferencedEnvelope(env, crs); + if (clear) { + bgcolor = null; + } + return StyleUtility.mapToImage(map, dims, re, bgcolor); + } finally { + if (map != null) { + // map.dispose(); + } + } + } - protected static void populateMap(MapContext map, List images, - GeneralEnvelope bounds) { - for (WmsImage i : images) { - switch (i.getType()) { - case COVERAGE: - map.addLayer(i.getCoverage(), i.getStyle()); - break; - case FEATURE: - map.addLayer(i.getFeatures(), i.getStyle()); - break; - case STYLE_EMBEDDED_FEATURE: - handleStyledFeatures(map, i.getFeatures()); - break; - case BLANK: - // skip - break; - default: - throw new IllegalStateException("Unkown WMS data type: " - + i.getType()); - } - } - } + protected static void populateMap(MapContext map, List images, + GeneralEnvelope bounds) { + for (WmsImage i : images) { + switch (i.getType()) { + case COVERAGE: + map.addLayer(i.getCoverage(), i.getStyle()); + break; + case FEATURE: + map.addLayer(i.getFeatures(), i.getStyle()); + break; + case STYLE_EMBEDDED_FEATURE: + handleStyledFeatures(map, i.getFeatures()); + break; + case BLANK: + // skip + break; + default: + throw new IllegalStateException("Unkown WMS data type: " + + i.getType()); + } + } + } - /** - * @param map - * @param features - */ - protected static void handleStyledFeatures(MapContext map, - FeatureCollection features) { - Iterator i = features.iterator(); - StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory(null); - while (i.hasNext()) { - SimpleFeature feature = i.next(); - Style style = extractStyle(feature, styleFactory); - MemoryFeatureCollection coll = new MemoryFeatureCollection( - feature.getFeatureType()); - coll.addAll(features); - map.addLayer(coll, style); - } - } + /** + * @param map + * @param features + */ + protected static void handleStyledFeatures(MapContext map, + FeatureCollection features) { + Iterator i = features.iterator(); + StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory(null); + while (i.hasNext()) { + SimpleFeature feature = i.next(); + Style style = extractStyle(feature, styleFactory); + MemoryFeatureCollection coll = new MemoryFeatureCollection( + feature.getFeatureType()); + coll.addAll(features); + map.addLayer(coll, style); + } + } - protected static Style extractStyle(SimpleFeature feature, - StyleFactory factory) { - Object styleObj = feature.getAttribute("Style"); - Style style = null; - if (styleObj == null) { - return null; - } - if (styleObj instanceof FeatureTypeStyle) { - style = factory.createStyle(); - style.featureTypeStyles().add((FeatureTypeStyle) styleObj); - } else if (styleObj instanceof Style) { - style = (Style) styleObj; - } - return style; - } + protected static Style extractStyle(SimpleFeature feature, + StyleFactory factory) { + Object styleObj = feature.getAttribute("Style"); + Style style = null; + if (styleObj == null) { + return null; + } + if (styleObj instanceof FeatureTypeStyle) { + style = factory.createStyle(); + style.featureTypeStyles().add((FeatureTypeStyle) styleObj); + } else if (styleObj instanceof Style) { + style = (Style) styleObj; + } + return style; + } - @Deprecated - protected BufferedImage mergeImages(List images, - boolean clear, Color bgcolor, int width, int height) - throws WmsException { - Iterator i = images.iterator(); - BufferedImage rval = createBlank(width, height); - Graphics2D graphics = rval.createGraphics(); - if (!clear) { - graphics.setColor(bgcolor); - graphics.fillRect(0, 0, width, height); - } - while (i.hasNext()) { - graphics.drawImage(i.next(), 0, 0, null); - } - graphics.dispose(); - return rval; - } + @Deprecated + protected BufferedImage mergeImages(List images, + boolean clear, Color bgcolor, int width, int height) + throws WmsException { + Iterator i = images.iterator(); + BufferedImage rval = createBlank(width, height); + Graphics2D graphics = rval.createGraphics(); + if (!clear) { + graphics.setColor(bgcolor); + graphics.fillRect(0, 0, width, height); + } + while (i.hasNext()) { + graphics.drawImage(i.next(), 0, 0, null); + } + graphics.dispose(); + return rval; + } - protected boolean parseTransparent(Boolean transparent) { - if (transparent == null) { - return false; - } - return transparent; - } + protected boolean parseTransparent(Boolean transparent) { + if (transparent == null) { + return false; + } + return transparent; + } - @Override - public OgcResponse getError(WmsException e, String exceptionFormat) { - if (exceptionFormat == null) { - exceptionFormat = "text/xml"; - } + @Override + public OgcResponse getError(WmsException e, MimeType exceptionFormat) { + if (exceptionFormat == null) { + exceptionFormat = OgcResponse.TEXT_XML_MIME; + } - String rval = ""; - String mimeType = "text/xml"; - if (exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_HTML_MIME)) { - rval = ""; - rval += "
An error occurred performing the request:
"; - rval += "
Error Code: " + e.getCode().toString(); - rval += "
Message: " + e.getMessage() + ""; - mimeType = OgcResponse.TEXT_HTML_MIME; - } else if (exceptionFormat.equalsIgnoreCase(OgcResponse.TEXT_XML_MIME) - || exceptionFormat - .equalsIgnoreCase(OgcResponse.APP_VND_OGC_SE_XML)) { - rval = wmsExceptionToXml(e); - mimeType = OgcResponse.TEXT_XML_MIME; - } - OgcResponse resp = new OgcResponse(rval, mimeType, TYPE.TEXT); - switch (e.getCode()) { - case InternalServerError: - resp.setError(ErrorType.INT_ERR); - break; - case OperationNotSupported: - resp.setError(ErrorType.NOT_IMPLEMENTED); - break; - default: - resp.setError(ErrorType.BAD_REQ); - } - return resp; - } + String rval = ""; + MimeType mimeType = OgcResponse.TEXT_XML_MIME; + if (exceptionFormat.equalsIgnoreParams(OgcResponse.TEXT_HTML_MIME)) { + rval = ""; + rval += "
An error occurred performing the request:
"; + rval += "
Error Code: " + e.getCode().toString(); + rval += "
Message: " + e.getMessage() + ""; + mimeType = OgcResponse.TEXT_HTML_MIME; + } else if (exceptionFormat + .equalsIgnoreParams(OgcResponse.TEXT_XML_MIME) + || exceptionFormat + .equalsIgnoreParams(OgcResponse.APP_VND_OGC_SE_XML)) { + rval = wmsExceptionToXml(e); + mimeType = OgcResponse.TEXT_XML_MIME; + } + OgcResponse resp = new OgcResponse(rval, mimeType, TYPE.TEXT); + switch (e.getCode()) { + case InternalServerError: + resp.setError(ErrorType.INT_ERR); + break; + case OperationNotSupported: + resp.setError(ErrorType.NOT_IMPLEMENTED); + break; + default: + resp.setError(ErrorType.BAD_REQ); + } + return resp; + } - private String wmsExceptionToXml(WmsException e) { - ServiceExceptionType exType = new ServiceExceptionType(); - exType.setCode(e.getCode().toString()); - exType.setValue(e.getMessage()); - ServiceExceptionReport report = new ServiceExceptionReport(); - report.setServiceException(Arrays.asList(exType)); - String rval = ""; - try { - JAXBContext context = JAXBContext - .newInstance(ServiceExceptionReport.class); - Marshaller marshaller = context.createMarshaller(); + private String wmsExceptionToXml(WmsException e) { + ServiceExceptionType exType = new ServiceExceptionType(); + exType.setCode(e.getCode().toString()); + exType.setValue(e.getMessage()); + ServiceExceptionReport report = new ServiceExceptionReport(); + report.setServiceException(Arrays.asList(exType)); + String rval = ""; + try { + JAXBContext context = JAXBContext + .newInstance(ServiceExceptionReport.class); + Marshaller marshaller = context.createMarshaller(); - StringWriter writer = new StringWriter(); - marshaller.marshal(report, writer); - rval = writer.toString(); - } catch (JAXBException e1) { - log.error(e1); - return fallbackXmlError(e); - } - return rval; - } + StringWriter writer = new StringWriter(); + marshaller.marshal(report, writer); + rval = writer.toString(); + } catch (JAXBException e1) { + log.error(e1.getLocalizedMessage(), e1); + return fallbackXmlError(e); + } + return rval; + } - private String fallbackXmlError(WmsException e) { - String rval = ""; - rval += ""; - rval += ""; - rval += ""; - rval += e.getMessage(); - rval += ""; - return rval; - } + private String fallbackXmlError(WmsException e) { + String rval = ""; + rval += ""; + rval += ""; + rval += ""; + rval += e.getMessage(); + rval += ""; + return rval; + } - protected OgcResponse checkGetMapArgs(GetMapRequest req) { - StyledLayerDescriptor sld = req.getSld(); - String[] layers = req.getLayers(); - boolean sldOnly = sld != null && layers == null; - OgcResponse rval = null; - List missing = new LinkedList(); - if (!sldOnly && (layers == null || layers.length < 1)) { - missing.add(WmsHttpHandler.LAYERS_HEADER); - } - String[] styles = req.getStyles(); - if (!sldOnly && (styles == null || styles.length < 1)) { - missing.add(WmsHttpHandler.STYLES_HEADER); - } - String crs = req.getCrs(); - if (crs == null || crs.isEmpty()) { - missing.add(WmsHttpHandler.CRS_HEADER); - } - if (req.getBbox() == null) { - missing.add(WmsHttpHandler.BBOX_HEADER); - } - if (req.getWidth() == null) { - missing.add(WmsHttpHandler.WIDTH_HEADER); - } - if (req.getHeight() == null) { - missing.add(WmsHttpHandler.HEIGHT_HEADER); - } - String format = req.getFormat(); - if (format == null || format.isEmpty()) { - missing.add(WmsHttpHandler.FORMAT_HEADER); - } - if (!missing.isEmpty()) { - Iterator i = missing.iterator(); - String msg = "Missing the following parameter(s): " + i.next(); - while (i.hasNext()) { - msg += ", " + i.next(); - } - WmsException e = new WmsException(Code.MissingParameterValue, msg); - rval = getError(e, req.getExceptionFormat()); - } else if (!sldOnly && (layers.length != styles.length)) { - WmsException e = new WmsException(Code.MissingParameterValue, - "must have the same number of layers and styles"); - rval = getError(e, req.getExceptionFormat()); - } - return rval; - } + protected OgcResponse checkGetMapArgs(GetMapRequest req) { + StyledLayerDescriptor sld = req.getSld(); + String[] layers = req.getLayers(); + boolean sldOnly = sld != null && layers == null; + OgcResponse rval = null; + List missing = new LinkedList(); + if (!sldOnly && (layers == null || layers.length < 1)) { + missing.add(WmsHttpHandler.LAYERS_HEADER); + } + String[] styles = req.getStyles(); + if (!sldOnly && (styles == null || styles.length < 1)) { + missing.add(WmsHttpHandler.STYLES_HEADER); + } + String crs = req.getCrs(); + if (crs == null || crs.isEmpty()) { + missing.add(WmsHttpHandler.CRS_HEADER); + } + if (req.getBbox() == null) { + missing.add(WmsHttpHandler.BBOX_HEADER); + } + if (req.getWidth() == null) { + missing.add(WmsHttpHandler.WIDTH_HEADER); + } + if (req.getHeight() == null) { + missing.add(WmsHttpHandler.HEIGHT_HEADER); + } + MimeType format = req.getFormat(); + if (format == null) { + missing.add(WmsHttpHandler.FORMAT_HEADER); + } + if (!missing.isEmpty()) { + Iterator i = missing.iterator(); + String msg = "Missing the following parameter(s): " + i.next(); + while (i.hasNext()) { + msg += ", " + i.next(); + } + WmsException e = new WmsException(Code.MissingParameterValue, msg); + rval = getError(e, req.getExceptionFormat()); + } else if (!sldOnly && (layers.length != styles.length)) { + WmsException e = new WmsException(Code.MissingParameterValue, + "must have the same number of layers and styles"); + rval = getError(e, req.getExceptionFormat()); + } + return rval; + } - public String getResizeHint() { - return resizeHint; - } + public String getResizeHint() { + return resizeHint; + } - public void setResizeHint(String resizeHint) { - this.resizeHint = resizeHint; - } + public void setResizeHint(String resizeHint) { + this.resizeHint = resizeHint; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.WmsProvider#getFeatureInfo(com.raytheon.uf.edex - * .wms.GetFeatureInfoRequest) - */ - @Override - public OgcResponse getFeatureInfo(GetFeatureInfoRequest req) { - GetMapRequest mapReq = req.getMapRequest(); - OgcResponse rval; - if ((rval = checkGetMapArgs(mapReq)) != null) { - // problem - return rval; - } - try { - String[] layers = req.getReqLayers(); - if (layers == null || layers.length < 1) { - throw new WmsException(Code.MissingParameterValue, - "Missing query_layers parameter"); - } - if (req.getInfoFormat() == null) { - throw new WmsException(Code.MissingParameterValue, - "Missing info_format parameter"); - } - GridGeometry2D geom = createGridGeometry(mapReq); - Coordinate coord = getCrsCoord(geom, req); - CoordinateReferenceSystem crs = geom.getCoordinateReferenceSystem(); - Envelope bbox = parseEnvString(mapReq.getBbox(), crs); - List> features = new ArrayList>(); - double scale = getScale(bbox, req.getWidth(), req.getHeight()); - for (String layer : layers) { - WmsSource source = layerManager.getSource(layer); - List res = source.getFeatureInfo(layer, - geom.getCoordinateReferenceSystem(), bbox, - mapReq.getTime(), mapReq.getElevation(), - mapReq.getDimensions(), coord, scale); - if (!res.isEmpty()) { - features.add(res); - } - } - rval = formatFeatures(features, req.getInfoFormat()); - } catch (WmsException e) { - rval = getError(e, req.getExceptionFormat()); - } - return rval; - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.WmsProvider#getFeatureInfo(com.raytheon.uf.edex + * .wms.GetFeatureInfoRequest) + */ + @Override + public OgcResponse getFeatureInfo(GetFeatureInfoRequest req) { + GetMapRequest mapReq = req.getMapRequest(); + OgcResponse rval; + if ((rval = checkGetMapArgs(mapReq)) != null) { + // problem + return rval; + } + try { + String[] layers = req.getReqLayers(); + if (layers == null || layers.length < 1) { + throw new WmsException(Code.MissingParameterValue, + "Missing query_layers parameter"); + } + if (req.getInfoFormat() == null) { + throw new WmsException(Code.MissingParameterValue, + "Missing info_format parameter"); + } + String[] times = req.getTimes(); + GridGeometry2D geom = createGridGeometry(mapReq); + Coordinate coord = getCrsCoord(geom, req); + CoordinateReferenceSystem crs = geom.getCoordinateReferenceSystem(); + Envelope bbox = parseEnvString(mapReq.getBbox(), crs); + List> features = new ArrayList>(); + double scale = getScale(bbox, req.getWidth(), req.getHeight()); + for (int i = 0; i < layers.length; ++i) { + String layer = layers[i]; + String time = times[i]; + WmsSource source = layerManager.getSource(layer); + List res = source.getFeatureInfo(layer, + geom.getCoordinateReferenceSystem(), bbox, time, + mapReq.getElevation(), mapReq.getDimensions(), coord, + scale); + if (!res.isEmpty()) { + features.add(res); + } + } + rval = formatFeatures(features, req.getInfoFormat()); + } catch (WmsException e) { + rval = getError(e, req.getExceptionFormat()); + } + return rval; + } - public static double getScale(Envelope env, int width, int height) { - double xscale = Math.abs((double) env.getMaxX() - env.getMinX()) - / width; - double yscale = Math.abs((double) env.getMaxY() - env.getMinY()) - / height; - double average = (xscale + yscale) / 2; - return average; - } + public static double getScale(Envelope env, int width, int height) { + double xscale = Math.abs((double) env.getMaxX() - env.getMinX()) + / width; + double yscale = Math.abs((double) env.getMaxY() - env.getMinY()) + / height; + double average = (xscale + yscale) / 2; + return average; + } - protected OgcResponse formatFeatures(List> features, - String format) throws WmsException { - SimpleFeatureFormatter formatter = getFormatter(format); - if (formatter == null) { - throw new WmsException(Code.InvalidFormat, "Unknown format " - + format); - } - try { - return formatter.format(features); - } catch (java.lang.Exception e) { - log.error("Problem formatting features", e); - throw new WmsException(Code.InternalServerError); - } - } + protected OgcResponse formatFeatures(List> features, + MimeType format) throws WmsException { + SimpleFeatureFormatter formatter = getFormatter(format); + if (formatter == null) { + throw new WmsException(Code.InvalidFormat, "Unknown format " + + format); + } + try { + return formatter.format(features); + } catch (java.lang.Exception e) { + log.error("Problem formatting features", e); + throw new WmsException(Code.InternalServerError); + } + } - public static SimpleFeatureFormatter getFormatter(String format) { - ApplicationContext ctx = EDEXUtil.getSpringContext(); - String[] beans = ctx.getBeanNamesForType(SimpleFeatureFormatter.class); - for (String bean : beans) { - SimpleFeatureFormatter sff = (SimpleFeatureFormatter) ctx.getBean(bean); - if ( sff.matchesFormat(format) ){ - return sff; - } - } - return null; - } + public static SimpleFeatureFormatter getFormatter(MimeType format) { + ApplicationContext ctx = EDEXUtil.getSpringContext(); + String[] beans = ctx.getBeanNamesForType(SimpleFeatureFormatter.class); + for (String bean : beans) { + SimpleFeatureFormatter sff = (SimpleFeatureFormatter) ctx + .getBean(bean); + if (sff.matchesFormat(format)) { + return sff; + } + } + return null; + } - protected Coordinate getCrsCoord(GridGeometry2D geom, - GetFeatureInfoRequest req) throws WmsException { - Integer i = req.getI(); - Integer j = req.getJ(); - if (i == null || j == null) { - throw new WmsException(Code.MissingParameterValue, - "Missing I or J parameter"); - } - try { - return getCrsCoord(geom, i, j); - } catch (Throwable e) { - log.error("Problem getting CRS coordinates", e); - throw new WmsException(Code.InternalServerError); - } - } + protected Coordinate getCrsCoord(GridGeometry2D geom, + GetFeatureInfoRequest req) throws WmsException { + Integer i = req.getI(); + Integer j = req.getJ(); + if (i == null || j == null) { + throw new WmsException(Code.MissingParameterValue, + "Missing I or J parameter"); + } + try { + return getCrsCoord(geom, i, j); + } catch (Throwable e) { + log.error("Problem getting CRS coordinates", e); + throw new WmsException(Code.InternalServerError); + } + } - public static Coordinate getCrsCoord(GridGeometry2D geom, Integer i, - Integer j) throws Throwable { - MathTransform2D gridToCRS2D = geom.getGridToCRS2D(); - DirectPosition grid = new DirectPosition2D(i, j); - DirectPosition origCrs = new DirectPosition2D(); - gridToCRS2D.transform(grid, origCrs); - return new Coordinate(origCrs.getOrdinate(0), origCrs.getOrdinate(1)); - } + public static Coordinate getCrsCoord(GridGeometry2D geom, Integer i, + Integer j) throws Throwable { + MathTransform2D gridToCRS2D = geom.getGridToCRS2D(); + DirectPosition grid = new DirectPosition2D(i, j); + DirectPosition origCrs = new DirectPosition2D(); + gridToCRS2D.transform(grid, origCrs); + return new Coordinate(origCrs.getOrdinate(0), origCrs.getOrdinate(1)); + } - protected GridGeometry2D createGridGeometry(GetMapRequest mapReq) - throws WmsException { - CoordinateReferenceSystem crs = parseCrs(mapReq.getCrs()); - Envelope bbox = parseEnvString(mapReq.getBbox(), crs); - GeneralEnvelope env = new GeneralEnvelope(crs); - env.setEnvelope(bbox.getMinX(), bbox.getMinY(), bbox.getMaxX(), - bbox.getMaxY()); - GridEnvelope gridRange = new GeneralGridEnvelope(new int[] { 0, 0 }, - new int[] { mapReq.getWidth(), mapReq.getHeight() }); - GridGeometry2D rval = new GridGeometry2D(gridRange, env); - return rval; - } + protected GridGeometry2D createGridGeometry(GetMapRequest mapReq) + throws WmsException { + CoordinateReferenceSystem crs = parseCrs(mapReq.getCrs()); + Envelope bbox = parseEnvString(mapReq.getBbox(), crs); + GeneralEnvelope env = new GeneralEnvelope(crs); + env.setEnvelope(bbox.getMinX(), bbox.getMinY(), bbox.getMaxX(), + bbox.getMaxY()); + GridEnvelope gridRange = new GeneralGridEnvelope(new int[] { 0, 0 }, + new int[] { mapReq.getWidth(), mapReq.getHeight() }); + GridGeometry2D rval = new GridGeometry2D(gridRange, env); + return rval; + } - protected OgcResponse checkGetLegendGraphicArgs(GetLegendGraphicRequest req) { - StyledLayerDescriptor sld = req.getSld(); - String layer = req.getLayer(); - boolean sldOnly = sld != null && layer == null; - OgcResponse rval = null; - List missing = new LinkedList(); - if (!sldOnly && layer == null) { - missing.add(WmsHttpHandler.LAYER_HEADER); - } - String format = req.getFormat(); - if (format == null || format.isEmpty()) { - missing.add(WmsHttpHandler.FORMAT_HEADER); - } - if (!missing.isEmpty()) { - Iterator i = missing.iterator(); - String msg = "Missing the following parameter(s): " + i.next(); - while (i.hasNext()) { - msg += ", " + i.next(); - } - WmsException e = new WmsException(Code.MissingParameterValue, msg); - rval = getError(e, req.getExceptionFormat()); - } - return rval; - } + protected OgcResponse checkGetLegendGraphicArgs(GetLegendGraphicRequest req) { + StyledLayerDescriptor sld = req.getSld(); + String layer = req.getLayer(); + boolean sldOnly = sld != null && layer == null; + OgcResponse rval = null; + List missing = new LinkedList(); + if (!sldOnly && layer == null) { + missing.add(WmsHttpHandler.LAYER_HEADER); + } + MimeType format = req.getFormat(); + if (format == null) { + missing.add(WmsHttpHandler.FORMAT_HEADER); + } + if (!missing.isEmpty()) { + Iterator i = missing.iterator(); + String msg = "Missing the following parameter(s): " + i.next(); + while (i.hasNext()) { + msg += ", " + i.next(); + } + WmsException e = new WmsException(Code.MissingParameterValue, msg); + rval = getError(e, req.getExceptionFormat()); + } + return rval; + } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.edex.wms.WmsProvider#getFeatureInfo(com.raytheon.uf.edex - * .wms.GetFeatureInfoRequest) - */ - @Override - public OgcResponse getLegendGraphic(GetLegendGraphicRequest req) { - OgcResponse rval = null; - StyledLayerDescriptor sld = req.getSld(); - String layer = req.getLayer(); - String style = req.getStyle(); - String time = req.getTime(); - String elevation = req.getElevation(); - Map dimensions = req.getDimensions(); - Integer width = req.getWidth(); - Integer height = req.getHeight(); - boolean sldOnly = sld != null && layer == null; - if ((rval = checkGetLegendGraphicArgs(req)) != null) { - // problem - return rval; - } - String username = req.getUserName(); - String[] roles = req.getRoles(); - try { - BufferedImage legend = null; - GetLegendProcessor proc = new GetLegendProcessor(layerManager, - time, elevation, dimensions, width, height, username, roles); - if (sld == null) { - legend = proc.getLegend(layer, style, true); - } else if (sldOnly) { - // This should never happen because layers is a required. - legend = proc.getLegendSld(sld); - } else { - legend = proc.getLegendStyleLib(layer, style, sld); - } - if (!parseTransparent(req.getTransparent())) { - String bgString = req.getBgcolor(); - legend = GetLegendProcessor.applyBackground(legend, - parseColor(bgString)); - } - rval = new OgcResponse(legend, req.getFormat(), TYPE.IMAGE); - } catch (WmsException e) { - rval = getError(e, req.getExceptionFormat()); - } + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.edex.wms.WmsProvider#getFeatureInfo(com.raytheon.uf.edex + * .wms.GetFeatureInfoRequest) + */ + @Override + public OgcResponse getLegendGraphic(GetLegendGraphicRequest req) { + OgcResponse rval = null; + StyledLayerDescriptor sld = req.getSld(); + String layer = req.getLayer(); + String style = req.getStyle(); + String time = req.getTime(); + String elevation = req.getElevation(); + Map dimensions = req.getDimensions(); + Integer width = req.getWidth(); + Integer height = req.getHeight(); + boolean sldOnly = sld != null && layer == null; + if ((rval = checkGetLegendGraphicArgs(req)) != null) { + // problem + return rval; + } + String username = req.getUserName(); + String[] roles = req.getRoles(); + try { + BufferedImage legend = null; + GetLegendProcessor proc = new GetLegendProcessor(layerManager, + time, elevation, dimensions, width, height, username, roles); + if (sld == null) { + legend = proc.getLegend(layer, style, true); + } else if (sldOnly) { + // This should never happen because layers is a required. + legend = proc.getLegendSld(sld); + } else { + // empty datauri assumed non-issue since sld is defined + legend = proc.getLegendStyleLib(layer, "", style, sld); + } + if (!parseTransparent(req.getTransparent())) { + String bgString = req.getBgcolor(); + legend = GetLegendProcessor.applyBackground(legend, + parseColor(bgString)); + } + rval = new OgcResponse(legend, req.getFormat(), TYPE.IMAGE); + } catch (WmsException e) { + rval = getError(e, req.getExceptionFormat()); + } - return rval; - } + return rval; + } } diff --git a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/WmsLayerManager.java b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/WmsLayerManager.java index 01f24a4f63..0f5b6e1e63 100644 --- a/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/WmsLayerManager.java +++ b/edexOsgi/com.raytheon.uf.edex.wms/src/com/raytheon/uf/edex/wms/provider/WmsLayerManager.java @@ -45,9 +45,9 @@ import net.opengis.wms.v_1_3_0.OnlineResource; import net.opengis.wms.v_1_3_0.Style; import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; import com.raytheon.uf.edex.ogc.common.OgcDimension; import com.raytheon.uf.edex.ogc.common.OgcGeoBoundingBox; @@ -57,7 +57,8 @@ import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.ogc.common.OgcStyle; import com.raytheon.uf.edex.wms.WmsException; import com.raytheon.uf.edex.wms.WmsException.Code; -import com.raytheon.uf.edex.wms.WmsProvider.WmsOpType; +import com.raytheon.uf.edex.wms.WmsHttpHandler; +import com.raytheon.uf.edex.wms.IWmsProvider.WmsOpType; import com.raytheon.uf.edex.wms.reg.WmsSource; import com.raytheon.uf.edex.wms.reg.WmsSourceAccessor; @@ -67,288 +68,284 @@ import com.raytheon.uf.edex.wms.reg.WmsSourceAccessor; */ public class WmsLayerManager { - protected HashMap> layermap = new HashMap>(); + protected HashMap> layermap = new HashMap>(); - protected WmsSourceAccessor registry = new WmsSourceAccessor(); + protected WmsSourceAccessor registry = new WmsSourceAccessor(); - protected boolean caching = false; + protected boolean caching = false; - protected String componentPrefix = "wms"; + protected String componentPrefix = "wms"; - private OgcOperationInfo _getLegendOp = null; + protected IUFStatusHandler log = UFStatus.getHandler(this.getClass()); - protected Log log = LogFactory.getLog(this.getClass()); + public WmsSource getSource(String layer) throws WmsException { + return getSource(layer, null, null); + } - public WmsSource getSource(String layer) throws WmsException { - return getSource(layer, null, null); - } + public WmsSource getSource(String layer, String username, Set roles) + throws WmsException { + String key = OgcLayer.getKey(layer); + WmsSource rval = registry.getSources().get(key); + if (rval != null && username != null) { + // if (!OgcAuthUtils.isAuthorized(roles, getSourceRoles(key))) { + // // act like the layer doesn't exist + // rval = null; + // } + } + if (rval == null) { + throw new WmsException(Code.LayerNotDefined, + "No layer registered: " + layer); + } - public WmsSource getSource(String layer, String username, Set roles) - throws WmsException { - String key = OgcLayer.getKey(layer); - WmsSource rval = registry.getSources().get(key); - if (rval != null && username != null) { - // if (!OgcAuthUtils.isAuthorized(roles, getSourceRoles(key))) { - // // act like the layer doesn't exist - // rval = null; - // } - } - if (rval == null) { - throw new WmsException(Code.LayerNotDefined, - "No layer registered: " + layer); - } + return rval; + } - return rval; - } + public List getLayers(OgcServiceInfo ogcServiceInfo) { + if (caching) { + return getLayersCache(ogcServiceInfo); + } else { + return getLayersDirect(ogcServiceInfo); + } + } - public List getLayers(OgcServiceInfo ogcServiceInfo) { - if (caching) { - return getLayersCache(ogcServiceInfo); - } else { - return getLayersDirect(ogcServiceInfo); - } - } + protected List getLayersCache( + OgcServiceInfo ogcServiceInfo) { + List rval = new LinkedList(); + Map sources = registry.getSources(); + for (String key : sources.keySet()) { + WmsSource source = sources.get(key); + List layers; + if (layermap.isEmpty() || source.hasUpdated()) { + layers = getPluginLayers(source, ogcServiceInfo); + layermap.put(key, layers); + } else { + layers = layermap.get(key); + } + rval.addAll(layers); + } + return rval; + } - protected List getLayersCache( - OgcServiceInfo ogcServiceInfo) { - List rval = new LinkedList(); - Map sources = registry.getSources(); - for (String key : sources.keySet()) { - WmsSource source = sources.get(key); - List layers; - if (layermap.isEmpty() || source.hasUpdated()) { - layers = getPluginLayers(source, ogcServiceInfo); - layermap.put(key, layers); - } else { - layers = layermap.get(key); - } - rval.addAll(layers); - } - return rval; - } + protected List getLayersDirect( + OgcServiceInfo ogcServiceInfo) { + List rval = new LinkedList(); + Map sources = registry.getSources(); + for (WmsSource source : sources.values()) { + rval.addAll(getPluginLayers(source, ogcServiceInfo)); + } + return rval; + } - protected List getLayersDirect( - OgcServiceInfo ogcServiceInfo) { - List rval = new LinkedList(); - Map sources = registry.getSources(); - for (WmsSource source : sources.values()) { - rval.addAll(getPluginLayers(source, ogcServiceInfo)); - } - return rval; - } + /** + * @param source + * @param ogcServiceInfo + * @return + */ + protected List getPluginLayers(WmsSource source, + OgcServiceInfo ogcServiceInfo) { + List rval = new LinkedList(); + for (OgcLayer layer : source.listLayers()) { + rval.add(getLayerRecursive(layer, ogcServiceInfo)); + } + return rval; + } - /** - * @param source - * @param ogcServiceInfo - * @return - */ - protected List getPluginLayers(WmsSource source, - OgcServiceInfo ogcServiceInfo) { - List rval = new LinkedList(); - for (OgcLayer layer : source.listLayers()) { - rval.add(getLayerRecursive(layer, ogcServiceInfo)); - } - return rval; - } + /** + * @param layer + * @param ogcServiceInfo + * @return + */ + protected Layer getLayerRecursive(OgcLayer layer, + OgcServiceInfo ogcServiceInfo) { + Layer rval = new Layer(); + rval.setTitle(layer.getTitle()); + rval.setName(layer.getName()); + rval.setAbstract(layer.getAbs()); + rval.setKeywordList(getAsKeywordList(layer.getKeywords())); + List crs = layer.getCrs(); + if (crs != null) { + rval.setCRS(crs); + } + rval.setEXGeographicBoundingBox(getExBB(layer.getGeoBoundingBox())); + rval.setBoundingBox(getBB(layer.getBoundingBox())); + rval.setDimension(getDimensions(layer.getDimensions())); + rval.setStyle(getAsStyles(layer.getStyles(), ogcServiceInfo)); + setScaleDenom(rval, layer.getMinScaleDenom(), layer.getMaxScaleDenom()); + List children = new LinkedList(); + if (layer.getChildren() != null) { + for (OgcLayer child : layer.getChildren()) { + children.add(getLayerRecursive(child, ogcServiceInfo)); + } + } + rval.setLayer(children); + return rval; + } - /** - * @param layer - * @param ogcServiceInfo - * @return - */ - protected Layer getLayerRecursive(OgcLayer layer, - OgcServiceInfo ogcServiceInfo) { - Layer rval = new Layer(); - rval.setTitle(layer.getTitle()); - rval.setName(layer.getName()); - rval.setAbstract(layer.getAbs()); - rval.setKeywordList(getAsKeywordList(layer.getKeywords())); - List crs = layer.getCrs(); - if (crs != null) { - rval.setCRS(crs); - } - rval.setEXGeographicBoundingBox(getExBB(layer.getGeoBoundingBox())); - rval.setBoundingBox(getBB(layer.getBoundingBox())); - rval.setDimension(getDimensions(layer.getDimensions())); - rval.setStyle(getAsStyles(layer.getStyles(), ogcServiceInfo)); - setScaleDenom(rval, layer.getMinScaleDenom(), layer.getMaxScaleDenom()); - List children = new LinkedList(); - if (layer.getChildren() != null) { - for (OgcLayer child : layer.getChildren()) { - children.add(getLayerRecursive(child, ogcServiceInfo)); - } - } - rval.setLayer(children); - return rval; - } + protected void setScaleDenom(Layer layer, double min, double max) { + if (!Double.isNaN(min)) { + layer.setMinScaleDenominator(min); + } + if (!Double.isNaN(max)) { + layer.setMaxScaleDenominator(max); + } + } - protected void setScaleDenom(Layer layer, double min, double max) { - if (!Double.isNaN(min)) { - layer.setMinScaleDenominator(min); - } - if (!Double.isNaN(max)) { - layer.setMaxScaleDenominator(max); - } - } + /** + * @param styles + * @param ogcServiceInfo + * @return + */ + private List