1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-16 12:12:06 +01:00

Merge branch '3.4.0' into master

Conflicts:
	source/org/jivesoftware/smack/SmackConfiguration.java
This commit is contained in:
Florian Schmaus 2014-02-03 10:26:33 +01:00
commit b18a43920a
154 changed files with 3460 additions and 1650 deletions

BIN
build/ant-contrib-1.0b2.jar Normal file

Binary file not shown.

Binary file not shown.

View file

@ -17,7 +17,7 @@
<taskdef resource="net/sf/antcontrib/antcontrib.properties"> <taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath> <classpath>
<pathelement location="${basedir}/build/ant-contrib.jar"/> <pathelement location="${basedir}/build/ant-contrib-1.0b2.jar"/>
</classpath> </classpath>
</taskdef> </taskdef>
@ -26,29 +26,36 @@
<!-- Smack Version --> <!-- Smack Version -->
<property name="version.major" value="3" /> <property name="version.major" value="3" />
<property name="version.minor" value="3" /> <property name="version.minor" value="4" />
<property name="version.revision" value="1" /> <property name="version.revision" value="1" />
<property name="version.extra" value="" /> <property name="version.extra" value="SNAPSHOT" />
<if> <var name="mutable-version" value="${version.major}.${version.minor}.${version.revision}"/>
<equals arg1="${version.extra}" arg2=""/> <var name="mutable-experimental-version" value="0.1"/>
<if>
<length string="${version.extra}" when="greater" length="0"/>
<then> <then>
<property name="version" <var name="mutable-version" value="${mutable-version}.${version.extra}"/>
value="${version.major}.${version.minor}.${version.revision}"/> <var name="mutable-experimental-version" value="${mutable-experimental-version}.${version.extra}" />
<property name="version.filename"
value="${version.major}_${version.minor}_${version.revision}"/>
</then> </then>
<else>
<property name="version"
value="${version.major}.${version.minor}.${version.revision}.${version.extra}"/>
<property name="version.filename"
value="${version.major}_${version.minor}_${version.revision}_${version.extra}"/>
</else>
</if> </if>
<tstamp>
<format property="builddate" pattern="MM/dd/yyyy"/>
</tstamp>
<if>
<equals arg1="${dailybuild}" arg2="true" />
<then>
<tstamp>
<format property="build.date" pattern="yyyyMMdd" locale="en"/>
</tstamp>
<var name="mutable-version" value="${mutable-version}-${build.date}" />
<var name="mutable-experimental-version" value="${mutable-experimental-version}-${build.date}" />
</then>
</if>
<property name="version" value="${mutable-version}" />
<property name="experimental.version" value="${mutable-experimental-version}" />
<property name="bundle.name" value="org.igniterealtime.smack" />
<property file="${basedir}/build/build.properties" /> <property file="${basedir}/build/build.properties" />
<property name="compile.dir" value="${basedir}/target/classes" /> <property name="compile.dir" value="${basedir}/target/classes" />
<property name="compile.test.dir" value="${basedir}/target/classes-test" /> <property name="compile.test.dir" value="${basedir}/target/classes-test" />
@ -132,6 +139,40 @@
<pathelement path="${compile.dir}"/> <pathelement path="${compile.dir}"/>
</classpath> </classpath>
</javac> </javac>
<mkdir dir="${compile.dir}/workgroup" />
<javac
destdir="${compile.dir}/workgroup"
includeAntRuntime="no"
debug="on"
source="1.6"
target="1.6"
>
<src path="${basedir}/workgroup/source" />
<classpath>
<fileset dir="${merge.lib.dir}">
<include name="*.jar"/>
</fileset>
<pathelement path="${compile.dir}"/>
</classpath>
</javac>
<mkdir dir="${compile.dir}/experimental" />
<javac
destdir="${compile.dir}/experimental"
includeAntRuntime="no"
debug="on"
source="1.6"
target="1.6"
>
<src path="${basedir}/experimental/source" />
<classpath>
<fileset dir="${merge.lib.dir}">
<include name="*.jar"/>
</fileset>
<pathelement path="${compile.dir}"/>
</classpath>
</javac>
</target> </target>
<!-- compile-test --> <!-- compile-test -->
@ -170,54 +211,68 @@
<!-- jar --> <!-- jar -->
<!-- ======================================================================================= --> <!-- ======================================================================================= -->
<target name="jar" depends="compile" unless="jar.uptodate" description="Produces smack.jar"> <target name="jar" depends="compile" unless="jar.uptodate" description="Produces smack.jar">
<copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/jul.properties" />
<copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/smack-config.xml" /> <copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/smack-config.xml" />
<jar destfile="${jar.dest.dir}/smack.jar" <copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/core.providers" />
<property name="smack.jar.name" value="${jar.dest.dir}/smack-${version}.jar" />
<jar destfile="${smack.jar.name}"
basedir="${compile.dir}" basedir="${compile.dir}"
includes="org/jivesoftware/smack/**/*.class, **/smack-config.xml"> includes="org/jivesoftware/smack/**/*.class, **/smack-config.xml, **/core.providers, **/jul.properties">
<zipfileset src="${merge.lib.dir}/xpp.jar"/> <zipfileset src="${merge.lib.dir}/xpp.jar"/>
</jar> </jar>
<taskdef resource="aQute/bnd/ant/taskdef.properties" classpath="${basedir}/build/build/biz.aQute.bnd.jar"/> <taskdef resource="aQute/bnd/ant/taskdef.properties" classpath="${basedir}/build/build/biz.aQute.bnd.jar"/>
<bndwrap jars="${jar.dest.dir}/smack.jar" output="${jar.dest.dir}/smack.jar" /> <bndwrap jars="${smack.jar.name}" output="${smack.jar.name}" />
<jar file="${jar.dest.dir}/smack.jar" update="true"> <jar file="${smack.jar.name}" update="true">
<manifest> <manifest>
<attribute name="Bundle-SymbolicName" value="org.igniterealtime.smack" /> <attribute name="Bundle-SymbolicName" value="${bundle.name}" />
<attribute name="Bundle-Version" value="${version}" />
</manifest> </manifest>
</jar> </jar>
<copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/smack.providers" />
<jar destfile="${jar.dest.dir}/smackx.jar" <property name="smackx.jar.name" value="${jar.dest.dir}/smackx-${version}.jar" />
<copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/extension.providers" />
<jar destfile="${smackx.jar.name}"
basedir="${compile.dir}" basedir="${compile.dir}"
includes="org/jivesoftware/smackx/**/*.class, **/*.providers" includes="org/jivesoftware/smackx/**/*.class, **/extension.providers"
excludes="org/jivesoftware/smackx/debugger/*.class"> excludes="org/jivesoftware/smackx/debugger/*.class">
<manifest> <manifest>
<attribute name="Class-Path" value="smack.jar" /> <attribute name="Class-Path" value="smack.jar" />
</manifest> </manifest>
<zipfileset src="${merge.lib.dir}/jzlib.jar"/> <zipfileset src="${merge.lib.dir}/jzlib.jar"/>
</jar> </jar>
<bndwrap jars="${jar.dest.dir}/smackx.jar" output="${jar.dest.dir}/smackx.jar" /> <bndwrap jars="${smackx.jar.name}" output="${smackx.jar.name}" />
<jar file="${jar.dest.dir}/smackx.jar" update="true"> <jar file="${smackx.jar.name}" update="true">
<manifest> <manifest>
<attribute name="Bundle-SymbolicName" value="org.igniterealtime.smack-ext" /> <attribute name="Bundle-SymbolicName" value="${bundle.name}-ext" />
<attribute name="Bundle-Version" value="${version}" />
<attribute name="Fragment-Host" value="${bundle.name};bundle-version=${version}" />
</manifest> </manifest>
</jar> </jar>
<copy todir="${compile.dir}/images">
<property name="debug.jar.name" value="${jar.dest.dir}/smackx-debug-${version}.jar" />
<copy todir="${compile.dir}/images">
<fileset dir="${basedir}/build/resources/images"> <fileset dir="${basedir}/build/resources/images">
<include name="*.png"/> <include name="*.png"/>
</fileset> </fileset>
</copy> </copy>
<jar destfile="${jar.dest.dir}/smackx-debug.jar" <jar destfile="${debug.jar.name}"
basedir="${compile.dir}" basedir="${compile.dir}"
includes="org/jivesoftware/smackx/debugger/*.class, **/*.png"> includes="org/jivesoftware/smackx/debugger/*.class, **/*.png">
<manifest> <manifest>
<attribute name="Class-Path" value="smack.jar" /> <attribute name="Class-Path" value="smack.jar" />
</manifest> </manifest>
</jar> </jar>
<bndwrap jars="${jar.dest.dir}/smackx-debug.jar" output="${jar.dest.dir}/smackx-debug.jar" /> <bndwrap jars="${debug.jar.name}" output="${debug.jar.name}" />
<jar file="${jar.dest.dir}/smackx-debug.jar" update="true"> <jar file="${debug.jar.name}" update="true">
<manifest> <manifest>
<attribute name="Bundle-SymbolicName" value="org.igniterealtime.smack-ext-debug" /> <attribute name="Bundle-SymbolicName" value="${bundle.name}-debug" />
<attribute name="Bundle-Version" value="${version}" />
<attribute name="Fragment-Host" value="${bundle.name};bundle-version=${version}" />
</manifest> </manifest>
</jar> </jar>
<jar destfile="${jar.dest.dir}/smackx-jingle.jar"
<property name="jingle.jar.name" value="${jar.dest.dir}/smackx-jingle-${version}.jar" />
<jar destfile="${jingle.jar.name}"
basedir="${compile.dir}/jingle/extension" basedir="${compile.dir}/jingle/extension"
includes="org/jivesoftware/smackx/**/*.class"> includes="org/jivesoftware/smackx/**/*.class">
<manifest> <manifest>
@ -225,35 +280,79 @@
</manifest> </manifest>
<zipfileset src="${jingle.extension.merge.lib.dir}/jstun.jar"/> <zipfileset src="${jingle.extension.merge.lib.dir}/jstun.jar"/>
</jar> </jar>
<bndwrap jars="${jar.dest.dir}/smackx-jingle.jar" output="${jar.dest.dir}/smackx-jingle.jar" /> <bndwrap jars="${jingle.jar.name}" output="${jingle.jar.name}" />
<jar file="${jar.dest.dir}/smackx-jingle.jar" update="true"> <jar file="${jingle.jar.name}" update="true">
<manifest> <manifest>
<attribute name="Bundle-SymbolicName" value="org.igniterealtime.smack-ext-jingle" /> <attribute name="Bundle-SymbolicName" value="${bundle.name}-jingle" />
<attribute name="Bundle-Version" value="${version}" />
<attribute name="Fragment-Host" value="${bundle.name};bundle-version=${version}" />
</manifest> </manifest>
</jar> </jar>
<delete file="${compile.dir}/META-INF/smack-config.xml" />
<delete file="${compile.dir}/META-INF/smack.providers" /> <property name="workgroup.jar.name" value="${jar.dest.dir}/smackx-workgroup-${version}.jar" />
<copy todir="${compile.dir}/workgroup/META-INF" file="${basedir}/workgroup/resources/META-INF/workgroup.providers" />
<jar destfile="${workgroup.jar.name}"
basedir="${compile.dir}/workgroup"
includes="org/jivesoftware/smackx/workgroup/**/*.class, **/workgroup.providers">
<manifest>
<attribute name="Class-Path" value="smack.jar, smackx.jar" />
</manifest>
</jar>
<bndwrap jars="${workgroup.jar.name}" output="${workgroup.jar.name}" />
<jar file="${workgroup.jar.name}" update="true">
<manifest>
<attribute name="Bundle-SymbolicName" value="${bundle.name}-workgroup" />
<attribute name="Bundle-Version" value="${version}" />
<attribute name="Fragment-Host" value="${bundle.name};bundle-version=${version}" />
</manifest>
</jar>
<property name="experimental.jar.name" value="${jar.dest.dir}/smackx-experimental-${experimental.version}.jar" />
<copy todir="${compile.dir}/experimental/META-INF" file="${basedir}/experimental/resources/META-INF/experimental.providers" />
<jar destfile="${experimental.jar.name}"
basedir="${compile.dir}/experimental"
includes="org/jivesoftware/smackx/**/*.class, **/experimental.providers">
<manifest>
<attribute name="Class-Path" value="smack.jar, smackx.jar" />
</manifest>
</jar>
<bndwrap jars="${experimental.jar.name}" output="${experimental.jar.name}" />
<jar file="${experimental.jar.name}" update="true">
<manifest>
<attribute name="Bundle-SymbolicName" value="${bundle.name}-experimental" />
<attribute name="Bundle-Version" value="${version}" />
<attribute name="Fragment-Host" value="${bundle.name};bundle-version=${experimental.version}" />
</manifest>
</jar>
<!--
<delete file="${compile.dir}/META-INF/smack-config.xml" />
<delete file="${compile.dir}/META-INF/*.providers" />
<delete> <delete>
<fileset dir="${compile.dir}/images"> <fileset dir="${compile.dir}/images">
<include name="*.png"/> <include name="*.png"/>
</fileset> </fileset>
</delete> </delete>
-->
</target> </target>
<!-- jar --> <!-- jar -->
<!-- ======================================================================================= --> <!-- ======================================================================================= -->
<target name="jar-test" depends="compile-test" description="Produces jar of test code"> <target name="jar-test" depends="compile-test" description="Produces jar of test code">
<copy todir="${compile.test.dir}/META-INF" file="${basedir}/build/resources/META-INF/jul.properties" />
<copy todir="${compile.test.dir}/META-INF" file="${basedir}/build/resources/META-INF/smack-config.xml" />
<copy todir="${compile.test.dir}/META-INF" file="${basedir}/build/resources/META-INF/core.providers" />
<jar destfile="${jar.dest.dir}/smack-test.jar" <jar destfile="${jar.dest.dir}/smack-test.jar"
basedir="${compile.test.dir}" basedir="${compile.test.dir}"
includes="org/jivesoftware/smack/**/*.class" includes="org/jivesoftware/smack/**/*.class, **/smack-config.xml, **/core.providers, **/jul.properties"
/> />
</target> </target>
<target name="jar-test-smackx" depends="compile-test" description="Produces jar of test code"> <target name="jar-test-smackx" depends="compile-test" description="Produces jar of test code">
<copy todir="${compile.test.dir}/META-INF" file="${basedir}/build/resources/META-INF/extension.providers" />
<jar destfile="${jar.dest.dir}/smack-test-smackx.jar" <jar destfile="${jar.dest.dir}/smack-test-smackx.jar"
basedir="${compile.test.dir}" basedir="${compile.test.dir}"
includes="org/jivesoftware/smackx/**/*.class includes="org/jivesoftware/smackx/**/*.class, org/jivesoftware/util/**/*.class, **/extension.providers"
org/jivesoftware/util/**/*.class"
/> />
</target> </target>
@ -283,7 +382,7 @@
<link href="http://java.sun.com/j2se/1.3/docs/api/" /> <link href="http://java.sun.com/j2se/1.3/docs/api/" />
<link href="http://java.sun.com/j2ee/sdk_1.2.1/techdocs/api/" /> <link href="http://java.sun.com/j2ee/sdk_1.2.1/techdocs/api/" />
</javadoc> </javadoc>
</target> </target>
<!-- test --> <!-- test -->
@ -365,7 +464,7 @@
<!-- ======================================================================================= --> <!-- ======================================================================================= -->
<target name="test-unit" depends="compile, jar-test, jar-test-smackx" unless="no.test"> <target name="test-unit" depends="compile, jar-test, jar-test-smackx" unless="no.test">
<junit printsummary="on" <junit printsummary="on"
fork="true" fork="false"
haltonfailure="false" haltonfailure="false"
failureproperty="tests.failed" failureproperty="tests.failed"
showoutput="true"> showoutput="true">
@ -385,7 +484,7 @@
</fileset> </fileset>
<fileset dir="${jar.dest.dir}"> <fileset dir="${jar.dest.dir}">
<include name="smack-test.jar"/> <include name="smack-test.jar"/>
<include name="smack-test-smackx.jar" /> <include name="smack-test-smackx.jar" />
</fileset> </fileset>
<pathelement location="${compile.dir}" /> <pathelement location="${compile.dir}" />
<pathelement location="${test-unit.dir}" /> <pathelement location="${test-unit.dir}" />

View file

@ -5,7 +5,11 @@
<classpathentry kind="src" path="source"/> <classpathentry kind="src" path="source"/>
<classpathentry kind="src" path="test"/> <classpathentry kind="src" path="test"/>
<classpathentry kind="src" path="test-unit"/> <classpathentry kind="src" path="test-unit"/>
<classpathentry kind="lib" path="build/ant-contrib.jar"/> <classpathentry kind="src" path="workgroup/source"/>
<classpathentry kind="src" path="experimental/source"/>
<classpathentry kind="src" path="experimental/test"/>
<classpathentry kind="src" path="workgroup/resources"/>
<classpathentry kind="src" path="experimental/resources"/>
<classpathentry kind="lib" path="build/asm.jar"/> <classpathentry kind="lib" path="build/asm.jar"/>
<classpathentry kind="lib" path="build/build/java-xmlbuilder-0.3.jar"/> <classpathentry kind="lib" path="build/build/java-xmlbuilder-0.3.jar"/>
<classpathentry kind="lib" path="build/build/xmlunit.jar"/> <classpathentry kind="lib" path="build/build/xmlunit.jar"/>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>smack-3.3.x</name> <name>smack-3.4.x</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>

View file

@ -14,7 +14,7 @@
<!-- Include Ant Optional Tasks --> <!-- Include Ant Optional Tasks -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties"> <taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath> <classpath>
<pathelement location="${basedir}/build/ant-contrib.jar"/> <pathelement location="${basedir}/build/ant-contrib-1.0b2.jar"/>
</classpath> </classpath>
</taskdef> </taskdef>
@ -28,155 +28,66 @@
<!-- ======================================================================================= --> <!-- ======================================================================================= -->
<target name="all"> <target name="all">
<!-- create release properties --> <!-- create release properties -->
<if> <property name="release.dir" value="${basedir}/target/release/${version}" />
<equals arg1="${dailybuild}" arg2="true" /> <property name="release.samples.dir" value="${release.dir}/samples" />
<then> <tstamp>
<tstamp> <format property="release.date" pattern="dd/MM/yyyy" locale="en"/>
<format property="build.date" pattern="yyyy-MM-dd" locale="en"/> </tstamp>
</tstamp>
<property name="release.name" value="smack-${build.date}" /> <!-- create release dirs -->
<property name="release-dev.name" value="smack_src_${build.date}" />
</then>
<else>
<property name="release.name" value="smack_${version.filename}" />
<property name="release-dev.name" value="smack_src_${version.filename}" />
</else>
</if>
<property name="release.dir" value="${basedir}/target/release/${release.name}" />
<property name="release-dev.dir" value="${basedir}/target/release/${release-dev.name}" />
<!-- create release dirs -->
<mkdir dir="${release.dir}" /> <mkdir dir="${release.dir}" />
<mkdir dir="${release-dev.dir}" /> <mkdir dir="${release.samples.dir}" />
<!-- Copy smack.jar -->
<!-- Copy smack.jar -->
<copy todir="${release.dir}"> <copy todir="${release.dir}">
<fileset dir="${jar.dest.dir}" includes="smack.jar" /> <fileset dir="${jar.dest.dir}" includes="smack-${version}.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx.jar" /> <fileset dir="${jar.dest.dir}" includes="smackx-${version}.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx-debug.jar" /> <fileset dir="${jar.dest.dir}" includes="smackx-debug-${version}.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx-jingle.jar" /> <fileset dir="${jar.dest.dir}" includes="smackx-jingle-${version}.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx-workgroup-${version}.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx-experimental-${experimental.version}.jar" />
</copy> </copy>
<copy todir="${release-dev.dir}"> <copy todir="${release.samples.dir}">
<fileset dir="${jar.dest.dir}" includes="smack.jar" /> <fileset dir="${basedir}/build/resources/META-INF" includes="sample.providers" />
<fileset dir="${jar.dest.dir}" includes="smackx.jar" /> <fileset dir="${basedir}/build/resources/META-INF" includes="smack-config.xml" />
<fileset dir="${jar.dest.dir}" includes="smackx-debug.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx-jingle.jar" />
</copy> </copy>
<!-- Copy build dir -->
<copy todir="${release-dev.dir}/build">
<fileset dir="${basedir}/build"> <!-- Copy Javadocs -->
<include name="ant*" />
<include name="junit.jar" />
<include name="build.xml" />
<include name="README.html" />
<include name="lib/*.jar" />
<include name="merge/*.jar" />
<include name="build/*.jar" />
</fileset>
</copy>
<copy todir="${release-dev.dir}/jingle/extension/build">
<fileset dir="${basedir}/jingle/extension/build">
<include name="ant*" />
<include name="junit.jar" />
<include name="build.xml" />
<include name="README.html" />
<include name="lib/*.jar" />
<include name="merge/*.jar" />
</fileset>
</copy>
<!-- Copy Javadocs -->
<copy todir="${release.dir}/javadoc"> <copy todir="${release.dir}/javadoc">
<fileset dir="${basedir}/target/javadoc" includes="**/*.*" /> <fileset dir="${basedir}/target/javadoc" includes="**/*.*" />
</copy> </copy>
<copy todir="${release-dev.dir}/javadoc">
<fileset dir="${basedir}/target/javadoc" includes="**/*.*" /> <!-- Copy documentation -->
</copy>
<!-- Copy documentation -->
<copy todir="${release.dir}/documentation"> <copy todir="${release.dir}/documentation">
<fileset dir="${basedir}/documentation" includes="**/*.*" /> <fileset dir="${basedir}/documentation" includes="**/*.*" />
</copy> </copy>
<copy todir="${release-dev.dir}/documentation">
<fileset dir="${basedir}/documentation" includes="**/*.*" />
</copy> <!-- Copy readme.html and changelog.html -->
<!-- Copy source -->
<copy todir="${release-dev.dir}/source">
<fileset dir="${basedir}/source" includes="**/*.java" />
<fileset dir="${basedir}/source" includes="**/*.html" />
</copy>
<copy todir="${release-dev.dir}/jingle/extension/source">
<fileset dir="${basedir}/jingle/extension/source" includes="**/*.java" />
<fileset dir="${basedir}/jingle/extension/source" includes="**/*.html" />
</copy>
<copy todir="${release-dev.dir}/test">
<fileset dir="${basedir}/test" includes="**/*.java" />
</copy>
<!-- Copy resources -->
<copy todir="${release-dev.dir}/build/resources">
<fileset dir="${basedir}/build/resources" includes="META-INF/smack.providers" />
<fileset dir="${basedir}/build/resources" includes="META-INF/smack-config.xml" />
</copy>
<copy todir="${release-dev.dir}/build/resources/images">
<fileset dir="${basedir}/build/resources/images">
<include name="*.png"/>
</fileset>
</copy>
<!-- Copy readme.html and changelog.html -->
<copy todir="${release.dir}"> <copy todir="${release.dir}">
<fileset dir="${basedir}/build/resources/releasedocs" includes="*.html" /> <fileset dir="${basedir}/build/resources/releasedocs" includes="*.html" />
<filterset> <filterset>
<filter token="builddate" value="${builddate}"/> <filter token="releasedate" value="${release.date}"/>
<filter token="version" value="${version}"/> <filter token="version" value="${version}"/>
</filterset> </filterset>
</copy> </copy>
<copy todir="${release-dev.dir}">
<fileset dir="${basedir}/build/resources/releasedocs" includes="*.html" />
<filterset>
<filter token="builddate" value="${builddate}"/>
<filter token="version" value="${version}"/>
</filterset>
</copy>
<!-- Package -->
<if>
<equals arg1="${dailybuild}" arg2="true" />
<then>
<zip destfile="${basedir}/target/release/${release-dev.name}.zip"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
/>
<tar destfile="${basedir}/target/release/${release-dev.name}.tar.gz"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
compression="gzip"
/>
</then>
<else>
<zip destfile="${basedir}/target/release/${release.name}.zip"
basedir="${release.dir}/.."
includes="${release.name}/**/*.*"
/>
<tar destfile="${basedir}/target/release/${release.name}.tar.gz"
basedir="${release.dir}/.."
includes="${release.name}/**/*.*"
compression="gzip"
/>
<zip destfile="${basedir}/target/release/${release-dev.name}.zip"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
/>
<tar destfile="${basedir}/target/release/${release-dev.name}.tar.gz"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
compression="gzip"
/>
</else>
</if>
<!-- Package -->
<zip destfile="${basedir}/target/release/smack-${version}.zip"
basedir="${release.dir}"
includes="**/*.*"
/>
<tar destfile="${basedir}/target/release/smack-${version}.tar.gz"
basedir="${release.dir}"
includes="**/*.*"
compression="gzip"
/>
<echo> <echo>
----------------------------------------------- -----------------------------------------------
Release made, testing Ant targets of release... Release made
----------------------------------------------- -----------------------------------------------
</echo> </echo>
<!-- call the release tester -->
<antcall target="test" />
</target> </target>
<!-- test --> <!-- test -->

