diff --git a/CoTreceiver/build.xml b/CoTreceiver/build.xml index 9b078f002bfa6f4fd3535d16f3a84dc845ce210a..17f3dd023411cc1ad31282d9b7394142148b23f5 100644 --- a/CoTreceiver/build.xml +++ b/CoTreceiver/build.xml @@ -71,6 +71,10 @@ --> + <target name="-post-compile"> + <copy file="${src.resources.dir}/log4j2.xml" todir="${build.classes.dir}"/> + </target> + <target name="clean.logs"> <delete quiet="true" includeemptydirs="true" failonerror="false"> <fileset dir="logs" includes="**/*" excludes="*.default/*,README.md" /> diff --git a/CoTreceiver/CoTtypesTMSWeb.xml b/CoTreceiver/doc/CoTtypesTMSWeb.xml similarity index 100% rename from CoTreceiver/CoTtypesTMSWeb.xml rename to CoTreceiver/doc/CoTtypesTMSWeb.xml diff --git a/CoTreceiver/SDK-Java-1.0.1.zip b/CoTreceiver/doc/SDK-Java-1.0.1.zip similarity index 100% rename from CoTreceiver/SDK-Java-1.0.1.zip rename to CoTreceiver/doc/SDK-Java-1.0.1.zip diff --git a/CoTreceiver/lib/log4j-api-2.23.1.jar b/CoTreceiver/lib/log4j-api-2.23.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..0e8e3f5e5928c3dc9d8d8d06e4f7aacfb5090ed4 Binary files /dev/null and b/CoTreceiver/lib/log4j-api-2.23.1.jar differ diff --git a/CoTreceiver/lib/log4j-core-2.23.1.jar b/CoTreceiver/lib/log4j-core-2.23.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..4a5d553d897b9eb341cc0c818d54b07d5c012f7b Binary files /dev/null and b/CoTreceiver/lib/log4j-core-2.23.1.jar differ diff --git a/CoTreceiver/lib/support/commons-collections4-4.1.jar b/CoTreceiver/lib/support/commons-collections4-4.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..43a9413b930b0f474efd2817c195ef2a88d7f7b2 Binary files /dev/null and b/CoTreceiver/lib/support/commons-collections4-4.1.jar differ diff --git a/CoTreceiver/lib/support/xmlunit-core-2.10.0.jar b/CoTreceiver/lib/support/xmlunit-core-2.10.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..4606e65b28fb27f733c6f6abe9cf55c66574cc0d Binary files /dev/null and b/CoTreceiver/lib/support/xmlunit-core-2.10.0.jar differ diff --git a/CoTreceiver/lib/support/xmlunit-matchers-2.10.0.jar b/CoTreceiver/lib/support/xmlunit-matchers-2.10.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..656cf1b96d766feee254047a65c69a42f9de50db Binary files /dev/null and b/CoTreceiver/lib/support/xmlunit-matchers-2.10.0.jar differ diff --git a/CoTreceiver/nbproject/build-impl.xml b/CoTreceiver/nbproject/build-impl.xml index def1bfc85e82ef5d0ad631860e170a8c6befcc93..4121cd2eebcc3f5ee82b2fc6e842b2cc08f26957 100644 --- a/CoTreceiver/nbproject/build-impl.xml +++ b/CoTreceiver/nbproject/build-impl.xml @@ -90,7 +90,7 @@ is divided into following sections: </not> </condition> </fail> - <j2seproject3:modulename property="module.name" sourcepath="${src.dir}"/> + <j2seproject3:modulename property="module.name" sourcepath="${src.java.dir}:${src.resources.dir}"/> <condition property="named.module.internal"> <and> <isset property="module.name"/> @@ -180,12 +180,14 @@ is divided into following sections: </condition> <condition property="have.tests"> <or> - <available file="${test.src.dir}"/> + <available file="${test.java.dir}"/> + <available file="${test.resources.dir}"/> </or> </condition> <condition property="have.sources"> <or> - <available file="${src.dir}"/> + <available file="${src.java.dir}"/> + <available file="${src.resources.dir}"/> </or> </condition> <condition property="netbeans.home+have.tests"> @@ -288,8 +290,10 @@ is divided into following sections: <!-- You can override this target in the ../build.xml file. --> </target> <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check"> - <fail unless="src.dir">Must set src.dir</fail> - <fail unless="test.src.dir">Must set test.src.dir</fail> + <fail unless="src.java.dir">Must set src.java.dir</fail> + <fail unless="src.resources.dir">Must set src.resources.dir</fail> + <fail unless="test.java.dir">Must set test.java.dir</fail> + <fail unless="test.resources.dir">Must set test.resources.dir</fail> <fail unless="build.dir">Must set build.dir</fail> <fail unless="dist.dir">Must set dist.dir</fail> <fail unless="build.classes.dir">Must set build.classes.dir</fail> @@ -310,7 +314,7 @@ is divided into following sections: </target> <target depends="-init-ap-cmdline-properties,-init-source-module-properties" if="modules.supported.internal" name="-init-macrodef-javac-with-module"> <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3"> - <attribute default="${src.dir}" name="srcdir"/> + <attribute default="${src.java.dir}:${src.resources.dir}" name="srcdir"/> <attribute default="${build.classes.dir}" name="destdir"/> <attribute default="${javac.classpath}" name="classpath"/> <attribute default="${javac.modulepath}" name="modulepath"/> @@ -322,7 +326,7 @@ is divided into following sections: <attribute default="${excludes}" name="excludes"/> <attribute default="${javac.debug}" name="debug"/> <attribute default="${empty.dir}" name="sourcepath" unless:set="named.module.internal"/> - <attribute default="${src.dir}" if:set="named.module.internal" name="sourcepath"/> + <attribute default="${src.java.dir}:${src.resources.dir}" if:set="named.module.internal" name="sourcepath"/> <attribute default="${empty.dir}" name="gensrcdir"/> <element name="customize" optional="true"/> <sequential> @@ -377,7 +381,7 @@ is divided into following sections: </target> <target depends="-init-ap-cmdline-properties,-init-source-module-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors" unless="modules.supported.internal"> <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3"> - <attribute default="${src.dir}" name="srcdir"/> + <attribute default="${src.java.dir}:${src.resources.dir}" name="srcdir"/> <attribute default="${build.classes.dir}" name="destdir"/> <attribute default="${javac.classpath}" name="classpath"/> <attribute default="${javac.modulepath}" name="modulepath"/> @@ -420,7 +424,7 @@ is divided into following sections: </target> <target depends="-init-ap-cmdline-properties,-init-source-module-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal"> <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3"> - <attribute default="${src.dir}" name="srcdir"/> + <attribute default="${src.java.dir}:${src.resources.dir}" name="srcdir"/> <attribute default="${build.classes.dir}" name="destdir"/> <attribute default="${javac.classpath}" name="classpath"/> <attribute default="${javac.modulepath}" name="modulepath"/> @@ -455,7 +459,7 @@ is divided into following sections: </target> <target depends="-init-macrodef-javac-with-module,-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac"> <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3"> - <attribute default="${src.dir}" name="srcdir"/> + <attribute default="${src.java.dir}:${src.resources.dir}" name="srcdir"/> <attribute default="${build.classes.dir}" name="destdir"/> <attribute default="${javac.classpath}" name="classpath"/> <sequential> @@ -588,7 +592,10 @@ is divided into following sections: <j2seproject3:junit-prototype> <customizePrototype> <batchtest todir="${build.test.results.dir}"> - <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}"> + <fileset dir="${test.java.dir}" excludes="@{excludes},${excludes}" includes="@{includes}"> + <filename name="@{testincludes}"/> + </fileset> + <fileset dir="${test.resources.dir}" excludes="@{excludes},${excludes}" includes="@{includes}"> <filename name="@{testincludes}"/> </fileset> <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}"> @@ -614,7 +621,10 @@ is divided into following sections: <isset property="test.method"/> </condition> <union id="test.set"> - <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}"> + <fileset dir="${test.java.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}"> + <filename name="@{testincludes}"/> + </fileset> + <fileset dir="${test.resources.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}"> <filename name="@{testincludes}"/> </fileset> </union> @@ -1090,12 +1100,13 @@ is divided into following sections: <include name="*"/> </dirset> </pathconvert> - <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/> + <j2seproject3:depend srcdir="${src.java.dir}:${src.resources.dir}:${build.generated.subdirs}"/> </target> <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile"> <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/> <copy todir="${build.classes.dir}"> - <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> + <fileset dir="${src.java.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> + <fileset dir="${src.resources.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> </copy> </target> <target if="has.persistence.xml" name="-copy-persistence-xml"> @@ -1116,7 +1127,7 @@ is divided into following sections: <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single"> <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail> <j2seproject3:force-recompile/> - <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}, module-info.java" sourcepath="${src.dir}"/> + <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}, module-info.java" sourcepath="${src.java.dir}:${src.resources.dir}"/> </target> <target name="-post-compile-single"> <!-- Empty placeholder for easier customization. --> @@ -1508,7 +1519,10 @@ is divided into following sections: <classpath> <path path="${javac.classpath}"/> </classpath> - <fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}"> + <fileset dir="${src.java.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}"> + <filename name="**/*.java"/> + </fileset> + <fileset dir="${src.resources.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}"> <filename name="**/*.java"/> </fileset> <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false"> @@ -1519,7 +1533,10 @@ is divided into following sections: <arg line="${javadoc.html5.cmd.line.arg}"/> </javadoc> <copy todir="${dist.javadoc.dir}"> - <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}"> + <fileset dir="${src.java.dir}" excludes="${excludes}" includes="${includes}"> + <filename name="**/doc-files/**"/> + </fileset> + <fileset dir="${src.resources.dir}" excludes="${excludes}" includes="${includes}"> <filename name="**/doc-files/**"/> </fileset> <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false"> @@ -1544,14 +1561,14 @@ is divided into following sections: <!-- You can override this target in the ../build.xml file. --> </target> <target depends="-init-source-module-properties" if="named.module.internal" name="-init-test-javac-module-properties-with-module"> - <j2seproject3:modulename property="test.module.name" sourcepath="${test.src.dir}"/> - <condition else="${empty.dir}" property="javac.test.sourcepath" value="${test.src.dir}"> + <j2seproject3:modulename property="test.module.name" sourcepath="${test.java.dir}:${test.resources.dir}"/> + <condition else="${empty.dir}" property="javac.test.sourcepath" value="${test.java.dir}:${test.resources.dir}"> <and> <isset property="test.module.name"/> <length length="0" string="${test.module.name}" when="greater"/> </and> </condition> - <condition else="--patch-module ${module.name}=${test.src.dir} --add-reads ${module.name}=ALL-UNNAMED" property="javac.test.compilerargs" value="--add-reads ${test.module.name}=ALL-UNNAMED"> + <condition else="--patch-module ${module.name}=${test.java.dir}:${test.resources.dir} --add-reads ${module.name}=ALL-UNNAMED" property="javac.test.compilerargs" value="--add-reads ${test.module.name}=ALL-UNNAMED"> <and> <isset property="test.module.name"/> <length length="0" string="${test.module.name}" when="greater"/> @@ -1592,16 +1609,17 @@ is divided into following sections: </target> <target depends="-init-test-javac-module-properties-with-module,-init-test-module-properties-without-module" name="-init-test-module-properties"/> <target if="do.depend.true" name="-compile-test-depend"> - <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/> + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.java.dir}:${test.resources.dir}"/> </target> <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test"> - <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${javac.test.sourcepath}" srcdir="${test.src.dir}"> + <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${javac.test.sourcepath}" srcdir="${test.java.dir}:${test.resources.dir}"> <customize> <compilerarg line="${javac.test.compilerargs}"/> </customize> </j2seproject3:javac> <copy todir="${build.test.classes.dir}"> - <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> + <fileset dir="${test.java.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> + <fileset dir="${test.resources.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> </copy> </target> <target name="-post-compile-test"> @@ -1616,13 +1634,14 @@ is divided into following sections: <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single"> <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail> <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/> - <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}, module-info.java" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"> + <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}, module-info.java" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${test.java.dir}:${test.resources.dir}" srcdir="${test.java.dir}:${test.resources.dir}"> <customize> <compilerarg line="${javac.test.compilerargs}"/> </customize> </j2seproject3:javac> <copy todir="${build.test.classes.dir}"> - <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> + <fileset dir="${test.java.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> + <fileset dir="${test.resources.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/> </copy> </target> <target name="-post-compile-test-single"> diff --git a/CoTreceiver/nbproject/configs/tcp_home.properties b/CoTreceiver/nbproject/configs/tcp_home.properties index e8b4208aadf4f6a1509080e53a203e94685d7607..83feeee5b4934a5448d2ef6d417ca19db73e1a05 100644 --- a/CoTreceiver/nbproject/configs/tcp_home.properties +++ b/CoTreceiver/nbproject/configs/tcp_home.properties @@ -1,2 +1,2 @@ $label=tcp home -main.class=edu.nps.moves.cot.main.CoTMsgReceiver +main.class=edu.nps.moves.cot.net.CoTMsgReceiverDemo diff --git a/CoTreceiver/nbproject/configs/udp_home.properties b/CoTreceiver/nbproject/configs/udp_home.properties index 6430802c49297e05c315c3fdf877e167cc427026..4886aa4e7eb7e6d29584c73ba5dfca0c80f9b1ff 100644 --- a/CoTreceiver/nbproject/configs/udp_home.properties +++ b/CoTreceiver/nbproject/configs/udp_home.properties @@ -1,2 +1,2 @@ $label=udp home -main.class=edu.nps.moves.cot.main.CoTMsgReceiver +main.class=edu.nps.moves.cot.net.CoTMsgReceiverDemo diff --git a/CoTreceiver/nbproject/genfiles.properties b/CoTreceiver/nbproject/genfiles.properties index df80c3935d4287b1313be88dab75c0713a3c6e79..8593c777aed93b0855236a920d4e5a2993f6d9a6 100644 --- a/CoTreceiver/nbproject/genfiles.properties +++ b/CoTreceiver/nbproject/genfiles.properties @@ -3,6 +3,6 @@ build.xml.script.CRC32=17b920f7 build.xml.stylesheet.CRC32=f85dc8f2@1.111.0.48 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=5995fe75 -nbproject/build-impl.xml.script.CRC32=af40aa00 +nbproject/build-impl.xml.data.CRC32=f6268d2f +nbproject/build-impl.xml.script.CRC32=62a7780b nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.111.0.48 diff --git a/CoTreceiver/nbproject/project.properties b/CoTreceiver/nbproject/project.properties index c58268eeb508f0b0f1c308ef2b6f1150c97a1e0d..18745cd3304c142eafd4d1a24525feb763f83887 100644 --- a/CoTreceiver/nbproject/project.properties +++ b/CoTreceiver/nbproject/project.properties @@ -27,8 +27,7 @@ dist.jlink.dir=${dist.dir}/jlink dist.jlink.output=${dist.jlink.dir}/CoTreceiver endorsed.classpath= excludes= -file.reference.CoTreceiver-src=src -file.reference.CoTreceiver-test=test +file.reference.commons-collections4-4.1.jar=lib/support/commons-collections4-4.1.jar file.reference.commons-io-2.15.1.jar=lib/commons-io-2.15.1.jar file.reference.CoTPLITool.jar=lib/CoTPLITool.jar file.reference.CursorOnTarget-1.0.1.jar=lib/CursorOnTarget-1.0.1.jar @@ -36,21 +35,29 @@ file.reference.guava-28.0-jre.jar=lib/guava-28.0-jre.jar file.reference.jdom-2.0.6.1.jar=lib/jdom-2.0.6.1.jar file.reference.json-20180813.jar=lib/json-20180813.jar file.reference.lib-xsd=lib/xsd +file.reference.log4j-api-2.23.1.jar=lib/log4j-api-2.23.1.jar +file.reference.log4j-core-2.23.1.jar=lib/log4j-core-2.23.1.jar file.reference.opendis7-enumerations-classes.jar=lib/opendis7-enumerations-classes.jar file.reference.opendis7-pdus-classes.jar=lib/opendis7-pdus-classes.jar +file.reference.xmlunit-core-2.10.0.jar=lib/support/xmlunit-core-2.10.0.jar +file.reference.xmlunit-matchers-2.10.0.jar=lib/support/xmlunit-matchers-2.10.0.jar includes=** +jar.archive.disabled=${jnlp.enabled} jar.compress=false +jar.index=${jnlp.enabled} javac.classpath=\ ${libs.jaxb.classpath}:\ ${file.reference.CoTPLITool.jar}:\ ${file.reference.CursorOnTarget-1.0.1.jar}:\ ${file.reference.jdom-2.0.6.1.jar}:\ ${file.reference.json-20180813.jar}:\ + ${file.reference.log4j-api-2.23.1.jar}:\ + ${file.reference.log4j-core-2.23.1.jar}:\ ${file.reference.opendis7-enumerations-classes.jar}:\ ${file.reference.opendis7-pdus-classes.jar}:\ ${file.reference.lib-xsd} javac.compilerargs= -javac.deprecation=false +javac.deprecation=true javac.external.vm=true javac.modulepath= javac.processormodulepath= @@ -62,7 +69,10 @@ javac.test.classpath=\ ${javac.classpath}:\ ${build.classes.dir}:\ ${libs.junit_4.classpath}:\ - ${libs.hamcrest.classpath} + ${libs.hamcrest.classpath}:\ + ${file.reference.commons-collections4-4.1.jar}:\ + ${file.reference.xmlunit-core-2.10.0.jar}:\ + ${file.reference.xmlunit-matchers-2.10.0.jar} javac.test.modulepath=\ ${javac.modulepath} javac.test.processorpath=${javac.test.classpath} @@ -82,8 +92,25 @@ jlink.additionalmodules= jlink.additionalparam= jlink.launcher=true jlink.launcher.name=CoTreceiver +jnlp.codebase.type=no.codebase +jnlp.descriptor=application +jnlp.enabled=false +jnlp.mixed.code=default +jnlp.offline-allowed=false +jnlp.signed=false +jnlp.signing= +jnlp.signing.alias= +jnlp.signing.keystore= junit.selected.version=3 -main.class=edu.nps.moves.cot.main.CoTMsgReceiver +main.class=edu.nps.moves.cot.main.CoTMsgReceiverDemo +# Optional override of default Application-Library-Allowable-Codebase attribute identifying the locations where your signed RIA is expected to be found. +manifest.custom.application.library.allowable.codebase= +# Optional override of default Caller-Allowable-Codebase attribute identifying the domains from which JavaScript code can make calls to your RIA without security prompts. +manifest.custom.caller.allowable.codebase= +# Optional override of default Codebase manifest attribute, use to prevent RIAs from being repurposed +manifest.custom.codebase= +# Optional override of default Permissions manifest attribute (supported values: sandbox, all-permissions) +manifest.custom.permissions= manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF mkdist.disabled=false @@ -99,9 +126,13 @@ run.modulepath=\ ${javac.modulepath} run.test.classpath=\ ${javac.test.classpath}:\ - ${build.test.classes.dir} + ${build.test.classes.dir}:\ + ${file.reference.commons-io-2.15.1.jar}:\ + ${file.reference.guava-28.0-jre.jar} run.test.modulepath=\ ${javac.test.modulepath} source.encoding=UTF-8 -src.dir=${file.reference.CoTreceiver-src} -test.src.dir=${file.reference.CoTreceiver-test} +src.java.dir=src/main/java +src.resources.dir=src/main/resources +test.java.dir=src/test/java +test.resources.dir=src/test/resources diff --git a/CoTreceiver/nbproject/project.xml b/CoTreceiver/nbproject/project.xml index 5f1c15a4d8fe4fa189afd35e5b1917df8c90c3d8..05d50b607689088f9e976de31b3c8b035952ab89 100644 --- a/CoTreceiver/nbproject/project.xml +++ b/CoTreceiver/nbproject/project.xml @@ -5,10 +5,12 @@ <data xmlns="http://www.netbeans.org/ns/j2se-project/3"> <name>CoTreceiver</name> <source-roots> - <root id="src.dir"/> + <root id="src.java.dir"/> + <root id="src.resources.dir"/> </source-roots> <test-roots> - <root id="test.src.dir"/> + <root id="test.java.dir"/> + <root id="test.resources.dir"/> </test-roots> </data> </configuration> diff --git a/CoTreceiver/src/edu/nps/moves/cot/dis/CoTMsgParserDisRunner.java b/CoTreceiver/src/main/java/edu/nps/moves/cot/dis/CoTMsgParserDisRunner.java similarity index 100% rename from CoTreceiver/src/edu/nps/moves/cot/dis/CoTMsgParserDisRunner.java rename to CoTreceiver/src/main/java/edu/nps/moves/cot/dis/CoTMsgParserDisRunner.java diff --git a/CoTreceiver/src/main/java/edu/nps/moves/cot/file/CoTFileReader.java b/CoTreceiver/src/main/java/edu/nps/moves/cot/file/CoTFileReader.java new file mode 100644 index 0000000000000000000000000000000000000000..a4ee667789389ca29c3e74ab2de13475b24cf944 --- /dev/null +++ b/CoTreceiver/src/main/java/edu/nps/moves/cot/file/CoTFileReader.java @@ -0,0 +1,131 @@ +/* +Copyright (c) 1995-2024 held by the author(s). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the names of the Naval Postgraduate School (NPS) + Modeling, Virtual Environments and Simulation (MOVES) Institute + (http://www.nps.edu and https://my.nps.edu/web/moves) + nor the names of its contributors may be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +package edu.nps.moves.cot.file; + +import edu.nps.moves.cot.dis.CoTMsgParserDisRunner; +import edu.nps.moves.util.LogUtils; + +import java.io.IOException; +import java.io.Reader; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import mil.army.usareur.g3.mcsd.CoTExample.CustomCoTparser; +import mil.army.usareur.g3.mcsd.CoTUtils.CoTparser; + +import org.apache.logging.log4j.Logger; + +/** CoT message reader demonstration. This will first read a CoT PLI message. + * Two parsers will process the read message. One will display to console as + * a JSON object. The other will generate DIS PDUs populated with CoT PLI data + * and record to a PDU log. + * + * @author <a href="mailto:tdnorbra@nps.edu?subject=edu.nps.moves.cot.file.CoTFileReader">Terry Norbraten, NPS MOVES</a> + */ +public class CoTFileReader { + + private static final Logger LOG = LogUtils.getLogger(CoTFileReader.class); + private static final String USAGE_MSG = "[relative path to CoT file]"; + + private final List<CoTparser> cotParsers; + + private boolean customParsersSet; + + /** Default constructor */ + public CoTFileReader() { + customParsersSet = false; + cotParsers = new ArrayList<>(); + } + + /** + * Add a customized CoT parser to be used for parsing the CoT events. This + * customized parser contains the developers specific implementation and + * handling of CoT events. + * + * @param cp an implementation of the CoTparser + */ + public void addCoTparser(CoTparser cp) { + this.cotParsers.add(cp); + customParsersSet = true; + } + + /** Reads and processes CoT PLI files + * + * @param file the CoT PLI file to read and process + */ + public void readAndProcessCoTFile(Path file) { + String cotXml; + + if (!this.customParsersSet) + cotParsers.add(new CoTparser()); // Create a default Cursor on Target parser + + // Convert the byte stream to characters + CharBuffer cbuff = CharBuffer.allocate((int) file.toFile().length()); + try (Reader reader = Files.newBufferedReader(file)) { + reader.read(cbuff); + } catch (IOException ex) { + LOG.error(ex); + } + cotXml = cbuff.flip().toString(); // don't forget to flip the buffer!! + + for (CoTparser p : cotParsers) + p.coTeventHandler(cotXml); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + + Path p; + if (args.length != USAGE_MSG.length()) { + p = Path.of("src/test/resources/MT-5_Alert_Example_without_Alert_ObjectCutout_Image.cot"); + LOG.warn("Arguments must be: {}", USAGE_MSG); + LOG.info("Using default CoT file: {}", p); + } else + p = Path.of(args[0]); + + CustomCoTparser cp = new CustomCoTparser(); + CoTMsgParserDisRunner disr = new CoTMsgParserDisRunner("CoT PLI data DIS transmitter"); + + CoTFileReader r = new CoTFileReader(); + r.addCoTparser(cp); + r.addCoTparser(disr); + r.readAndProcessCoTFile(p); + } + +} // end class CoTFileReader diff --git a/CoTreceiver/src/edu/nps/moves/cot/main/CoTMsgReceiver.java b/CoTreceiver/src/main/java/edu/nps/moves/cot/net/CoTMsgReceiverDemo.java similarity index 79% rename from CoTreceiver/src/edu/nps/moves/cot/main/CoTMsgReceiver.java rename to CoTreceiver/src/main/java/edu/nps/moves/cot/net/CoTMsgReceiverDemo.java index 6868271132ba147ea240ae80311a5757e46686b3..dc8eb0833af00cb6aef7e953119d284741ed1457 100644 --- a/CoTreceiver/src/edu/nps/moves/cot/main/CoTMsgReceiver.java +++ b/CoTreceiver/src/main/java/edu/nps/moves/cot/net/CoTMsgReceiverDemo.java @@ -31,27 +31,36 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package edu.nps.moves.cot.main; +package edu.nps.moves.cot.net; import edu.nps.moves.cot.dis.CoTMsgParserDisRunner; +import edu.nps.moves.util.LogUtils; + import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.Arrays; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; + import mil.army.usareur.g3.mcsd.CoTUtils.*; import mil.army.usareur.g3.mcsd.CoTExample.CustomCoTparser; +import org.apache.logging.log4j.Logger; -/** CoT message receiver (UPD, TCP) main entry class. +/** CoT message receiver (UPD, TCP) demonstration. This will start a CoT PLI + * message generator which will transmit CoT (XML) over a local network Socket. + * Two parsers will process the received message. One will display to console as + * a JSON object. The other will generate DIS PDUs populated with CoT PLI data + * and record to a PDU log. + * * Based off of mil.army.usareur.g3.mcsd.CoTExample.CoTreceiver - * + * * System.in simulation based on: https://stackoverflow.com/questions/1647907/junit-how-to-simulate-system-in-testing * - * @author <a href="mailto:tdnorbra@nps.edu?subject=edu.nps.moves.main.CoTMsgReceiver">Terry Norbraten, NPS MOVES</a> + * @author <a href="mailto:tdnorbra@nps.edu?subject=edu.nps.moves.main.CoTMsgReceiverDemo">Terry Norbraten, NPS MOVES</a> */ -public class CoTMsgReceiver { +public class CoTMsgReceiverDemo { + + private static final Logger LOG = LogUtils.getLogger(CoTMsgReceiverDemo.class); /** * Utility method that sleeps for a period of time @@ -62,25 +71,25 @@ public class CoTMsgReceiver { try { TimeUnit.SECONDS.sleep(seconds); } catch (InterruptedException ex) { - Logger.getLogger(CoTMsgReceiver.class.getName()).log(Level.SEVERE, null, ex); + LOG.error(ex); } }//sleep - + static final String[] ARGS_DEFAULT = {"--performanceTestSendCoT", "udp", "localhost", "9999", "1", "1"}; /** * @param args the command line arguments */ public static void main(String[] args) - { - - System.out.print ("CoTMsgReceiver"); + { + + LOG.info("Input args:"); for (String arg:args) { - System.out.print (" " + arg); + LOG.info(arg); } System.out.println(); - + boolean isTcp = false; if (args.length > 0) { @@ -88,7 +97,7 @@ public class CoTMsgReceiver { } else { - System.out.println ("CoTMsgReceiver invoked without parameter args, using default args " + Arrays.toString(ARGS_DEFAULT)); + LOG.info("Invoked without parameter args, using default args {} ", Arrays.toString(ARGS_DEFAULT)); } // - Create a custom CoTparser class. See CustomCoTparser.java. @@ -101,70 +110,75 @@ public class CoTMsgReceiver { // - Create a CoT connector CoTconnectors connectors = new CoTconnectors(); - // - Assign custom parsers to be used by the listeners. Note that the + // - Assign custom parsers to be used by the listeners. Note that the // CoT custom parser must be assigned before the listeners are started connectors.addCoTparser(cp); connectors.addCoTparser(disr); // - Common usage example: - System.out.println("\nStarting listener pool\n"); - - if (isTcp) + System.out.println(); + LOG.info("Starting listener pool\n"); + + if (isTcp) { connectors.addTcpListener(CoTtcpListener.DEFAULT_COT_TCP_PORT); connectors.startListener (CoTtcpListener.DEFAULT_COT_TCP_PORT); - } - else + } + else { connectors.addUdpListener(CoTudpListener.DEFAULT_COT_UDP_PORT); // default packet size 1024 connectors.startListener (CoTudpListener.DEFAULT_COT_UDP_PORT); } - + PipedOutputStream pipedOutputStream = null; - + // Redirect an output stream to be read by an input stream in order to // stop the TCP listener try { - pipedOutputStream = new PipedOutputStream(); + pipedOutputStream = new PipedOutputStream(); System.setIn(new PipedInputStream(pipedOutputStream)); - } - catch (IOException ioe) + } + catch (IOException ioe) { - System.out.println("*** pipedOutputStream ioe " + ioe.getMessage()); + LOG.error(ioe); } - + // Start the CoT message generator/server Runnable r = () -> { // odd invocation avoids resetting empty args array, which can provoke following obscure Java error // error: local variables referenced from a lambda expression must be final or effectively final // com.aciedge.cotplitool.Main.main(args); if (args.length > 0) - com.aciedge.cotplitool.Main.main(args); - else com.aciedge.cotplitool.Main.main(ARGS_DEFAULT); + com.aciedge.cotplitool.Main.main(args); + else + com.aciedge.cotplitool.Main.main(ARGS_DEFAULT); }; Thread t = new Thread(r); t.setDaemon(true); t.start(); - + // TODO: can make this another input argument sleep(5L); // default to 5 seconds of operation - - System.out.println("\nStopping listener pool\n"); - + + System.out.println(); + LOG.info("Stopping listener pool\n"); + if (isTcp) connectors.stopListener(CoTtcpListener.DEFAULT_COT_TCP_PORT); else connectors.stopListener(CoTudpListener.DEFAULT_COT_UDP_PORT); - + // Issue the CoT message generator/server quit/exit command try { if (pipedOutputStream != null) pipedOutputStream.write("quit\n".getBytes("utf-8")); - } catch (IOException ex) {} - + } catch (IOException ex) { + LOG.error(ex); + } + // Shutdown the DIS listerner disr.getDisChannel().tearDownNetworkInterface(); - + }// main -} // end class CoTMsgReceiver +} // end class CoTMsgReceiverDemo diff --git a/CoTreceiver/src/main/java/edu/nps/moves/util/LogUtils.java b/CoTreceiver/src/main/java/edu/nps/moves/util/LogUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..8ead2a5834f139eaa0e10314840260761a7ec168 --- /dev/null +++ b/CoTreceiver/src/main/java/edu/nps/moves/util/LogUtils.java @@ -0,0 +1,107 @@ +/* +Copyright (c) 1995-2024 held by the author(s). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the names of the Naval Postgraduate School (NPS) + Modeling, Virtual Environments and Simulation (MOVES) Institute + (http://www.nps.edu and https://my.nps.edu/web/moves) + nor the names of its contributors may be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +package edu.nps.moves.util; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.config.DefaultConfiguration; + +/** + * Log4j Logging utilities for Log4J2 v19+. + * + * @author <a href="mailto:tdnorbra@nps.edu?subject=edu.nps.util.LogUtils">Terry Norbraten, NPS MOVES</a> + */ +public class LogUtils { + + private static final Logger LOG; + + static { +// configureLog4j("log4j2.properties"); // log4j2.xml will seen on the classpath + LOG = getLogger(LogUtils.class); + } + + /**<p> + * This is a utility to configure the Log4J logger. + * </p> + * If requested configuration file can not be read, the default behavior + * will be to use a DefaultConfigurator and set the debug level to INFO. + * + * @param configFile The file name to configure the logger with. + * @return true if successful, false if failed to find/use the file + */ + public static boolean configureLog4j(String configFile) { + + if (!configFile.isEmpty()) { + + Configurator.initialize(null, ClassLoader.getPlatformClassLoader(), configFile); + + return true; + } else { + // Set up a simple configuration that logs on the console + // and set root logger level to INFO. + Configurator.initialize(new DefaultConfiguration()); + Configurator.setRootLevel(Level.INFO); + + // The following is useful early on when developers are starting to + // use log4j to know what is going on. We can remove this printout + // in the future, or turn it into a log4j message! + LOG.warn("Failed to read {}. Assuming INFO level and Console appender.", configFile); + + return false; + } + } + + /** Provide a synchronized method for multiple threads to use single + * run-time logger + * @param clazz the class type of the caller + * @return synchronized method for multiple threads to use a single run-time logger + */ + public static synchronized Logger getLogger(Class clazz) { + return LogManager.getLogger(clazz); + } + + /** @return a model to print a stack trace of calling classes and their methods */ + public static String printCallerLog() { + StringBuilder sb = new StringBuilder(); + sb.append("("); + sb.append(new Throwable().fillInStackTrace().getStackTrace()[4].getClassName()); + sb.append(" :"); + sb.append(new Throwable().fillInStackTrace().getStackTrace()[4].getLineNumber()); + sb.append(")"); + return sb.toString(); + } + +} // end class file LogUtils.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTExample/CoTreceiver.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTExample/CoTreceiver.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTExample/CoTreceiver.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTExample/CoTreceiver.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTExample/CustomCoTparser.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTExample/CustomCoTparser.java similarity index 94% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTExample/CustomCoTparser.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTExample/CustomCoTparser.java index 8132b8b30b0f686c254b8e0dba97561245a1203e..f4fa033cc9e3c188b2d4948c8964c8f576e54968 100644 --- a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTExample/CustomCoTparser.java +++ b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTExample/CustomCoTparser.java @@ -83,6 +83,7 @@ public class CustomCoTparser extends CoTparser { /** Our SAXBuilder */ private SAXBuilder builder; private final XMLOutputter xmlOutput; + private File cotXmlFile; public CustomCoTparser() { super(); @@ -160,6 +161,14 @@ public class CustomCoTparser extends CoTparser { } }//coTeventHandler + /** Handle to the last CoT file logged + * + * @return a handle to the last file logged + */ + public File getCotXmlFile() { + return cotXmlFile; + } + /** * Write out a received CoT XML message to file with its timestamp in the filename * @param cotEvent a received CoT message @@ -179,10 +188,10 @@ public class CustomCoTparser extends CoTparser { ldt = new java.sql.Timestamp(cotEvent.getTime().getTime()).toLocalDateTime(); dtgStamp = DATE_TIME_GROUP_FORMAT.format(ldt); - File cotxml = new File(dir2, "CoTEvt-" + dtgStamp + ".xml"); + cotXmlFile = new File(dir2, "CoTEvt-" + dtgStamp + ".xml"); Document cotMsg = validateCotMsg(cotEvent.toXml()); - try (OutputStream out = new FileOutputStream(cotxml)) { + try (OutputStream out = new FileOutputStream(cotXmlFile)) { xmlOutput.output(cotMsg, out); } catch (IOException ex) { Logger.getLogger(CustomCoTparser.class.getName()).log(Level.SEVERE, null, ex); diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTconnectors.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTconnectors.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTconnectors.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTconnectors.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTparser.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTparser.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTparser.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTparser.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTtcpListener.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTtcpListener.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTtcpListener.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTtcpListener.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTtypes.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTtypes.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTtypes.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTtypes.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTudpListener.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTudpListener.java similarity index 96% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTudpListener.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTudpListener.java index e7b2e457438f32409ad143fec9642c55e7ac88a5..7b990b580a0569335c8434fe7dee569ce31079a2 100644 --- a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CoTUtils/CoTudpListener.java +++ b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CoTUtils/CoTudpListener.java @@ -155,9 +155,9 @@ public class CoTudpListener extends Thread { DatagramPacket rcvPacket; String cotXml; byte[] rcvData = new byte[packetSize]; - if (!this.customParsersSet) { + if (!this.customParsersSet) cotParsers.add(new CoTparser()); // Create a default Cursor on Target parser - } + try { serverSocket = new DatagramSocket(cotUdpPort); debugToConsole(UDP_LISTENER + " thread started, port: " + cotUdpPort); diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Contact.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Contact.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Contact.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Contact.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/FlowTags.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/FlowTags.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/FlowTags.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/FlowTags.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Image.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Image.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Image.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Image.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Link.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Link.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Link.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Link.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/ObjectFactory.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/ObjectFactory.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/ObjectFactory.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/ObjectFactory.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Remarks.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Remarks.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Remarks.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Remarks.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Request.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Request.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Request.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Request.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Sensor.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Sensor.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Sensor.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Sensor.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Shape.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Shape.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Shape.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Shape.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Spatial.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Spatial.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Spatial.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Spatial.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Track.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Track.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Track.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Track.java diff --git a/CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Uid.java b/CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Uid.java similarity index 100% rename from CoTreceiver/src/mil/army/usareur/g3/mcsd/CotBindings/Uid.java rename to CoTreceiver/src/main/java/mil/army/usareur/g3/mcsd/CotBindings/Uid.java diff --git a/CoTreceiver/src/main/resources/log4j2.xml b/CoTreceiver/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..3d25444bf2a670715c5ae8dd3732e9a8e624d18d --- /dev/null +++ b/CoTreceiver/src/main/resources/log4j2.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Configuration status="WARN"> + <Properties> + <Property name="CONSOLE_PATTERN">%highlight{%-5level}{FATAL=bg_red, ERROR=red, WARN=yellow, INFO=green} %style{%d{yyyy MMM dd HH:mm:ss 'GMT'Z}}{blue} [%t] %C:%L - %m%n</Property> + <Property name="LOG_PATTERN">[%-5level] %d{yyyy MMM dd HH:mm:ss 'GMT'Z} [%t] %C:%L - %m%n</Property> + </Properties> + <Appenders> + <Console name="Console" target="SYSTEM_OUT"> + <PatternLayout pattern="${CONSOLE_PATTERN}"/> + </Console> + <RollingFile name="RollingLogFile" fileName="logs/error.log.0" filePattern="logs/error.log.%i" > + <LevelRangeFilter minLevel="FATAL" maxLevel="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> + <PatternLayout pattern="${LOG_PATTERN}"/> + <Policies> + <OnStartupTriggeringPolicy/> + </Policies> + <DefaultRolloverStrategy max="20"/> + </RollingFile> + <RollingFile name="InfoLog" fileName="logs/cot.log.0" filePattern="logs/cot.log.%i"> + <LevelRangeFilter minLevel="WARN" maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/> + <PatternLayout pattern="${LOG_PATTERN}"/> + <Policies> + <OnStartupTriggeringPolicy/> + </Policies> + <DefaultRolloverStrategy max="20" fileIndex="min"/> + </RollingFile> + <RollingFile name="DebugLog" fileName="logs/debug.log.0" filePattern="logs/debug.log.%i"> + <LevelRangeFilter minLevel="DEBUG" maxLevel="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> + <PatternLayout pattern="${LOG_PATTERN}"/> + <Policies> + <OnStartupTriggeringPolicy/> + </Policies> + <DefaultRolloverStrategy max="10"/> + </RollingFile> + </Appenders> + <Loggers> + <Root level="INFO"> + <AppenderRef ref="Console"/> + <AppenderRef ref="RollingLogFile"/> + <AppenderRef ref="InfoLog" /> + <AppenderRef ref="DebugLog"/> + </Root> + </Loggers> +</Configuration> diff --git a/CoTreceiver/src/test/java/edu/nps/moves/cot/file/CotFileReaderTest.java b/CoTreceiver/src/test/java/edu/nps/moves/cot/file/CotFileReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5637588ea21082d5440af0478331921e0130356e --- /dev/null +++ b/CoTreceiver/src/test/java/edu/nps/moves/cot/file/CotFileReaderTest.java @@ -0,0 +1,138 @@ +/* +Copyright (c) 1995-2023 held by the author(s). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the names of the Naval Postgraduate School (NPS) + Modeling Virtual Environments and Simulation (MOVES) Institute + (https://www.nps.edu and https://my.nps.edu/web/moves) + nor the names of its contributors may be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +package edu.nps.moves.cot.file; + +import java.io.IOException; +import java.nio.file.Path; + +import mil.army.usareur.g3.mcsd.CoTExample.CustomCoTparser; + +import org.apache.commons.collections4.IterableUtils; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; + +import org.xmlunit.builder.DiffBuilder; +import org.xmlunit.diff.Diff; +import org.xmlunit.diff.Difference; + +/** Test that an output file exactly matches a known reference + * + * @author <a href="mailto:tdnorbra@nps.edu?subject=edu.nps.moves.cot.file.CotFileReaderTest">Terry D. Norbraten</a> + */ +public class CotFileReaderTest { + + Path control, test; + CustomCoTparser ccp; + CoTFileReader cfr; + + @Before + public void before() { + ccp = new CustomCoTparser(); + cfr = new CoTFileReader(); + cfr.addCoTparser(ccp); + } + + @After + public void after() { + control = test = null; + ccp = null; + cfr = null; + } + + @Test + public void compare1() throws IOException { + control = Path.of("src/test/resources/MT-5_Alert_Example_without_Alert_ObjectCutout_Image.cot"); + cfr.readAndProcessCoTFile(control); + test = Path.of(ccp.getCotXmlFile().getAbsolutePath()); + + Diff diff = DiffBuilder.compare(control) + .withTest(test) +// .checkForSimilar() +// .checkForIdentical() // [1] +// .ignoreComments() // [2] + .ignoreWhitespace() // [3] +// .normalizeWhitespace() // [4] +// .withNodeMatcher(new DefaultNodeMatcher( ElementSelectors.byName)) // [10] +// .ignoreElementContentWhitespace() // [15] + .build(); + + for (Difference d : diff.getDifferences()) + System.err.println(d); + + assertThat(IterableUtils.size(diff.getDifferences()), equalTo(0)); + } + + @Test + public void compare2() throws IOException { + control = Path.of("src/test/resources/MT-5_Alert_Example_with_Alert_ObjectCutout_Image.cot"); + cfr.readAndProcessCoTFile(control); + test = Path.of(ccp.getCotXmlFile().getAbsolutePath()); + + Diff diff = DiffBuilder.compare(control) + .withTest(test) +// .checkForSimilar() +// .checkForIdentical() // [1] +// .ignoreComments() // [2] + .ignoreWhitespace() // [3] +// .normalizeWhitespace() // [4] +// .withNodeMatcher(new DefaultNodeMatcher( ElementSelectors.byName)) // [10] +// .ignoreElementContentWhitespace() // [15] + .build(); + + for (Difference d : diff.getDifferences()) + System.err.println(d); + + assertThat(IterableUtils.size(diff.getDifferences()), equalTo(0)); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + + Result result = JUnitCore.runClasses(CotFileReaderTest.class); + for (Failure failure : result.getFailures()) + System.err.println(failure.toString()); + + System.out.println(CotFileReaderTest.class.getName() + " success: " + result.wasSuccessful()); + } +} diff --git a/CoTreceiver/src/test/resources/MT-5_Alert_Example_with_Alert_ObjectCutout_Image.cot b/CoTreceiver/src/test/resources/MT-5_Alert_Example_with_Alert_ObjectCutout_Image.cot new file mode 100644 index 0000000000000000000000000000000000000000..8e03b2d00062306325177646f1cabfc1b976fd3e --- /dev/null +++ b/CoTreceiver/src/test/resources/MT-5_Alert_Example_with_Alert_ObjectCutout_Image.cot @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<event version="2.0" uid="Gantz_ISN_1Obj_101" type="a-u-G" how="h-g-i-g-o" time="2024-02-23T19:50:54.00Z" start="2024-02-23T19:50:54.00Z" stale="2025-02-23T19:50:54.00Z"> + <point lat="38.2831745" lon="-121.9006541" hae="-5.73" le="9999999.0" ce="9999999.0" /> + <detail> + <remarks to="MT5" keywords="Object" version="1.0" /> + <contact callsign="ISN 1Object 101" /> + <link type="a-f-G-U-C-I" uid="ISN1" parent_callsign="GANTZ_MOUNTAIN_MT5" relation="p-p" /> + <usericon iconsetpath="COT_MAPPING_2525C/a-u/a-u-G" /> + <image mime="image/jpeg" type="VIS" width="528" height="172"> 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 + </image> + </detail> +</event> diff --git a/CoTreceiver/src/test/resources/MT-5_Alert_Example_without_Alert_ObjectCutout_Image.cot b/CoTreceiver/src/test/resources/MT-5_Alert_Example_without_Alert_ObjectCutout_Image.cot new file mode 100644 index 0000000000000000000000000000000000000000..4f2ae5e6cf61f893ac56dda74af8cfe217c51612 --- /dev/null +++ b/CoTreceiver/src/test/resources/MT-5_Alert_Example_without_Alert_ObjectCutout_Image.cot @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<event version="2.0" uid="Gantz_ISN_1Obj_101" type="a-u-G" how="h-g-i-g-o" time="2024-02-23T19:49:10.00Z" start="2024-02-23T19:49:10.00Z" stale="2025-02-23T19:49:10.00Z"> + <point lat="38.2831745" lon="-121.9006541" hae="-5.73" le="9999999.0" ce="9999999.0" /> + <detail> + <remarks to="MT5" keywords="Object" version="1.0" /> + <contact callsign="ISN 1Object 101" /> + <link type="a-f-G-U-C-I" uid="ISN1" parent_callsign="GANTZ_MOUNTAIN_MT5" relation="p-p" /> + <usericon iconsetpath="COT_MAPPING_2525C/a-u/a-u-G" /> + </detail> +</event> diff --git a/CoTreceiver/src/test/resources/Screenshot_20240807_091552_Gmail.jpg b/CoTreceiver/src/test/resources/Screenshot_20240807_091552_Gmail.jpg new file mode 100644 index 0000000000000000000000000000000000000000..607538c3c6231f2f9c7ea603dd5c6f2428cfef5f Binary files /dev/null and b/CoTreceiver/src/test/resources/Screenshot_20240807_091552_Gmail.jpg differ