View file

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<!-- Providers file for default Smack extensions -->
<smackProviders>
<!-- Privacy -->
<iqProvider>
<elementName>query</elementName>
<namespace>jabber:iq:privacy</namespace>
<className>org.jivesoftware.smack.provider.PrivacyProvider</className>
</iqProvider>
<!-- Ping (XEP-199) Manager -->
<iqProvider>
<elementName>ping</elementName>
<namespace>urn:xmpp:ping</namespace>
<className>org.jivesoftware.smack.ping.provider.PingProvider</className>
</iqProvider>
</smackProviders>

View file

@ -223,13 +223,6 @@
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.DataPacketProvider</className> <className>org.jivesoftware.smackx.bytestreams.ibb.provider.DataPacketProvider</className>
</extensionProvider> </extensionProvider>
<!-- Privacy -->
<iqProvider>
<elementName>query</elementName>
<namespace>jabber:iq:privacy</namespace>
<className>org.jivesoftware.smack.provider.PrivacyProvider</className>
</iqProvider>
<!-- Ad-Hoc Command --> <!-- Ad-Hoc Command -->
<iqProvider> <iqProvider>
<elementName>command</elementName> <elementName>command</elementName>
@ -273,217 +266,6 @@
<className>org.jivesoftware.smackx.provider.AdHocCommandDataProvider$SessionExpiredError</className> <className>org.jivesoftware.smackx.provider.AdHocCommandDataProvider$SessionExpiredError</className>
</extensionProvider> </extensionProvider>
<!-- Fastpath providers -->
<iqProvider>
<elementName>offer</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.OfferRequestProvider</className>
</iqProvider>
<iqProvider>
<elementName>offer-revoke</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.OfferRevokeProvider</className>
</iqProvider>
<iqProvider>
<elementName>agent-status-request</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentStatusRequest$Provider</className>
</iqProvider>
<iqProvider>
<elementName>transcripts</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.TranscriptsProvider</className>
</iqProvider>
<iqProvider>
<elementName>transcript</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.TranscriptProvider</className>
</iqProvider>
<iqProvider>
<elementName>workgroups</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentWorkgroups$Provider</className>
</iqProvider>
<iqProvider>
<elementName>agent-info</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentInfo$Provider</className>
</iqProvider>
<iqProvider>
<elementName>transcript-search</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.TranscriptSearch$Provider</className>
</iqProvider>
<iqProvider>
<elementName>occupants-info</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.OccupantsInfo$Provider</className>
</iqProvider>
<iqProvider>
<elementName>chat-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.ChatSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>chat-notes</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.notes.ChatNotes$Provider</className>
</iqProvider>
<iqProvider>
<elementName>chat-sessions</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.history.AgentChatHistory$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>offline-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.OfflineSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>sound-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.SoundSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>workgroup-properties</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.WorkgroupProperties$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>search-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.SearchSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>workgroup-form</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.forms.WorkgroupForm$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>macros</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.macros.Macros$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>chat-metadata</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.history.ChatMetadata$Provider</className>
</iqProvider>
<!--
org.jivesoftware.smackx.workgroup.site is missing ...
<iqProvider>
<elementName>site-user</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.site.SiteUser$Provider</className>
</iqProvider>
<iqProvider>
<elementName>site-invite</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.site.SiteInvitation$Provider</className>
</iqProvider>
<iqProvider>
<elementName>site-user-history</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.site.SiteUserHistory$Provider</className>
</iqProvider>
-->
<iqProvider>
<elementName>generic-metadata</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.GenericSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>monitor</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.MonitorPacket$InternalProvider</className>
</iqProvider>
<!-- Packet Extension Providers -->
<extensionProvider>
<elementName>queue-status</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.QueueUpdate$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>workgroup</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.WorkgroupInformation$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>metadata</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.MetaDataProvider</className>
</extensionProvider>
<extensionProvider>
<elementName>session</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.SessionID$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>user</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.UserID$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>agent-status</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentStatus$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>notify-queue-details</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.QueueDetails$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>notify-queue</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.QueueOverview$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>invite</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.RoomInvitation$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>transfer</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.RoomTransfer$Provider</className>
</extensionProvider>
<!-- SHIM --> <!-- SHIM -->
<extensionProvider> <extensionProvider>
<elementName>headers</elementName> <elementName>headers</elementName>
@ -653,11 +435,11 @@
<className>org.jivesoftware.smackx.entitycaps.provider.CapsExtensionProvider</className> <className>org.jivesoftware.smackx.entitycaps.provider.CapsExtensionProvider</className>
</extensionProvider> </extensionProvider>
<!-- Ping (XEP-199) Manager --> <!-- XEP-0297 Stanza Forwarding -->
<iqProvider> <extensionProvider>
<elementName>ping</elementName> <elementName>forwarded</elementName>
<namespace>urn:xmpp:ping</namespace> <namespace>urn:xmpp:forward:0</namespace>
<className>org.jivesoftware.smack.ping.provider.PingProvider</className> <className>org.jivesoftware.smackx.forward.provider.ForwardedProvider</className>
</iqProvider> </extensionProvider>
</smackProviders> </smackProviders>

View file

@ -0,0 +1,3 @@
# Java Util Logging configuration for Smack.
handlers = java.util.logging.ConsoleHandler
.level = WARNING

View file

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<!-- Sample providers file -->
<smackProviders>
<iqProvider>
<elementName>element</elementName>
<namespace>ns</namespace>
<className>com.myco.MyIQProvider</className>
</iqProvider>
<extensionProvider>
<elementName>elem</elementName>
<namespace>http://jabber.org/protocol/whoknows</namespace>
<className>com.myco.MyExtProvider</className>
</extensionProvider>
</smackProviders>

View file

@ -22,9 +22,12 @@
<!-- Classes that will be loaded when Smack starts --> <!-- Classes that will be loaded when Smack starts -->
<startupClasses> <startupClasses>
<className>org.jivesoftware.smackx.ServiceDiscoveryManager</className> <className>org.jivesoftware.smack.provider.CoreInitializer</className>
<className>org.jivesoftware.smack.provider.VmArgInitializer</className>
<className>org.jivesoftware.smack.PrivacyListManager</className> <className>org.jivesoftware.smack.PrivacyListManager</className>
<className>org.jivesoftware.smack.keepalive.KeepAliveManager</className> <className>org.jivesoftware.smack.keepalive.KeepAliveManager</className>
<className>org.jivesoftware.smackx.provider.ExtensionInitializer</className>
<className>org.jivesoftware.smackx.ServiceDiscoveryManager</className>
<className>org.jivesoftware.smackx.XHTMLManager</className> <className>org.jivesoftware.smackx.XHTMLManager</className>
<className>org.jivesoftware.smackx.muc.MultiUserChat</className> <className>org.jivesoftware.smackx.muc.MultiUserChat</className>
<className>org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager</className> <className>org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager</className>

View file

@ -148,7 +148,7 @@ hr {
<td><b>@version@</b></td> <td><b>@version@</b></td>
</tr><tr> </tr><tr>
<td align="right">released:</td> <td align="right">released:</td>
<td><b>@builddate@</b></td> <td><b>@releasedate@</b></td>
</tr> </tr>
</table> </table>

View file

@ -141,6 +141,47 @@ hr {
<div id="pageBody"> <div id="pageBody">
<h2>3.4.0 -- <span style="font-weight: normal;">Feb 2, 2014</span></h2>
<h2>Bug Fixes</h2>
<ul>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-442'>SMACK-442</a>] - Manager&#39;s should also handle connectionClosedOnError()</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-443'>SMACK-443</a>] - ReconnectionSuccessful listeners are invoked twice on reconnection if connect() failed before</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-452'>SMACK-452</a>] - PacketParserUtils.parseStreamError() is not aware of optional text element and therefore failes to parse stream error&#39;s correctly. Prevents ReconnectionManager from reconnecting.</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-458'>SMACK-458</a>] - Smack&#39;s Managers should not remove itself when the connection is closed or should re-add themselfs if the connection get reconnected</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-462'>SMACK-462</a>] - Prevent duplicate manager instances by using the manager&#39;s constructor in the ConnectionCreationListener&#39;s connectionCreated</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-463'>SMACK-463</a>] - packet listeners silently fail when preceding listener caused exception</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-524'>SMACK-524</a>] - Use correct block-size definition for IBB transfers</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-525'>SMACK-525</a>] - NPE in XMPPConnection.notifyConnectionError</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-529'>SMACK-529</a>] - Add support for XEP-0280 &quot;Message Carbons&quot;</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-530'>SMACK-530</a>] - DNSUtilTest requires an internet connection to work, it should be moved to integration tests.</li>
</ul>
<h2>New Feature</h2>
<ul>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-286'>SMACK-286</a>] - Need to change ProviderManager to support loading smack.providers from alternative locations</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-387'>SMACK-387</a>] - Allow configuration of ChatManager to be able to allow message handling to be customized.</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-403'>SMACK-403</a>] - Add support for XEP-0297 &quot;Stanza Forwarding&quot;</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-434'>SMACK-434</a>] - Create a project to contain non production ready implementations of specifications</li>
</ul>
<h2>Improvement</h2>
<ul>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-343'>SMACK-343</a>] - Make Smack jar an OSGi bundle.</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-381'>SMACK-381</a>] - Separate the configuration for smack extension related classes from the smack jar.</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-444'>SMACK-444</a>] - Allow &#39;null&#39; for TruststorePath and TruststorePassword in ServerTrustManager</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-456'>SMACK-456</a>] - Add the causing exception to the XMPPExceptions thrown in XMPPConnection</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-457'>SMACK-457</a>] - Remove unnecessary printStackTrace() in XMPPConnection</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-460'>SMACK-460</a>] - ServiceDiscoveryManager should not use the constructor in connectionCreated()</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-461'>SMACK-461</a>] - Remove incorrect deprecated marker for DiscoverInfo.Identity.setType()</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-464'>SMACK-464</a>] - Make it clear that PacketListener&#39;s added with Connection.addPacketListener() are only for received packets</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-534'>SMACK-534</a>] - Convert all System.out and printStackTrace calls to use Java util logging.</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-339'>SMACK-339</a>] - Allow ConnectionListeners to be added before Connection is connected. Currently throws exception</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-373'>SMACK-373</a>] - Don&#39;t remove listeners after a disconnect() , keep state of Connection between disconnect() and connect()/login()</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-434'>SMACK-434</a>] - Create a project to contain non production ready implementations of specifications</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-526'>SMACK-526</a>] - Deprecate all PEP related classes.</li>
</ul>
<h2>3.3.1 -- <span style="font-weight: normal;">Oct 6, 2013</span></h2> <h2>3.3.1 -- <span style="font-weight: normal;">Oct 6, 2013</span></h2>
<h2>Bug Fixes</h2> <h2>Bug Fixes</h2>

View file

@ -40,6 +40,37 @@ over which features applications require:
</ul> </ul>
<p class="subheader">Configuration</p>
Smack has an initialization process that involves 2 phases.
<ul>
<li>Initializing system properties - Initializing all the system properties accessible through the class
<b>SmackConfiguration</b>. These properties are retrieve by the <i>getXXX</i> methods on that class.
<li>Initializing startup classes - Initializing any classes meant to be active at startup by instantiating
the class, and then calling the <i>initialize</i> method on that class if it extends <b>SmackInitializer</b>.
If it does not extend this interface, then initialization will have to take place in a static block of code
which is automatically executed when the class is loaded.
</ul>
<p>
Initialization is accomplished via a configuration file. By default, Smack will load the one embedded in
the Smack jar at <i>META-INF/smack-config.xml</i>. This particular configuration contains all the default
property values as well as a list of initializer classes to load. All manager type classes are contained
in this list of initializers. If your application does not use all the features provided by Smack via the
aforementioned managers, you may want to 'turn them off' by providing a custom config file that does not
include that feature.
<p>
If you want to change the configuration file used, you have two options:
<ul>
<li>Programmatically - Call the <i>setConfigFileUrl</i> method of <b>SmackConfiguration</b> with the location
of a new config file.
<pre>SmackConfiguration.setConfigFileUrl("classpath:test/smack-config.xml", null)</pre>
<li>VM Argument - Set the VM argument <i>smack.config.file</i> to the location of a new config file.
<pre>-Dsmack.config.file=file:///c:/com/myco/provider/myco_custom_config.xml</pre>
</ul>
<p>
Please note, there is a copy of the <b>smack-config.xml</b> in the <i>samples</i> directory of the deployment
archive file (zip or tar).
<p class="subheader"> <p class="subheader">
Establishing a Connection Establishing a Connection
</p> </p>

View file

@ -15,44 +15,68 @@ Provider Architecture: Packet Extensions and Custom IQ's
</div> </div>
<p> <p>
<p class="subheader">Introduction</p>
The Smack provider architecture is a system for plugging in The Smack provider architecture is a system for plugging in
custom XML parsing of packet extensions and IQ packets. The custom XML parsing of packet extensions and IQ packets. The
standard <a href="extensions/index.html">Smack Extensions</a> standard <a href="extensions/index.html">Smack Extensions</a>
are built using the provider architecture. Two types of are built using the provider architecture. There are two types of
providers exist:<ul> providers:<ul>
<li><tt>IQProvider</tt> -- parses IQ requests into Java objects. <li><tt>IQProvider</tt> -- parses IQ requests into Java objects.
<li><tt>PacketExtension</tt> -- parses XML sub-documents attached to <li><tt>Extension Provider</tt> -- parses XML sub-documents attached to
packets into PacketExtension instances.</ul> packets into PacketExtension instances.</ul>
<p class="subheader">IQProvider</p> By default, Smack only knows how to process a few standard packets and sub-packets
that are in a few namespaces such as:<ul>
By default, Smack only knows how to process IQ packets with sub-packets that
are in a few namespaces such as:<ul>
<li>jabber:iq:auth <li>jabber:iq:auth
<li>jabber:iq:roster <li>jabber:iq:roster
<li>jabber:iq:register</ul> <li>jabber:iq:register</ul>
Because many more IQ types are part of XMPP and its extensions, a pluggable IQ parsing There are many more IQ types and extensions that are part of XMPP standards, and of
mechanism is provided. IQ providers are registered programatically or by creating a course an endless number that can be added as custom extensions. To support this, an
smack.providers file in the META-INF directory of your JAR file. The file is an XML extensible parsing mechanism is provided via Smack and user build providers.
document that contains one or more iqProvider entries, as in the following example: <p>
Whenever a packet extension is found in a packet, parsing will
be passed to the correct provider. Each provider can either implement the
PacketExtensionProvider interface or be a standard Java Bean. In the
former case, each extension provider is responsible for parsing the raw
XML stream, via the <a href="http://www.xmlpull.org/">XML Pull Parser</a>, to contruct an object. In the latter case, bean introspection
is used to try to automatically set the properties of the class using
the values in the packet extension sub-element.
<p>
When no extension provider is registered for an element name and
namespace combination, Smack will store all top-level elements of the
sub-packet in the DefaultPacketExtension object and then attach it to the packet.
<p>
Management of these providers is accomplished via the <a href="">ProviderManager</a>
class. There are multiple ways to add providers to the manager.<ul>
<li>Call addXXProvider methods - You can call the appropriate add methods directly.
<pre>
ProviderManager.getInstance().addIQProvider("element", "namespace", new MyIQProvider());
ProviderManager.getInstance().addExtensionProvider("element", "namespace", new MyExtProvider());
</pre>
<li>Add a loader - You can add a ProviderLoader which will inject a means of loading multiple
providers (both types) into the manager. This is the mechanism used by Smack to load from the
Smack specific file format (via ProviderFileLoader). Implementers can provide the means to load
providers from any source they wish, or simply reuse the ProviderFileLoader to load from
their own provider files.
<pre>
ProviderManager.getInstance().addLoader(new ProviderFileLoader(FileUtils.getStreamForUrl("classpath:com/myco/provider/myco_custom.providers", null)));
</pre>
<li>VM Argument - You can add a provider file via the VM argument <i>smack.provider.file</i>.
This will load the file at the specified URL during startup when Smack initializes.
This also assumes the default configuration, since it requires that the <b>VmArgInitializer</b> was
part of the startup configuration.
<pre> <pre>
&lt;?xml version="1.0"?&gt; -Dsmack.provider.file=classpath:com/myco/provider/myco_custom.providers
&lt;smackProviders&gt; or
&lt;iqProvider&gt; -Dsmack.provider.file=file:///c:/myco/provider/myco_custom.providers
&lt;elementName&gt;query&lt;/elementName&gt; </pre>
&lt;namespace&gt;jabber:iq:time&lt;/namespace&gt; </ul>
&lt;className&gt;org.jivesoftware.smack.packet.Time&lt/className&gt;
&lt;/iqProvider&gt;
&lt;/smackProviders&gt;</pre>
Each IQ provider is associated with an element name and a namespace. In the <p class="subheader">IQ Providers</p>
example above, the element name is <tt>query</tt> and the namespace is
<tt>abber:iq:time</tt>. If multiple provider entries attempt to register to
handle the same namespace, the first entry loaded from the classpath will
take precedence. <p>
The IQ provider class can either implement the IQProvider The IQ provider class can either implement the IQProvider
interface, or extend the IQ class. In the former case, each IQProvider is interface, or extend the IQ class. In the former case, each IQProvider is
@ -61,54 +85,191 @@ the latter case, bean introspection is used to try to automatically set
properties of the IQ instance using the values found in the IQ packet XML. properties of the IQ instance using the values found in the IQ packet XML.
For example, an XMPP time packet resembles the following: For example, an XMPP time packet resembles the following:
<p>
<i>Introspection</i>
<p>
<u>Time Packet</u>
<pre> <pre>
&lt;iq type='result' to='joe@example.com' from='mary@example.com' id='time_1'&gt; &lt;iq type='result' to='joe@example.com' from='mary@example.com' id='time_1'&gt;
&lt;query xmlns='jabber:iq:time'&gt; &lt;query xmlns='jabber:iq:time'&gt;
&lt;utc&gt;20020910T17:58:35&lt;/utc&gt; &lt;utc&gt;20020910T17:58:35&lt;/utc&gt;
&lt;tz&gt;MDT&lt;/tz&gt; &lt;tz&gt;MDT&lt;/tz&gt;
&lt;display&gt;Tue Sep 10 12:58:35 2002&lt;/display&gt; &lt;display&gt;Tue Sep 10 12:58:35 2002&lt;/display&gt;
&lt;/query&gt; &lt;/query&gt;
&lt;/iq&gt;</pre> &lt;/iq&gt;
</pre>
In order for this packet to be automatically mapped to the Time object listed in the <p>
providers file above, it must have the methods setUtc(String), setTz(String), and <u>Time IQ Class</u>
setDisplay(String). The introspection service will automatically try to convert the String <pre>
class Time extends IQ {
private Date utc;
private TimeZone timeZone;
private String display;
@Override
public String getChildElementXML() {
return null;
}
public void setUtc(String utcString) {
try {
utc = StringUtils.parseDate(utcString);
} catch (ParseException e) {
}
}
public void setTimeZone(String zone) {
timeZone = TimeZone.getTimeZone(zone);
}
public void setDisplay(String timeDisplay) {
display = timeDisplay;
}
}
</pre>
The introspection service will automatically try to convert the String
value from the XML into a boolean, int, long, float, double, or Class depending on the value from the XML into a boolean, int, long, float, double, or Class depending on the
type the IQ instance expects.<p> type the IQ instance expects.
<p class="subheader">PacketExtensionProvider</p> <p>
<i>IQProvider Implementation</i>
<p>
<u>Disco Items Packet</u>
<pre>
&lt;iq type='result' from='shakespeare.lit' to='romeo@montague.net/orchard' id='items1'&gt;
&lt;query xmlns='http://jabber.org/protocol/disco#items'&gt;
&lt;item jid='people.shakespeare.lit' name='Directory of Characters'/&gt;
&lt;item jid='plays.shakespeare.lit' name='Play-Specific Chatrooms'/&gt;
&lt;item jid='mim.shakespeare.lit' name='Gateway to Marlowe IM'/&gt;
&lt;item jid='words.shakespeare.lit' name='Shakespearean Lexicon'/&gt;
&lt;item jid='globe.shakespeare.lit' name='Calendar of Performances'/&gt;
&lt;item jid='headlines.shakespeare.lit' name='Latest Shakespearean News'/&gt;
&lt;item jid='catalog.shakespeare.lit' name='Buy Shakespeare Stuff!'/&gt;
&lt;item jid='en2fr.shakespeare.lit' name='French Translation Service'/&gt;
&lt;/query&gt;
&lt;/iq&gt;
</pre>
Packet extension providers provide a pluggable system for <p>
packet extensions, which are child elements in a custom namespace <u>Disco Items IQProvider</u>
of IQ, message and presence packets. <pre>
Each extension provider is registered with an element name and namespace public class DiscoverItemsProvider implements IQProvider {
in the smack.providers file as in the following example:
public IQ parseIQ(XmlPullParser parser) throws Exception {
DiscoverItems discoverItems = new DiscoverItems();
boolean done = false;
DiscoverItems.Item item;
String jid = "";
String name = "";
String action = "";
String node = "";
discoverItems.setNode(parser.getAttributeValue("", "node"));
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG && "item".equals(parser.getName())) {
// Initialize the variables from the parsed XML
jid = parser.getAttributeValue("", "jid");
name = parser.getAttributeValue("", "name");
node = parser.getAttributeValue("", "node");
action = parser.getAttributeValue("", "action");
}
else if (eventType == XmlPullParser.END_TAG && "item".equals(parser.getName())) {
// Create a new Item and add it to DiscoverItems.
item = new DiscoverItems.Item(jid);
item.setName(name);
item.setNode(node);
item.setAction(action);
discoverItems.addItem(item);
}
else if (eventType == XmlPullParser.END_TAG && "query".equals(parser.getName())) {
done = true;
}
}
return discoverItems;
}
}
</pre>
<p class="subheader">Extension Providers</p>
Packet extension providers are responsible for parsing packet extensions, which are
child elements in a custom namespace of IQ, message and presence packets.
<p>
<u>Pubsub Subscription Packet</u>
<pre> <pre>
&lt;?xml version="1.0"?&gt; &lt;iq type='result' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='sub1'&gt;
&lt;smackProviders&gt; &lt;pubsub xmlns='http://jabber.org/protocol/pubsub'&gt;
&lt;subscription node='princely_musings' jid='francisco@denmark.lit' subscription='unconfigured'&gt;
&lt;subscribe-options&gt;
&lt;required/&gt;
&lt;/subscribe-options&gt;
&lt;/subscription&gt;
&lt;/pubsub&gt;
&lt;/iq&gt;
</pre>
<p>
<u>Subscription PacketExtensionProvider Implementation</u>
<pre>
public class SubscriptionProvider implements PacketExtensionProvider {
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
String jid = parser.getAttributeValue(null, "jid");
String nodeId = parser.getAttributeValue(null, "node");
String subId = parser.getAttributeValue(null, "subid");
String state = parser.getAttributeValue(null, "subscription");
boolean isRequired = false;
int tag = parser.next();
if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("subscribe-options")) {
tag = parser.next();
if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("required"))
isRequired = true;
while (parser.next() != XmlPullParser.END_TAG && parser.getName() != "subscribe-options");
}
while (parser.getEventType() != XmlPullParser.END_TAG) parser.next();
return new Subscription(jid, nodeId, subId, (state == null ? null : Subscription.State.valueOf(state)), isRequired);
}
}
</pre>
<p class="subheader">Provider file format</p>
This is the format for a provider file which can be parsed by the <b>ProviderFileLoader</b>.
<pre>
&lt;?xml version="1.0"?&gt;
&lt;smackProviders&gt;
&lt;iqProvider&gt;
&lt;elementName&gt;query&lt;/elementName&gt;
&lt;namespace&gt;jabber:iq:time&lt;/namespace&gt;
&lt;className&gt;org.jivesoftware.smack.packet.Time&lt/className&gt;
&lt;/iqProvider&gt;
&lt;iqProvider&gt;
&lt;elementName&gt;query&lt;/elementName&gt;
&lt;namespace&gt;http://jabber.org/protocol/disco#items&lt;/namespace&gt;
&lt;className&gt;org.jivesoftware.smackx.provider.DiscoverItemsProvider&lt/className&gt;
&lt;/iqProvider&gt;
&lt;extensionProvider&gt; &lt;extensionProvider&gt;
&lt;elementName&gt;x&lt;/elementName&gt; &lt;elementName&gt;subscription&lt;/elementName&gt;
&lt;namespace&gt;jabber:iq:event&lt;/namespace&gt; &lt;namespace&gt;http://jabber.org/protocol/pubsub&lt;/namespace&gt;
&lt;className&gt;org.jivesoftware.smack.packet.MessageEvent&lt/className&gt; &lt;className&gt;org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider&lt/className&gt;
&lt;/extensionProvider&gt; &lt;/extensionProvider&gt;
&lt;/smackProviders&gt;</pre> &lt;/smackProviders&gt;</pre>
If multiple provider entries attempt to register to handle the same element Each provider is associated with an element name and a namespace. If multiple provider entries attempt to register to
name and namespace, the first entry loaded from the classpath will take handle the same namespace, the last entry added to the <b>ProviderManager</b> will overwrite any other that was loaded
precedence.<p> before it.
<p>
Whenever a packet extension is found in a packet, parsing will
be passed to the correct provider. Each provider can either implement the
PacketExtensionProvider interface or be a standard Java Bean. In the
former case, each extension provider is responsible for parsing the raw
XML stream to contruct an object. In the latter case, bean introspection
is used to try to automatically set the properties of the class using
the values in the packet extension sub-element.<p>
When an extension provider is not registered for an element name and
namespace combination, Smack will store all top-level elements of the
sub-packet in DefaultPacketExtension object and then attach it to the packet.
<br clear="all" /><br><br> <br clear="all" /><br><br>

View file

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<!-- Providers for workgroup extensions -->
<smackProviders>
<!-- XEP-0280 Message Carbons -->
<extensionProvider>
<elementName>sent</elementName>
<namespace>urn:xmpp:carbons:2</namespace>
<className>org.jivesoftware.smackx.carbons.provider.CarbonManagerProvider</className>
</extensionProvider>
<extensionProvider>
<elementName>received</elementName>
<namespace>urn:xmpp:carbons:2</namespace>
<className>org.jivesoftware.smackx.carbons.provider.CarbonManagerProvider</className>
</extensionProvider>
</smackProviders>

View file

@ -0,0 +1,117 @@
/**
* Copyright 2013 Georg Lukas
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.carbons;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.forward.Forwarded;
/**
* Packet extension for XEP-0280: Message Carbons. The extension
* <a href="http://xmpp.org/extensions/xep-0280.html">XEP-0280</a> is
* meant to synchronize a message flow to multiple presences of a user.
*
* <p>
* It accomplishes this by wrapping a {@link Forwarded} packet in a <b>sent</b>
* or <b>received</b> element
*
* @author Georg Lukas
*/
public class Carbon implements PacketExtension {
public static final String NAMESPACE = "urn:xmpp:carbons:2";
private Direction dir;
private Forwarded fwd;
/**
* Construct a Carbon message extension.
*
* @param dir Determines if the carbon is being sent/received
* @param fwd The forwarded message.
*/
public Carbon(Direction dir, Forwarded fwd) {
this.dir = dir;
this.fwd = fwd;
}
/**
* Get the direction (sent or received) of the carbon.
*
* @return the {@link Direction} of the carbon.
*/
public Direction getDirection() {
return dir;
}
/**
* Get the forwarded packet.
*
* @return the {@link Forwarded} message contained in this Carbon.
*/
public Forwarded getForwarded() {
return fwd;
}
@Override
public String getElementName() {
return dir.toString();
}
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<").append(getElementName()).append(" xmlns=\"")
.append(getNamespace()).append("\">");
buf.append(fwd.toXML());
buf.append("</").append(getElementName()).append(">");
return buf.toString();
}
/**
* Defines the direction of a {@link Carbon} message.
*/
public static enum Direction {
received,
sent
}
/**
* Packet extension indicating that a message may not be carbon-copied. Adding this
* extension to any message will disallow that message from being copied.
*/
public static class Private implements PacketExtension {
public static final String ELEMENT = "private";
public String getElementName() {
return ELEMENT;
}
public String getNamespace() {
return Carbon.NAMESPACE;
}
public String toXML() {
return "<" + ELEMENT + " xmlns=\"" + Carbon.NAMESPACE + "\"/>";
}
}
}

View file

@ -0,0 +1,213 @@
/**
* Copyright 2013 Georg Lukas
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.carbons;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
/**
* Packet extension for XEP-0280: Message Carbons. This class implements
* the manager for registering {@link Carbon} support, enabling and disabling
* message carbons.
*
* You should call enableCarbons() before sending your first undirected
* presence.
*
* @author Georg Lukas
*/
public class CarbonManager {
private static Map<Connection, CarbonManager> instances =
Collections.synchronizedMap(new WeakHashMap<Connection, CarbonManager>());
static {
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(Connection connection) {
new CarbonManager(connection);
}
});
}
private Connection connection;
private volatile boolean enabled_state = false;
private CarbonManager(Connection connection) {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(Carbon.NAMESPACE);
this.connection = connection;
instances.put(connection, this);
}
/**
* Obtain the CarbonManager responsible for a connection.
*
* @param connection the connection object.
*
* @return a CarbonManager instance
*/
public static CarbonManager getInstanceFor(Connection connection) {
CarbonManager carbonManager = instances.get(connection);
if (carbonManager == null) {
carbonManager = new CarbonManager(connection);
}
return carbonManager;
}
private IQ carbonsEnabledIQ(final boolean new_state) {
IQ setIQ = new IQ() {
public String getChildElementXML() {
return "<" + (new_state? "enable" : "disable") + " xmlns='" + Carbon.NAMESPACE + "'/>";
}
};
setIQ.setType(IQ.Type.SET);
return setIQ;
}
/**
* Returns true if XMPP Carbons are supported by the server.
*
* @return true if supported
*/
public boolean isSupportedByServer() {
try {
DiscoverInfo result = ServiceDiscoveryManager
.getInstanceFor(connection).discoverInfo(connection.getServiceName());
return result.containsFeature(Carbon.NAMESPACE);
}
catch (XMPPException e) {
return false;
}
}
/**
* Notify server to change the carbons state. This method returns
* immediately and changes the variable when the reply arrives.
*
* You should first check for support using isSupportedByServer().
*
* @param new_state whether carbons should be enabled or disabled
*/
public void sendCarbonsEnabled(final boolean new_state) {
IQ setIQ = carbonsEnabledIQ(new_state);
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
IQ result = (IQ)packet;
if (result.getType() == IQ.Type.RESULT) {
enabled_state = new_state;
}
connection.removePacketListener(this);
}
}, new PacketIDFilter(setIQ.getPacketID()));
connection.sendPacket(setIQ);
}
/**
* Notify server to change the carbons state. This method blocks
* some time until the server replies to the IQ and returns true on
* success.
*
* You should first check for support using isSupportedByServer().
*
* @param new_state whether carbons should be enabled or disabled
*
* @return true if the operation was successful
*/
public boolean setCarbonsEnabled(final boolean new_state) {
if (enabled_state == new_state)
return true;
IQ setIQ = carbonsEnabledIQ(new_state);
PacketCollector collector =
connection.createPacketCollector(new PacketIDFilter(setIQ.getPacketID()));
connection.sendPacket(setIQ);
IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (result != null && result.getType() == IQ.Type.RESULT) {
enabled_state = new_state;
return true;
}
return false;
}
/**
* Helper method to enable carbons.
*
* @return true if the operation was successful
*/
public boolean enableCarbons() {
return setCarbonsEnabled(true);
}
/**
* Helper method to disable carbons.
*
* @return true if the operation was successful
*/
public boolean disableCarbons() {
return setCarbonsEnabled(false);
}
/**
* Check if carbons are enabled on this connection.
*/
public boolean getCarbonsEnabled() {
return this.enabled_state;
}
/**
* Obtain a Carbon from a message, if available.
*
* @param msg Message object to check for carbons
*
* @return a Carbon if available, null otherwise.
*/
public static Carbon getCarbon(Message msg) {
Carbon cc = (Carbon)msg.getExtension("received", Carbon.NAMESPACE);
if (cc == null)
cc = (Carbon)msg.getExtension("sent", Carbon.NAMESPACE);
return cc;
}
/**
* Mark a message as "private", so it will not be carbon-copied.
*
* @param msg Message object to mark private
*/
public static void disableCarbons(Message msg) {
msg.addExtension(new Carbon.Private());
}
}

View file

@ -0,0 +1,53 @@
/**
* Copyright 2013 Georg Lukas
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.carbons.provider;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.carbons.Carbon;
import org.jivesoftware.smackx.carbons.Carbon.Direction;
import org.jivesoftware.smackx.forward.Forwarded;
import org.xmlpull.v1.XmlPullParser;
/**
* This class implements the {@link PacketExtensionProvider} to parse
* cabon copied messages from a packet. It will return a {@link Carbon} packet extension.
*
* @author Georg Lukas
*
*/
public class CarbonManagerProvider implements PacketExtensionProvider {
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
Direction dir = Direction.valueOf(parser.getName());
Forwarded fwd = null;
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("forwarded")) {
fwd = (Forwarded) PacketParserUtils.parsePacketExtension(Forwarded.ELEMENT_NAME, Forwarded.NAMESPACE, parser);
}
else if (eventType == XmlPullParser.END_TAG && dir == Direction.valueOf(parser.getName()))
done = true;
}
if (fwd == null)
throw new Exception("sent/received must contain exactly one <forwarded> tag");
return new Carbon(dir, fwd);
}
}

View file

@ -0,0 +1,33 @@
/**
* Copyright 2013 Robin Collier
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.experimental;
import org.jivesoftware.smack.provider.UrlProviderFileInitializer;
/**
* Initializes the providers in the experimental code stream.
*
* @author Robin Collier
*
*/
public class ExperimentalProviderInitializer extends UrlProviderFileInitializer {
@Override
protected String getFilePath() {
return "classpath:META-INF/experimental.providers";
}
}

View file

@ -0,0 +1,110 @@
/**
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.carbons;
import static org.junit.Assert.assertEquals;
import java.util.Properties;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smackx.carbons.provider.CarbonManagerProvider;
import org.jivesoftware.smackx.forward.Forwarded;
import org.jivesoftware.smackx.forward.provider.ForwardedProvider;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import com.jamesmurty.utils.XMLBuilder;
public class CarbonTest {
private static Properties outputProperties = new Properties();
static {
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@BeforeClass
public static void setup() {
ProviderManager.getInstance().addExtensionProvider("forwarded", "urn:xmpp:forward:0", new ForwardedProvider());
}
@Test
public void carbonSentTest() throws Exception {
XmlPullParser parser;
String control;
Carbon cc;
Forwarded fwd;
control = XMLBuilder.create("sent")
.e("forwarded")
.a("xmlns", "urn:xmpp:forwarded:0")
.e("message")
.a("from", "romeo@montague.com")
.asString(outputProperties);
parser = TestUtils.getParser(control, "sent");
cc = (Carbon) new CarbonManagerProvider().parseExtension(parser);
fwd = cc.getForwarded();
// meta
assertEquals(Carbon.Direction.sent, cc.getDirection());
// no delay in packet
assertEquals(null, fwd.getDelayInfo());
// check message
assertEquals("romeo@montague.com", fwd.getForwardedPacket().getFrom());
// check end of tag
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("sent", parser.getName());
}
@Test
public void carbonReceivedTest() throws Exception {
XmlPullParser parser;
String control;
Carbon cc;
control = XMLBuilder.create("received")
.e("forwarded")
.a("xmlns", "urn:xmpp:forwarded:0")
.e("message")
.a("from", "romeo@montague.com")
.asString(outputProperties);
parser = TestUtils.getParser(control, "received");
cc = (Carbon) new CarbonManagerProvider().parseExtension(parser);
assertEquals(Carbon.Direction.received, cc.getDirection());
// check end of tag
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("received", parser.getName());
}
@Test(expected=Exception.class)
public void carbonEmptyTest() throws Exception {
XmlPullParser parser;
String control;
control = XMLBuilder.create("sent")
.a("xmlns", "urn:xmpp:forwarded:0")
.asString(outputProperties);
parser = TestUtils.getParser(control, "sent");
new CarbonManagerProvider().parseExtension(parser);
}
}

View file

@ -32,6 +32,8 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Allows creation and management of accounts on an XMPP server. * Allows creation and management of accounts on an XMPP server.
@ -40,6 +42,7 @@ import java.util.Map;
* @author Matt Tucker * @author Matt Tucker
*/ */
public class AccountManager { public class AccountManager {
private static Logger logger = Logger.getLogger(AccountManager.class.getName());
private Connection connection; private Connection connection;
private Registration info = null; private Registration info = null;
@ -134,7 +137,7 @@ public class AccountManager {
} }
} }
catch (XMPPException xe) { catch (XMPPException xe) {
xe.printStackTrace(); logger.log(Level.SEVERE, "Error retrieving account attributes from server", xe);
} }
return Collections.emptySet(); return Collections.emptySet();
} }
@ -155,7 +158,7 @@ public class AccountManager {
return info.getAttributes().get(name); return info.getAttributes().get(name);
} }
catch (XMPPException xe) { catch (XMPPException xe) {
xe.printStackTrace(); logger.log(Level.SEVERE, "Error retrieving account attribute " + name + " info from server", xe);
} }
return null; return null;
} }
@ -175,6 +178,7 @@ public class AccountManager {
return info.getInstructions(); return info.getInstructions();
} }
catch (XMPPException xe) { catch (XMPPException xe) {
logger.log(Level.SEVERE, "Error retrieving account instructions from server", xe);
return null; return null;
} }
} }

View file

@ -170,6 +170,18 @@ public class Chat {
} }
} }
@Override
public String toString() {
return "Chat [(participant=" + participant + "), (thread=" + threadID + ")]";
}
@Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + threadID.hashCode();
hash = hash * 31 + participant.hashCode();
return hash;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {

View file

@ -24,6 +24,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
@ -33,38 +34,58 @@ import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.ThreadFilter; import org.jivesoftware.smack.filter.ThreadFilter;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.collections.ReferenceMap; import org.jivesoftware.smack.util.collections.ReferenceMap;
/** /**
* The chat manager keeps track of references to all current chats. It will not hold any references * The chat manager keeps track of references to all current chats. It will not hold any references
* in memory on its own so it is neccesary to keep a reference to the chat object itself. To be * in memory on its own so it is necessary to keep a reference to the chat object itself. To be
* made aware of new chats, register a listener by calling {@link #addChatListener(ChatManagerListener)}. * made aware of new chats, register a listener by calling {@link #addChatListener(ChatManagerListener)}.
* *
* @author Alexander Wenckus * @author Alexander Wenckus
*/ */
public class ChatManager { public class ChatManager {
/*
* Sets the default behaviour for allowing 'normal' messages to be used in chats. As some clients don't set
* the message type to chat, the type normal has to be accepted to allow chats with these clients.
*/
private static boolean defaultIsNormalInclude = true;
/*
* Sets the default behaviour for how to match chats when there is NO thread id in the incoming message.
*/
private static MatchMode defaultMatchMode = MatchMode.BARE_JID;
/** /**
* Returns the next unique id. Each id made up of a short alphanumeric * Defines the different modes under which a match will be attempted with an existing chat when
* prefix along with a unique numeric value. * the incoming message does not have a thread id.
*
* @return the next id.
*/ */
private static synchronized String nextID() { public enum MatchMode {
return prefix + Long.toString(id++); /**
* Will not attempt to match, always creates a new chat.
*/
NONE,
/**
* Will match on the JID in the from field of the message.
*/
SUPPLIED_JID,
/**
* Will attempt to match on the JID in the from field, and then attempt the base JID if no match was found.
* This is the most lenient matching.
*/
BARE_JID;
} }
/** /*
* A prefix helps to make sure that ID's are unique across mutliple instances. * Determines whether incoming messages of type normal can create chats.
*/ */
private static String prefix = StringUtils.randomString(5); private boolean normalIncluded = defaultIsNormalInclude;
/** /*
* Keeps track of the current increment, which is appended to the prefix to * Determines how incoming message with no thread will be matched to existing chats.
* forum a unique ID.
*/ */
private static long id = 0; private MatchMode matchMode = defaultMatchMode;
/** /**
* Maps thread ID to chat. * Maps thread ID to chat.
@ -101,11 +122,11 @@ public class ChatManager {
return false; return false;
} }
Message.Type messageType = ((Message) packet).getType(); Message.Type messageType = ((Message) packet).getType();
return messageType != Message.Type.groupchat && return (messageType == Type.chat) || (normalIncluded ? messageType == Type.normal : false);
messageType != Message.Type.headline;
} }
}; };
// Add a listener for all message packets so that we can deliver errant
// Add a listener for all message packets so that we can deliver
// messages to the best Chat instance available. // messages to the best Chat instance available.
connection.addPacketListener(new PacketListener() { connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) { public void processPacket(Packet packet) {
@ -116,10 +137,6 @@ public class ChatManager {
} }
else { else {
chat = getThreadChat(message.getThread()); chat = getThreadChat(message.getThread());
if (chat == null) {
// Try to locate the chat based on the sender of the message
chat = getUserChat(message.getFrom());
}
} }
if(chat == null) { if(chat == null) {
@ -130,6 +147,44 @@ public class ChatManager {
}, filter); }, filter);
} }
/**
* Determines whether incoming messages of type <i>normal</i> will be used for creating new chats or matching
* a message to existing ones.
*
* @return true if normal is allowed, false otherwise.
*/
public boolean isNormalIncluded() {
return normalIncluded;
}
/**
* Sets whether to allow incoming messages of type <i>normal</i> to be used for creating new chats or matching
* a message to an existing one.
*
* @param normalIncluded true to allow normal, false otherwise.
*/
public void setNormalIncluded(boolean normalIncluded) {
this.normalIncluded = normalIncluded;
}
/**
* Gets the current mode for matching messages with <b>NO</b> thread id to existing chats.
*
* @return The current mode.
*/
public MatchMode getMatchMode() {
return matchMode;
}
/**
* Sets the mode for matching messages with <b>NO</b> thread id to existing chats.
*
* @param matchMode The mode to set.
*/
public void setMatchMode(MatchMode matchMode) {
this.matchMode = matchMode;
}
/** /**
* Creates a new chat and returns it. * Creates a new chat and returns it.
* *
@ -138,12 +193,7 @@ public class ChatManager {
* @return the created chat. * @return the created chat.
*/ */
public Chat createChat(String userJID, MessageListener listener) { public Chat createChat(String userJID, MessageListener listener) {
String threadID; return createChat(userJID, null, listener);
do {
threadID = nextID();
} while (threadChats.get(threadID) != null);
return createChat(userJID, threadID, listener);
} }
/** /**
@ -155,7 +205,7 @@ public class ChatManager {
* @return the created chat. * @return the created chat.
*/ */
public Chat createChat(String userJID, String thread, MessageListener listener) { public Chat createChat(String userJID, String thread, MessageListener listener) {
if(thread == null) { if (thread == null) {
thread = nextID(); thread = nextID();
} }
Chat chat = threadChats.get(thread); Chat chat = threadChats.get(thread);
@ -191,20 +241,25 @@ public class ChatManager {
} }
/** /**
* Try to get a matching chat for the given user JID. Try the full * Try to get a matching chat for the given user JID, based on the {@link MatchMode}.
* JID map first, the try to match on the base JID if no match is * <li>NONE - return null
* found. * <li>SUPPLIED_JID - match the jid in the from field of the message exactly.
* <li>BARE_JID - if not match for from field, try the bare jid.
* *
* @param userJID * @param userJID jid in the from field of message.
* @return * @return Matching chat, or null if no match found.
*/ */
private Chat getUserChat(String userJID) { private Chat getUserChat(String userJID) {
Chat match = jidChats.get(userJID); if (matchMode == MatchMode.NONE) {
return null;
}
if (match == null) { Chat match = jidChats.get(userJID);
match = baseJidChats.get(StringUtils.parseBareAddress(userJID));
} if (match == null && (matchMode == MatchMode.BARE_JID)) {
return match; match = baseJidChats.get(StringUtils.parseBareAddress(userJID));
}
return match;
} }
public Chat getThreadChat(String thread) { public Chat getThreadChat(String thread) {
@ -278,4 +333,21 @@ public class ChatManager {
interceptors.put(packetInterceptor, filter); interceptors.put(packetInterceptor, filter);
} }
} }
/**
* Returns a unique id.
*
* @return the next id.
*/
private static String nextID() {
return UUID.randomUUID().toString();
}
public static void setDefaultMatchMode(MatchMode mode) {
defaultMatchMode = mode;
}
public static void setDefaultIsNormalIncluded(boolean allowNormal) {
defaultIsNormalInclude = allowNormal;
}
} }

View file

@ -34,6 +34,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import org.jivesoftware.smack.compression.JzlibInputOutputStream; import org.jivesoftware.smack.compression.JzlibInputOutputStream;
import org.jivesoftware.smack.compression.XMPPInputOutputStream; import org.jivesoftware.smack.compression.XMPPInputOutputStream;
@ -83,6 +84,7 @@ import org.jivesoftware.smack.packet.Presence;
* @author Guenther Niess * @author Guenther Niess
*/ */
public abstract class Connection { public abstract class Connection {
private static Logger log = Logger.getLogger(Connection.class.getName());
/** /**
* Counter to uniquely identify connections that are created. * Counter to uniquely identify connections that are created.
@ -593,10 +595,14 @@ public abstract class Connection {
} }
/** /**
* Registers a packet listener with this connection. A packet filter determines * Registers a packet listener with this connection. A packet listener will be invoked only
* when an incoming packet is received. A packet filter determines
* which packets will be delivered to the listener. If the same packet listener * which packets will be delivered to the listener. If the same packet listener
* is added again with a different filter, only the new filter will be used. * is added again with a different filter, only the new filter will be used.
* *
* <p>
* NOTE: If you want get a similar callback for outgoing packets, see {@link #addPacketInterceptor(PacketInterceptor, PacketFilter)}.
*
* @param packetListener the packet listener to notify of new received packets. * @param packetListener the packet listener to notify of new received packets.
* @param packetFilter the packet filter to use. * @param packetFilter the packet filter to use.
*/ */
@ -682,6 +688,9 @@ public abstract class Connection {
* may modify the packet to be sent. A packet filter determines which packets * may modify the packet to be sent. A packet filter determines which packets
* will be delivered to the interceptor. * will be delivered to the interceptor.
* *
* <p>
* NOTE: For a similar functionality on incoming packets, see {@link #addPacketListener(PacketListener, PacketFilter)}.
*
* @param packetInterceptor the packet interceptor to notify of packets about to be sent. * @param packetInterceptor the packet interceptor to notify of packets about to be sent.
* @param packetFilter the packet filter to use. * @param packetFilter the packet filter to use.
*/ */
@ -757,7 +766,7 @@ public abstract class Connection {
debuggerClass = Class.forName(className); debuggerClass = Class.forName(className);
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); log.warning("Unabled to instantiate debugger class " + className);
} }
} }
if (debuggerClass == null) { if (debuggerClass == null) {
@ -771,7 +780,7 @@ public abstract class Connection {
Class.forName("org.jivesoftware.smack.debugger.LiteDebugger"); Class.forName("org.jivesoftware.smack.debugger.LiteDebugger");
} }
catch (Exception ex2) { catch (Exception ex2) {
ex2.printStackTrace(); log.warning("Unabled to instantiate either Smack debugger class");
} }
} }
} }

View file

@ -0,0 +1,28 @@
package org.jivesoftware.smack;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.jivesoftware.smack.util.FileUtils;
/**
* Initializes the Java logging system.
*
* @author Robin Collier
*
*/
public class LoggingInitializer implements SmackInitializer {
private static Logger log = Logger.getLogger(LoggingInitializer.class.getName());
@Override
public void initialize() {
try {
LogManager.getLogManager().readConfiguration(FileUtils.getStreamForUrl("classpath:META-INF/jul.properties", null));
}
catch (Exception e) {
log .log(Level.WARNING, "Could not initialize Java Logging from default file.", e);
}
}
}

View file

@ -34,6 +34,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Listens for XML traffic from the XMPP server and parses it into packet objects. * Listens for XML traffic from the XMPP server and parses it into packet objects.
@ -45,6 +47,8 @@ import java.util.concurrent.*;
*/ */
class PacketReader { class PacketReader {
private static Logger log = Logger.getLogger(PacketReader.class.getName());
private Thread readerThread; private Thread readerThread;
private ExecutorService listenerExecutor; private ExecutorService listenerExecutor;
@ -134,7 +138,7 @@ class PacketReader {
catch (Exception e) { catch (Exception e) {
// Catch and print any exception so we can recover // Catch and print any exception so we can recover
// from a faulty listener and finish the shutdown process // from a faulty listener and finish the shutdown process
e.printStackTrace(); log.log(Level.SEVERE, "Error in listener while closing connection", e);
} }
} }
} }
@ -156,7 +160,7 @@ class PacketReader {
parser.setInput(connection.reader); parser.setInput(connection.reader);
} }
catch (XmlPullParserException xppe) { catch (XmlPullParserException xppe) {
xppe.printStackTrace(); log.log(Level.WARNING, "Error while resetting parser", xppe);
} }
} }
@ -451,8 +455,7 @@ class PacketReader {
try { try {
listenerWrapper.notifyListener(packet); listenerWrapper.notifyListener(packet);
} catch (Exception e) { } catch (Exception e) {
System.err.println("Exception in packet listener: " + e); log.log(Level.SEVERE, "Exception in packet listener", e);
e.printStackTrace();
} }
} }
} }

View file

@ -26,6 +26,8 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Writes packets to a XMPP server. Packets are sent using a dedicated thread. Packet * Writes packets to a XMPP server. Packets are sent using a dedicated thread. Packet
@ -38,6 +40,7 @@ import java.util.concurrent.BlockingQueue;
* @author Matt Tucker * @author Matt Tucker
*/ */
class PacketWriter { class PacketWriter {
private static Logger log = Logger.getLogger(PacketWriter.class.getName());
private Thread writerThread; private Thread writerThread;
private Writer writer; private Writer writer;
@ -88,7 +91,7 @@ class PacketWriter {
queue.put(packet); queue.put(packet);
} }
catch (InterruptedException ie) { catch (InterruptedException ie) {
ie.printStackTrace(); log.log(Level.SEVERE, "Failed to queue packet to send to server: " + packet.toString(), ie);
return; return;
} }
synchronized (queue) { synchronized (queue) {
@ -165,14 +168,14 @@ class PacketWriter {
// we won't have time to entirely flush it before the socket is forced closed // we won't have time to entirely flush it before the socket is forced closed
// by the shutdown process. // by the shutdown process.
try { try {
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
Packet packet = queue.remove(); Packet packet = queue.remove();
writer.write(packet.toXML()); writer.write(packet.toXML());
} }
writer.flush(); writer.flush();
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); log.warning("Error flushing queue during shutdown, ignore and continue");
} }
// Delete the queue contents (hopefully nothing is left). // Delete the queue contents (hopefully nothing is left).

View file

@ -19,6 +19,7 @@ package org.jivesoftware.smack;
import org.jivesoftware.smack.packet.StreamError; import org.jivesoftware.smack.packet.StreamError;
import java.util.Random; import java.util.Random;
import java.util.logging.Logger;
/** /**
* Handles the automatic reconnection process. Every time a connection is dropped without * Handles the automatic reconnection process. Every time a connection is dropped without
* the application explictly closing it, the manager automatically tries to reconnect to * the application explictly closing it, the manager automatically tries to reconnect to
@ -34,6 +35,7 @@ import java.util.Random;
* @author Francisco Vives * @author Francisco Vives
*/ */
public class ReconnectionManager implements ConnectionListener { public class ReconnectionManager implements ConnectionListener {
private static Logger log = Logger.getLogger(ReconnectionManager.class.getName());
// Holds the connection to the server // Holds the connection to the server
private Connection connection; private Connection connection;
@ -133,7 +135,7 @@ public class ReconnectionManager implements ConnectionListener {
.notifyAttemptToReconnectIn(remainingSeconds); .notifyAttemptToReconnectIn(remainingSeconds);
} }
catch (InterruptedException e1) { catch (InterruptedException e1) {
e1.printStackTrace(); log.warning("Sleeping thread interrupted");
// Notify the reconnection has failed // Notify the reconnection has failed
ReconnectionManager.this.notifyReconnectionFailed(e1); ReconnectionManager.this.notifyReconnectionFailed(e1);
} }

View file

@ -29,6 +29,7 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException; import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.*;
import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -41,6 +42,7 @@ import java.util.regex.Pattern;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
class ServerTrustManager implements X509TrustManager { class ServerTrustManager implements X509TrustManager {
private static Logger log = Logger.getLogger(ServerTrustManager.class.getName());
private static Pattern cnPattern = Pattern.compile("(?i)(cn=)([^,]*)"); private static Pattern cnPattern = Pattern.compile("(?i)(cn=)([^,]*)");
@ -153,8 +155,7 @@ class ServerTrustManager implements X509TrustManager {
trusted = trustStore.getCertificateAlias(x509Certificates[nSize - 1]) != null; trusted = trustStore.getCertificateAlias(x509Certificates[nSize - 1]) != null;
if (!trusted && nSize == 1 && configuration.isSelfSignedCertificateEnabled()) if (!trusted && nSize == 1 && configuration.isSelfSignedCertificateEnabled())
{ {
System.out.println("Accepting self-signed certificate of remote server: " + log.info("Accepting self-signed certificate of remote server: " + peerIdentities);
peerIdentities);
trusted = true; trusted = true;
} }
} }
@ -268,7 +269,7 @@ class ServerTrustManager implements X509TrustManager {
} }
} }
// Other types are not good for XMPP so ignore them // Other types are not good for XMPP so ignore them
System.out.println("SubjectAltName of invalid type found: " + certificate); log.info("SubjectAltName of invalid type found: " + certificate);
}*/ }*/
} }
catch (CertificateParsingException e) { catch (CertificateParsingException e) {

View file

@ -20,16 +20,18 @@
package org.jivesoftware.smack; package org.jivesoftware.smack;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Enumeration; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Vector; import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.parsing.ExceptionThrowingCallback; import org.jivesoftware.smack.parsing.ExceptionThrowingCallback;
import org.jivesoftware.smack.parsing.ParsingExceptionCallback; import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
import org.jivesoftware.smack.util.FileUtils;
import org.xmlpull.mxp1.MXParser; import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -49,17 +51,23 @@ import org.xmlpull.v1.XmlPullParser;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public final class SmackConfiguration { public final class SmackConfiguration {
private static final String SMACK_VERSION = "3.4.0";
private static final String DEFAULT_CONFIG_FILE = "classpath:META-INF/smack-config.xml";
private static final String SMACK_VERSION = "3.3.1"; private static final Logger log = Logger.getLogger(SmackConfiguration.class.getName());
private static InputStream configFileStream;
private static int packetReplyTimeout = 5000; private static int packetReplyTimeout = 5000;
private static int keepAliveInterval = 30000; private static int keepAliveInterval = 30000;
private static Vector<String> defaultMechs = new Vector<String>(); private static List<String> defaultMechs = new ArrayList<String>();
private static boolean localSocks5ProxyEnabled = true; private static boolean localSocks5ProxyEnabled = true;
private static int localSocks5ProxyPort = 7777; private static int localSocks5ProxyPort = 7777;
private static int packetCollectorSize = 5000; private static int packetCollectorSize = 5000;
private static boolean initialized = false;
/** /**
* The default parsing exception callback is {@link ExceptionThrowingCallback} which will * The default parsing exception callback is {@link ExceptionThrowingCallback} which will
* throw an exception and therefore disconnect the active connection. * throw an exception and therefore disconnect the active connection.
@ -81,73 +89,37 @@ public final class SmackConfiguration {
* 1) a set of classes will be loaded in order to execute their static init block * 1) a set of classes will be loaded in order to execute their static init block
* 2) retrieve and set the current Smack release * 2) retrieve and set the current Smack release
*/ */
static {
/**
* Sets the location of the config file on the classpath. Only required if changing from the default location of <i>classpath:META-INF/smack-config.xml</i>.
*
* <p>
* This method must be called before accessing any other class in Smack.
*
* @param configFileUrl The location of the config file.
* @param loader The classloader to use if the URL has a protocol of <b>classpath</> and the file is not located on the default classpath.
* This can be set to null to use defaults and is ignored for all other protocols.
* @throws IllegalArgumentException If the config URL is invalid in that it cannot open an {@link InputStream}
*/
public static void setConfigFileUrl(String configFileUrl, ClassLoader loader) {
try { try {
// Get an array of class loaders to try loading the providers files from. configFileStream = FileUtils.getStreamForUrl(configFileUrl, loader);
ClassLoader[] classLoaders = getClassLoaders();
for (ClassLoader classLoader : classLoaders) {
Enumeration<URL> configEnum = classLoader.getResources("META-INF/smack-config.xml");
while (configEnum.hasMoreElements()) {
URL url = configEnum.nextElement();
InputStream systemStream = null;
try {
systemStream = url.openStream();
XmlPullParser parser = new MXParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(systemStream, "UTF-8");
int eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("className")) {
// Attempt to load the class so that the class can get initialized
parseClassToLoad(parser);
}
else if (parser.getName().equals("packetReplyTimeout")) {
packetReplyTimeout = parseIntProperty(parser, packetReplyTimeout);
}
else if (parser.getName().equals("keepAliveInterval")) {
keepAliveInterval = parseIntProperty(parser, keepAliveInterval);
}
else if (parser.getName().equals("mechName")) {
defaultMechs.add(parser.nextText());
}
else if (parser.getName().equals("localSocks5ProxyEnabled")) {
localSocks5ProxyEnabled = Boolean.parseBoolean(parser.nextText());
}
else if (parser.getName().equals("localSocks5ProxyPort")) {
localSocks5ProxyPort = parseIntProperty(parser, localSocks5ProxyPort);
}
else if (parser.getName().equals("packetCollectorSize")) {
packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
}
else if (parser.getName().equals("autoEnableEntityCaps")) {
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
}
else if (parser.getName().equals("autoEnableEntityCaps")) {
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
}
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
systemStream.close();
}
catch (Exception e) {
// Ignore.
}
}
}
}
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); throw new IllegalArgumentException("Failed to create input stream from specified file URL ["+ configFileUrl + "]", e);
} }
initialize();
}
/**
* Sets the {@link InputStream} representing the smack configuration file. This can be used to override the default with something that is not on the classpath.
* <p>
* This method must be called before accessing any other class in Smack.
* @param configFile
*/
public static void setConfigFileStream(InputStream configFile) {
configFileStream = configFile;
initialize();
} }
/** /**
@ -166,6 +138,8 @@ public final class SmackConfiguration {
* @return the milliseconds to wait for a response from the server * @return the milliseconds to wait for a response from the server
*/ */
public static int getPacketReplyTimeout() { public static int getPacketReplyTimeout() {
initialize();
// The timeout value must be greater than 0 otherwise we will answer the default value // The timeout value must be greater than 0 otherwise we will answer the default value
if (packetReplyTimeout <= 0) { if (packetReplyTimeout <= 0) {
packetReplyTimeout = 5000; packetReplyTimeout = 5000;
@ -180,6 +154,8 @@ public final class SmackConfiguration {
* @param timeout the milliseconds to wait for a response from the server * @param timeout the milliseconds to wait for a response from the server
*/ */
public static void setPacketReplyTimeout(int timeout) { public static void setPacketReplyTimeout(int timeout) {
initialize();
if (timeout <= 0) { if (timeout <= 0) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@ -195,6 +171,7 @@ public final class SmackConfiguration {
* no keep-alive should be sent. * no keep-alive should be sent.
*/ */
public static int getKeepAliveInterval() { public static int getKeepAliveInterval() {
initialize();
return keepAliveInterval; return keepAliveInterval;
} }
@ -207,6 +184,7 @@ public final class SmackConfiguration {
* or -1 if no keep-alive should be sent. * or -1 if no keep-alive should be sent.
*/ */
public static void setKeepAliveInterval(int interval) { public static void setKeepAliveInterval(int interval) {
initialize();
keepAliveInterval = interval; keepAliveInterval = interval;
} }
@ -217,6 +195,7 @@ public final class SmackConfiguration {
* @return The number of packets to queue before deleting older packets. * @return The number of packets to queue before deleting older packets.
*/ */
public static int getPacketCollectorSize() { public static int getPacketCollectorSize() {
initialize();
return packetCollectorSize; return packetCollectorSize;
} }
@ -227,6 +206,7 @@ public final class SmackConfiguration {
* @param The number of packets to queue before deleting older packets. * @param The number of packets to queue before deleting older packets.
*/ */
public static void setPacketCollectorSize(int collectorSize) { public static void setPacketCollectorSize(int collectorSize) {
initialize();
packetCollectorSize = collectorSize; packetCollectorSize = collectorSize;
} }
@ -236,6 +216,8 @@ public final class SmackConfiguration {
* @param mech the SASL mechanism to be added * @param mech the SASL mechanism to be added
*/ */
public static void addSaslMech(String mech) { public static void addSaslMech(String mech) {
initialize();
if(! defaultMechs.contains(mech) ) { if(! defaultMechs.contains(mech) ) {
defaultMechs.add(mech); defaultMechs.add(mech);
} }
@ -247,6 +229,8 @@ public final class SmackConfiguration {
* @param mechs the Collection of SASL mechanisms to be added * @param mechs the Collection of SASL mechanisms to be added
*/ */
public static void addSaslMechs(Collection<String> mechs) { public static void addSaslMechs(Collection<String> mechs) {
initialize();
for(String mech : mechs) { for(String mech : mechs) {
addSaslMech(mech); addSaslMech(mech);
} }
@ -258,9 +242,8 @@ public final class SmackConfiguration {
* @param mech the SASL mechanism to be removed * @param mech the SASL mechanism to be removed
*/ */
public static void removeSaslMech(String mech) { public static void removeSaslMech(String mech) {
if( defaultMechs.contains(mech) ) { initialize();
defaultMechs.remove(mech); defaultMechs.remove(mech);
}
} }
/** /**
@ -269,9 +252,8 @@ public final class SmackConfiguration {
* @param mechs the Collection of SASL mechanisms to be removed * @param mechs the Collection of SASL mechanisms to be removed
*/ */
public static void removeSaslMechs(Collection<String> mechs) { public static void removeSaslMechs(Collection<String> mechs) {
for(String mech : mechs) { initialize();
removeSaslMech(mech); defaultMechs.removeAll(mechs);
}
} }
/** /**
@ -282,7 +264,7 @@ public final class SmackConfiguration {
* @return the list of SASL mechanisms to be used. * @return the list of SASL mechanisms to be used.
*/ */
public static List<String> getSaslMechs() { public static List<String> getSaslMechs() {
return defaultMechs; return Collections.unmodifiableList(defaultMechs);
} }
/** /**
@ -291,6 +273,7 @@ public final class SmackConfiguration {
* @return if the local Socks5 proxy should be started * @return if the local Socks5 proxy should be started
*/ */
public static boolean isLocalSocks5ProxyEnabled() { public static boolean isLocalSocks5ProxyEnabled() {
initialize();
return localSocks5ProxyEnabled; return localSocks5ProxyEnabled;
} }
@ -300,6 +283,7 @@ public final class SmackConfiguration {
* @param localSocks5ProxyEnabled if the local Socks5 proxy should be started * @param localSocks5ProxyEnabled if the local Socks5 proxy should be started
*/ */
public static void setLocalSocks5ProxyEnabled(boolean localSocks5ProxyEnabled) { public static void setLocalSocks5ProxyEnabled(boolean localSocks5ProxyEnabled) {
initialize();
SmackConfiguration.localSocks5ProxyEnabled = localSocks5ProxyEnabled; SmackConfiguration.localSocks5ProxyEnabled = localSocks5ProxyEnabled;
} }
@ -309,6 +293,7 @@ public final class SmackConfiguration {
* @return the port of the local Socks5 proxy * @return the port of the local Socks5 proxy
*/ */
public static int getLocalSocks5ProxyPort() { public static int getLocalSocks5ProxyPort() {
initialize();
return localSocks5ProxyPort; return localSocks5ProxyPort;
} }
@ -319,26 +304,29 @@ public final class SmackConfiguration {
* @param localSocks5ProxyPort the port of the local Socks5 proxy to set * @param localSocks5ProxyPort the port of the local Socks5 proxy to set
*/ */
public static void setLocalSocks5ProxyPort(int localSocks5ProxyPort) { public static void setLocalSocks5ProxyPort(int localSocks5ProxyPort) {
initialize();
SmackConfiguration.localSocks5ProxyPort = localSocks5ProxyPort; SmackConfiguration.localSocks5ProxyPort = localSocks5ProxyPort;
} }
/**
* Check if Entity Caps are enabled as default for every new connection
* @return
*/
public static boolean autoEnableEntityCaps() {
initialize();
return autoEnableEntityCaps;
}
/** /**
* Set if Entity Caps are enabled or disabled for every new connection * Set if Entity Caps are enabled or disabled for every new connection
* *
* @param true if Entity Caps should be auto enabled, false if not * @param true if Entity Caps should be auto enabled, false if not
*/ */
public static void setAutoEnableEntityCaps(boolean b) { public static void setAutoEnableEntityCaps(boolean b) {
initialize();
autoEnableEntityCaps = b; autoEnableEntityCaps = b;
} }
/**
* Check if Entity Caps are enabled as default for every new connection
* @return
*/
public static boolean autoEnableEntityCaps() {
return autoEnableEntityCaps;
}
/** /**
* Set the default parsing exception callback for all newly created connections * Set the default parsing exception callback for all newly created connections
* *
@ -346,6 +334,7 @@ public final class SmackConfiguration {
* @see ParsingExceptionCallback * @see ParsingExceptionCallback
*/ */
public static void setDefaultParsingExceptionCallback(ParsingExceptionCallback callback) { public static void setDefaultParsingExceptionCallback(ParsingExceptionCallback callback) {
initialize();
defaultCallback = callback; defaultCallback = callback;
} }
@ -356,6 +345,7 @@ public final class SmackConfiguration {
* @see ParsingExceptionCallback * @see ParsingExceptionCallback
*/ */
public static ParsingExceptionCallback getDefaultParsingExceptionCallback() { public static ParsingExceptionCallback getDefaultParsingExceptionCallback() {
initialize();
return defaultCallback; return defaultCallback;
} }
@ -363,11 +353,15 @@ public final class SmackConfiguration {
String className = parser.nextText(); String className = parser.nextText();
// Attempt to load the class so that the class can get initialized // Attempt to load the class so that the class can get initialized
try { try {
Class.forName(className); Class<?> initClass = Class.forName(className);
if (SmackInitializer.class.isAssignableFrom(initClass)) {
SmackInitializer initializer = (SmackInitializer) initClass.newInstance();
initializer.initialize();
}
} }
catch (ClassNotFoundException cnfe) { catch (ClassNotFoundException cnfe) {
System.err.println("Error! A startup class specified in smack-config.xml could " + log.log(Level.WARNING, "A startup class [" + className + "] specified in smack-config.xml could not be loaded: ");
"not be loaded: " + className);
} }
} }
@ -378,27 +372,93 @@ public final class SmackConfiguration {
return Integer.parseInt(parser.nextText()); return Integer.parseInt(parser.nextText());
} }
catch (NumberFormatException nfe) { catch (NumberFormatException nfe) {
nfe.printStackTrace(); log.log(Level.SEVERE, "Could not parse integer", nfe);
return defaultValue; return defaultValue;
} }
} }
/** /*
* Returns an array of class loaders to load resources from. * Order of precedence for config file is VM arg, setConfigXXX methods and embedded default file location.
*
* @return an array of ClassLoader instances.
*/ */
private static ClassLoader[] getClassLoaders() { private static void initialize() {
ClassLoader[] classLoaders = new ClassLoader[2]; if (initialized) {
classLoaders[0] = SmackConfiguration.class.getClassLoader(); return;
classLoaders[1] = Thread.currentThread().getContextClassLoader(); }
// Clean up possible null values. Note that #getClassLoader may return a null value. initialized = true;
List<ClassLoader> loaders = new ArrayList<ClassLoader>();
for (ClassLoader classLoader : classLoaders) { String configFileLocation = System.getProperty("smack.config.file");
if (classLoader != null) {
loaders.add(classLoader); if (configFileLocation != null) {
try {
configFileStream = FileUtils.getStreamForUrl(configFileLocation, null);
}
catch (Exception e) {
log.log(Level.SEVERE, "Error creating input stream for config file [" + configFileLocation + "] from VM argument", e);
}
}
if (configFileStream == null) {
try {
configFileStream = FileUtils.getStreamForUrl(DEFAULT_CONFIG_FILE, null);
}
catch (Exception e) {
log.log(Level.INFO, "Could not create input stream for default config file [" + DEFAULT_CONFIG_FILE + "]", e);
}
}
if (configFileStream != null) {
readFile(configFileStream);
}
else {
log.log(Level.INFO, "No configuration file found");
}
}
private static void readFile(InputStream cfgFileStream) {
XmlPullParser parser = new MXParser();
try {
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(cfgFileStream, "UTF-8");
int eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("className")) {
// Attempt to load the class so that the class can get initialized
parseClassToLoad(parser);
}
else if (parser.getName().equals("packetReplyTimeout")) {
packetReplyTimeout = parseIntProperty(parser, packetReplyTimeout);
}
else if (parser.getName().equals("keepAliveInterval")) {
keepAliveInterval = parseIntProperty(parser, keepAliveInterval);
}
else if (parser.getName().equals("mechName")) {
defaultMechs.add(parser.nextText());
}
else if (parser.getName().equals("localSocks5ProxyEnabled")) {
localSocks5ProxyEnabled = Boolean.parseBoolean(parser.nextText());
}
else if (parser.getName().equals("localSocks5ProxyPort")) {
localSocks5ProxyPort = parseIntProperty(parser, localSocks5ProxyPort);
}
else if (parser.getName().equals("packetCollectorSize")) {
packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
}
else if (parser.getName().equals("autoEnableEntityCaps")) {
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
}
}
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
} catch (Exception e) {
log.log(Level.SEVERE, "Error occurred while reading config file", e);
}
finally {
try {
cfgFileStream.close();
} catch (IOException e) {
log.log(Level.INFO, "Error while closing config file input stream", e);
} }
} }
return loaders.toArray(new ClassLoader[loaders.size()]);
} }
} }

View file

@ -0,0 +1,14 @@
package org.jivesoftware.smack;
/**
* Defines an initialization class that will be instantiated and invoked by the {@link SmackConfiguration} class during initialization.
*
* <p>
* Any implementation of this class MUST have a default constructor.
*
* @author Robin Collier
*
*/
public interface SmackInitializer {
void initialize();
}

View file

@ -788,7 +788,6 @@ public class XMPPConnection extends Connection {
if(config.getCallbackHandler() == null) { if(config.getCallbackHandler() == null) {
ks = null; ks = null;
} else if (context == null) { } else if (context == null) {
//System.out.println("Keystore type: "+configuration.getKeystoreType());
if(config.getKeystoreType().equals("NONE")) { if(config.getKeystoreType().equals("NONE")) {
ks = null; ks = null;
pcb = null; pcb = null;
@ -1043,10 +1042,13 @@ public class XMPPConnection extends Connection {
*/ */
synchronized void notifyConnectionError(Exception e) { synchronized void notifyConnectionError(Exception e) {
// Listeners were already notified of the exception, return right here. // Listeners were already notified of the exception, return right here.
if (packetReader.done && packetWriter.done) return; if ((packetReader == null || packetReader.done) &&
(packetWriter == null || packetWriter.done)) return;
packetReader.done = true; if (packetReader != null)
packetWriter.done = true; packetReader.done = true;
if (packetWriter != null)
packetWriter.done = true;
// Closes the connection temporary. A reconnection is possible // Closes the connection temporary. A reconnection is possible
shutdown(new Presence(Presence.Type.unavailable)); shutdown(new Presence(Presence.Type.unavailable));
// Notify connection listeners of the error. // Notify connection listeners of the error.

View file

@ -80,7 +80,10 @@ public class Message extends Packet {
*/ */
public Message(String to, Type type) { public Message(String to, Type type) {
setTo(to); setTo(to);
this.type = type;
if (type != null) {
this.type = type;
}
} }
/** /**

View file

@ -27,6 +27,8 @@ import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.*; import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Base class for XMPP packets. Every packet has a unique ID (which is automatically * Base class for XMPP packets. Every packet has a unique ID (which is automatically
@ -41,6 +43,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* @author Matt Tucker * @author Matt Tucker
*/ */
public abstract class Packet { public abstract class Packet {
private static Logger log = Logger.getLogger(Packet.class.getName());
protected static final String DEFAULT_LANGUAGE = protected static final String DEFAULT_LANGUAGE =
java.util.Locale.getDefault().getLanguage().toLowerCase(); java.util.Locale.getDefault().getLanguage().toLowerCase();
@ -411,7 +414,7 @@ public abstract class Packet {
buf.append(encodedVal).append("</value>"); buf.append(encodedVal).append("</value>");
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error encoding java object", e);
} }
finally { finally {
if (out != null) { if (out != null) {
@ -452,6 +455,7 @@ public abstract class Packet {
return DEFAULT_LANGUAGE; return DEFAULT_LANGUAGE;
} }
@Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
@ -472,6 +476,7 @@ public abstract class Packet {
return !(xmlns != null ? !xmlns.equals(packet.xmlns) : packet.xmlns != null); return !(xmlns != null ? !xmlns.equals(packet.xmlns) : packet.xmlns != null);
} }
@Override
public int hashCode() { public int hashCode() {
int result; int result;
result = (xmlns != null ? xmlns.hashCode() : 0); result = (xmlns != null ? xmlns.hashCode() : 0);
@ -483,4 +488,9 @@ public abstract class Packet {
result = 31 * result + (error != null ? error.hashCode() : 0); result = 31 * result + (error != null ? error.hashCode() : 0);
return result; return result;
} }
@Override
public String toString() {
return toXML();
}
} }

View file

@ -20,18 +20,21 @@
package org.jivesoftware.smack.parsing; package org.jivesoftware.smack.parsing;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Simple parsing exception callback that only logs the encountered parsing exception to stderr. * Simple parsing exception callback that only logs the encountered parsing exception to java util logging.
* *
* @author Florian Schmaus * @author Florian Schmaus
* *
*/ */
public class ExceptionLoggingCallback extends ParsingExceptionCallback { public class ExceptionLoggingCallback extends ParsingExceptionCallback {
private static Logger log = Logger.getLogger(ExceptionLoggingCallback.class.getName());
@Override @Override
public void handleUnparsablePacket(UnparsablePacket unparsed) throws Exception { public void handleUnparsablePacket(UnparsablePacket unparsed) throws Exception {
System.err.print("Smack message parsing exception: " + unparsed.getParsingException().getMessage()); log.log(Level.SEVERE, "Smack message parsing exception: ", unparsed.getParsingException());
unparsed.getParsingException().printStackTrace(); log.severe("Unparsed content: " + unparsed.getContent());
System.err.println("Unparsed content: " + unparsed.getContent());
} }
} }

View file

@ -0,0 +1,26 @@
package org.jivesoftware.smack.provider;
abstract class AbstractProviderInfo {
private String element;
private String ns;
private Object provider;
AbstractProviderInfo(String elementName, String namespace, Object iqOrExtProvider) {
element = elementName;
ns = namespace;
provider = iqOrExtProvider;
}
public String getElementName() {
return element;
}
public String getNamespace() {
return ns;
}
Object getProvider() {
return provider;
}
}

View file

@ -0,0 +1,15 @@
package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.SmackInitializer;
/**
* Loads the default provider file for the Smack core on initialization.
*
* @author Robin Collier
*
*/
public class CoreInitializer extends UrlProviderFileInitializer implements SmackInitializer {
protected String getFilePath() {
return "classpath:META-INF/core.providers";
}
}

View file

@ -0,0 +1,33 @@
package org.jivesoftware.smack.provider;
/**
* Defines the information required to register a packet extension Provider with the {@link ProviderManager} when using the
* {@link ProviderLoader}.
*
* @author Robin Collier
*
*/
public final class ExtensionProviderInfo extends AbstractProviderInfo {
/**
* Defines an extension provider which implements the <code>PacketExtensionProvider</code> interface.
*
* @param elementName Element that provider parses.
* @param namespace Namespace that provider parses.
* @param extProvider The provider implementation.
*/
public ExtensionProviderInfo(String elementName, String namespace, PacketExtensionProvider extProvider) {
super(elementName, namespace, extProvider);
}
/**
* Defines an extension provider which is adheres to the JavaBean spec for parsing the extension.
*
* @param elementName Element that provider parses.
* @param namespace Namespace that provider parses.
* @param beanClass The provider bean class.
*/
public ExtensionProviderInfo(String elementName, String namespace, Class<?> beanClass) {
super(elementName, namespace, beanClass);
}
}

View file

@ -0,0 +1,35 @@
package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.packet.IQ;
/**
* Defines the information required to register an IQ Provider with the {@link ProviderManager} when using the
* {@link ProviderLoader}.
*
* @author Robin Collier
*
*/
public final class IQProviderInfo extends AbstractProviderInfo {
/**
* Defines an IQ provider which implements the <code>IQProvider</code> interface.
*
* @param elementName Element that provider parses.
* @param namespace Namespace that provider parses.
* @param iqProvider The provider implementation.
*/
public IQProviderInfo(String elementName, String namespace, IQProvider iqProvider) {
super(elementName, namespace, iqProvider);
}
/**
* Defines an IQ class which can be used as a provider via introspection.
*
* @param elementName Element that provider parses.
* @param namespace Namespace that provider parses.
* @param iqProviderClass The IQ class being parsed.
*/
public IQProviderInfo(String elementName, String namespace, Class<? extends IQ> iqProviderClass) {
super(elementName, namespace, iqProviderClass);
}
}

View file

@ -0,0 +1,146 @@
package org.jivesoftware.smack.provider;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.PacketExtension;
import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParser;
/**
* Loads the {@link IQProvider} and {@link PacketExtensionProvider} information from a standard provider file in preparation
* for loading into the {@link ProviderManager}.
*
* @author Robin Collier
*
*/
public class ProviderFileLoader implements ProviderLoader {
private final static Logger log = Logger.getLogger(ProviderFileLoader.class.getName());
private Collection<IQProviderInfo> iqProviders;
private Collection<ExtensionProviderInfo> extProviders;
private InputStream providerStream;
public ProviderFileLoader(InputStream providerFileInputStream) {
setInputStream(providerFileInputStream);
}
public ProviderFileLoader() {
}
@Override
public Collection<IQProviderInfo> getIQProviderInfo() {
initialize();
return iqProviders;
}
@Override
public Collection<ExtensionProviderInfo> getExtensionProviderInfo() {
initialize();
return extProviders;
}
@SuppressWarnings("unchecked")
private synchronized void initialize() {
// Check to see if already initialized
if (iqProviders != null) {
return;
}
if (providerStream == null) {
throw new IllegalArgumentException("No input stream set for loader");
}
iqProviders = new ArrayList<IQProviderInfo>();
extProviders = new ArrayList<ExtensionProviderInfo>();
// Load processing providers.
try {
XmlPullParser parser = new MXParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(providerStream, "UTF-8");
int eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
String typeName = parser.getName();
try {
if (!"smackProviders".equals(typeName)) {
parser.next();
parser.next();
String elementName = parser.nextText();
parser.next();
parser.next();
String namespace = parser.nextText();
parser.next();
parser.next();
String className = parser.nextText();
try {
// Attempt to load the provider class and then create
// a new instance if it's an IQProvider. Otherwise, if it's
// an IQ class, add the class object itself, then we'll use
// reflection later to create instances of the class.
if ("iqProvider".equals(typeName)) {
// Add the provider to the map.
Class<?> provider = Class.forName(className);
if (IQProvider.class.isAssignableFrom(provider)) {
iqProviders.add(new IQProviderInfo(elementName, namespace, (IQProvider) provider.newInstance()));
}
else if (IQ.class.isAssignableFrom(provider)) {
iqProviders.add(new IQProviderInfo(elementName, namespace, (Class<? extends IQ>)provider));
}
}
else {
// Attempt to load the provider class and then create
// a new instance if it's an ExtensionProvider. Otherwise, if it's
// a PacketExtension, add the class object itself and
// then we'll use reflection later to create instances
// of the class.
Class<?> provider = Class.forName(className);
if (PacketExtensionProvider.class.isAssignableFrom(provider)) {
extProviders.add(new ExtensionProviderInfo(elementName, namespace, (PacketExtensionProvider) provider.newInstance()));
}
else if (PacketExtension.class.isAssignableFrom(provider)) {
extProviders.add(new ExtensionProviderInfo(elementName, namespace, provider));
}
}
}
catch (ClassNotFoundException cnfe) {
log.log(Level.SEVERE, "Could not find provider class", cnfe);
}
}
}
catch (IllegalArgumentException illExc) {
log.log(Level.SEVERE, "Invalid provider type found [" + typeName + "] when expecting iqProvider or extensionProvider", illExc);
}
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
}
catch (Exception e){
log.log(Level.SEVERE, "Unknown error occurred while parsing provider file", e);
}
finally {
try {
providerStream.close();
}
catch (Exception e) {
// Ignore.
}
}
}
public void setInputStream(InputStream providerFileInput) {
if (providerFileInput == null) {
throw new IllegalArgumentException("InputStream cannot be null");
}
providerStream = providerFileInput;
initialize();
}
}

View file

@ -0,0 +1,23 @@
package org.jivesoftware.smack.provider;
import java.util.Collection;
/**
* Used to load providers into the {@link ProviderManager}.
*
* @author Robin Collier
*/
public interface ProviderLoader {
/**
* Provides the IQ provider info for the creation of IQ providers to be added to the <code>ProviderManager</code>.
* @return The IQ provider info to load.
*/
Collection<IQProviderInfo> getIQProviderInfo();
/**
* Provides the extension providers for the creation of extension providers to be added to the <code>ProviderManager</code>.
* @return The extension provider info to load.
*/
Collection<ExtensionProviderInfo> getExtensionProviderInfo();
}

View file

@ -20,16 +20,13 @@
package org.jivesoftware.smack.provider; package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.packet.IQ; import java.util.Collection;
import org.jivesoftware.smack.packet.PacketExtension; import java.util.Collections;
import org.xmlpull.mxp1.MXParser; import java.util.Map;
import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.smack.packet.IQ;
/** /**
* Manages providers for parsing custom XML sub-documents of XMPP packets. Two types of * Manages providers for parsing custom XML sub-documents of XMPP packets. Two types of
* providers exist:<ul> * providers exist:<ul>
@ -102,20 +99,14 @@ import java.util.concurrent.ConcurrentHashMap;
* can either implement the PacketExtensionProvider interface or be a standard Java Bean. In * can either implement the PacketExtensionProvider interface or be a standard Java Bean. In
* the former case, each extension provider is responsible for parsing the raw XML stream to * the former case, each extension provider is responsible for parsing the raw XML stream to
* contruct an object. In the latter case, bean introspection is used to try to automatically * contruct an object. In the latter case, bean introspection is used to try to automatically
* set the properties of the class using the values in the packet extension sub-element. When an * set the properties of th class using the values in the packet extension sub-element. When an
* extension provider is not registered for an element name and namespace combination, Smack will * extension provider is not registered for an element name and namespace combination, Smack will
* store all top-level elements of the sub-packet in DefaultPacketExtension object and then * store all top-level elements of the sub-packet in DefaultPacketExtension object and then
* attach it to the packet.<p> * attach it to the packet.<p>
* *
* It is possible to provide a custom provider manager instead of the default implementation
* provided by Smack. If you want to provide your own provider manager then you need to do it
* before creating any {@link org.jivesoftware.smack.Connection} by sending the static
* {@link #setInstance(ProviderManager)} message. Trying to change the provider manager after
* an Connection was created will result in an {@link IllegalStateException} error.
*
* @author Matt Tucker * @author Matt Tucker
*/ */
public class ProviderManager { public final class ProviderManager {
private static ProviderManager instance; private static ProviderManager instance;
@ -123,9 +114,7 @@ public class ProviderManager {
private Map<String, Object> iqProviders = new ConcurrentHashMap<String, Object>(); private Map<String, Object> iqProviders = new ConcurrentHashMap<String, Object>();
/** /**
* Returns the only ProviderManager valid instance. Use {@link #setInstance(ProviderManager)} * Returns the ProviderManager instance.
* to configure your own provider manager. If non was provided then an instance of this
* class will be used.
* *
* @return the only ProviderManager valid instance. * @return the only ProviderManager valid instance.
*/ */
@ -136,127 +125,25 @@ public class ProviderManager {
return instance; return instance;
} }
/** private ProviderManager() {
* Sets the only ProviderManager valid instance to be used by all Connections. If you super();
* want to provide your own provider manager then you need to do it before creating
* any Connection. Otherwise an IllegalStateException will be thrown.
*
* @param providerManager the only ProviderManager valid instance to be used.
* @throws IllegalStateException if a provider manager was already configued.
*/
public static synchronized void setInstance(ProviderManager providerManager) {
if (instance != null) {
throw new IllegalStateException("ProviderManager singleton already set");
}
instance = providerManager;
} }
protected void initialize() { public void addLoader(ProviderLoader loader) {
// Load IQ processing providers. if (loader == null) {
try { throw new IllegalArgumentException("loader cannot be null");
// Get an array of class loaders to try loading the providers files from. }
ClassLoader[] classLoaders = getClassLoaders();
for (ClassLoader classLoader : classLoaders) { if (loader.getIQProviderInfo() != null) {
Enumeration<URL> providerEnum = classLoader.getResources( for (IQProviderInfo info : loader.getIQProviderInfo()) {
"META-INF/smack.providers"); iqProviders.put(getProviderKey(info.getElementName(), info.getNamespace()), info.getProvider());
while (providerEnum.hasMoreElements()) {
URL url = providerEnum.nextElement();
InputStream providerStream = null;
try {
providerStream = url.openStream();
XmlPullParser parser = new MXParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(providerStream, "UTF-8");
int eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("iqProvider")) {
parser.next();
parser.next();
String elementName = parser.nextText();
parser.next();
parser.next();
String namespace = parser.nextText();
parser.next();
parser.next();
String className = parser.nextText();
// Only add the provider for the namespace if one isn't
// already registered.
String key = getProviderKey(elementName, namespace);
if (!iqProviders.containsKey(key)) {
// Attempt to load the provider class and then create
// a new instance if it's an IQProvider. Otherwise, if it's
// an IQ class, add the class object itself, then we'll use
// reflection later to create instances of the class.
try {
// Add the provider to the map.
Class<?> provider = Class.forName(className);
if (IQProvider.class.isAssignableFrom(provider)) {
iqProviders.put(key, provider.newInstance());
}
else if (IQ.class.isAssignableFrom(provider)) {
iqProviders.put(key, provider);
}
}
catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
}
else if (parser.getName().equals("extensionProvider")) {
parser.next();
parser.next();
String elementName = parser.nextText();
parser.next();
parser.next();
String namespace = parser.nextText();
parser.next();
parser.next();
String className = parser.nextText();
// Only add the provider for the namespace if one isn't
// already registered.
String key = getProviderKey(elementName, namespace);
if (!extensionProviders.containsKey(key)) {
// Attempt to load the provider class and then create
// a new instance if it's a Provider. Otherwise, if it's
// a PacketExtension, add the class object itself and
// then we'll use reflection later to create instances
// of the class.
try {
// Add the provider to the map.
Class<?> provider = Class.forName(className);
if (PacketExtensionProvider.class.isAssignableFrom(
provider)) {
extensionProviders.put(key, provider.newInstance());
}
else if (PacketExtension.class.isAssignableFrom(
provider)) {
extensionProviders.put(key, provider);
}
}
catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
}
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
}
finally {
try {
providerStream.close();
}
catch (Exception e) {
// Ignore.
}
}
}
} }
} }
catch (Exception e) {
e.printStackTrace(); if (loader.getExtensionProviderInfo() != null) {
for (ExtensionProviderInfo info : loader.getExtensionProviderInfo()) {
extensionProviders.put(getProviderKey(info.getElementName(), info.getNamespace()), info.getProvider());
}
} }
} }
@ -411,28 +298,4 @@ public class ProviderManager {
buf.append("<").append(elementName).append("/><").append(namespace).append("/>"); buf.append("<").append(elementName).append("/><").append(namespace).append("/>");
return buf.toString(); return buf.toString();
} }
/**
* Returns an array of class loaders to load resources from.
*
* @return an array of ClassLoader instances.
*/
private ClassLoader[] getClassLoaders() {
ClassLoader[] classLoaders = new ClassLoader[2];
classLoaders[0] = ProviderManager.class.getClassLoader();
classLoaders[1] = Thread.currentThread().getContextClassLoader();
// Clean up possible null values. Note that #getClassLoader may return a null value.
List<ClassLoader> loaders = new ArrayList<ClassLoader>();
for (ClassLoader classLoader : classLoaders) {
if (classLoader != null) {
loaders.add(classLoader);
}
}
return loaders.toArray(new ClassLoader[loaders.size()]);
}
private ProviderManager() {
super();
initialize();
}
} }

View file

@ -0,0 +1,54 @@
package org.jivesoftware.smack.provider;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackInitializer;
import org.jivesoftware.smack.util.FileUtils;
/**
* Loads the provider file defined by the URL returned by {@link #getFilePath()}. This file will be loaded on Smack initialization.
*
* @author Robin Collier
*
*/
public abstract class UrlProviderFileInitializer implements SmackInitializer {
private static final Logger log = Logger.getLogger(UrlProviderFileInitializer.class.getName());
@Override
public void initialize() {
String filePath = getFilePath();
try {
InputStream is = FileUtils.getStreamForUrl(filePath, getClassLoader());
if (is != null) {
log.log(Level.INFO, "Loading providers for file [" + filePath + "]");
ProviderManager.getInstance().addLoader(new ProviderFileLoader(is));
}
else {
log.log(Level.WARNING, "No input stream created for " + filePath);
}
}
catch (Exception e) {
log.log(Level.SEVERE, "Error trying to load provider file " + filePath, e);
}
}
protected abstract String getFilePath();
/**
* Returns an array of class loaders to load resources from.
*
* @return an array of ClassLoader instances.
*/
protected ClassLoader getClassLoader() {
return null;
}
}

View file

@ -0,0 +1,23 @@
package org.jivesoftware.smack.provider;
/**
* Looks for a provider file location based on the VM argument <i>smack.provider.file</>. If it is supplied, its value will
* be used as a file location for a providers file and loaded into the {@link ProviderManager} on Smack initialization.
*
* @author Robin Collier
*
*/
public class VmArgInitializer extends UrlProviderFileInitializer {
protected String getFilePath() {
return System.getProperty("smack.provider.file");
}
@Override
public void initialize() {
if (getFilePath() != null) {
super.initialize();
}
}
}

View file

@ -6,6 +6,9 @@
*/ */
package org.jivesoftware.smack.util; package org.jivesoftware.smack.util;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* <p>Encodes and decodes to and from Base64 notation.</p> * <p>Encodes and decodes to and from Base64 notation.</p>
* This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p> * This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p>
@ -17,9 +20,9 @@ package org.jivesoftware.smack.util;
*/ */
public class Base64 public class Base64
{ {
private static Logger log = Logger.getLogger(Base64.class.getName());
/* ******** P U B L I C F I E L D S ******** */ /* ******** P U B L I C F I E L D S ******** */
/** No options specified. Value is zero. */ /** No options specified. Value is zero. */
public final static int NO_OPTIONS = 0; public final static int NO_OPTIONS = 0;
@ -311,18 +314,6 @@ public class Base64
/** Defeats instantiation. */ /** Defeats instantiation. */
private Base64(){} private Base64(){}
/**
* Prints command line usage.
*
* @param msg A message to include with usage info.
*/
private final static void usage( String msg )
{
System.err.println( msg );
System.err.println( "Usage: java Base64 -e|-d inputfile outputfile" );
} // end usage
/* ******** E N C O D I N G M E T H O D S ******** */ /* ******** E N C O D I N G M E T H O D S ******** */
@ -494,7 +485,7 @@ public class Base64
} // end try } // end try
catch( java.io.IOException e ) catch( java.io.IOException e )
{ {
e.printStackTrace(); log.log(Level.SEVERE, "Error encoding object", e);
return null; return null;
} // end catch } // end catch
finally finally
@ -623,7 +614,7 @@ public class Base64
} // end try } // end try
catch( java.io.IOException e ) catch( java.io.IOException e )
{ {
e.printStackTrace(); log.log(Level.SEVERE, "Error encoding bytes", e);
return null; return null;
} // end catch } // end catch
finally finally
@ -778,10 +769,11 @@ public class Base64
return 3; return 3;
}catch( Exception e){ }catch( Exception e){
System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) ); log.log(Level.SEVERE, e.getMessage(), e);
System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) ); log.severe(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) );
System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) ); log.severe(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) );
System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) ); log.severe(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) );
log.severe(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) );
return -1; return -1;
} // end catch } // end catch
} }
@ -839,7 +831,7 @@ public class Base64
} // end if: white space, equals sign or better } // end if: white space, equals sign or better
else else
{ {
System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); log.warning("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)");
return null; return null;
} // end else: } // end else:
} // each input character } // each input character
@ -967,12 +959,12 @@ public class Base64
} // end try } // end try
catch( java.io.IOException e ) catch( java.io.IOException e )
{ {
e.printStackTrace(); log.log(Level.SEVERE, "Error reading object", e);
obj = null; obj = null;
} // end catch } // end catch
catch( java.lang.ClassNotFoundException e ) catch( java.lang.ClassNotFoundException e )
{ {
e.printStackTrace(); log.log(Level.SEVERE, "Class not found for encoded object", e);
obj = null; obj = null;
} // end catch } // end catch
finally finally
@ -1079,7 +1071,7 @@ public class Base64
// Check for size of file // Check for size of file
if( file.length() > Integer.MAX_VALUE ) if( file.length() > Integer.MAX_VALUE )
{ {
System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." ); log.warning("File is too big for this convenience method (" + file.length() + " bytes).");
return null; return null;
} // end if: file too big for int index } // end if: file too big for int index
buffer = new byte[ (int)file.length() ]; buffer = new byte[ (int)file.length() ];
@ -1100,7 +1092,7 @@ public class Base64
} // end try } // end try
catch( java.io.IOException e ) catch( java.io.IOException e )
{ {
System.err.println( "Error decoding from file " + filename ); log.log(Level.SEVERE, "Error decoding from file " + filename, e);
} // end catch: IOException } // end catch: IOException
finally finally
{ {
@ -1148,7 +1140,7 @@ public class Base64
} // end try } // end try
catch( java.io.IOException e ) catch( java.io.IOException e )
{ {
System.err.println( "Error encoding from file " + filename ); log.log(Level.SEVERE, "Error encoding from file " + filename, e);
} // end catch: IOException } // end catch: IOException
finally finally
{ {
@ -1175,7 +1167,7 @@ public class Base64
out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output. out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.
} // end try } // end try
catch( java.io.IOException ex ) { catch( java.io.IOException ex ) {
ex.printStackTrace(); log.log(Level.SEVERE, "Error encoding file " + infile, ex);
} // end catch } // end catch
finally { finally {
try { out.close(); } try { out.close(); }
@ -1201,7 +1193,7 @@ public class Base64
out.write( decoded ); out.write( decoded );
} // end try } // end try
catch( java.io.IOException ex ) { catch( java.io.IOException ex ) {
ex.printStackTrace(); log.log(Level.SEVERE, "Error decoding file " + infile, ex);
} // end catch } // end catch
finally { finally {
try { out.close(); } try { out.close(); }

View file

@ -22,6 +22,7 @@ package org.jivesoftware.smack.util;
import org.jivesoftware.smack.util.collections.AbstractMapEntry; import org.jivesoftware.smack.util.collections.AbstractMapEntry;
import java.util.*; import java.util.*;
import java.util.logging.Logger;
/** /**
* A specialized Map that is size-limited (using an LRU algorithm) and * A specialized Map that is size-limited (using an LRU algorithm) and
@ -49,7 +50,7 @@ import java.util.*;
* @author Matt Tucker * @author Matt Tucker
*/ */
public class Cache<K, V> implements Map<K, V> { public class Cache<K, V> implements Map<K, V> {
private static Logger log = Logger.getLogger(Cache.class.getName());
/** /**
* The map the keys and values are stored in. * The map the keys and values are stored in.
*/ */
@ -382,8 +383,7 @@ public class Cache<K, V> implements Map<K, V> {
while (expireTime > node.timestamp) { while (expireTime > node.timestamp) {
if (remove(node.object, true) == null) { if (remove(node.object, true) == null) {
System.err.println("Error attempting to remove(" + node.object.toString() + log.warning("Error attempting to remove(" + node.object.toString() + ") - cacheObject not found in cache!");
") - cacheObject not found in cache!");
// remove from the ageList // remove from the ageList
node.remove(); node.remove();
} }
@ -417,9 +417,7 @@ public class Cache<K, V> implements Map<K, V> {
for (int i=map.size(); i>desiredSize; i--) { for (int i=map.size(); i>desiredSize; i--) {
// Get the key and invoke the remove method on it. // Get the key and invoke the remove method on it.
if (remove(lastAccessedList.getLast().object, true) == null) { if (remove(lastAccessedList.getLast().object, true) == null) {
System.err.println("Error attempting to cullCache with remove(" + log.warning("Error attempting to cullCache with remove(" + lastAccessedList.getLast().object.toString() + ") - cacheObject not found in cache!");
lastAccessedList.getLast().object.toString() + ") - " +
"cacheObject not found in cache!");
lastAccessedList.getLast().remove(); lastAccessedList.getLast().remove();
} }
} }

View file

@ -0,0 +1,59 @@
package org.jivesoftware.smack.util;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
public final class FileUtils {
private FileUtils() {
}
public static InputStream getStreamForUrl(String url, ClassLoader loader) throws MalformedURLException, IOException {
URI fileUri = URI.create(url);
if (fileUri.getScheme() == null) {
throw new MalformedURLException("No protocol found in file URL: " + url);
}
if (fileUri.getScheme().equals("classpath")) {
// Get an array of class loaders to try loading the providers files from.
ClassLoader[] classLoaders = getClassLoaders();
for (ClassLoader classLoader : classLoaders) {
InputStream is = classLoader.getResourceAsStream(fileUri.getSchemeSpecificPart());
if (is != null) {
return is;
}
}
}
else {
return fileUri.toURL().openStream();
}
return null;
}
/**
* Returns default classloaders.
*
* @return an array of ClassLoader instances.
*/
public static ClassLoader[] getClassLoaders() {
ClassLoader[] classLoaders = new ClassLoader[2];
classLoaders[0] = FileUtils.class.getClassLoader();
classLoaders[1] = Thread.currentThread().getContextClassLoader();
// Clean up possible null values. Note that #getClassLoader may return a null value.
List<ClassLoader> loaders = new ArrayList<ClassLoader>();
for (ClassLoader classLoader : classLoaders) {
if (classLoader != null) {
loaders.add(classLoader);
}
}
return loaders.toArray(new ClassLoader[loaders.size()]);
}
}

View file

@ -29,6 +29,8 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.packet.Authentication; import org.jivesoftware.smack.packet.Authentication;
@ -57,6 +59,7 @@ import org.xmlpull.v1.XmlPullParserException;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class PacketParserUtils { public class PacketParserUtils {
private static Logger logger = Logger.getLogger(PacketParserUtils.class.getName());
/** /**
* Namespace used to store packet properties. * Namespace used to store packet properties.
@ -198,7 +201,7 @@ public class PacketParserUtils {
type = Presence.Type.valueOf(typeString); type = Presence.Type.valueOf(typeString);
} }
catch (IllegalArgumentException iae) { catch (IllegalArgumentException iae) {
System.err.println("Found invalid presence type " + typeString); logger.warning("Found invalid presence type " + typeString);
} }
} }
Presence presence = new Presence(type); Presence presence = new Presence(type);
@ -242,7 +245,7 @@ public class PacketParserUtils {
presence.setMode(Presence.Mode.valueOf(modeText)); presence.setMode(Presence.Mode.valueOf(modeText));
} }
catch (IllegalArgumentException iae) { catch (IllegalArgumentException iae) {
System.err.println("Found invalid presence mode " + modeText); logger.warning("Found invalid presence mode " + modeText);
} }
} }
else if (elementName.equals("error")) { else if (elementName.equals("error")) {
@ -263,7 +266,7 @@ public class PacketParserUtils {
presence.addExtension(PacketParserUtils.parsePacketExtension(elementName, namespace, parser)); presence.addExtension(PacketParserUtils.parsePacketExtension(elementName, namespace, parser));
} }
catch (Exception e) { catch (Exception e) {
System.err.println("Failed to parse extension packet in Presence packet."); logger.warning("Failed to parse extension packet in Presence packet.");
} }
} }
} }
@ -639,7 +642,7 @@ public class PacketParserUtils {
value = in.readObject(); value = in.readObject();
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); logger.log(Level.SEVERE, "Error parsing java object", e);
} }
} }
if (name != null && value != null) { if (name != null && value != null) {
@ -782,8 +785,7 @@ public class PacketParserUtils {
} }
} }
catch (IllegalArgumentException iae) { catch (IllegalArgumentException iae) {
// Print stack trace. We shouldn't be getting an illegal error type. logger.log(Level.SEVERE, "Could not find error type for " + type.toUpperCase(), iae);
iae.printStackTrace();
} }
return new XMPPError(Integer.parseInt(errorCode), errorType, condition, message, extensions); return new XMPPError(Integer.parseInt(errorCode), errorType, condition, message, extensions);
} }

View file

@ -34,6 +34,8 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -41,6 +43,7 @@ import java.util.regex.Pattern;
* A collection of utility methods for String objects. * A collection of utility methods for String objects.
*/ */
public class StringUtils { public class StringUtils {
private static Logger log = Logger.getLogger(StringUtils.class.getName());
/** /**
* Date format as defined in XEP-0082 - XMPP Date and Time Profiles. The time zone is set to * Date format as defined in XEP-0082 - XMPP Date and Time Profiles. The time zone is set to
@ -619,8 +622,7 @@ public class StringUtils {
digest = MessageDigest.getInstance("SHA-1"); digest = MessageDigest.getInstance("SHA-1");
} }
catch (NoSuchAlgorithmException nsae) { catch (NoSuchAlgorithmException nsae) {
System.err.println("Failed to load the SHA-1 MessageDigest. " + log.log(Level.SEVERE, "Failed to load the SHA-1 MessageDigest. Smack will be unable to function normally.", nsae);
"Jive will be unable to function normally.");
} }
} }
// Now, compute hash. // Now, compute hash.
@ -628,7 +630,7 @@ public class StringUtils {
digest.update(data.getBytes("UTF-8")); digest.update(data.getBytes("UTF-8"));
} }
catch (UnsupportedEncodingException e) { catch (UnsupportedEncodingException e) {
System.err.println(e); log.log(Level.SEVERE, "Error computing hash", e);
} }
return encodeHex(digest.digest()); return encodeHex(digest.digest());
} }
@ -664,7 +666,7 @@ public class StringUtils {
bytes = data.getBytes("ISO-8859-1"); bytes = data.getBytes("ISO-8859-1");
} }
catch (UnsupportedEncodingException uee) { catch (UnsupportedEncodingException uee) {
uee.printStackTrace(); throw new IllegalStateException(uee);
} }
return encodeBase64(bytes); return encodeBase64(bytes);
} }

View file

@ -25,6 +25,8 @@ import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.Connection;
@ -42,6 +44,7 @@ import org.jivesoftware.smackx.packet.MessageEvent;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class MessageEventManager { public class MessageEventManager {
private static Logger log = Logger.getLogger(MessageEventManager.class.getName());
private List<MessageEventNotificationListener> messageEventNotificationListeners = new ArrayList<MessageEventNotificationListener>(); private List<MessageEventNotificationListener> messageEventNotificationListeners = new ArrayList<MessageEventNotificationListener>();
private List<MessageEventRequestListener> messageEventRequestListeners = new ArrayList<MessageEventRequestListener>(); private List<MessageEventRequestListener> messageEventRequestListeners = new ArrayList<MessageEventRequestListener>();
@ -157,12 +160,8 @@ public class MessageEventManager {
for (int i = 0; i < listeners.length; i++) { for (int i = 0; i < listeners.length; i++) {
method.invoke(listeners[i], new Object[] { from, packetID, this }); method.invoke(listeners[i], new Object[] { from, packetID, this });
} }
} catch (NoSuchMethodException e) { } catch (Exception e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error while invoking MessageEventRequestListener", e);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} }
} }
@ -188,12 +187,8 @@ public class MessageEventManager {
for (int i = 0; i < listeners.length; i++) { for (int i = 0; i < listeners.length; i++) {
method.invoke(listeners[i], new Object[] { from, packetID }); method.invoke(listeners[i], new Object[] { from, packetID });
} }
} catch (NoSuchMethodException e) { } catch (Exception e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error while invoking MessageEventNotificationListener", e);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} }
} }

View file

@ -33,6 +33,8 @@ import org.jivesoftware.smackx.packet.MultipleAddresses;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* A MultipleRecipientManager allows to send packets to multiple recipients by making use of * A MultipleRecipientManager allows to send packets to multiple recipients by making use of
@ -42,6 +44,7 @@ import java.util.List;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class MultipleRecipientManager { public class MultipleRecipientManager {
private static Logger log = Logger.getLogger(MultipleRecipientManager.class.getName());
/** /**
* Create a cache to hold the 100 most recently accessed elements for a period of * Create a cache to hold the 100 most recently accessed elements for a period of
@ -309,13 +312,12 @@ public class MultipleRecipientManager {
break; break;
} }
} }
} }
// Cache the discovered information // Cache the discovered information
services.put(serviceName, serviceAddress == null ? "" : serviceAddress); services.put(serviceName, serviceAddress == null ? "" : serviceAddress);
} }
catch (XMPPException e) { catch (XMPPException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error occurred retrieving multiple recipients service", e);
} }
} }
} }

View file

@ -29,6 +29,7 @@ import org.jivesoftware.smackx.packet.PEPEvent;
* *
* @author Jeff Williams * @author Jeff Williams
*/ */
@Deprecated
public interface PEPListener { public interface PEPListener {
/** /**

View file

@ -60,6 +60,7 @@ import org.jivesoftware.smackx.packet.PEPPubSub;
* *
* @author Jeff Williams * @author Jeff Williams
*/ */
@Deprecated
public class PEPManager { public class PEPManager {
private List<PEPListener> pepListeners = new ArrayList<PEPListener>(); private List<PEPListener> pepListeners = new ArrayList<PEPListener>();

View file

@ -28,6 +28,8 @@ import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.packet.XHTMLExtension; import org.jivesoftware.smackx.packet.XHTMLExtension;
import java.util.Iterator; import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Manages XHTML formatted texts within messages. A XHTMLManager provides a high level access to * Manages XHTML formatted texts within messages. A XHTMLManager provides a high level access to
@ -38,6 +40,8 @@ import java.util.Iterator;
*/ */
public class XHTMLManager { public class XHTMLManager {
private static Logger log = Logger.getLogger(XHTMLManager.class.getName());
private final static String namespace = "http://jabber.org/protocol/xhtml-im"; private final static String namespace = "http://jabber.org/protocol/xhtml-im";
// Enable the XHTML support on every established connection // Enable the XHTML support on every established connection
@ -137,7 +141,7 @@ public class XHTMLManager {
return result.containsFeature(namespace); return result.containsFeature(namespace);
} }
catch (XMPPException e) { catch (XMPPException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error checking if service is available", e);
return false; return false;
} }
} }

View file

@ -594,7 +594,7 @@ public class InBandBytestreamSession implements BytestreamSession {
* Constructor. * Constructor.
*/ */
public IBBOutputStream() { public IBBOutputStream() {
this.buffer = new byte[(byteStreamRequest.getBlockSize()/4)*3]; this.buffer = new byte[byteStreamRequest.getBlockSize()];
} }
/** /**

View file

@ -29,6 +29,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
@ -67,6 +69,7 @@ import org.jivesoftware.smack.XMPPException;
* @author Henning Staib * @author Henning Staib
*/ */
public class Socks5Proxy { public class Socks5Proxy {
private static Logger log = Logger.getLogger(Socks5Proxy.class.getName());
/* SOCKS5 proxy singleton */ /* SOCKS5 proxy singleton */
private static Socks5Proxy socks5Server; private static Socks5Proxy socks5Server;
@ -150,8 +153,7 @@ public class Socks5Proxy {
} }
catch (IOException e) { catch (IOException e) {
// couldn't setup server // couldn't setup server
System.err.println("couldn't setup local SOCKS5 proxy on port " log.log(Level.SEVERE, "couldn't setup local SOCKS5 proxy on port " + SmackConfiguration.getLocalSocks5ProxyPort(), e);
+ SmackConfiguration.getLocalSocks5ProxyPort() + ": " + e.getMessage());
} }
} }

View file

@ -46,6 +46,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
/** /**
* An AdHocCommandManager is responsible for keeping the list of available * An AdHocCommandManager is responsible for keeping the list of available
@ -58,7 +59,6 @@ import java.util.concurrent.ConcurrentHashMap;
* @author Gabriel Guardincerri * @author Gabriel Guardincerri
*/ */
public class AdHocCommandManager { public class AdHocCommandManager {
private static final String DISCO_NAMESPACE = "http://jabber.org/protocol/commands"; private static final String DISCO_NAMESPACE = "http://jabber.org/protocol/commands";
private static final String discoNode = DISCO_NAMESPACE; private static final String discoNode = DISCO_NAMESPACE;
@ -470,7 +470,6 @@ public class AdHocCommandManager {
executingCommands.remove(sessionId); executingCommands.remove(sessionId);
} }
respondError(response, error); respondError(response, error);
e.printStackTrace();
} }
} }
else { else {
@ -527,7 +526,7 @@ public class AdHocCommandManager {
} }
try { try {
// TODO: Check that all the requierd fields of the form are // TODO: Check that all the required fields of the form are
// TODO: filled, if not throw an exception. This will simplify the // TODO: filled, if not throw an exception. This will simplify the
// TODO: construction of new commands // TODO: construction of new commands
@ -585,8 +584,6 @@ public class AdHocCommandManager {
executingCommands.remove(sessionId); executingCommands.remove(sessionId);
} }
respondError(response, error); respondError(response, error);
e.printStackTrace();
} }
} }
} }
@ -650,12 +647,10 @@ public class AdHocCommandManager {
command.setNode(commandInfo.getNode()); command.setNode(commandInfo.getNode());
} }
catch (InstantiationException e) { catch (InstantiationException e) {
e.printStackTrace();
throw new XMPPException(new XMPPError( throw new XMPPException(new XMPPError(
XMPPError.Condition.interna_server_error)); XMPPError.Condition.interna_server_error));
} }
catch (IllegalAccessException e) { catch (IllegalAccessException e) {
e.printStackTrace();
throw new XMPPException(new XMPPError( throw new XMPPException(new XMPPError(
XMPPError.Condition.interna_server_error)); XMPPError.Condition.interna_server_error));
} }

View file

@ -52,6 +52,8 @@ import java.io.Writer;
import java.net.URL; import java.net.URL;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* The EnhancedDebugger is a debugger that allows to debug sent, received and interpreted messages * The EnhancedDebugger is a debugger that allows to debug sent, received and interpreted messages
@ -64,6 +66,8 @@ import java.util.Date;
*/ */
public class EnhancedDebugger implements SmackDebugger { public class EnhancedDebugger implements SmackDebugger {
private static Logger log = Logger.getLogger(EnhancedDebugger.class.getName());
private static final String NEWLINE = "\n"; private static final String NEWLINE = "\n";
private static ImageIcon packetReceivedIcon; private static ImageIcon packetReceivedIcon;
@ -427,7 +431,7 @@ public class EnhancedDebugger implements SmackDebugger {
receivedText.replaceRange("", 0, receivedText.getLineEndOffset(0)); receivedText.replaceRange("", 0, receivedText.getLineEndOffset(0));
} }
catch (BadLocationException e) { catch (BadLocationException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error with line offset, MAX_TABLE_ROWS is set too low: " + EnhancedDebuggerWindow.MAX_TABLE_ROWS, e);
} }
} }
receivedText.append(str.substring(0, index + 1)); receivedText.append(str.substring(0, index + 1));
@ -462,7 +466,7 @@ public class EnhancedDebugger implements SmackDebugger {
sentText.replaceRange("", 0, sentText.getLineEndOffset(0)); sentText.replaceRange("", 0, sentText.getLineEndOffset(0));
} }
catch (BadLocationException e) { catch (BadLocationException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error with line offset, MAX_TABLE_ROWS is set too low: " + EnhancedDebuggerWindow.MAX_TABLE_ROWS, e);
} }
} }
@ -895,28 +899,10 @@ public class EnhancedDebugger implements SmackDebugger {
} }
catch (TransformerConfigurationException tce) { catch (TransformerConfigurationException tce) {
// Error generated by the parser log.log(Level.SEVERE, "Transformer Factory error", tce);
System.out.println("\n** Transformer Factory error");
System.out.println(" " + tce.getMessage());
// Use the contained exception, if any
Throwable x = tce;
if (tce.getException() != null)
x = tce.getException();
x.printStackTrace();
} }
catch (TransformerException te) { catch (TransformerException te) {
// Error generated by the parser log.log(Level.SEVERE, "Transformation error", te);
System.out.println("\n** Transformation error");
System.out.println(" " + te.getMessage());
// Use the contained exception, if any
Throwable x = te;
if (te.getException() != null)
x = te.getException();
x.printStackTrace();
} }
return str; return str;
} }

View file

@ -24,6 +24,8 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.IQProvider;
@ -39,12 +41,13 @@ import org.xmlpull.v1.XmlPullParserException;
/** /**
* Simple implementation of an EntityCapsPersistentCache that uses a directory * Simple implementation of an EntityCapsPersistentCache that uses a directory
* to store the Caps information for every known node. Every node is represented * to store the Caps information for every known node. Every node is represented
* by an file. * by a file.
* *
* @author Florian Schmaus * @author Florian Schmaus
* *
*/ */
public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache { public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache {
private static Logger log = Logger.getLogger(SimpleDirectoryPersistentCache.class.getName());
private File cacheDir; private File cacheDir;
private StringEncoder filenameEncoder; private StringEncoder filenameEncoder;
@ -54,7 +57,7 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
* cacheDir exists and that it's an directory. * cacheDir exists and that it's an directory.
* <p> * <p>
* Default filename encoder {@link Base32Encoder}, as this will work on all * Default filename encoder {@link Base32Encoder}, as this will work on all
* filesystems, both case sensitive and case insensitive. It does however * file systems, both case sensitive and case insensitive. It does however
* produce longer filenames. * produce longer filenames.
* *
* @param cacheDir * @param cacheDir
@ -91,7 +94,7 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
if (nodeFile.createNewFile()) if (nodeFile.createNewFile())
writeInfoToFile(nodeFile, info); writeInfoToFile(nodeFile, info);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to write disco info to file", e);
} }
} }
@ -160,7 +163,7 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(reader); parser.setInput(reader);
} catch (XmlPullParserException xppe) { } catch (XmlPullParserException xppe) {
xppe.printStackTrace(); log.log(Level.SEVERE, "Exception initializing parser", xppe);
return null; return null;
} }

View file

@ -0,0 +1,97 @@
/**
* Copyright 2013 Georg Lukas
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.forward;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.packet.DelayInfo;
/**
* Packet extension for <a href="http://xmpp.org/extensions/xep-0297.html">XEP-0297</a>: Stanza Forwarding.
*
* @author Georg Lukas
*/
public class Forwarded implements PacketExtension {
public static final String NAMESPACE = "urn:xmpp:forward:0";
public static final String ELEMENT_NAME = "forwarded";
private DelayInfo delay;
private Packet forwardedPacket;
/**
* Creates a new Forwarded packet extension.
*
* @param delay an optional {@link DelayInfo} timestamp of the packet.
* @param fwdPacket the packet that is forwarded (required).
*/
public Forwarded(DelayInfo delay, Packet fwdPacket) {
this.delay = delay;
this.forwardedPacket = fwdPacket;
}
/**
* Creates a new Forwarded packet extension.
*
* @param delay an optional {@link DelayInfo} timestamp of the packet.
* @param fwdPacket the packet that is forwarded (required).
*/
public Forwarded(Packet fwdPacket) {
this.forwardedPacket = fwdPacket;
}
@Override
public String getElementName() {
return ELEMENT_NAME;
}
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<").append(getElementName()).append(" xmlns=\"")
.append(getNamespace()).append("\">");
if (delay != null)
buf.append(delay.toXML());
buf.append(forwardedPacket.toXML());
buf.append("</").append(getElementName()).append(">");
return buf.toString();
}
/**
* get the packet forwarded by this stanza.
*
* @return the {@link Packet} instance (typically a message) that was forwarded.
*/
public Packet getForwardedPacket() {
return forwardedPacket;
}
/**
* get the timestamp of the forwarded packet.
*
* @return the {@link DelayInfo} representing the time when the original packet was sent. May be null.
*/
public DelayInfo getDelayInfo() {
return delay;
}
}

View file

@ -0,0 +1,55 @@
/**
* Copyright 2013 Georg Lukas
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.forward.provider;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.forward.Forwarded;
import org.jivesoftware.smackx.packet.DelayInfo;
import org.xmlpull.v1.XmlPullParser;
/**
* This class implements the {@link PacketExtensionProvider} to parse
* forwarded messages from a packet. It will return a {@link Forwarded} packet extension.
*
* @author Georg Lukas
*/
public class ForwardedProvider implements PacketExtensionProvider {
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
DelayInfo di = null;
Packet packet = null;
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("delay"))
di = (DelayInfo)PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser);
else if (parser.getName().equals("message"))
packet = PacketParserUtils.parseMessage(parser);
else throw new Exception("Unsupported forwarded packet type: " + parser.getName());
}
else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(Forwarded.ELEMENT_NAME))
done = true;
}
if (packet == null)
throw new Exception("forwarded extension must contain a packet");
return new Forwarded(di, packet);
}
}

View file

@ -31,6 +31,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.ConnectionCreationListener;
@ -76,6 +78,7 @@ import org.jivesoftware.smackx.packet.MUCUser;
* @author Gaston Dombiak, Larry Kirschner * @author Gaston Dombiak, Larry Kirschner
*/ */
public class MultiUserChat { public class MultiUserChat {
private static Logger log = Logger.getLogger(MultiUserChat.class.getName());
private final static String discoNamespace = "http://jabber.org/protocol/muc"; private final static String discoNamespace = "http://jabber.org/protocol/muc";
private final static String discoNode = "http://jabber.org/protocol/muc#rooms"; private final static String discoNode = "http://jabber.org/protocol/muc#rooms";
@ -179,7 +182,7 @@ public class MultiUserChat {
return result.containsFeature(discoNamespace); return result.containsFeature(discoNamespace);
} }
catch (XMPPException e) { catch (XMPPException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error checking user [" + user + "] for MUC support", e);
return false; return false;
} }
} }
@ -222,7 +225,7 @@ public class MultiUserChat {
return answer.iterator(); return answer.iterator();
} }
catch (XMPPException e) { catch (XMPPException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error getting joined rooms for user [" + user + "]", e);
// Return an iterator on an empty collection // Return an iterator on an empty collection
return new ArrayList<String>().iterator(); return new ArrayList<String>().iterator();
} }
@ -953,13 +956,12 @@ public class MultiUserChat {
DiscoverInfo.Identity identity = identities.next(); DiscoverInfo.Identity identity = identities.next();
return identity.getName(); return identity.getName();
} }
// If no Identity was found then the user does not have a reserved room nickname
return null;
} }
catch (XMPPException e) { catch (XMPPException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error retrieving room nickname", e);
return null;
} }
// If no Identity was found then the user does not have a reserved room nickname
return null;
} }
/** /**
@ -2061,11 +2063,11 @@ public class MultiUserChat {
method.invoke(listener, params); method.invoke(listener, params);
} }
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to invoke method on UserStatusListener", e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to invoke method on UserStatusListener", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to invoke method on UserStatusListener", e);
} }
} }
@ -2112,11 +2114,11 @@ public class MultiUserChat {
method.invoke(listener, params.toArray()); method.invoke(listener, params.toArray());
} }
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to invoke method on ParticipantStatusListener", e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to invoke method on ParticipantStatusListener", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to invoke method on ParticipantStatusListener", e);
} }
} }

View file

@ -337,6 +337,7 @@ public class DiscoverInfo extends IQ {
* 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a> * 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
* *
* @param type the identity's type. * @param type the identity's type.
* @deprecated As per the spec, this field is mandatory and the 3 argument constructor should be used instead.
*/ */
public void setType(String type) { public void setType(String type) {
this.type = type; this.type = type;

View file

@ -30,6 +30,7 @@ import org.jivesoftware.smack.packet.PacketExtension;
* *
* @author Jeff Williams * @author Jeff Williams
*/ */
@Deprecated
public class PEPEvent implements PacketExtension { public class PEPEvent implements PacketExtension {
PEPItem item; PEPItem item;

View file

@ -30,6 +30,7 @@ import org.jivesoftware.smack.packet.PacketExtension;
* *
* @author Jeff Williams * @author Jeff Williams
*/ */
@Deprecated
public abstract class PEPItem implements PacketExtension { public abstract class PEPItem implements PacketExtension {
String id; String id;

View file

@ -30,6 +30,7 @@ import org.jivesoftware.smack.packet.IQ;
* *
* @author Jeff Williams * @author Jeff Williams
*/ */
@Deprecated
public class PEPPubSub extends IQ { public class PEPPubSub extends IQ {
PEPItem item; PEPItem item;

View file

@ -27,6 +27,8 @@ import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* A Time IQ packet, which is used by XMPP clients to exchange their respective local * A Time IQ packet, which is used by XMPP clients to exchange their respective local
@ -61,6 +63,7 @@ import java.util.TimeZone;
* @author Matt Tucker * @author Matt Tucker
*/ */
public class Time extends IQ { public class Time extends IQ {
private static Logger log = Logger.getLogger(Time.class.getName());
private static SimpleDateFormat utcFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss"); private static SimpleDateFormat utcFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
private static DateFormat displayFormat = DateFormat.getDateTimeInstance(); private static DateFormat displayFormat = DateFormat.getDateTimeInstance();
@ -94,7 +97,7 @@ public class Time extends IQ {
/** /**
* Returns the local time or <tt>null</tt> if the time hasn't been set. * Returns the local time or <tt>null</tt> if the time hasn't been set.
* *
* @return the lcocal time. * @return the local time.
*/ */
public Date getTime() { public Date getTime() {
if (utc == null) { if (utc == null) {
@ -109,7 +112,7 @@ public class Time extends IQ {
date = cal.getTime(); date = cal.getTime();
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error getting local time", e);
} }
return date; return date;
} }

View file

@ -33,6 +33,8 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.PacketCollector;
@ -85,6 +87,8 @@ import org.jivesoftware.smack.util.StringUtils;
* @author Kirill Maximov (kir@maxkir.com) * @author Kirill Maximov (kir@maxkir.com)
*/ */
public class VCard extends IQ { public class VCard extends IQ {
private static Logger log = Logger.getLogger(VCard.class.getName());
private static final String DEFAULT_MIME_TYPE = "image/jpeg"; private static final String DEFAULT_MIME_TYPE = "image/jpeg";
/** /**
@ -332,7 +336,7 @@ public class VCard extends IQ {
bytes = getBytes(avatarURL); bytes = getBytes(avatarURL);
} }
catch (IOException e) { catch (IOException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error getting bytes from URL: " + avatarURL, e);
} }
setAvatar(bytes); setAvatar(bytes);
@ -489,7 +493,7 @@ public class VCard extends IQ {
digest = MessageDigest.getInstance("SHA-1"); digest = MessageDigest.getInstance("SHA-1");
} }
catch (NoSuchAlgorithmException e) { catch (NoSuchAlgorithmException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to get message digest", e);
return null; return null;
} }
@ -582,7 +586,7 @@ public class VCard extends IQ {
result = (VCard) packet; result = (VCard) packet;
} }
catch (ClassCastException e) { catch (ClassCastException e) {
System.out.println("No VCard for " + user); log.log(Level.SEVERE, "No VCard for " + user, e);
return; return;
} }

View file

@ -0,0 +1,16 @@
package org.jivesoftware.smackx.provider;
import org.jivesoftware.smack.provider.UrlProviderFileInitializer;
/**
* Loads the default provider file for the Smack extensions on initialization.
*
* @author Robin Collier
*
*/
public class ExtensionInitializer extends UrlProviderFileInitializer {
@Override
protected String getFilePath() {
return "classpath:META-INF/extension.providers";
}
}

View file

@ -21,6 +21,8 @@ package org.jivesoftware.smackx.provider;
import java.text.ParseException; import java.text.ParseException;
import java.util.Date; import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.IQProvider;
@ -37,6 +39,7 @@ import org.xmlpull.v1.XmlPullParser;
* *
*/ */
public class StreamInitiationProvider implements IQProvider { public class StreamInitiationProvider implements IQProvider {
private static Logger log = Logger.getLogger(StreamInitiationProvider.class.getName());
public IQ parseIQ(final XmlPullParser parser) throws Exception { public IQ parseIQ(final XmlPullParser parser) throws Exception {
boolean done = false; boolean done = false;
@ -90,7 +93,7 @@ public class StreamInitiationProvider implements IQProvider {
fileSize = Long.parseLong(size); fileSize = Long.parseLong(size);
} }
catch (NumberFormatException e) { catch (NumberFormatException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Failed to parse file size from " + fileSize, e);
} }
} }

View file

@ -34,6 +34,8 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* vCard provider. * vCard provider.
@ -42,6 +44,7 @@ import java.util.List;
* @author Derek DeMoro * @author Derek DeMoro
*/ */
public class VCardProvider implements IQProvider { public class VCardProvider implements IQProvider {
private static Logger log = Logger.getLogger(VCardProvider.class.getName());
private static final String PREFERRED_ENCODING = "UTF-8"; private static final String PREFERRED_ENCODING = "UTF-8";
@ -71,10 +74,10 @@ public class VCardProvider implements IQProvider {
} }
} }
catch (XmlPullParserException e) { catch (XmlPullParserException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Exception parsing VCard", e);
} }
catch (IOException e) { catch (IOException e) {
e.printStackTrace(); log.log(Level.SEVERE, "Exception parsing VCard", e);
} }
String xmlText = sb.toString(); String xmlText = sb.toString();

View file

@ -22,267 +22,419 @@ package org.jivesoftware.smack;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import org.jivesoftware.smack.ChatManager.MatchMode;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
/**
* Tests that verifies the correct behavior of the {@see Roster} implementation.
*
* @see Roster
* @see <a href="http://xmpp.org/rfcs/rfc3921.html#roster">Roster Management</a>
* @author Guenther Niess
*/
public class ChatConnectionTest { public class ChatConnectionTest {
private DummyConnection connection; private DummyConnection connection;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
// Uncomment this to enable debug output connection = getConnection();
//Connection.DEBUG_ENABLED = true;
connection = new DummyConnection();
connection.connect();
connection.login("me", "secret");
} }
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
if (connection != null) if (connection != null)
connection.disconnect(); connection.disconnect();
}
@Test
public void validateDefaultSetNormalIncluded() {
ChatManager.setDefaultIsNormalIncluded(false);
assertFalse(getConnection().getChatManager().isNormalIncluded());
ChatManager.setDefaultIsNormalIncluded(true);
assertTrue(getConnection().getChatManager().isNormalIncluded());
}
@Test
public void validateDefaultSetMatchMode() {
ChatManager.setDefaultMatchMode(MatchMode.NONE);
assertEquals(MatchMode.NONE, getConnection().getChatManager().getMatchMode());
ChatManager.setDefaultMatchMode(MatchMode.BARE_JID);
assertEquals(MatchMode.BARE_JID, getConnection().getChatManager().getMatchMode());
}
@Test
public void validateMessageTypeWithDefaults() {
DummyConnection dc = getConnection();
ChatManager cm = dc.getChatManager();
TestChatManagerListener listener = new TestChatManagerListener();
cm.addChatListener(listener);
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.chat);
processServerMessage(incomingChat, dc);
assertNotNull(listener.getNewChat());
dc = getConnection();
cm = dc.getChatManager();
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.normal);
processServerMessage(incomingChat, dc);
assertNotNull(listener.getNewChat());
dc = getConnection();
cm = dc.getChatManager();
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.groupchat);
processServerMessage(incomingChat, dc);
assertNull(listener.getNewChat());
dc = getConnection();
cm = dc.getChatManager();
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.headline);
processServerMessage(incomingChat, dc);
assertNull(listener.getNewChat());
}
@Test
public void validateMessageTypeWithNoNormal() {
ChatManager.setDefaultIsNormalIncluded(false);
DummyConnection dc = getConnection();
ChatManager cm = dc.getChatManager();
TestChatManagerListener listener = new TestChatManagerListener();
cm.addChatListener(listener);
Message incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.chat);
processServerMessage(incomingChat, dc);
assertNotNull(listener.getNewChat());
dc = getConnection();
cm = dc.getChatManager();
listener = new TestChatManagerListener();
cm.addChatListener(listener);
incomingChat = createChatPacket("134", true);
incomingChat.setType(Type.normal);
processServerMessage(incomingChat, dc);
assertNull(listener.getNewChat());
}
// No thread behaviour
@Test
public void chatMatchedOnJIDWhenNoThreadBareMode() {
// MatchMode.BARE_JID is the default, so setting required.
DummyConnection con = getConnection();
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
con.getChatManager().addChatListener(listener);
Packet incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
Chat newChat = listener.getNewChat();
assertNotNull(newChat);
// Should match on chat with full jid
incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
assertEquals(2, msgListener.getNumMessages());
// Should match on chat with bare jid
incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat, con);
assertEquals(3, msgListener.getNumMessages());
}
@Test
public void chatMatchedOnJIDWhenNoThreadJidMode() {
DummyConnection con = getConnection();
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
ChatManager cm = con.getChatManager();
cm.setMatchMode(MatchMode.SUPPLIED_JID);
cm.addChatListener(listener);
Packet incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
Chat newChat = listener.getNewChat();
assertNotNull(newChat);
cm.removeChatListener(listener);
// Should match on chat with full jid
incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
assertEquals(2, msgListener.getNumMessages());
// Should not match on chat with bare jid
TestChatManagerListener listener2 = new TestChatManagerListener();
cm.addChatListener(listener2);
incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat, con);
assertEquals(2, msgListener.getNumMessages());
assertNotNull(listener2.getNewChat());
}
@Test
public void chatMatchedOnJIDWhenNoThreadNoneMode() {
DummyConnection con = getConnection();
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
ChatManager cm = con.getChatManager();
cm.setMatchMode(MatchMode.NONE);
cm.addChatListener(listener);
Packet incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
Chat newChat = listener.getNewChat();
assertNotNull(newChat);
assertEquals(1, msgListener.getNumMessages());
cm.removeChatListener(listener);
// Should not match on chat with full jid
TestChatManagerListener listener2 = new TestChatManagerListener();
cm.addChatListener(listener2);
incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat, con);
assertEquals(1, msgListener.getNumMessages());
assertNotNull(newChat);
cm.removeChatListener(listener2);
// Should not match on chat with bare jid
TestChatManagerListener listener3 = new TestChatManagerListener();
cm.addChatListener(listener3);
incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat, con);
assertEquals(1, msgListener.getNumMessages());
assertNotNull(listener3.getNewChat());
} }
/** /**
* Confirm that a new chat is created when a chat message is received but * Confirm that an existing chat created with a base jid is matched to an incoming chat message that has no thread
* there is no thread id for a user with only a base jid. * id and the user is a full jid.
*/ */
@Test @Test
public void chatCreatedWithIncomingChatNoThreadBaseJid() public void chatFoundWhenNoThreadFullJid() {
{ TestChatManagerListener listener = new TestChatManagerListener();
TestChatManagerListener listener = new TestChatManagerListener(); connection.getChatManager().addChatListener(listener);
connection.getChatManager().addChatListener(listener); Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Packet incomingChat = createChatPacket(null, false); Packet incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat); processServerMessage(incomingChat);
Chat newChat = listener.getNewChat(); Chat newChat = listener.getNewChat();
assertNotNull(newChat); assertNotNull(newChat);
assertTrue(newChat == outgoing);
} }
/** /**
* Confirm that a new chat is created when a chat message is received but * Confirm that an existing chat created with a base jid is matched to an incoming chat message that has no thread
* there is no thread id for a user with a full jid. * id and the user is a base jid.
*/ */
@Test @Test
public void chatCreatedWhenIncomingChatNoThreadFullJid() public void chatFoundWhenNoThreadBaseJid() {
{ TestChatManagerListener listener = new TestChatManagerListener();
TestChatManagerListener listener = new TestChatManagerListener(); connection.getChatManager().addChatListener(listener);
connection.getChatManager().addChatListener(listener); Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Packet incomingChat = createChatPacket(null, true); Packet incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat); processServerMessage(incomingChat);
Chat newChat = listener.getNewChat(); Chat newChat = listener.getNewChat();
assertNotNull(newChat); assertNotNull(newChat);
assertTrue(newChat == outgoing);
} }
/** /**
* Confirm that an existing chat created with a base jid is matched to an * Confirm that an existing chat created with a base jid is matched to an incoming chat message that has the same id
* incoming chat message that has no thread id and the user is a full jid. * and the user is a full jid.
*/ */
@Test @Test
public void chatFoundWhenNoThreadFullJid() public void chatFoundWithSameThreadFullJid() {
{ TestChatManagerListener listener = new TestChatManagerListener();
TestChatManagerListener listener = new TestChatManagerListener(); connection.getChatManager().addChatListener(listener);
connection.getChatManager().addChatListener(listener); Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Packet incomingChat = createChatPacket(null, true); Packet incomingChat = createChatPacket(outgoing.getThreadID(), true);
processServerMessage(incomingChat); processServerMessage(incomingChat);
Chat newChat = listener.getNewChat(); Chat newChat = listener.getNewChat();
assertNotNull(newChat); assertNotNull(newChat);
assertTrue(newChat == outgoing); assertTrue(newChat == outgoing);
} }
/** /**
* Confirm that an existing chat created with a base jid is matched to an * Confirm that an existing chat created with a base jid is matched to an incoming chat message that has the same id
* incoming chat message that has no thread id and the user is a base jid. * and the user is a base jid.
*/ */
@Test @Test
public void chatFoundWhenNoThreadBaseJid() public void chatFoundWithSameThreadBaseJid() {
{ TestChatManagerListener listener = new TestChatManagerListener();
TestChatManagerListener listener = new TestChatManagerListener(); connection.getChatManager().addChatListener(listener);
connection.getChatManager().addChatListener(listener); Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Packet incomingChat = createChatPacket(null, false); Packet incomingChat = createChatPacket(outgoing.getThreadID(), false);
processServerMessage(incomingChat); processServerMessage(incomingChat);
Chat newChat = listener.getNewChat(); Chat newChat = listener.getNewChat();
assertNotNull(newChat); assertNotNull(newChat);
assertTrue(newChat == outgoing); assertTrue(newChat == outgoing);
} }
/** /**
* Confirm that an existing chat created with a base jid is matched to an * Confirm that an existing chat created with a base jid is not matched to an incoming chat message that has a
* incoming chat message that has the same id and the user is a full jid. * different id and the same user as a base jid.
*/ */
@Test @Test
public void chatFoundWithSameThreadFullJid() public void chatNotFoundWithDiffThreadBaseJid() {
{ TestChatManagerListener listener = new TestChatManagerListener();
TestChatManagerListener listener = new TestChatManagerListener(); connection.getChatManager().addChatListener(listener);
connection.getChatManager().addChatListener(listener); Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Packet incomingChat = createChatPacket(outgoing.getThreadID(), true); Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", false);
processServerMessage(incomingChat); processServerMessage(incomingChat);
Chat newChat = listener.getNewChat(); Chat newChat = listener.getNewChat();
assertNotNull(newChat); assertNotNull(newChat);
assertTrue(newChat == outgoing); assertFalse(newChat == outgoing);
} }
/** /**
* Confirm that an existing chat created with a base jid is matched to an * Confirm that an existing chat created with a base jid is not matched to an incoming chat message that has a
* incoming chat message that has the same id and the user is a base jid. * different id and the same base jid.
*/ */
@Test @Test
public void chatFoundWithSameThreadBaseJid() public void chatNotFoundWithDiffThreadFullJid() {
{ TestChatManagerListener listener = new TestChatManagerListener();
TestChatManagerListener listener = new TestChatManagerListener(); connection.getChatManager().addChatListener(listener);
connection.getChatManager().addChatListener(listener); Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Packet incomingChat = createChatPacket(outgoing.getThreadID(), false); Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", true);
processServerMessage(incomingChat); processServerMessage(incomingChat);
Chat newChat = listener.getNewChat(); Chat newChat = listener.getNewChat();
assertNotNull(newChat); assertNotNull(newChat);
assertTrue(newChat == outgoing); assertFalse(newChat == outgoing);
} }
/**
* Confirm that an existing chat created with a base jid is not matched to
* an incoming chat message that has a different id and the same user as a
* base jid.
*/
@Ignore
@Test @Test
public void chatNotFoundWithDiffThreadBaseJid() public void chatNotMatchedWithTypeNormal() {
{ TestChatManagerListener listener = new TestChatManagerListener();
TestChatManagerListener listener = new TestChatManagerListener(); DummyConnection con = getConnection();
connection.getChatManager().addChatListener(listener); ChatManager cm = con.getChatManager();
Chat outgoing = connection.getChatManager().createChat("you@testserver", null); cm.setNormalIncluded(false);
cm.addChatListener(listener);
Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", false); Message incomingChat = createChatPacket(null, false);
processServerMessage(incomingChat); incomingChat.setType(Type.normal);
processServerMessage(incomingChat);
Chat newChat = listener.getNewChat(); assertNull(listener.getNewChat());
assertNotNull(newChat);
assertFalse(newChat == outgoing);
} }
/** private ChatManager getChatManager(boolean includeNormal, MatchMode mode) {
* Confirm that an existing chat created with a base jid is not matched to ChatManager cm = getConnection().getChatManager();
* an incoming chat message that has a different id and the same base jid. cm.setMatchMode(mode);
*/ cm.setNormalIncluded(includeNormal);
@Ignore return cm;
@Test
public void chatNotFoundWithDiffThreadFullJid()
{
TestChatManagerListener listener = new TestChatManagerListener();
connection.getChatManager().addChatListener(listener);
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", true);
processServerMessage(incomingChat);
Chat newChat = listener.getNewChat();
assertNotNull(newChat);
assertFalse(newChat == outgoing);
} }
private Packet createChatPacket(final String threadId, final boolean isFullJid) private DummyConnection getConnection() {
{ DummyConnection con = new DummyConnection();
Message chatMsg = new Message("me@testserver", Message.Type.chat);
chatMsg.setBody("the body message");
chatMsg.setFrom("you@testserver" + (isFullJid ? "/resource" : ""));
if (threadId != null) try {
chatMsg.addExtension(new PacketExtension() con.connect();
{ con.login("me", "secret");
@Override } catch (XMPPException e) {
public String toXML() // No need for handling in a dummy connection.
{ }
return "<thread>" + threadId + "</thread>"; return con;
} }
private Message createChatPacket(final String threadId, final boolean isFullJid) {
Message chatMsg = new Message("me@testserver", Message.Type.chat);
chatMsg.setBody("the body message - " + System.currentTimeMillis());
chatMsg.setFrom("you@testserver" + (isFullJid ? "/resource" : ""));
@Override if (threadId != null)
public String getNamespace() chatMsg.setThread(threadId);
{ return chatMsg;
return null;
}
@Override
public String getElementName()
{
return "thread";
}
});
return chatMsg;
} }
private void processServerMessage(Packet incomingChat) private void processServerMessage(Packet incomingChat) {
{ processServerMessage(incomingChat, connection);
TestChatServer chatServer = new TestChatServer(incomingChat);
chatServer.start();
try
{
chatServer.join();
} catch (InterruptedException e)
{
fail();
}
} }
class TestChatManagerListener implements ChatManagerListener private void processServerMessage(Packet incomingChat, DummyConnection con) {
{ TestChatServer chatServer = new TestChatServer(incomingChat, con);
private Chat newChat; chatServer.start();
try {
@Override chatServer.join();
public void chatCreated(Chat chat, boolean createdLocally) } catch (InterruptedException e) {
{ fail();
newChat = chat; }
}
public Chat getNewChat()
{
return newChat;
}
} }
private class TestChatServer extends Thread class TestChatManagerListener implements ChatManagerListener {
{ private Chat newChat;
private Packet chatPacket; private MessageListener listener;
TestChatServer(Packet chatMsg) public TestChatManagerListener(TestMessageListener msgListener) {
{ listener = msgListener;
chatPacket = chatMsg; }
}
@Override public TestChatManagerListener() {
public void run() }
{
connection.processPacket(chatPacket); @Override
} public void chatCreated(Chat chat, boolean createdLocally) {
newChat = chat;
if (listener != null)
newChat.addMessageListener(listener);
}
public Chat getNewChat() {
return newChat;
}
} }
private class TestChatServer extends Thread {
private Packet chatPacket;
private DummyConnection con;
TestChatServer(Packet chatMsg, DummyConnection conect) {
chatPacket = chatMsg;
con = conect;
}
@Override
public void run() {
con.processPacket(chatPacket);
}
}
private class TestMessageListener implements MessageListener {
private Chat msgChat;
private int counter = 0;
@Override
public void processMessage(Chat chat, Message message) {
msgChat = chat;
counter++;
}
public Chat getChat() {
return msgChat;
}
public int getNumMessages() {
return counter;
}
};
} }

View file

@ -26,6 +26,14 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.Connection.ListenerWrapper;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence;

View file

@ -1,7 +1,6 @@
package org.jivesoftware.smack.keepalive; package org.jivesoftware.smack.keepalive;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.Properties; import java.util.Properties;
@ -13,16 +12,13 @@ import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.PacketInterceptor; import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.TestUtils;
import org.jivesoftware.smack.ThreadedDummyConnection; import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.filter.IQTypeFilter; import org.jivesoftware.smack.filter.IQTypeFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.keepalive.KeepAliveManager;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.ping.PingFailedListener; import org.jivesoftware.smack.ping.PingFailedListener;
import org.jivesoftware.smack.ping.packet.Ping; import org.jivesoftware.smack.ping.packet.Ping;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;

View file

@ -2,8 +2,8 @@ package org.jivesoftware.smack.packet;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.jivesoftware.smack.TestUtils;
import org.jivesoftware.smack.packet.StreamError; import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.junit.Test; import org.junit.Test;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;

View file

@ -3,11 +3,11 @@ package org.jivesoftware.smack.parsing;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import org.jivesoftware.smack.TestUtils;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider; import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.provider.ProviderManager; import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;

View file

@ -17,7 +17,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.jivesoftware.smack; package org.jivesoftware.smack.test.util;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;

View file

@ -24,10 +24,10 @@ import java.util.TimeZone;
import org.custommonkey.xmlunit.DetailedDiff; import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.Diff; import org.custommonkey.xmlunit.Diff;
import org.jivesoftware.smack.TestUtils;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smackx.packet.DelayInformation; import org.jivesoftware.smackx.packet.DelayInformation;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;

View file

@ -57,7 +57,6 @@ public class InBandBytestreamSessionMessageTest {
String sessionID = "session_id"; String sessionID = "session_id";
int blockSize = 10; int blockSize = 10;
int dataSize = blockSize/4 * 3;
// protocol verifier // protocol verifier
Protocol protocol; Protocol protocol;
@ -120,7 +119,7 @@ public class InBandBytestreamSessionMessageTest {
protocol.addResponse(null, incrementingSequence); protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence); protocol.addResponse(null, incrementingSequence);
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream(); OutputStream outputStream = session.getOutputStream();
outputStream.write(controlData); outputStream.write(controlData);
@ -145,7 +144,7 @@ public class InBandBytestreamSessionMessageTest {
protocol.addResponse(null, incrementingSequence); protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence); protocol.addResponse(null, incrementingSequence);
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream(); OutputStream outputStream = session.getOutputStream();
for (byte b : controlData) { for (byte b : controlData) {
@ -172,11 +171,11 @@ public class InBandBytestreamSessionMessageTest {
protocol.addResponse(null, incrementingSequence); protocol.addResponse(null, incrementingSequence);
protocol.addResponse(null, incrementingSequence); protocol.addResponse(null, incrementingSequence);
byte[] controlData = new byte[(dataSize * 3) - 2]; byte[] controlData = new byte[(blockSize * 3) - 2];
OutputStream outputStream = session.getOutputStream(); OutputStream outputStream = session.getOutputStream();
int off = 0; int off = 0;
for (int i = 1; off+i <= controlData.length; i++) { for (int i = 1; i <= 7; i++) {
outputStream.write(controlData, off, i); outputStream.write(controlData, off, i);
off += i; off += i;
} }
@ -193,7 +192,7 @@ public class InBandBytestreamSessionMessageTest {
*/ */
@Test @Test
public void shouldSendThirtyDataPackets() throws Exception { public void shouldSendThirtyDataPackets() throws Exception {
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream, InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID); initiatorJID);
@ -220,7 +219,7 @@ public class InBandBytestreamSessionMessageTest {
*/ */
@Test @Test
public void shouldSendNothingOnSuccessiveCallsToFlush() throws Exception { public void shouldSendNothingOnSuccessiveCallsToFlush() throws Exception {
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream, InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID); initiatorJID);
@ -291,7 +290,7 @@ public class InBandBytestreamSessionMessageTest {
public void shouldReadAllReceivedData1() throws Exception { public void shouldReadAllReceivedData1() throws Exception {
// create random data // create random data
Random rand = new Random(); Random rand = new Random();
byte[] controlData = new byte[3 * dataSize]; byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData); rand.nextBytes(controlData);
// get IBB sessions data packet listener // get IBB sessions data packet listener
@ -301,8 +300,8 @@ public class InBandBytestreamSessionMessageTest {
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class); PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// verify data packet and notify listener // verify data packet and notify listener
for (int i = 0; i < controlData.length / dataSize; i++) { for (int i = 0; i < controlData.length / blockSize; i++) {
String base64Data = StringUtils.encodeBase64(controlData, i * dataSize, dataSize, String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false); false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data); DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Message dataMessage = new Message(); Message dataMessage = new Message();
@ -310,14 +309,14 @@ public class InBandBytestreamSessionMessageTest {
listener.processPacket(dataMessage); listener.processPacket(dataMessage);
} }
byte[] bytes = new byte[3 * dataSize]; byte[] bytes = new byte[3 * blockSize];
int read = 0; int read = 0;
read = inputStream.read(bytes, 0, dataSize); read = inputStream.read(bytes, 0, blockSize);
assertEquals(dataSize, read); assertEquals(blockSize, read);
read = inputStream.read(bytes, dataSize, dataSize); read = inputStream.read(bytes, 10, blockSize);
assertEquals(dataSize, read); assertEquals(blockSize, read);
read = inputStream.read(bytes, dataSize*2, dataSize); read = inputStream.read(bytes, 20, blockSize);
assertEquals(dataSize, read); assertEquals(blockSize, read);
// verify data // verify data
for (int i = 0; i < bytes.length; i++) { for (int i = 0; i < bytes.length; i++) {
@ -337,7 +336,7 @@ public class InBandBytestreamSessionMessageTest {
public void shouldReadAllReceivedData2() throws Exception { public void shouldReadAllReceivedData2() throws Exception {
// create random data // create random data
Random rand = new Random(); Random rand = new Random();
byte[] controlData = new byte[3 * dataSize]; byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData); rand.nextBytes(controlData);
// get IBB sessions data packet listener // get IBB sessions data packet listener
@ -347,8 +346,8 @@ public class InBandBytestreamSessionMessageTest {
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class); PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// verify data packet and notify listener // verify data packet and notify listener
for (int i = 0; i < controlData.length / dataSize; i++) { for (int i = 0; i < controlData.length / blockSize; i++) {
String base64Data = StringUtils.encodeBase64(controlData, i * dataSize, dataSize, String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false); false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data); DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Message dataMessage = new Message(); Message dataMessage = new Message();
@ -357,7 +356,7 @@ public class InBandBytestreamSessionMessageTest {
} }
// read data // read data
byte[] bytes = new byte[3 * dataSize]; byte[] bytes = new byte[3 * blockSize];
for (int i = 0; i < bytes.length; i++) { for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) inputStream.read(); bytes[i] = (byte) inputStream.read();
} }

View file

@ -57,8 +57,7 @@ public class InBandBytestreamSessionTest {
String xmppServer = "xmpp-server"; String xmppServer = "xmpp-server";
String sessionID = "session_id"; String sessionID = "session_id";
int blockSize = 20; int blockSize = 10;
int dataSize = blockSize/4 * 3;
// protocol verifier // protocol verifier
Protocol protocol; Protocol protocol;
@ -120,7 +119,7 @@ public class InBandBytestreamSessionTest {
protocol.addResponse(resultIQ, incrementingSequence); protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence); protocol.addResponse(resultIQ, incrementingSequence);
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream(); OutputStream outputStream = session.getOutputStream();
outputStream.write(controlData); outputStream.write(controlData);
@ -146,7 +145,7 @@ public class InBandBytestreamSessionTest {
protocol.addResponse(resultIQ, incrementingSequence); protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence); protocol.addResponse(resultIQ, incrementingSequence);
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
OutputStream outputStream = session.getOutputStream(); OutputStream outputStream = session.getOutputStream();
for (byte b : controlData) { for (byte b : controlData) {
@ -174,11 +173,11 @@ public class InBandBytestreamSessionTest {
protocol.addResponse(resultIQ, incrementingSequence); protocol.addResponse(resultIQ, incrementingSequence);
protocol.addResponse(resultIQ, incrementingSequence); protocol.addResponse(resultIQ, incrementingSequence);
byte[] controlData = new byte[(dataSize * 3) - 2]; byte[] controlData = new byte[(blockSize * 3) - 2];
OutputStream outputStream = session.getOutputStream(); OutputStream outputStream = session.getOutputStream();
int off = 0; int off = 0;
for (int i = 1; i+off <= controlData.length; i++) { for (int i = 1; i <= 7; i++) {
outputStream.write(controlData, off, i); outputStream.write(controlData, off, i);
off += i; off += i;
} }
@ -195,7 +194,7 @@ public class InBandBytestreamSessionTest {
*/ */
@Test @Test
public void shouldSendThirtyDataPackets() throws Exception { public void shouldSendThirtyDataPackets() throws Exception {
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream, InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID); initiatorJID);
@ -223,7 +222,7 @@ public class InBandBytestreamSessionTest {
*/ */
@Test @Test
public void shouldSendNothingOnSuccessiveCallsToFlush() throws Exception { public void shouldSendNothingOnSuccessiveCallsToFlush() throws Exception {
byte[] controlData = new byte[dataSize * 3]; byte[] controlData = new byte[blockSize * 3];
InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream, InBandBytestreamSession session = new InBandBytestreamSession(connection, initBytestream,
initiatorJID); initiatorJID);
@ -254,7 +253,7 @@ public class InBandBytestreamSessionTest {
public void shouldSendDataCorrectly() throws Exception { public void shouldSendDataCorrectly() throws Exception {
// create random data // create random data
Random rand = new Random(); Random rand = new Random();
final byte[] controlData = new byte[256 * dataSize]; final byte[] controlData = new byte[256 * blockSize];
rand.nextBytes(controlData); rand.nextBytes(controlData);
// compares the data of each packet with the control data // compares the data of each packet with the control data
@ -264,7 +263,7 @@ public class InBandBytestreamSessionTest {
byte[] decodedData = request.getDataPacketExtension().getDecodedData(); byte[] decodedData = request.getDataPacketExtension().getDecodedData();
int seq = (int) request.getDataPacketExtension().getSeq(); int seq = (int) request.getDataPacketExtension().getSeq();
for (int i = 0; i < decodedData.length; i++) { for (int i = 0; i < decodedData.length; i++) {
assertEquals(controlData[(seq * dataSize) + i], decodedData[i]); assertEquals(controlData[(seq * blockSize) + i], decodedData[i]);
} }
} }
@ -272,7 +271,7 @@ public class InBandBytestreamSessionTest {
// set acknowledgments for the data packets // set acknowledgments for the data packets
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID); IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
for (int i = 0; i < controlData.length / dataSize; i++) { for (int i = 0; i < controlData.length / blockSize; i++) {
protocol.addResponse(resultIQ, incrementingSequence, dataVerification); protocol.addResponse(resultIQ, incrementingSequence, dataVerification);
} }
@ -480,7 +479,7 @@ public class InBandBytestreamSessionTest {
public void shouldReadAllReceivedData1() throws Exception { public void shouldReadAllReceivedData1() throws Exception {
// create random data // create random data
Random rand = new Random(); Random rand = new Random();
byte[] controlData = new byte[3 * dataSize]; byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData); rand.nextBytes(controlData);
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID); IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
@ -491,24 +490,24 @@ public class InBandBytestreamSessionTest {
InputStream inputStream = session.getInputStream(); InputStream inputStream = session.getInputStream();
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class); PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// set data packet acknowledgement and notify listener // set data packet acknowledgment and notify listener
for (int i = 0; i < controlData.length / dataSize; i++) { for (int i = 0; i < controlData.length / blockSize; i++) {
protocol.addResponse(resultIQ); protocol.addResponse(resultIQ);
String base64Data = StringUtils.encodeBase64(controlData, i * dataSize, dataSize, String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false); false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data); DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Data data = new Data(dpe); Data data = new Data(dpe);
listener.processPacket(data); listener.processPacket(data);
} }
byte[] bytes = new byte[3 * dataSize]; byte[] bytes = new byte[3 * blockSize];
int read = 0; int read = 0;
read = inputStream.read(bytes, 0, dataSize); read = inputStream.read(bytes, 0, blockSize);
assertEquals(dataSize, read); assertEquals(blockSize, read);
read = inputStream.read(bytes, dataSize, dataSize); read = inputStream.read(bytes, 10, blockSize);
assertEquals(dataSize, read); assertEquals(blockSize, read);
read = inputStream.read(bytes, dataSize*2, dataSize); read = inputStream.read(bytes, 20, blockSize);
assertEquals(dataSize, read); assertEquals(blockSize, read);
// verify data // verify data
for (int i = 0; i < bytes.length; i++) { for (int i = 0; i < bytes.length; i++) {
@ -528,7 +527,7 @@ public class InBandBytestreamSessionTest {
public void shouldReadAllReceivedData2() throws Exception { public void shouldReadAllReceivedData2() throws Exception {
// create random data // create random data
Random rand = new Random(); Random rand = new Random();
byte[] controlData = new byte[3 * dataSize]; byte[] controlData = new byte[3 * blockSize];
rand.nextBytes(controlData); rand.nextBytes(controlData);
IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID); IQ resultIQ = IBBPacketUtils.createResultIQ(initiatorJID, targetJID);
@ -540,9 +539,9 @@ public class InBandBytestreamSessionTest {
PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class); PacketListener listener = Whitebox.getInternalState(inputStream, PacketListener.class);
// set data packet acknowledgment and notify listener // set data packet acknowledgment and notify listener
for (int i = 0; i < controlData.length / dataSize; i++) { for (int i = 0; i < controlData.length / blockSize; i++) {
protocol.addResponse(resultIQ); protocol.addResponse(resultIQ);
String base64Data = StringUtils.encodeBase64(controlData, i * dataSize, dataSize, String base64Data = StringUtils.encodeBase64(controlData, i * blockSize, blockSize,
false); false);
DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data); DataPacketExtension dpe = new DataPacketExtension(sessionID, i, base64Data);
Data data = new Data(dpe); Data data = new Data(dpe);
@ -550,7 +549,7 @@ public class InBandBytestreamSessionTest {
} }
// read data // read data
byte[] bytes = new byte[3 * dataSize]; byte[] bytes = new byte[3 * blockSize];
for (int i = 0; i < bytes.length; i++) { for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) inputStream.read(); bytes[i] = (byte) inputStream.read();
} }

View file

@ -0,0 +1,86 @@
/**
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.forward;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.TimeZone;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smackx.packet.DelayInfo;
import org.jivesoftware.smackx.packet.DelayInformation;
import org.jivesoftware.smackx.forward.Forwarded;
import org.jivesoftware.smackx.forward.provider.ForwardedProvider;
import org.junit.Test;
import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import com.jamesmurty.utils.XMLBuilder;
public class ForwardedTest {
private static Properties outputProperties = new Properties();
static {
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void forwardedTest() throws Exception {
XmlPullParser parser;
String control;
Forwarded fwd;
control = XMLBuilder.create("forwarded")
.a("xmlns", "urn:xmpp:forwarded:0")
.e("message")
.a("from", "romeo@montague.com")
.asString(outputProperties);
parser = TestUtils.getParser(control, "forwarded");
fwd = (Forwarded) new ForwardedProvider().parseExtension(parser);
// no delay in packet
assertEquals(null, fwd.getDelayInfo());
// check message
assertEquals("romeo@montague.com", fwd.getForwardedPacket().getFrom());
// check end of tag
assertEquals(XmlPullParser.END_TAG, parser.getEventType());
assertEquals("forwarded", parser.getName());
}
@Test(expected=Exception.class)
public void forwardedEmptyTest() throws Exception {
XmlPullParser parser;
String control;
control = XMLBuilder.create("forwarded")
.a("xmlns", "urn:xmpp:forwarded:0")
.asString(outputProperties);
parser = TestUtils.getParser(control, "forwarded");
new ForwardedProvider().parseExtension(parser);
}
}

View file

@ -15,19 +15,21 @@
*/ */
package org.jivesoftware.smackx.ping; package org.jivesoftware.smackx.ping;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.jivesoftware.smack.DummyConnection; import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.TestUtils;
import org.jivesoftware.smack.ThreadedDummyConnection; import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.ping.packet.Ping; import org.jivesoftware.smack.ping.packet.Ping;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
public class PingTest { public class PingTest {
private DummyConnection dummyCon; private DummyConnection dummyCon;
private ThreadedDummyConnection threadedCon; private ThreadedDummyConnection threadedCon;

View file

@ -0,0 +1,55 @@
package org.jivesoftware.smackx.provider;
import java.util.ArrayList;
import java.util.Collection;
import junit.framework.Assert;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.ExtensionProviderInfo;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.IQProviderInfo;
import org.jivesoftware.smack.provider.ProviderFileLoader;
import org.jivesoftware.smack.provider.ProviderLoader;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.util.FileUtils;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
public class ProviderConfigTest {
@Test
public void addGenericLoaderProvider() {
ProviderManager.getInstance().addLoader(new ProviderLoader() {
@Override
public Collection<IQProviderInfo> getIQProviderInfo() {
ArrayList<IQProviderInfo> l = new ArrayList<IQProviderInfo>(1);
l.add(new IQProviderInfo("provider", "test:provider", new TestIQProvider()));
return l;
}
@Override
public Collection<ExtensionProviderInfo> getExtensionProviderInfo() {
return null;
}
});
Assert.assertNotNull(ProviderManager.getInstance().getIQProvider("provider", "test:provider"));
}
@Test
public void addClasspathFileLoaderProvider() throws Exception{
ProviderManager.getInstance().addLoader(new ProviderFileLoader(FileUtils.getStreamForUrl("classpath:org/jivesoftware/smackx/provider/test.providers", null)));
Assert.assertNotNull(ProviderManager.getInstance().getIQProvider("provider", "test:file_provider"));
}
public static class TestIQProvider implements IQProvider {
@Override
public IQ parseIQ(XmlPullParser parser) throws Exception {
return null;
}
}
}

View file

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- Providers file for default Smack extensions -->
<smackProviders>
<iqProvider>
<elementName>provider</elementName>
<namespace>test:file_provider</namespace>
<className>org.jivesoftware.smackx.provider.ProviderConfigTest$TestIQProvider</className>
</iqProvider>
</smackProviders>

View file

@ -26,10 +26,10 @@ import static org.junit.Assert.assertTrue;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import org.jivesoftware.smack.TestUtils;
import org.jivesoftware.smack.ThreadedDummyConnection; import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.jivesoftware.smackx.pubsub.provider.ItemsProvider; import org.jivesoftware.smackx.pubsub.provider.ItemsProvider;

View file

@ -0,0 +1,214 @@
<?xml version="1.0"?>
<!-- Providers for workgroup extensions -->
<smackProviders>
<!-- Fastpath providers -->
<iqProvider>
<elementName>offer</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.OfferRequestProvider</className>
</iqProvider>
<iqProvider>
<elementName>offer-revoke</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.OfferRevokeProvider</className>
</iqProvider>
<iqProvider>
<elementName>agent-status-request</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentStatusRequest$Provider</className>
</iqProvider>
<iqProvider>
<elementName>transcripts</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.TranscriptsProvider</className>
</iqProvider>
<iqProvider>
<elementName>transcript</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.TranscriptProvider</className>
</iqProvider>
<iqProvider>
<elementName>workgroups</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentWorkgroups$Provider</className>
</iqProvider>
<iqProvider>
<elementName>agent-info</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentInfo$Provider</className>
</iqProvider>
<iqProvider>
<elementName>transcript-search</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.TranscriptSearch$Provider</className>
</iqProvider>
<iqProvider>
<elementName>occupants-info</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.OccupantsInfo$Provider</className>
</iqProvider>
<iqProvider>
<elementName>chat-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.ChatSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>chat-notes</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.notes.ChatNotes$Provider</className>
</iqProvider>
<iqProvider>
<elementName>chat-sessions</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.history.AgentChatHistory$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>offline-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.OfflineSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>sound-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.SoundSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>workgroup-properties</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.WorkgroupProperties$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>search-settings</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.SearchSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>workgroup-form</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.forms.WorkgroupForm$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>macros</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.macros.Macros$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>chat-metadata</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.ext.history.ChatMetadata$Provider</className>
</iqProvider>
<!--
org.jivesoftware.smackx.workgroup.site is missing ...
<iqProvider>
<elementName>site-user</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.site.SiteUser$Provider</className>
</iqProvider>
<iqProvider>
<elementName>site-invite</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.site.SiteInvitation$Provider</className>
</iqProvider>
<iqProvider>
<elementName>site-user-history</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.site.SiteUserHistory$Provider</className>
</iqProvider>
-->
<iqProvider>
<elementName>generic-metadata</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.settings.GenericSettings$InternalProvider</className>
</iqProvider>
<iqProvider>
<elementName>monitor</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.MonitorPacket$InternalProvider</className>
</iqProvider>
<!-- Packet Extension Providers -->
<extensionProvider>
<elementName>queue-status</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.QueueUpdate$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>workgroup</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.WorkgroupInformation$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>metadata</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.MetaDataProvider</className>
</extensionProvider>
<extensionProvider>
<elementName>session</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.SessionID$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>user</elementName>
<namespace>http://jivesoftware.com/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.UserID$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>agent-status</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.AgentStatus$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>notify-queue-details</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.QueueDetails$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>notify-queue</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.QueueOverview$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>invite</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.RoomInvitation$Provider</className>
</extensionProvider>
<extensionProvider>
<elementName>transfer</elementName>
<namespace>http://jabber.org/protocol/workgroup</namespace>
<className>org.jivesoftware.smackx.workgroup.packet.RoomTransfer$Provider</className>
</extensionProvider>
</smackProviders>

View file

@ -0,0 +1,11 @@
package org.jivesoftware.smackx.workgroup;
import org.jivesoftware.smack.provider.UrlProviderFileInitializer;
public class WorkgroupProviderInitializer extends UrlProviderFileInitializer {
@Override
protected String getFilePath() {
return "classpath:META-INF/workgroup.providers";
}
}

View file

@ -37,6 +37,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Logger;
/** /**
* Manges information about the agents in a workgroup and their presence. * Manges information about the agents in a workgroup and their presence.
@ -45,7 +46,7 @@ import java.util.Set;
* @see AgentSession#getAgentRoster() * @see AgentSession#getAgentRoster()
*/ */
public class AgentRoster { public class AgentRoster {
private static Logger log = Logger.getLogger(AgentRoster.class.getName());
private static final int EVENT_AGENT_ADDED = 0; private static final int EVENT_AGENT_ADDED = 0;
private static final int EVENT_AGENT_REMOVED = 1; private static final int EVENT_AGENT_REMOVED = 1;
private static final int EVENT_PRESENCE_CHANGED = 2; private static final int EVENT_PRESENCE_CHANGED = 2;
@ -284,7 +285,7 @@ public class AgentRoster {
String from = presence.getFrom(); String from = presence.getFrom();
if (from == null) { if (from == null) {
// TODO Check if we need to ignore these presences or this is a server bug? // TODO Check if we need to ignore these presences or this is a server bug?
System.out.println("Presence with no FROM: " + presence.toXML()); log.warning("Presence with no FROM: " + presence.toXML());
return; return;
} }
String key = getPresenceMapKey(from); String key = getPresenceMapKey(from);

View file

@ -40,6 +40,8 @@ import org.jivesoftware.smackx.ReportedData;
import org.jivesoftware.smackx.packet.MUCUser; import org.jivesoftware.smackx.packet.MUCUser;
import java.util.*; import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* This class embodies the agent's active presence within a given workgroup. The application * This class embodies the agent's active presence within a given workgroup. The application
@ -53,6 +55,7 @@ import java.util.*;
* @author Derek DeMoro * @author Derek DeMoro
*/ */
public class AgentSession { public class AgentSession {
private static Logger log = Logger.getLogger(AgentSession.class.getName());
private Connection connection; private Connection connection;
@ -118,7 +121,7 @@ public class AgentSession {
handlePacket(packet); handlePacket(packet);
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); log.log(Level.SEVERE, "Error processing packet", e);
} }
} }
}; };

Some files were not shown because too many files have changed in this diff Show more