Merge branch '4.0'

Conflicts:
	build.gradle
	documentation/connections.html
	documentation/gettingstarted.html
	smack-core/src/main/java/org/jivesoftware/smack/SmackException.java
	smack-core/src/test/java/org/jivesoftware/smack/parsing/ParsingExceptionTest.java
	smack-core/src/test/java/org/jivesoftware/smack/test/util/TestUtils.java
	smack-core/src/test/java/org/jivesoftware/smack/util/PacketParserUtilsTest.java
	smack-extensions/src/main/java/org/jivesoftware/smackx/caps/cache/SimpleDirectoryPersistentCache.java
	smack-extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java
	smack-tcp/src/main/java/org/jivesoftware/smack/tcp/PacketReader.java
This commit is contained in:
Florian Schmaus 2014-07-05 14:37:22 +02:00
commit 94a16ba41e
61 changed files with 806 additions and 300 deletions

View File

@ -19,6 +19,7 @@ allprojects {
sonatypeStagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2' sonatypeStagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2'
buildDate = (new java.text.SimpleDateFormat("yyyy-MM-dd")).format(new Date()) buildDate = (new java.text.SimpleDateFormat("yyyy-MM-dd")).format(new Date())
oneLineDesc = 'An Open Source XMPP (Jabber) client library' oneLineDesc = 'An Open Source XMPP (Jabber) client library'
jxmppVersion = "0.1.0"
} }
group = 'org.igniterealtime.smack' group = 'org.igniterealtime.smack'
sourceCompatibility = 1.7 sourceCompatibility = 1.7
@ -35,7 +36,12 @@ allprojects {
// first occurence of an dash with a dot. // first occurence of an dash with a dot.
// For example 4.0.0-rc1 becomes 4.0.0.rc1, but // For example 4.0.0-rc1 becomes 4.0.0.rc1, but
// 4.0.0-SNAPSHOT-2014-05-01 becomes 4.0.0.SNAPSHOT-2014-05-01 // 4.0.0-SNAPSHOT-2014-05-01 becomes 4.0.0.SNAPSHOT-2014-05-01
'Bundle-Version': version.replaceFirst("-", ".")) 'Bundle-Version': version.replaceFirst("-", "."),
'Built-Date': new Date(),
'Built-JDK': System.getProperty('java.version'),
'Built-Gradle': gradle.gradleVersion,
'Built-By': System.getProperty('user.name')
)
} }
eclipse { eclipse {
@ -73,6 +79,9 @@ task javadocAll(type: Javadoc) {
// Might need a classpath // Might need a classpath
classpath = files(subprojects.collect {project -> classpath = files(subprojects.collect {project ->
project.sourceSets.main.compileClasspath}) project.sourceSets.main.compileClasspath})
options.linkSource = true
options.use = true
options.links = ["http://docs.oracle.com/javase/$sourceCompatibility/docs/api/"] as String[]
} }
import org.apache.tools.ant.filters.ReplaceTokens import org.apache.tools.ant.filters.ReplaceTokens
@ -100,6 +109,9 @@ jar {
enabled = false enabled = false
} }
// Disable upload archives for the root project
uploadArchives.enabled = false
description = """\ description = """\
Smack ${version} Smack ${version}
${oneLineDesc}.""" ${oneLineDesc}."""
@ -157,7 +169,7 @@ subprojects {
issueManagement { issueManagement {
system 'JIRA' system 'JIRA'
url 'http://issues.igniterealtime.org/browse/SMACK' url 'https://igniterealtime.org/issues/browse/SMACK'
} }
distributionManagement { distributionManagement {
@ -195,7 +207,9 @@ subprojects {
rootProject.distributionZip { rootProject.distributionZip {
dependsOn build dependsOn build
from(buildDir) { from(buildDir) {
include "$libsDirName/**" include "$libsDirName/*${version}.jar"
include "$libsDirName/*${version}-javadoc.jar"
include "$libsDirName/*${version}-sources.jar"
} }
} }
signing { signing {
@ -204,7 +218,7 @@ subprojects {
} }
} }
['smack-extensions', 'smack-experimental', 'smack-legacy'].each { name -> ['smack-resolver-javax', 'smack-extensions', 'smack-experimental', 'smack-legacy'].each { name ->
project(":$name") { project(":$name") {
jar { jar {
manifest { manifest {

View File

@ -16,8 +16,8 @@ Debugging with Smack
<p> <p>
Smack includes two built-in debugging consoles that will let you track all XML traffic between Smack includes two built-in debugging consoles that will let you track all XML traffic between
the client and server. A <a href="#lite">lite debugger</a> which is part of the <tt>smack.jar</tt> the client and server. A <a href="#lite">lite debugger</a> which is part of the <tt>smack-core.jar</tt>
and an <a href="#enhanced">enhanced debugger</a> contained in <tt>smackx-debug.jar</tt>. and an <a href="#enhanced">enhanced debugger</a> contained in <tt>smack-debug.jar</tt>.
</p> </p>
<p> <p>
@ -56,7 +56,7 @@ Smack uses the following logic to decide the debugger console to use:
<li>If step 1 fails then Smack will try to use the enhanced debugger. The <li>If step 1 fails then Smack will try to use the enhanced debugger. The
file <tt>smackx-debug.jar</tt> contains the enhanced debugger. Therefore you will need file <tt>smackx-debug.jar</tt> contains the enhanced debugger. Therefore you will need
to place the jar file in the classpath. For situations where space is an issue you to place the jar file in the classpath. For situations where space is an issue you
may want to only deploy <tt>smack.jar</tt> in which case the enhanced debugger won't be may want to only deploy <tt>smack-core.jar</tt> in which case the enhanced debugger won't be
available.<p> available.<p>
<li>The last option if the previous two steps fail is to use the lite debugger. The lite <li>The last option if the previous two steps fail is to use the lite debugger. The lite

View File

@ -15,7 +15,7 @@ tasks such as registration and searching using Forms.
<li><a href="#gather">Create a Form to fill out</a></li> <li><a href="#gather">Create a Form to fill out</a></li>
<li><a href="#fillout">Answer a Form</a></li> <li><a href="#fillout">Answer a Form</a></li>
</ul> </ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0004.html">JEP-4</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0004.html">XEP-4</a>
<hr> <hr>

View File

@ -18,7 +18,7 @@ entities. Follow these links to learn how to use this extension.
<li><a href="#discoinfo">Discover information about an XMPP entity</a></li> <li><a href="#discoinfo">Discover information about an XMPP entity</a></li>
<li><a href="#discopublish">Publish publicly available items</a></li> <li><a href="#discopublish">Publish publicly available items</a></li>
</ul> </ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0030.html">JEP-30</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0030.html">XEP-30</a>
<hr> <hr>

View File

@ -17,10 +17,10 @@ The file transfer extension allows the user to transmit and receive files.
<li><a href="#recievefile">Recieving a file from another user</a></li> <li><a href="#recievefile">Recieving a file from another user</a></li>
<li><a href="#monitorprogress">Monitoring the progress of a file transfer</a></li> <li><a href="#monitorprogress">Monitoring the progress of a file transfer</a></li>
</ul> </ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0095.html">JEP-95</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0095.html">XEP-95</a>
<a href="http://www.jabber.org/jeps/jep-0096.html">JEP-96</a> <a href="http://www.xmpp.org/extensions/xep-0096.html">XEP-96</a>
<a href="http://www.jabber.org/jeps/jep-0065.html">JEP-65</a> <a href="http://www.xmpp.org/extensions/xep-0065.html">XEP-65</a>
<a href="http://www.jabber.org/jeps/jep-0047.html">JEP-47</a> <a href="http://www.xmpp.org/extensions/xep-0047.html">XEP-47</a>
<hr> <hr>
<div class="subheader"><a name="sendfile">Send a file to another user</a></div><p> <div class="subheader"><a name="sendfile">Send a file to another user</a></div><p>

View File

@ -32,17 +32,17 @@
</tr> </tr>
<tr> <tr>
<td><a href="messageevents.html">Message Events</a></td> <td><a href="messageevents.html">Message Events</a></td>
<td><a href="http://www.xmpp.org/extensions/xep-0022.html">JEP-0022</a></td> <td><a href="http://www.xmpp.org/extensions/xep-0022.html">XEP-0022</a></td>
<td>Requests and responds to message events.</td> <td>Requests and responds to message events.</td>
</tr> </tr>
<tr> <tr>
<td><a href="dataforms.html">Data Forms</a></td> <td><a href="dataforms.html">Data Forms</a></td>
<td><a href="http://www.xmpp.org/extensions/xep-0004.html">JEP-0004</a></td> <td><a href="http://www.xmpp.org/extensions/xep-0004.html">XEP-0004</a></td>
<td>Allows to gather data using Forms.</td> <td>Allows to gather data using Forms.</td>
</tr> </tr>
<tr> <tr>
<td><a href="muc.html">Multi User Chat</a></td> <td><a href="muc.html">Multi User Chat</a></td>
<td><a href="http://www.xmpp.org/extensions/xep-0045.html">JEP-0045</a></td> <td><a href="http://www.xmpp.org/extensions/xep-0045.html">XEP-0045</a></td>
<td>Allows configuration of, participation in, and administration of individual text-based conference rooms.</td> <td>Allows configuration of, participation in, and administration of individual text-based conference rooms.</td>
</tr> </tr>
<tr> <tr>

View File

@ -17,8 +17,8 @@ users to a group chat room.
</ul> </ul>
<p> <p>
<b>JEP related:</b> N/A -- this protocol is outdated now that the Multi-User Chat (MUC) JEP is available <b>XEP related:</b> N/A -- this protocol is outdated now that the Multi-User Chat (MUC) XEP is available
(<a href="http://www.jabber.org/jeps/jep-0045.html">JEP-45</a>). However, most (<a href="http://www.xmpp.org/extensions/xep-0045.html">XEP-45</a>). However, most
existing clients still use this older protocol. Once MUC support becomes more existing clients still use this older protocol. Once MUC support becomes more
widespread, this API may be deprecated. widespread, this API may be deprecated.

View File

@ -19,7 +19,7 @@ display, and composition of messages. There are three stages in this extension:<
<li><a href="#lstevnotreq">Reacting to Event Notification Requests</a></li> <li><a href="#lstevnotreq">Reacting to Event Notification Requests</a></li>
<li><a href="#lstevnot">Reacting to Event Notifications</a></li> <li><a href="#lstevnot">Reacting to Event Notifications</a></li>
</ul> </ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0022.html">JEP-22</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0022.html">XEP-22</a>
<hr> <hr>
<div class="subheader"><a name="reqevnot">Requesting Event Notifications</a></div><p> <div class="subheader"><a name="reqevnot">Requesting Event Notifications</a></div><p>
<b>Description</b><p> <b>Description</b><p>

View File

@ -22,7 +22,7 @@ Allows configuration of, participation in, and administration of individual text
<li><a href="#role">Manage role modifications</a></li> <li><a href="#role">Manage role modifications</a></li>
<li><a href="#afiliation">Manage affiliation modifications</a></li> <li><a href="#afiliation">Manage affiliation modifications</a></li>
</ul> </ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0045.html">JEP-45</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0045.html">XEP-45</a>
<hr> <hr>

View File

@ -19,7 +19,7 @@ XML namespace. Example private data:
&lt;/color&gt; &lt;/color&gt;
</pre><p> </pre><p>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0049.html">JEP-49</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0049.html">XEP-49</a>
<hr> <hr>

View File

@ -17,7 +17,7 @@ are received from other XMPP clients.
<li><a href="#riesendentry">Send a roster's entry</a></li> <li><a href="#riesendentry">Send a roster's entry</a></li>
<li><a href="#riercventry">Receive roster entries</a></li> <li><a href="#riercventry">Receive roster entries</a></li>
</ul> </ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0093.html">JEP-93</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0093.html">XEP-93</a>
<hr> <hr>

View File

@ -11,7 +11,7 @@
Supports a protocol that XMPP clients use to exchange their respective local Supports a protocol that XMPP clients use to exchange their respective local
times and time zones.<p> times and time zones.<p>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0090.html">JEP-90</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0090.html">XEP-90</a>
<hr> <hr>

View File

@ -18,7 +18,7 @@ XHTML messages:</p>
<li><a href="#xhtmlreceive">Receive an XHTML Message</a></li> <li><a href="#xhtmlreceive">Receive an XHTML Message</a></li>
<li><a href="#xhtmldiscover">Discover support for XHTML Messages</a></li> <li><a href="#xhtmldiscover">Discover support for XHTML Messages</a></li>
</ul> </ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0071.html">JEP-71</a> <b>XEP related:</b> <a href="http://www.xmpp.org/extensions/xep-0071.html">XEP-71</a>
<hr> <hr>

View File

@ -29,8 +29,8 @@ to be as small as possible. The library ships as several JAR files to provide mo
over which features applications require: over which features applications require:
<ul> <ul>
<li><tt>smack-core.jar</tt> -- provides core XMPP functionality and is the only <b>required</b> <li><tt>smack-core.jar</tt> -- provides core XMPP functionality. All XMPP features that are
library. All XMPP features that are part of the XMPP RFCs are included.</li> part of the XMPP RFCs are included.</li>
<li><tt>smack-extensions.jar</tt> -- support for many of the extensions (XEPs) defined <li><tt>smack-extensions.jar</tt> -- support for many of the extensions (XEPs) defined
by the XMPP Standards Foundation, including multi-user chat, file transfer, user search, etc. by the XMPP Standards Foundation, including multi-user chat, file transfer, user search, etc.
The extensions are documented in the <a href="extensions/index.html">extensions manual</a>.</li> The extensions are documented in the <a href="extensions/index.html">extensions manual</a>.</li>
@ -52,7 +52,6 @@ over which features applications require:
is enabled.</li> is enabled.</li>
</ul> </ul>
<p class="subheader">Configuration</p> <p class="subheader">Configuration</p>
Smack has an initialization process that involves 2 phases. Smack has an initialization process that involves 2 phases.
<ul> <ul>

View File

@ -28,7 +28,7 @@ Smack Key Advantages
can be accomplished in only a few lines of code: can be accomplished in only a few lines of code:
<div class="code"><pre> <div class="code"><pre>
Connection connection = <font color="navy"><b>new</b></font> XMPPConnection(<font color="green">"jabber.org"</font>); XMPPConnection connection = <font color="navy"><b>new</b></font> XMPPTCPConnection(<font color="green">"jabber.org"</font>);
connection.connect(); connection.connect();
connection.login(<font color="green">"mtucker"</font>, <font color="green">"password"</font>); connection.login(<font color="green">"mtucker"</font>, <font color="green">"password"</font>);
Chat chat = connection.getChatManager().createChat(<font color="green">"jsmith@jivesoftware.com"</font>, new MessageListener() { Chat chat = connection.getChatManager().createChat(<font color="green">"jsmith@jivesoftware.com"</font>, new MessageListener() {

View File

@ -55,9 +55,9 @@ possible, instructions are provided for both Unix/Linux and Windows users.
<p> <p>
<b><a name="javaSetup">Configure Java</a></b> <b><a name="javaSetup">Configure Java</a></b>
<ul> <ul>
Java 6 (JDK 1.6 or later) must be installed and setup on your machine. To test the installation, A Java Development Kit (JDK) must be installed and setup on your machine. To test the installation,
open a shell in a Unix or a MS-DOS prompt in Windows. Check your version of open a shell in a Unix or a MS-DOS prompt in Windows. Check your version of
Java with "java -version". Java with "javac -version".
If Java isn't installed, download a copy from the If Java isn't installed, download a copy from the
<a href="http://java.oracle.com/">Java website</a>. <a href="http://java.oracle.com/">Java website</a>.
</ul> </ul>

View File

@ -163,12 +163,11 @@ that can be found in the "documentation" directory included with this distributi
Further information can be found on the <a href="http://www.igniterealtime.org/projects/smack"> Further information can be found on the <a href="http://www.igniterealtime.org/projects/smack">
Smack website</a>. If you need help using or would like to make contributions or Smack website</a>. If you need help using or would like to make contributions or
fixes to the code, please visit the fixes to the code, please visit the
<a href="http://www.igniterealtime.org/forum/forum.jspa?forumID=39">online forum</a>. <a href="https://community.igniterealtime.org">online forum</a>.
<p><b>About the Distribution</b><p> <p><b>About the Distribution</b><p>
The <tt>smack.jar</tt> file in the main distribution folder is the only binary file The <tt>smack-core.jar</tt> file in the main distribution folder. The optional
required for embedding XMPP functionality into client applications. The optional
<tt>smack-extensions.jar</tt> contains the <a href="documentation/extensions/index.html">Smack extensions</a> <tt>smack-extensions.jar</tt> contains the <a href="documentation/extensions/index.html">Smack extensions</a>
while <tt>smack-debug.jar</tt> contains an enhanced debugger.<p> while <tt>smack-debug.jar</tt> contains an enhanced debugger.<p>
@ -176,6 +175,7 @@ while <tt>smack-debug.jar</tt> contains an enhanced debugger.<p>
View the <a href="changelog.html">changelog</a> for a list of changes since the View the <a href="changelog.html">changelog</a> for a list of changes since the
last release. last release.
If you are upgrading from Smack 3 to Smack 4, then please consult the <a href="https://community.igniterealtime.org/docs/DOC-2703">Smack 4 Readme and Upgrade Guide</a>
<p><b>License Agreements</b><p> <p><b>License Agreements</b><p>
<ul> <ul>

View File

@ -141,6 +141,129 @@ hr {
<div id="pageBody"> <div id="pageBody">
<h2>4.0.0 -- <span style="font-weight: normal;">2014-06-08</span></h2>
<h2> Sub-task
</h2>
<ul>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-399'>SMACK-399</a>] - Add support for Roster Versioning (was XEP-0237, now in RFC 6121)
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-400'>SMACK-400</a>] - Change xml-not-well-formed to not-well-formed
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-401'>SMACK-401</a>] - Remove &lt;invalid-id/&gt;
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-445'>SMACK-445</a>] - XMPPError class is based on deprecated XEP-0086
</li>
</ul>
<h2> Bug
</h2>
<ul>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-357'>SMACK-357</a>] - Error in SASL authentication when SASL authzid parameter is null
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-410'>SMACK-410</a>] - Any valid SSL server certificate can be used to perform a man-in-the-middle attack
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-411'>SMACK-411</a>] - ServiceDiscoveryManager identities should be non-static and kept in a Set to allow multiple identities as per XEP-30
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-414'>SMACK-414</a>] - Smack does not announce the support for XEP-54 aka vcard-temp
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-427'>SMACK-427</a>] - Typo in code - StreamInitiation.setSesssionID()
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-467'>SMACK-467</a>] - Don&#39;t use the default locale for machine-readable output, use Locale.US instead
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-531'>SMACK-531</a>] - Add missing namespace attribute to XHTML-IM body tags
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-533'>SMACK-533</a>] - Smack should prevent IQ response spoofing
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-535'>SMACK-535</a>] - jul.properties should only configure the &#39;org.igniterealtime&#39; namespace
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-538'>SMACK-538</a>] - ParseRoster does not check the sender of the roster and for pending roster queries
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-541'>SMACK-541</a>] - XHTMLExtensionProvider relies on incorrect behavior of MXParser, violating the contract of the XMLPullParser interface
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-543'>SMACK-543</a>] - packet.Time is not thread-safe
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-546'>SMACK-546</a>] - PubSub&#39;s Item needs to escape its XML payload
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-548'>SMACK-548</a>] - PingManager notifies pingFailedListeners multiple times
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-551'>SMACK-551</a>] - ChatManager throws NPE, when Message has no &#39;from&#39; attribute
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-554'>SMACK-554</a>] - Memory leak in BookmarkManager
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-555'>SMACK-555</a>] - VCardProvider should consider some elements as optional
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-558'>SMACK-558</a>] - connect() must wait until the stream features have been parsed
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-559'>SMACK-559</a>] - Roster entries without a group are not updated
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-560'>SMACK-560</a>] - Race condition in PacketWriter
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-567'>SMACK-567</a>] - XMPPConnection leaks listenerExecutor ExecutorService
</li>
</ul>
<h2> Improvement
</h2>
<ul>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-343'>SMACK-343</a>] - Make Smack jar an OSGi bundle.
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-356'>SMACK-356</a>] - There is no way to reliably end a Chat and have a new one created.
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-454'>SMACK-454</a>] - Follow XEP-0170 recommendation: Compression before Resource Binding
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-459'>SMACK-459</a>] - Add option to configure the default identity in ServiceDiscoveryManager
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-465'>SMACK-465</a>] - Replace custom wrapped Throwable in XMPPException with Exception.cause
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-468'>SMACK-468</a>] - Don&#39;t throw an IOException in IBBStreams when the stream got closed by the remote
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-536'>SMACK-536</a>] - JUL Loggers should become final
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-537'>SMACK-537</a>] - Move XMPP Ping code to smackx, add keep-alive functionality to PingManager
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-545'>SMACK-545</a>] - Change API to the style mentioned in Smack&#39;s Code Guidelines
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-547'>SMACK-547</a>] - Consistent behavior for &quot;from&quot; attribute on outgoing stanzas
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-556'>SMACK-556</a>] - Make ConnectionConfigration getters public
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-557'>SMACK-557</a>] - Provide a MultiUserChat method to create *or* join a room
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-568'>SMACK-568</a>] - Don&#39;t exclude groupchat messages without body element in MultiUserChat MessageListeners
</li>
</ul>
<h2> New Feature
</h2>
<ul>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-53'>SMACK-53</a>] - Add support for XEP-0092: Software Version
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-71'>SMACK-71</a>] - Create new FromFilter that checks for exact matching
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-187'>SMACK-187</a>] - Add HTTP Binding support (BOSH / XEP-0124)
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-265'>SMACK-265</a>] - Move to a newer build process with artifacts published to maven central repo
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-426'>SMACK-426</a>] - Improve XMPPException
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-544'>SMACK-544</a>] - Add support for XEP-0079: Advanced Message Processing
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-552'>SMACK-552</a>] - Add support for &quot;HTTP over XMPP transport&quot; aka. XEP-0332
</li>
</ul>
<h2> Task
</h2>
<ul>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-371'>SMACK-371</a>] - Some MUC tasks are using stanza&#39;s as defined in an older version of the spec. Fails to work on some servers.
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-432'>SMACK-432</a>] - Code cleanup of deprecated methods
</li>
<li>[<a href='https://igniterealtime.org/issues/browse/SMACK-446'>SMACK-446</a>] - Remove non-SASL authentication code
</li>
</ul>
<h2>3.4.1 -- <span style="font-weight: normal;">Feb 9, 2014</span></h2> <h2>3.4.1 -- <span style="font-weight: normal;">Feb 9, 2014</span></h2>
<h2>Bug</h2> <h2>Bug</h2>

View File

@ -4,6 +4,7 @@ include 'smack-core',
'smack-experimental', 'smack-experimental',
'smack-debug', 'smack-debug',
'smack-resolver-dnsjava', 'smack-resolver-dnsjava',
'smack-resolver-minidns',
'smack-resolver-javax', 'smack-resolver-javax',
'smack-compression-jzlib', 'smack-compression-jzlib',
'smack-legacy', 'smack-legacy',

View File

@ -35,6 +35,7 @@ task dnsJar(type: Jar) {
from sourceSets.main.output from sourceSets.main.output
include('org/jivesoftware/smack/util/dns/**') include('org/jivesoftware/smack/util/dns/**')
include('org/jivesoftware/smack/util/DNSUtil.class') include('org/jivesoftware/smack/util/DNSUtil.class')
include('org/jivesoftware/smack/initializer/**')
} }
artifacts { artifacts {

View File

@ -17,8 +17,10 @@
package org.jivesoftware.smack; package org.jivesoftware.smack;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -34,6 +36,7 @@ import org.jivesoftware.smack.compression.XMPPInputOutputStream;
import org.jivesoftware.smack.initializer.SmackInitializer; import org.jivesoftware.smack.initializer.SmackInitializer;
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.DNSUtil;
import org.jivesoftware.smack.util.FileUtils; import org.jivesoftware.smack.util.FileUtils;
import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -49,8 +52,7 @@ import org.xmlpull.v1.XmlPullParserException;
* via the API will override settings in the configuration file. * via the API will override settings in the configuration file.
* </ul> * </ul>
* *
* Configuration settings are stored in org.jivesoftware.smack/smack-config.xml (typically inside the * Configuration settings are stored in org.jivesoftware.smack/smack-config.xml.
* smack.jar file).
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
@ -95,10 +97,13 @@ public final class SmackConfiguration {
static { static {
String smackVersion; String smackVersion;
try { try {
InputStream is = FileUtils.getStreamForUrl("classpath:org.jivesoftware.smack/version", null); BufferedReader reader = new BufferedReader(new InputStreamReader(FileUtils.getStreamForUrl("classpath:org.jivesoftware.smack/version", null)));
byte[] buf = new byte[1024]; smackVersion = reader.readLine();
is.read(buf); try {
smackVersion = new String(buf, "UTF-8"); reader.close();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "IOException closing stream", e);
}
} catch(Exception e) { } catch(Exception e) {
LOGGER.log(Level.SEVERE, "Could not determine Smack version", e); LOGGER.log(Level.SEVERE, "Could not determine Smack version", e);
smackVersion = "unkown"; smackVersion = "unkown";
@ -162,6 +167,9 @@ public final class SmackConfiguration {
catch (Exception e) { catch (Exception e) {
// Ignore. // Ignore.
} }
// Initialize the DNS resolvers
DNSUtil.init();
} }
/** /**

View File

@ -134,6 +134,12 @@ public class SmackException extends Exception {
} }
} }
/**
* ConnectionException is thrown if Smack is unable to connect to all hosts of a given XMPP
* service. The failed hosts can be retrieved with
* {@link ConnectionException#getFailedAddresses()}, which will have the exception causing the
* connection failure set and retrievable with {@link HostAddress#getException()}.
*/
public static class ConnectionException extends SmackException { public static class ConnectionException extends SmackException {
/** /**

View File

@ -16,6 +16,8 @@
*/ */
package org.jivesoftware.smack.util; package org.jivesoftware.smack.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
@ -39,6 +41,31 @@ public class DNSUtil {
private static final Logger LOGGER = Logger.getLogger(DNSUtil.class.getName()); private static final Logger LOGGER = Logger.getLogger(DNSUtil.class.getName());
private static DNSResolver dnsResolver = null; private static DNSResolver dnsResolver = null;
/**
* Initializes DNSUtil. This method is automatically called by SmackConfiguration, you don't
* have to call it manually.
*/
public static void init() {
final String[] RESOLVERS = new String[] { "javax.JavaxResolver", "minidns.MiniDnsResolver",
"dnsjava.DNSJavaResolver" };
for (String resolver :RESOLVERS) {
DNSResolver availableResolver = null;
String resolverFull = "org.jivesoftware.smack.util.dns" + resolver;
try {
Class<?> resolverClass = Class.forName(resolverFull);
Method getInstanceMethod = resolverClass.getMethod("getInstance");
availableResolver = (DNSResolver) getInstanceMethod.invoke(null);
if (availableResolver != null) {
setDNSResolver(availableResolver);
break;
}
}
catch (ClassNotFoundException|NoSuchMethodException|SecurityException|IllegalAccessException|IllegalArgumentException|InvocationTargetException e) {
LOGGER.log(Level.FINE, "Exception on init", e);
}
}
}
/** /**
* Set the DNS resolver that should be used to perform DNS lookups. * Set the DNS resolver that should be used to perform DNS lookups.
* *

View File

@ -22,13 +22,20 @@ import java.util.List;
public class LazyStringBuilder implements Appendable, CharSequence { public class LazyStringBuilder implements Appendable, CharSequence {
private final List<CharSequence> list; private final List<CharSequence> list;
private String cache;
private void invalidateCache() {
cache = null;
}
public LazyStringBuilder() { public LazyStringBuilder() {
list = new ArrayList<CharSequence>(20); list = new ArrayList<CharSequence>(20);
} }
public LazyStringBuilder append(LazyStringBuilder lsb) { public LazyStringBuilder append(LazyStringBuilder lsb) {
list.addAll(lsb.list); list.addAll(lsb.list);
invalidateCache();
return this; return this;
} }
@ -36,6 +43,7 @@ public class LazyStringBuilder implements Appendable, CharSequence {
public LazyStringBuilder append(CharSequence csq) { public LazyStringBuilder append(CharSequence csq) {
assert csq != null; assert csq != null;
list.add(csq); list.add(csq);
invalidateCache();
return this; return this;
} }
@ -43,17 +51,22 @@ public class LazyStringBuilder implements Appendable, CharSequence {
public LazyStringBuilder append(CharSequence csq, int start, int end) { public LazyStringBuilder append(CharSequence csq, int start, int end) {
CharSequence subsequence = csq.subSequence(start, end); CharSequence subsequence = csq.subSequence(start, end);
list.add(subsequence); list.add(subsequence);
invalidateCache();
return this; return this;
} }
@Override @Override
public LazyStringBuilder append(char c) { public LazyStringBuilder append(char c) {
list.add(Character.toString(c)); list.add(Character.toString(c));
invalidateCache();
return this; return this;
} }
@Override @Override
public int length() { public int length() {
if (cache != null) {
return cache.length();
}
int length = 0; int length = 0;
for (CharSequence csq : list) { for (CharSequence csq : list) {
length += csq.length(); length += csq.length();
@ -63,6 +76,9 @@ public class LazyStringBuilder implements Appendable, CharSequence {
@Override @Override
public char charAt(int index) { public char charAt(int index) {
if (cache != null) {
return cache.charAt(index);
}
for (CharSequence csq : list) { for (CharSequence csq : list) {
if (index < csq.length()) { if (index < csq.length()) {
return csq.charAt(index); return csq.charAt(index);
@ -80,10 +96,13 @@ public class LazyStringBuilder implements Appendable, CharSequence {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(length()); if (cache == null) {
for (CharSequence csq : list) { StringBuilder sb = new StringBuilder(length());
sb.append(csq); for (CharSequence csq : list) {
sb.append(csq);
}
cache = sb.toString();
} }
return sb.toString(); return cache;
} }
} }

View File

@ -134,6 +134,24 @@ public class PacketParserUtils {
} }
} }
/**
* Creates a new XmlPullParser suitable for parsing XMPP. This means in particular that
* FEATURE_PROCESS_NAMESPACES is enabled.
* <p>
* Note that not all XmlPullParser implementations will return a String on
* <code>getText()</code> if the parser is on START_TAG or END_TAG. So you must not rely on this
* behavior when using the parser.
* </p>
*
* @return A suitable XmlPullParser for XMPP parsing
* @throws XmlPullParserException
*/
public static XmlPullParser newXmppParser() throws XmlPullParserException {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
return parser;
}
/** /**
* Parses a message packet. * Parses a message packet.
* *
@ -179,7 +197,7 @@ public class PacketParserUtils {
xmlLang = defaultLanguage; xmlLang = defaultLanguage;
} }
String subject = parseContent(parser); String subject = parseElementText(parser);
if (message.getSubject(xmlLang) == null) { if (message.getSubject(xmlLang) == null) {
message.addSubject(xmlLang, subject); message.addSubject(xmlLang, subject);
@ -191,8 +209,8 @@ public class PacketParserUtils {
xmlLang = defaultLanguage; xmlLang = defaultLanguage;
} }
String body = parseContent(parser); String body = parseElementText(parser);
if (message.getBody(xmlLang) == null) { if (message.getBody(xmlLang) == null) {
message.addBody(xmlLang, body); message.addBody(xmlLang, body);
} }
@ -223,29 +241,156 @@ public class PacketParserUtils {
} }
/** /**
* Returns the content of a tag as string regardless of any tags included. * Returns the textual content of an element as String.
* <p>
* The parser must be positioned on a START_TAG of an element which MUST NOT contain Mixed
* Content (as defined in XML 3.2.2), or else an XmlPullParserException will be thrown.
* </p>
* This method is used for the parts where the XMPP specification requires elements that contain
* only text or are the empty element.
*
* @param parser
* @return the textual content of the element as String
* @throws XmlPullParserException
* @throws IOException
*/
public static String parseElementText(XmlPullParser parser) throws XmlPullParserException, IOException {
assert (parser.getEventType() == XmlPullParser.START_TAG);
String res;
if (parser.isEmptyElementTag()) {
res = "";
}
else {
// Advance to the text of the Element
int event = parser.next();
if (event != XmlPullParser.TEXT) {
throw new XmlPullParserException(
"Non-empty element tag not followed by text, while Mixed Content (XML 3.2.2) is disallowed");
}
res = parser.getText();
event = parser.next();
if (event != XmlPullParser.END_TAG) {
throw new XmlPullParserException(
"Non-empty element tag contains child-elements, while Mixed Content (XML 3.2.2) is disallowed");
}
}
return res;
}
/**
* Returns the current element as string.
* <p>
* The parser must be positioned on START_TAG.
* </p>
* Note that only the outermost namespace attributes ("xmlns") will be returned, not nested ones.
*
* @param parser the XML pull parser
* @return the element as string
* @throws XmlPullParserException
* @throws IOException
*/
public static String parseElement(XmlPullParser parser) throws XmlPullParserException, IOException {
assert(parser.getEventType() == XmlPullParser.START_TAG);
return parseContentDepth(parser, parser.getDepth());
}
/**
* Returns the content of a element as string.
* <p>
* The parser must be positioned on the START_TAG of the element which content is going to get
* returned. If the current element is the empty element, then the empty string is returned. If
* it is a element which contains just text, then just the text is returned. If it contains
* nested elements (and text), then everything from the current opening tag to the corresponding
* closing tag of the same depth is returned as String.
* </p>
* Note that only the outermost namespace attributes ("xmlns") will be returned, not nested ones.
* *
* @param parser the XML pull parser * @param parser the XML pull parser
* @return the content of a tag as string * @return the content of a tag as string
* @throws XmlPullParserException if parser encounters invalid XML * @throws XmlPullParserException if parser encounters invalid XML
* @throws IOException if an IO error occurs * @throws IOException if an IO error occurs
*/ */
private static String parseContent(XmlPullParser parser) public static String parseContent(XmlPullParser parser)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
int parserDepth = parser.getDepth(); assert(parser.getEventType() == XmlPullParser.START_TAG);
return parseContentDepth(parser, parserDepth); if (parser.isEmptyElementTag()) {
return "";
}
// Advance the parser, since we want to parse the content of the current element
parser.next();
return parseContentDepth(parser, parser.getDepth());
} }
/**
* Returns the content from the current position of the parser up to the closing tag of the
* given depth. Note that only the outermost namespace attributes ("xmlns") will be returned,
* not nested ones.
* <p>
* This method is able to parse the content with MX- and KXmlParser. In order to achieve
* this some trade-off has to be make, because KXmlParser does not support xml-roundtrip (ie.
* return a String on getText() on START_TAG and END_TAG). We are therefore required to work
* around this limitation, which results in only partial support for XML namespaces ("xmlns"):
* Only the outermost namespace of elements will be included in the resulting String.
* </p>
*
* @param parser
* @param depth
* @return the content of the current depth
* @throws XmlPullParserException
* @throws IOException
*/
public static String parseContentDepth(XmlPullParser parser, int depth) throws XmlPullParserException, IOException { public static String parseContentDepth(XmlPullParser parser, int depth) throws XmlPullParserException, IOException {
StringBuilder content = new StringBuilder(); XmlStringBuilder xml = new XmlStringBuilder();
while (!(parser.next() == XmlPullParser.END_TAG && parser.getDepth() == depth)) { int event = parser.getEventType();
String text = parser.getText(); boolean isEmptyElement = false;
if (text == null) { // XmlPullParser reports namespaces in nested elements even if *only* the outer ones defines
throw new IllegalStateException("Parser should never return 'null' on getText() here"); // it. This 'flag' ensures that when a namespace is set for an element, it won't be set again
// in a nested element. It's an ugly workaround that has the potential to break things.
String namespaceElement = null;;
while (true) {
if (event == XmlPullParser.START_TAG) {
xml.halfOpenElement(parser.getName());
if (namespaceElement == null) {
String namespace = parser.getNamespace();
if (StringUtils.isNotEmpty(namespace)) {
xml.attribute("xmlns", namespace);
namespaceElement = parser.getName();
}
}
for (int i = 0; i < parser.getAttributeCount(); i++) {
xml.attribute(parser.getAttributeName(i), parser.getAttributeValue(i));
}
if (parser.isEmptyElementTag()) {
xml.closeEmptyElement();
isEmptyElement = true;
}
else {
xml.rightAngelBracket();
}
} }
content.append(text); else if (event == XmlPullParser.END_TAG) {
if (isEmptyElement) {
// Do nothing as the element was already closed, just reset the flag
isEmptyElement = false;
}
else {
xml.closeElement(parser.getName());
}
if (namespaceElement != null && namespaceElement.equals(parser.getName())) {
// We are on the closing tag, which defined the namespace as starting tag, reset the 'flag'
namespaceElement = null;
}
if (parser.getDepth() <= depth) {
// Abort parsing, we are done
break;
}
}
else if (event == XmlPullParser.TEXT) {
xml.append(parser.getText());
}
event = parser.next();
} }
return content.toString(); return xml.toString();
} }
/** /**

View File

@ -174,6 +174,25 @@ public class XmlStringBuilder implements Appendable, CharSequence {
return this; return this;
} }
public XmlStringBuilder emptyElement(String element) {
halfOpenElement(element);
return closeEmptyElement();
}
public XmlStringBuilder condEmptyElement(boolean condition, String element) {
if (condition) {
emptyElement(element);
}
return this;
}
public XmlStringBuilder condAttribute(boolean condition, String name, String value) {
if (condition) {
attribute(name, value);
}
return this;
}
@Override @Override
public XmlStringBuilder append(CharSequence csq) { public XmlStringBuilder append(CharSequence csq) {
assert csq != null; assert csq != null;
@ -213,4 +232,18 @@ public class XmlStringBuilder implements Appendable, CharSequence {
public String toString() { public String toString() {
return sb.toString(); return sb.toString();
} }
@Override
public boolean equals(Object other) {
if (!(other instanceof XmlStringBuilder)) {
return false;
}
XmlStringBuilder otherXmlStringBuilder = (XmlStringBuilder) other;
return toString().equals(otherXmlStringBuilder.toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
} }

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2013 Florian Schmaus * Copyright © 2013-2014 Florian Schmaus
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,9 +16,11 @@
*/ */
package org.jivesoftware.smack.util.dns; package org.jivesoftware.smack.util.dns;
import org.jivesoftware.smack.SmackException.ConnectionException;
public class HostAddress { public class HostAddress {
private String fqdn; private final String fqdn;
private int port; private final int port;
private Exception exception; private Exception exception;
/** /**
@ -28,16 +30,8 @@ public class HostAddress {
* @throws IllegalArgumentException If the fqdn is null. * @throws IllegalArgumentException If the fqdn is null.
*/ */
public HostAddress(String fqdn) { public HostAddress(String fqdn) {
if (fqdn == null)
throw new IllegalArgumentException("FQDN is null");
if (fqdn.charAt(fqdn.length() - 1) == '.') {
this.fqdn = fqdn.substring(0, fqdn.length() - 1);
}
else {
this.fqdn = fqdn;
}
// Set port to the default port for XMPP client communication // Set port to the default port for XMPP client communication
this.port = 5222; this(fqdn, 5222);
} }
/** /**
@ -48,11 +42,17 @@ public class HostAddress {
* @throws IllegalArgumentException If the fqdn is null or port is out of valid range (0 - 65535). * @throws IllegalArgumentException If the fqdn is null or port is out of valid range (0 - 65535).
*/ */
public HostAddress(String fqdn, int port) { public HostAddress(String fqdn, int port) {
this(fqdn); if (fqdn == null)
throw new IllegalArgumentException("FQDN is null");
if (port < 0 || port > 65535) if (port < 0 || port > 65535)
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Port must be a 16-bit unsiged integer (i.e. between 0-65535. Port was: " + port); "Port must be a 16-bit unsiged integer (i.e. between 0-65535. Port was: " + port);
if (fqdn.charAt(fqdn.length() - 1) == '.') {
this.fqdn = fqdn.substring(0, fqdn.length() - 1);
}
else {
this.fqdn = fqdn;
}
this.port = port; this.port = port;
} }
@ -68,6 +68,17 @@ public class HostAddress {
this.exception = e; this.exception = e;
} }
/**
* Retrieve the Exception that caused a connection failure to this HostAddress. Every
* HostAddress found in {@link ConnectionException} will have an Exception set,
* which can be retrieved with this method.
*
* @return the Exception causing this HostAddress to fail
*/
public Exception getException() {
return this.exception;
}
@Override @Override
public String toString() { public String toString() {
return fqdn + ":" + port; return fqdn + ":" + port;

View File

@ -19,7 +19,6 @@ package org.jivesoftware.smack;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.StringReader;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@ -31,11 +30,11 @@ import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.RosterPacket.Item; import org.jivesoftware.smack.packet.RosterPacket.Item;
import org.jivesoftware.smack.packet.RosterPacket.ItemType; import org.jivesoftware.smack.packet.RosterPacket.ItemType;
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;
import org.junit.Test; import org.junit.Test;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
/** /**
@ -315,8 +314,6 @@ public class RosterTest {
final String contactJID = "nurse@example.com"; final String contactJID = "nurse@example.com";
final Roster roster = connection.getRoster(); final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster); assertNotNull("Can't get the roster from the provided connection!", roster);
final XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("<iq id=\"rostertest1\" type=\"set\" ") sb.append("<iq id=\"rostertest1\" type=\"set\" ")
.append("to=\"").append(connection.getUser()).append("\">") .append("to=\"").append(connection.getUser()).append("\">")
@ -324,8 +321,7 @@ public class RosterTest {
.append("<item jid=\"").append(contactJID).append("\"/>") .append("<item jid=\"").append(contactJID).append("\"/>")
.append("</query>") .append("</query>")
.append("</iq>"); .append("</iq>");
parser.setInput(new StringReader(sb.toString())); final XmlPullParser parser = TestUtils.getIQParser(sb.toString());
parser.next();
final IQ rosterPush = PacketParserUtils.parseIQ(parser, connection); final IQ rosterPush = PacketParserUtils.parseIQ(parser, connection);
initRoster(connection, roster); initRoster(connection, roster);
rosterListener.reset(); rosterListener.reset();
@ -449,8 +445,6 @@ public class RosterTest {
final String contactJID = "nurse@example.com"; final String contactJID = "nurse@example.com";
final Roster roster = connection.getRoster(); final Roster roster = connection.getRoster();
assertNotNull("Can't get the roster from the provided connection!", roster); assertNotNull("Can't get the roster from the provided connection!", roster);
final XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("<iq id=\"rostertest2\" type=\"set\" ") sb.append("<iq id=\"rostertest2\" type=\"set\" ")
.append("to=\"").append(connection.getUser()).append("\">") .append("to=\"").append(connection.getUser()).append("\">")
@ -460,8 +454,7 @@ public class RosterTest {
.append("</item>") .append("</item>")
.append("</query>") .append("</query>")
.append("</iq>"); .append("</iq>");
parser.setInput(new StringReader(sb.toString())); final XmlPullParser parser = TestUtils.getIQParser(sb.toString());
parser.next();
final IQ rosterPush = PacketParserUtils.parseIQ(parser, connection); final IQ rosterPush = PacketParserUtils.parseIQ(parser, connection);
initRoster(connection, roster); initRoster(connection, roster);
rosterListener.reset(); rosterListener.reset();

View File

@ -23,6 +23,7 @@ import org.jivesoftware.smack.SmackException;
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;
@ -34,7 +35,7 @@ public class ParsingExceptionTest {
private final static String EXTENSION2 = private final static String EXTENSION2 =
"<extension2 xmlns='namespace'>" + "<extension2 xmlns='namespace'>" +
"<bar node='testNode'>" + "<bar node='testNode'>" +
"<i id='testid1' >" + "<i id='testid1'>" +
"</i>" + "</i>" +
"</bar>" + "</bar>" +
"</extension2>"; "</extension2>";
@ -51,12 +52,14 @@ public class ParsingExceptionTest {
@Test @Test
public void consumeUnparsedInput() throws Exception { public void consumeUnparsedInput() throws Exception {
XmlPullParser parser = PacketParserUtils.getParserFor( final String MESSAGE_EXCEPTION_ELEMENT =
"<" + ThrowException.ELEMENT + " xmlns='" + ThrowException.NAMESPACE + "'>" +
"<nothingInHere>" +
"</nothingInHere>" +
"</" + ThrowException.ELEMENT + ">";
XmlPullParser parser = TestUtils.getMessageParser(
"<message from='user@server.example' to='francisco@denmark.lit' id='foo'>" + "<message from='user@server.example' to='francisco@denmark.lit' id='foo'>" +
"<" + ThrowException.ELEMENT + " xmlns='" + ThrowException.NAMESPACE + "'>" + MESSAGE_EXCEPTION_ELEMENT +
"<nothingInHere>" +
"</nothingInHere>" +
"</" + ThrowException.ELEMENT + ">" +
EXTENSION2 + EXTENSION2 +
"</message>"); "</message>");
int parserDepth = parser.getDepth(); int parserDepth = parser.getDepth();
@ -67,8 +70,7 @@ public class ParsingExceptionTest {
content = PacketParserUtils.parseContentDepth(parser, parserDepth); content = PacketParserUtils.parseContentDepth(parser, parserDepth);
} }
assertNotNull(content); assertNotNull(content);
assertEquals(content, "<nothingInHere></nothingInHere>" + "</" + ThrowException.ELEMENT + ">" + EXTENSION2); assertEquals(MESSAGE_EXCEPTION_ELEMENT + EXTENSION2 + "</message>", content);
} }
static class ThrowException implements PacketExtensionProvider { static class ThrowException implements PacketExtensionProvider {

View File

@ -0,0 +1,72 @@
/**
*
* Copyright 2013 Robin Collier
*
* 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.smack.test.util;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
final public class TestUtils {
private TestUtils() {
}
public static XmlPullParser getIQParser(String stanza) {
return getParser(stanza, "iq");
}
public static XmlPullParser getMessageParser(String stanza) {
return getParser(stanza, "message");
}
public static XmlPullParser getPresenceParser(String stanza) {
return getParser(stanza, "presence");
}
public static XmlPullParser getParser(String string, String startTag) {
return getParser(new StringReader(string), startTag);
}
public static XmlPullParser getParser(Reader reader, String startTag) {
XmlPullParser parser;
try {
parser = PacketParserUtils.newXmppParser();
parser.setInput(reader);
if (startTag == null) {
return parser;
}
boolean found = false;
while (!found) {
if ((parser.next() == XmlPullParser.START_TAG) && parser.getName().equals(startTag))
found = true;
}
if (!found)
throw new IllegalArgumentException("Can not find start tag '" + startTag + "'");
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return parser;
}
}

View File

@ -27,12 +27,12 @@ import static org.junit.Assert.fail;
import java.util.Locale; import java.util.Locale;
import java.util.Properties; import java.util.Properties;
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.Diff; import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier; import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
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.junit.Test; import org.junit.Test;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@ -653,7 +653,13 @@ public class PacketParserUtilsTest {
} }
@Test /**
* RFC6121 5.2.3 explicitly disallows mixed content in <body/> elements. Make sure that we throw
* an exception if we encounter such an element.
*
* @throws Exception
*/
@Test(expected=XmlPullParserException.class)
public void invalidMessageBodyContainingTagTest() throws Exception { public void invalidMessageBodyContainingTagTest() throws Exception {
String control = XMLBuilder.create("message") String control = XMLBuilder.create("message")
.a("from", "romeo@montague.lit/orchard") .a("from", "romeo@montague.lit/orchard")
@ -667,23 +673,10 @@ public class PacketParserUtilsTest {
.a("style", "font-weight: bold;") .a("style", "font-weight: bold;")
.t("Bad Message Body") .t("Bad Message Body")
.asString(outputProperties); .asString(outputProperties);
try { Message message = (Message) PacketParserUtils.parseMessage(TestUtils.getMessageParser(control));
Message message = (Message) PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(control));
String body = "<span style=\"font-weight: bold;\">" fail("Should throw exception. Instead got message: " + message.toXML().toString());
+ "Bad Message Body</span>";
assertEquals(body, message.getBody());
assertXMLNotEqual(control, message.toXML().toString());
DetailedDiff diffs = new DetailedDiff(new Diff(control, message.toXML().toString()));
// body has no namespace URI, span is escaped
assertEquals(6, diffs.getAllDifferences().size());
} catch(XmlPullParserException e) {
fail("No parser exception should be thrown" + e.getMessage());
}
} }
@Test @Test
@ -792,8 +785,8 @@ public class PacketParserUtilsTest {
@Test @Test
public void parseContentDepthTest() throws Exception { public void parseContentDepthTest() throws Exception {
final String stanza = "<iq type='result' to='foo@bar.com' from='baz.com' id='42'/>"; final String stanza = "<iq type='result' to='foo@bar.com' from='baz.com' id='42'/>";
XmlPullParser parser = PacketParserUtils.getParserFor(stanza, "iq"); XmlPullParser parser = TestUtils.getParser(stanza, "iq");
String content = PacketParserUtils.parseContentDepth(parser, 1); String content = PacketParserUtils.parseContent(parser);
assertEquals("", content); assertEquals("", content);
} }

View File

@ -24,7 +24,7 @@ import org.jivesoftware.smack.test.SmackTestCase;
import org.jivesoftware.smackx.packet.Version; import org.jivesoftware.smackx.packet.Version;
/** /**
* Ensure that stream compression (JEP-138) is correctly supported by Smack. * Ensure that stream compression (XEP-138) is correctly supported by Smack.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */

View File

@ -30,7 +30,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* Tests that JEP-33 support in Smack is correct. * Tests that XEP-33 support in Smack is correct.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */

View File

@ -32,7 +32,7 @@ import java.util.List;
/** /**
* Tests handling of offline messaging using OfflineMessageManager. This server requires the * Tests handling of offline messaging using OfflineMessageManager. This server requires the
* server to support JEP-0013: Flexible Offline Message Retrieval. * server to support XEP-0013: Flexible Offline Message Retrieval.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
@ -44,7 +44,7 @@ public class OfflineMessageManagerTest extends SmackTestCase {
public void testDiscoverFlexibleRetrievalSupport() throws XMPPException { public void testDiscoverFlexibleRetrievalSupport() throws XMPPException {
OfflineMessageManager offlineManager = new OfflineMessageManager(getConnection(1)); OfflineMessageManager offlineManager = new OfflineMessageManager(getConnection(1));
assertTrue("Server does not support JEP-13", offlineManager.supportsFlexibleRetrieval()); assertTrue("Server does not support XEP-13", offlineManager.supportsFlexibleRetrieval());
} }
/** /**

View File

@ -40,7 +40,7 @@ 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
* <a href="http://www.jabber.org/jeps/jep-0033.html">JEP-33: Extended Stanza Addressing</a>. * <a href="http://www.xmpp.org/extensions/jep-0033.html">XEP-33: Extended Stanza Addressing</a>.
* It also allows to send replies to packets that were sent to multiple recipients. * It also allows to send replies to packets that were sent to multiple recipients.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
@ -57,9 +57,9 @@ public class MultipleRecipientManager {
/** /**
* Sends the specified packet to the list of specified recipients using the * Sends the specified packet to the list of specified recipients using the
* specified connection. If the server has support for JEP-33 then only one * specified connection. If the server has support for XEP-33 then only one
* packet is going to be sent to the server with the multiple recipient instructions. * packet is going to be sent to the server with the multiple recipient instructions.
* However, if JEP-33 is not supported by the server then the client is going to send * However, if XEP-33 is not supported by the server then the client is going to send
* the packet to each recipient. * the packet to each recipient.
* *
* @param connection the connection to use to send the packet. * @param connection the connection to use to send the packet.
@ -72,8 +72,8 @@ public class MultipleRecipientManager {
* list exists. * list exists.
* @throws FeatureNotSupportedException if special XEP-33 features where requested, but the * @throws FeatureNotSupportedException if special XEP-33 features where requested, but the
* server does not support them. * server does not support them.
* @throws XMPPErrorException if server does not support JEP-33: Extended Stanza Addressing and * @throws XMPPErrorException if server does not support XEP-33: Extended Stanza Addressing and
* some JEP-33 specific features were requested. * some XEP-33 specific features were requested.
* @throws NoResponseException if there was no response from the server. * @throws NoResponseException if there was no response from the server.
* @throws NotConnectedException * @throws NotConnectedException
*/ */
@ -84,8 +84,8 @@ public class MultipleRecipientManager {
/** /**
* Sends the specified packet to the list of specified recipients using the specified * Sends the specified packet to the list of specified recipients using the specified
* connection. If the server has support for JEP-33 then only one packet is going to be sent to * connection. If the server has support for XEP-33 then only one packet is going to be sent to
* the server with the multiple recipient instructions. However, if JEP-33 is not supported by * the server with the multiple recipient instructions. However, if XEP-33 is not supported by
* the server then the client is going to send the packet to each recipient. * the server then the client is going to send the packet to each recipient.
* *
* @param connection the connection to use to send the packet. * @param connection the connection to use to send the packet.
@ -99,8 +99,8 @@ public class MultipleRecipientManager {
* @param replyRoom JID of a MUC room to which responses should be sent or <tt>null</tt> * @param replyRoom JID of a MUC room to which responses should be sent or <tt>null</tt>
* indicating that they can reply to any address. * indicating that they can reply to any address.
* @param noReply true means that receivers should not reply to the message. * @param noReply true means that receivers should not reply to the message.
* @throws XMPPErrorException if server does not support JEP-33: Extended Stanza Addressing and * @throws XMPPErrorException if server does not support XEP-33: Extended Stanza Addressing and
* some JEP-33 specific features were requested. * some XEP-33 specific features were requested.
* @throws NoResponseException if there was no response from the server. * @throws NoResponseException if there was no response from the server.
* @throws FeatureNotSupportedException if special XEP-33 features where requested, but the * @throws FeatureNotSupportedException if special XEP-33 features where requested, but the
* server does not support them. * server does not support them.
@ -115,10 +115,10 @@ public class MultipleRecipientManager {
serviceAddress); serviceAddress);
} }
else { else {
// Server does not support JEP-33 so try to send the packet to each recipient // Server does not support XEP-33 so try to send the packet to each recipient
if (noReply || (replyTo != null && replyTo.trim().length() > 0) || if (noReply || (replyTo != null && replyTo.trim().length() > 0) ||
(replyRoom != null && replyRoom.trim().length() > 0)) { (replyRoom != null && replyRoom.trim().length() > 0)) {
// Some specified JEP-33 features were requested so throw an exception alerting // Some specified XEP-33 features were requested so throw an exception alerting
// the user that this features are not available // the user that this features are not available
throw new FeatureNotSupportedException("Extended Stanza Addressing"); throw new FeatureNotSupportedException("Extended Stanza Addressing");
} }
@ -191,7 +191,7 @@ public class MultipleRecipientManager {
serviceAddress); serviceAddress);
} }
else { else {
// Server does not support JEP-33 so try to send the packet to each recipient // Server does not support XEP-33 so try to send the packet to each recipient
sendToIndividualRecipients(connection, reply, to, cc, null); sendToIndividualRecipients(connection, reply, to, cc, null);
} }
} }

View File

@ -34,10 +34,10 @@ import org.jivesoftware.smackx.iqprivate.PrivateDataManager;
/** /**
* Provides methods to manage bookmarks in accordance with JEP-0048. Methods for managing URLs and * Provides methods to manage bookmarks in accordance with XEP-0048. Methods for managing URLs and
* Conferences are provided. * Conferences are provided.
* </p> * </p>
* It should be noted that some extensions have been made to the JEP. There is an attribute on URLs * It should be noted that some extensions have been made to the XEP. There is an attribute on URLs
* that marks a url as a news feed and also a sub-element can be added to either a URL or conference * that marks a url as a news feed and also a sub-element can be added to either a URL or conference
* indicated that it is shared amongst all users on a server. * indicated that it is shared amongst all users on a server.
* *

View File

@ -18,7 +18,7 @@
package org.jivesoftware.smackx.bookmarks; package org.jivesoftware.smackx.bookmarks;
/** /**
* Respresents a Conference Room bookmarked on the server using JEP-0048 Bookmark Storage JEP. * Respresents a Conference Room bookmarked on the server using XEP-0048 Bookmark Storage XEP.
* *
* @author Derek DeMoro * @author Derek DeMoro
*/ */

View File

@ -18,7 +18,7 @@
package org.jivesoftware.smackx.bookmarks; package org.jivesoftware.smackx.bookmarks;
/** /**
* Respresents one instance of a URL defined using JEP-0048 Bookmark Storage JEP. * Respresents one instance of a URL defined using XEP-0048 Bookmark Storage XEP.
* *
* @author Derek DeMoro * @author Derek DeMoro
*/ */

View File

@ -16,6 +16,7 @@
*/ */
package org.jivesoftware.smackx.bookmarks; package org.jivesoftware.smackx.bookmarks;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.iqprivate.packet.PrivateData; import org.jivesoftware.smackx.iqprivate.packet.PrivateData;
import org.jivesoftware.smackx.iqprivate.provider.PrivateDataProvider; import org.jivesoftware.smackx.iqprivate.provider.PrivateDataProvider;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -27,7 +28,7 @@ import java.util.List;
/** /**
* Bookmarks is used for storing and retrieving URLS and Conference rooms. * Bookmarks is used for storing and retrieving URLS and Conference rooms.
* Bookmark Storage (JEP-0048) defined a protocol for the storage of bookmarks to conference rooms and other entities * Bookmark Storage (XEP-0048) defined a protocol for the storage of bookmarks to conference rooms and other entities
* in a Jabber user's account. * in a Jabber user's account.
* See the following code sample for saving Bookmarks: * See the following code sample for saving Bookmarks:
* <p/> * <p/>
@ -59,6 +60,9 @@ import java.util.List;
*/ */
public class Bookmarks implements PrivateData { public class Bookmarks implements PrivateData {
public static final String NAMESPACE = "storage:bookmarks";
public static final String ELEMENT = "storage";
private List<BookmarkedURL> bookmarkedURLS; private List<BookmarkedURL> bookmarkedURLS;
private List<BookmarkedConference> bookmarkedConferences; private List<BookmarkedConference> bookmarkedConferences;
@ -145,7 +149,7 @@ public class Bookmarks implements PrivateData {
* @return the element name. * @return the element name.
*/ */
public String getElementName() { public String getElementName() {
return "storage"; return ELEMENT;
} }
/** /**
@ -154,28 +158,26 @@ public class Bookmarks implements PrivateData {
* @return the namespace. * @return the namespace.
*/ */
public String getNamespace() { public String getNamespace() {
return "storage:bookmarks"; return NAMESPACE;
} }
/** /**
* Returns the XML reppresentation of the PrivateData. * Returns the XML representation of the PrivateData.
* *
* @return the private data as XML. * @return the private data as XML.
*/ */
public String toXML() { @Override
StringBuilder buf = new StringBuilder(); public XmlStringBuilder toXML() {
buf.append("<storage xmlns=\"storage:bookmarks\">"); XmlStringBuilder buf = new XmlStringBuilder();
buf.openElement(ELEMENT).xmlnsAttribute(NAMESPACE);
for (BookmarkedURL urlStorage : getBookmarkedURLS()) { for (BookmarkedURL urlStorage : getBookmarkedURLS()) {
if(urlStorage.isShared()) { if(urlStorage.isShared()) {
continue; continue;
} }
buf.append("<url name=\"").append(urlStorage.getName()). buf.openElement("url").attribute("name", urlStorage.getName()).attribute("url", urlStorage.getURL());
append("\" url=\"").append(urlStorage.getURL()).append("\""); buf.condAttribute(urlStorage.isRss(), "rss", "true");
if(urlStorage.isRss()) { buf.closeEmptyElement();
buf.append(" rss=\"").append(true).append("\"");
}
buf.append(" />");
} }
// Add Conference additions // Add Conference additions
@ -183,26 +185,20 @@ public class Bookmarks implements PrivateData {
if(conference.isShared()) { if(conference.isShared()) {
continue; continue;
} }
buf.append("<conference "); buf.openElement("conference");
buf.append("name=\"").append(conference.getName()).append("\" "); buf.attribute("name", conference.getName());
buf.append("autojoin=\"").append(conference.isAutoJoin()).append("\" "); buf.attribute("autojoin", Boolean.toString(conference.isAutoJoin()));
buf.append("jid=\"").append(conference.getJid()).append("\" "); buf.attribute("jid", conference.getJid());
buf.append(">"); buf.rightAngelBracket();
if (conference.getNickname() != null) { buf.optElement("nick", conference.getNickname());
buf.append("<nick>").append(conference.getNickname()).append("</nick>"); buf.optElement("password", conference.getPassword());
}
buf.closeElement("conference");
if (conference.getPassword() != null) {
buf.append("<password>").append(conference.getPassword()).append("</password>");
}
buf.append("</conference>");
} }
buf.closeElement(ELEMENT);
buf.append("</storage>"); return buf;
return buf.toString();
} }
/** /**

View File

@ -45,7 +45,6 @@ import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Feature; import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Feature;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity; import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity;
import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item; import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item;
import org.jivesoftware.smackx.xdata.Form;
import org.jivesoftware.smackx.xdata.FormField; import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jivesoftware.smackx.xdata.packet.DataForm;
@ -536,7 +535,7 @@ public class EntityCapsManager extends Manager {
protected static boolean verifyPacketExtensions(DiscoverInfo info) { protected static boolean verifyPacketExtensions(DiscoverInfo info) {
List<FormField> foundFormTypes = new LinkedList<FormField>(); List<FormField> foundFormTypes = new LinkedList<FormField>();
for (PacketExtension pe : info.getExtensions()) { for (PacketExtension pe : info.getExtensions()) {
if (pe.getNamespace().equals(Form.NAMESPACE)) { if (pe.getNamespace().equals(DataForm.NAMESPACE)) {
DataForm df = (DataForm) pe; DataForm df = (DataForm) pe;
for (FormField f : df.getFields()) { for (FormField f : df.getFields()) {
if (f.getVariable().equals("FORM_TYPE")) { if (f.getVariable().equals("FORM_TYPE")) {
@ -569,7 +568,7 @@ public class EntityCapsManager extends Manager {
if (md == null) if (md == null)
return null; return null;
DataForm extendedInfo = (DataForm) discoverInfo.getExtension(Form.ELEMENT, Form.NAMESPACE); DataForm extendedInfo = (DataForm) discoverInfo.getExtension(DataForm.ELEMENT, DataForm.NAMESPACE);
// 1. Initialize an empty string S ('sb' in this method). // 1. Initialize an empty string S ('sb' in this method).
StringBuilder sb = new StringBuilder(); // Use StringBuilder as we don't StringBuilder sb = new StringBuilder(); // Use StringBuilder as we don't

View File

@ -43,7 +43,7 @@ import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jivesoftware.smackx.xdata.packet.DataForm;
/** /**
* Manages the negotiation of file transfers according to JEP-0096. If a file is * Manages the negotiation of file transfers according to XEP-0096. If a file is
* being sent the remote user chooses the type of stream under which the file * being sent the remote user chooses the type of stream under which the file
* will be sent. * will be sent.
* *
@ -287,13 +287,13 @@ public class FileTransferNegotiator extends Manager {
* If they accept, the packet will contain the other user's chosen stream * If they accept, the packet will contain the other user's chosen stream
* type to send the file across. The two choices this implementation * type to send the file across. The two choices this implementation
* provides to the other user for file transfer are <a * provides to the other user for file transfer are <a
* href="http://www.jabber.org/jeps/jep-0065.html">SOCKS5 Bytestreams</a>, * href="http://www.xmpp.org/extensions/jep-0065.html">SOCKS5 Bytestreams</a>,
* which is the preferred method of transfer, and <a * which is the preferred method of transfer, and <a
* href="http://www.jabber.org/jeps/jep-0047.html">In-Band Bytestreams</a>, * href="http://www.xmpp.org/extensions/jep-0047.html">In-Band Bytestreams</a>,
* which is the fallback mechanism. * which is the fallback mechanism.
* <p/> * <p/>
* The other user may choose to decline the file request if they do not * The other user may choose to decline the file request if they do not
* desire the file, their client does not support JEP-0096, or if there are * desire the file, their client does not support XEP-0096, or if there are
* no acceptable means to transfer the file. * no acceptable means to transfer the file.
* <p/> * <p/>
* Finally, if the other user does not respond this method will return null * Finally, if the other user does not respond this method will return null

View File

@ -36,7 +36,7 @@ import java.io.OutputStream;
/** /**
* After the file transfer negotiation process is completed according to * After the file transfer negotiation process is completed according to
* JEP-0096, the negotiation process is passed off to a particular stream * XEP-0096, the negotiation process is passed off to a particular stream
* negotiator. The stream negotiator will then negotiate the chosen stream and * negotiator. The stream negotiator will then negotiate the chosen stream and
* return the stream to transfer the file. * return the stream to transfer the file.
* *

View File

@ -50,7 +50,7 @@ import java.util.WeakHashMap;
* a {@link DefaultPrivateData} instance will be returned.<p> * a {@link DefaultPrivateData} instance will be returned.<p>
* *
* Warning: this is an non-standard protocol documented by * Warning: this is an non-standard protocol documented by
* <a href="http://www.jabber.org/jeps/jep-0049.html">JEP-49</a>. Because this is a * <a href="http://www.xmpp.org/extensions/jep-0049.html">XEP-49</a>. Because this is a
* non-standard protocol, it is subject to change. * non-standard protocol, it is subject to change.
* *
* @author Matt Tucker * @author Matt Tucker
@ -285,7 +285,7 @@ public class PrivateDataManager extends Manager {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append("<query xmlns=\"jabber:iq:private\">"); buf.append("<query xmlns=\"jabber:iq:private\">");
if (privateData != null) { if (privateData != null) {
privateData.toXML(); buf.append(privateData.toXML());
} }
buf.append("</query>"); buf.append("</query>");
return buf.toString(); return buf.toString();

View File

@ -45,5 +45,5 @@ public interface PrivateData {
* *
* @return the private data as XML. * @return the private data as XML.
*/ */
public String toXML(); public CharSequence toXML();
} }

View File

@ -43,8 +43,8 @@ import org.xmlpull.v1.XmlPullParser;
* // Create a packet collector or packet listeners using the filter... * // Create a packet collector or packet listeners using the filter...
* </pre> * </pre>
* *
* <b>Note</b>: this protocol is outdated now that the Multi-User Chat (MUC) JEP is available * <b>Note</b>: this protocol is outdated now that the Multi-User Chat (MUC) XEP is available
* (<a href="http://www.jabber.org/jeps/jep-0045.html">JEP-45</a>). However, most * (<a href="http://www.xmpp.org/extensions/jep-0045.html">XEP-45</a>). However, most
* existing clients still use this older protocol. Once MUC support becomes more * existing clients still use this older protocol. Once MUC support becomes more
* widespread, this API may be deprecated. * widespread, this API may be deprecated.
* *

View File

@ -520,7 +520,7 @@ public class MUCUser implements PacketExtension {
/** /**
* Status code assists in presenting notification messages. The following link provides the * Status code assists in presenting notification messages. The following link provides the
* list of existing error codes (@link http://www.jabber.org/jeps/jep-0045.html#errorstatus). * list of existing error codes (@link http://www.xmpp.org/extensions/jep-0045.html#errorstatus).
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */

View File

@ -20,7 +20,6 @@ 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.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.pubsub.Item; import org.jivesoftware.smackx.pubsub.Item;
import org.jivesoftware.smackx.pubsub.PayloadItem; import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smackx.pubsub.SimplePayload; import org.jivesoftware.smackx.pubsub.SimplePayload;
@ -41,7 +40,6 @@ public class ItemProvider implements PacketExtensionProvider
{ {
String id = parser.getAttributeValue(null, "id"); String id = parser.getAttributeValue(null, "id");
String node = parser.getAttributeValue(null, "node"); String node = parser.getAttributeValue(null, "node");
String elem = parser.getName();
int tag = parser.next(); int tag = parser.next();
@ -56,57 +54,8 @@ public class ItemProvider implements PacketExtensionProvider
if (ProviderManager.getExtensionProvider(payloadElemName, payloadNS) == null) if (ProviderManager.getExtensionProvider(payloadElemName, payloadNS) == null)
{ {
boolean done = false; String payloadText = PacketParserUtils.parseElement(parser);
boolean isEmptyElement = false; return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText));
StringBuilder payloadText = new StringBuilder();
while (!done)
{
if (tag == XmlPullParser.END_TAG && parser.getName().equals(elem))
{
done = true;
continue;
}
else if (parser.getEventType() == XmlPullParser.START_TAG)
{
payloadText.append("<").append(parser.getName());
if (parser.getName().equals(payloadElemName) && (payloadNS.length() > 0))
payloadText.append(" xmlns=\"").append(payloadNS).append("\"");
int n = parser.getAttributeCount();
for (int i = 0; i < n; i++)
payloadText.append(" ").append(parser.getAttributeName(i)).append("=\"")
.append(parser.getAttributeValue(i)).append("\"");
if (parser.isEmptyElementTag())
{
payloadText.append("/>");
isEmptyElement = true;
}
else
{
payloadText.append(">");
}
}
else if (parser.getEventType() == XmlPullParser.END_TAG)
{
if (isEmptyElement)
{
isEmptyElement = false;
}
else
{
payloadText.append("</").append(parser.getName()).append(">");
}
}
else if (parser.getEventType() == XmlPullParser.TEXT)
{
payloadText.append(StringUtils.escapeForXML(parser.getText()));
}
tag = parser.next();
}
return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText.toString()));
} }
else else
{ {

View File

@ -25,7 +25,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* SimpleUserSearch is used to support the non-dataform type of JEP 55. This provides * SimpleUserSearch is used to support the non-dataform type of XEP 55. This provides
* the mechanism for allowing always type ReportedData to be returned by any search result, * the mechanism for allowing always type ReportedData to be returned by any search result,
* regardless of the form of the data returned from the server. * regardless of the form of the data returned from the server.
* *

View File

@ -31,7 +31,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
* The UserSearchManager is a facade built upon Jabber Search Services (JEP-055) to allow for searching * The UserSearchManager is a facade built upon Jabber Search Services (XEP-055) to allow for searching
* repositories on a Jabber Server. This implementation allows for transparency of implementation of * repositories on a Jabber Server. This implementation allows for transparency of implementation of
* searching (DataForms or No DataForms), but allows the user to simply use the DataForm model for both * searching (DataForms or No DataForms), but allows the user to simply use the DataForm model for both
* types of support. * types of support.

View File

@ -45,7 +45,7 @@ import org.jivesoftware.smackx.vcardtemp.VCardManager;
* <a href="http://www.jivesoftware.org/smack/" target="_blank">SMACK jabber library</a>.<p> * <a href="http://www.jivesoftware.org/smack/" target="_blank">SMACK jabber library</a>.<p>
* <p/> * <p/>
* You should refer to the * You should refer to the
* <a href="http://www.jabber.org/jeps/jep-0054.html" target="_blank">JEP-54 documentation</a>.<p> * <a href="http://www.xmpp.org/extensions/jep-0054.html" target="_blank">XEP-54 documentation</a>.<p>
* <p/> * <p/>
* Please note that this class is incomplete but it does provide the most commonly found * Please note that this class is incomplete but it does provide the most commonly found
* information in vCards. Also remember that VCard transfer is not a standard, and the protocol * information in vCards. Also remember that VCard transfer is not a standard, and the protocol
@ -114,7 +114,7 @@ public class VCard extends IQ {
private String photoBinval; private String photoBinval;
/** /**
* Such as DESC ROLE GEO etc.. see JEP-0054 * Such as DESC ROLE GEO etc.. see XEP-0054
*/ */
private Map<String, String> otherSimpleFields = new HashMap<String, String>(); private Map<String, String> otherSimpleFields = new HashMap<String, String>();

View File

@ -49,9 +49,6 @@ public class Form {
public static final String TYPE_CANCEL = "cancel"; public static final String TYPE_CANCEL = "cancel";
public static final String TYPE_RESULT = "result"; public static final String TYPE_RESULT = "result";
public static final String NAMESPACE = "jabber:x:data";
public static final String ELEMENT = "x";
private DataForm dataForm; private DataForm dataForm;
/** /**

View File

@ -17,7 +17,6 @@
package org.jivesoftware.smackx.xdata; package org.jivesoftware.smackx.xdata;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smack.util.XmlStringBuilder;
import java.util.ArrayList; import java.util.ArrayList;
@ -33,6 +32,8 @@ import java.util.List;
*/ */
public class FormField { public class FormField {
public static final String ELEMENT = "field";
public static final String TYPE_BOOLEAN = "boolean"; public static final String TYPE_BOOLEAN = "boolean";
public static final String TYPE_FIXED = "fixed"; public static final String TYPE_FIXED = "fixed";
public static final String TYPE_HIDDEN = "hidden"; public static final String TYPE_HIDDEN = "hidden";
@ -263,25 +264,17 @@ public class FormField {
} }
} }
public String toXML() { public XmlStringBuilder toXML() {
XmlStringBuilder buf = new XmlStringBuilder(); XmlStringBuilder buf = new XmlStringBuilder();
buf.append("<field"); buf.halfOpenElement(ELEMENT);
// Add attributes // Add attributes
if (getLabel() != null) { buf.optAttribute("label", getLabel());
buf.append(" label=\"").append(getLabel()).append("\""); buf.optAttribute("var", getVariable());
} buf.optAttribute("type", getType());
buf.attribute("var", getVariable()); buf.rightAngelBracket();
if (getType() != null) {
buf.append(" type=\"").append(getType()).append("\"");
}
buf.append(">");
// Add elements // Add elements
if (getDescription() != null) { buf.optElement("desc", getDescription());
buf.append("<desc>").append(getDescription()).append("</desc>"); buf.condEmptyElement(isRequired(), "required");
}
if (isRequired()) {
buf.append("<required/>");
}
// Loop through all the values and append them to the string buffer // Loop through all the values and append them to the string buffer
for (String value : getValues()) { for (String value : getValues()) {
buf.element("value", value); buf.element("value", value);
@ -290,8 +283,8 @@ public class FormField {
for (Option option : getOptions()) { for (Option option : getOptions()) {
buf.append(option.toXML()); buf.append(option.toXML());
} }
buf.append("</field>"); buf.closeElement(ELEMENT);
return buf.toString(); return buf;
} }
@Override @Override
@ -320,8 +313,10 @@ public class FormField {
*/ */
public static class Option { public static class Option {
public static final String ELEMNT = "option";
private final String value;
private String label; private String label;
private String value;
public Option(String value) { public Option(String value) {
this.value = value; this.value = value;
@ -355,19 +350,18 @@ public class FormField {
return getLabel(); return getLabel();
} }
public String toXML() { public XmlStringBuilder toXML() {
StringBuilder buf = new StringBuilder(); XmlStringBuilder xml = new XmlStringBuilder();
buf.append("<option"); xml.halfOpenElement(ELEMNT);
// Add attribute // Add attribute
if (getLabel() != null) { xml.optAttribute("label", getLabel());
buf.append(" label=\"").append(getLabel()).append("\""); xml.rightAngelBracket();
}
buf.append(">");
// Add element
buf.append("<value>").append(StringUtils.escapeForXML(getValue())).append("</value>");
buf.append("</option>"); // Add element
return buf.toString(); xml.element("value", getValue());
xml.closeElement(ELEMENT);
return xml;
} }
@Override @Override

View File

@ -18,7 +18,7 @@
package org.jivesoftware.smackx.xdata.packet; package org.jivesoftware.smackx.xdata.packet;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.xdata.Form; import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.xdata.FormField; import org.jivesoftware.smackx.xdata.FormField;
import java.util.ArrayList; import java.util.ArrayList;
@ -33,6 +33,9 @@ import java.util.List;
*/ */
public class DataForm implements PacketExtension { public class DataForm implements PacketExtension {
public static final String NAMESPACE = "jabber:x:data";
public static final String ELEMENT = "x";
private String type; private String type;
private String title; private String title;
private List<String> instructions = new ArrayList<String>(); private List<String> instructions = new ArrayList<String>();
@ -120,11 +123,11 @@ public class DataForm implements PacketExtension {
} }
public String getElementName() { public String getElementName() {
return Form.ELEMENT; return ELEMENT;
} }
public String getNamespace() { public String getNamespace() {
return Form.NAMESPACE; return NAMESPACE;
} }
/** /**
@ -207,15 +210,15 @@ public class DataForm implements PacketExtension {
return found; return found;
} }
public String toXML() { @Override
StringBuilder buf = new StringBuilder(); public XmlStringBuilder toXML() {
buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( XmlStringBuilder buf = new XmlStringBuilder(this);
"\" type=\"" + getType() +"\">"); buf.attribute("type", getType());
if (getTitle() != null) { buf.rightAngelBracket();
buf.append("<title>").append(getTitle()).append("</title>");
} buf.optElement("title", getTitle());
for (String instruction : getInstructions()) { for (String instruction : getInstructions()) {
buf.append("<instructions>").append(instruction).append("</instructions>"); buf.element("instructions", instruction);
} }
// Append the list of fields returned from a search // Append the list of fields returned from a search
if (getReportedData() != null) { if (getReportedData() != null) {
@ -229,8 +232,8 @@ public class DataForm implements PacketExtension {
for (FormField field : getFields()) { for (FormField field : getFields()) {
buf.append(field.toXML()); buf.append(field.toXML());
} }
buf.append("</").append(getElementName()).append(">"); buf.closeElement(this);
return buf.toString(); return buf;
} }
/** /**
@ -241,6 +244,8 @@ public class DataForm implements PacketExtension {
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public static class ReportedData { public static class ReportedData {
public static final String ELEMENT = "reported";
private List<FormField> fields = new ArrayList<FormField>(); private List<FormField> fields = new ArrayList<FormField>();
public ReportedData(List<FormField> fields) { public ReportedData(List<FormField> fields) {
@ -256,15 +261,15 @@ public class DataForm implements PacketExtension {
return Collections.unmodifiableList(new ArrayList<FormField>(fields)); return Collections.unmodifiableList(new ArrayList<FormField>(fields));
} }
public String toXML() { public CharSequence toXML() {
StringBuilder buf = new StringBuilder(); XmlStringBuilder buf = new XmlStringBuilder();
buf.append("<reported>"); buf.openElement(ELEMENT);
// Loop through all the form items and append them to the string buffer // Loop through all the form items and append them to the string buffer
for (FormField field : getFields()) { for (FormField field : getFields()) {
buf.append(field.toXML()); buf.append(field.toXML());
} }
buf.append("</reported>"); buf.closeElement(ELEMENT);
return buf.toString(); return buf;
} }
} }
@ -275,6 +280,8 @@ public class DataForm implements PacketExtension {
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public static class Item { public static class Item {
public static final String ELEMENT = "item";
private List<FormField> fields = new ArrayList<FormField>(); private List<FormField> fields = new ArrayList<FormField>();
public Item(List<FormField> fields) { public Item(List<FormField> fields) {
@ -290,15 +297,15 @@ public class DataForm implements PacketExtension {
return Collections.unmodifiableList(new ArrayList<FormField>(fields)); return Collections.unmodifiableList(new ArrayList<FormField>(fields));
} }
public String toXML() { public CharSequence toXML() {
StringBuilder buf = new StringBuilder(); XmlStringBuilder buf = new XmlStringBuilder();
buf.append("<item>"); buf.openElement(ELEMENT);
// Loop through all the form items and append them to the string buffer // Loop through all the form items and append them to the string buffer
for (FormField field : getFields()) { for (FormField field : getFields()) {
buf.append(field.toXML()); buf.append(field.toXML());
} }
buf.append("</item>"); buf.closeElement(ELEMENT);
return buf.toString(); return buf;
} }
} }
} }

View File

@ -29,10 +29,10 @@ import java.util.List;
* extension is only a subset of XHTML 1.0.<p> * extension is only a subset of XHTML 1.0.<p>
* *
* The following link summarizes the requirements of XHTML IM: * The following link summarizes the requirements of XHTML IM:
* <a href="http://www.jabber.org/jeps/jep-0071.html#sect-id2598018">Valid tags</a>.<p> * <a href="http://www.xmpp.org/extensions/jep-0071.html#sect-id2598018">Valid tags</a>.<p>
* *
* Warning: this is an non-standard protocol documented by * Warning: this is an non-standard protocol documented by
* <a href="http://www.jabber.org/jeps/jep-0071.html">JEP-71</a>. Because this is a * <a href="http://www.xmpp.org/extensions/jep-0071.html">XEP-71</a>. Because this is a
* non-standard protocol, it is subject to change. * non-standard protocol, it is subject to change.
* *
* @author Gaston Dombiak * @author Gaston Dombiak

View File

@ -172,7 +172,7 @@
<className>org.jivesoftware.smackx.sharedgroups.packet.SharedGroupsInfo$Provider</className> <className>org.jivesoftware.smackx.sharedgroups.packet.SharedGroupsInfo$Provider</className>
</iqProvider> </iqProvider>
<!-- JEP-33: Extended Stanza Addressing --> <!-- XEP-33: Extended Stanza Addressing -->
<extensionProvider> <extensionProvider>
<elementName>addresses</elementName> <elementName>addresses</elementName>
<namespace>http://jabber.org/protocol/address</namespace> <namespace>http://jabber.org/protocol/address</namespace>

View File

@ -51,6 +51,6 @@ public class FileTransferNegotiatorTest {
fileNeg.negotiateOutgoingTransfer("me", "streamid", "file", 1024, null, 10); fileNeg.negotiateOutgoingTransfer("me", "streamid", "file", 1024, null, 10);
Packet packet = connection.getSentPacket(); Packet packet = connection.getSentPacket();
String xml = packet.toXML().toString(); String xml = packet.toXML().toString();
assertTrue(xml.indexOf("var='stream-method' type=\"list-single\"") != -1); assertTrue(xml.indexOf("var='stream-method' type='list-single'") != -1);
} }
} }

View File

@ -29,10 +29,10 @@ import java.util.List;
* An Jingle sub-packet, which is used by XMPP clients to exchange info like * An Jingle sub-packet, which is used by XMPP clients to exchange info like
* descriptions and transports. <p/> The following link summarizes the * descriptions and transports. <p/> The following link summarizes the
* requirements of Jingle IM: <a * requirements of Jingle IM: <a
* href="http://www.jabber.org/jeps/jep-0166.html">Valid tags</a>. * href="http://www.xmpp.org/extensions/jep-0166.html">Valid tags</a>.
* <p/> * <p/>
* <p/> Warning: this is an non-standard protocol documented by <a * <p/> Warning: this is an non-standard protocol documented by <a
* href="http://www.jabber.org/jeps/jep-0166.html">JEP-166</a>. Because this is * href="http://www.xmpp.org/extensions/jep-0166.html">XEP-166</a>. Because this is
* a non-standard protocol, it is subject to change. * a non-standard protocol, it is subject to change.
* *
* @author Alvaro Saurin * @author Alvaro Saurin

View File

@ -17,6 +17,7 @@
package org.jivesoftware.smack.util.dns.javax; package org.jivesoftware.smack.util.dns.javax;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
@ -27,6 +28,7 @@ import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext; import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext; import javax.naming.directory.InitialDirContext;
import org.jivesoftware.smack.initializer.SmackInitializer;
import org.jivesoftware.smack.util.DNSUtil; import org.jivesoftware.smack.util.DNSUtil;
import org.jivesoftware.smack.util.dns.DNSResolver; import org.jivesoftware.smack.util.dns.DNSResolver;
import org.jivesoftware.smack.util.dns.SRVRecord; import org.jivesoftware.smack.util.dns.SRVRecord;
@ -37,7 +39,7 @@ import org.jivesoftware.smack.util.dns.SRVRecord;
* @author Florian Schmaus * @author Florian Schmaus
* *
*/ */
public class JavaxResolver implements DNSResolver { public class JavaxResolver implements DNSResolver, SmackInitializer {
private static JavaxResolver instance; private static JavaxResolver instance;
private static DirContext dirContext; private static DirContext dirContext;
@ -52,24 +54,28 @@ public class JavaxResolver implements DNSResolver {
} }
// Try to set this DNS resolver as primary one // Try to set this DNS resolver as primary one
DNSUtil.setDNSResolver(getInstance()); setup();
} }
private JavaxResolver() { public JavaxResolver() {
} }
public static DNSResolver getInstance() { public static synchronized DNSResolver getInstance() {
if (instance == null && isSupported()) { if (instance == null && isSupported()) {
instance = new JavaxResolver(); instance = new JavaxResolver();
} }
return instance; return instance;
} }
public static boolean isSupported() { public static boolean isSupported() {
return dirContext != null; return dirContext != null;
} }
public static void setup() {
DNSUtil.setDNSResolver(getInstance());
}
@Override @Override
public List<SRVRecord> lookupSRVRecords(String name) throws NamingException { public List<SRVRecord> lookupSRVRecords(String name) throws NamingException {
List<SRVRecord> res = new ArrayList<SRVRecord>(); List<SRVRecord> res = new ArrayList<SRVRecord>();
@ -93,4 +99,15 @@ public class JavaxResolver implements DNSResolver {
} }
return res; return res;
} }
@Override
public List<Exception> initialize() {
return initialize(null);
}
@Override
public List<Exception> initialize(ClassLoader classLoader) {
setup();
return Collections.emptyList();
}
} }

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.2.0"
enabled="true" immediate="true" name="Smack Resolver JavaX API">
<implementation
class="org.jivesoftware.smack.util.dns.javax.JavaxResolver" />
</scr:component>

View File

@ -0,0 +1,10 @@
description = """\
DNS SRV with minidns
Use minidns for DNS SRV lookups. For platforms that don't provide the
javax.naming API (e.g. Android)."""
dependencies {
compile project(path: ':smack-core', configuration: 'dns')
compile 'de.measite.minidns:minidns:0.1.1'
compile "org.igniterealtime.jxmpp:jxmpp-util-cache:$jxmppVersion"
}

View File

@ -0,0 +1,84 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* 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.smack.util.dns.minidns;
import java.util.LinkedList;
import java.util.List;
import org.jivesoftware.smack.util.dns.DNSResolver;
import org.jivesoftware.smack.util.dns.SRVRecord;
import org.jxmpp.util.cache.ExpirationCache;
import de.measite.minidns.Client;
import de.measite.minidns.DNSCache;
import de.measite.minidns.DNSMessage;
import de.measite.minidns.Question;
import de.measite.minidns.Record;
import de.measite.minidns.Record.CLASS;
import de.measite.minidns.Record.TYPE;
import de.measite.minidns.record.SRV;
/**
* This implementation uses the <a href="https://github.com/rtreffer/minidns/">minidns</a> implementation for
* resolving DNS addresses.
*/
public class MiniDnsResolver implements DNSResolver {
private static final long ONE_DAY = 24*60*60*1000;
private static final MiniDnsResolver instance = new MiniDnsResolver();
private static final ExpirationCache<Question, DNSMessage> cache = new ExpirationCache<Question, DNSMessage>(10, ONE_DAY);
private final Client client;
private MiniDnsResolver() {
client = new Client(new DNSCache() {
@Override
public DNSMessage get(Question question) {
return cache.get(question);
}
@Override
public void put(Question question, DNSMessage message) {
long expirationTime = ONE_DAY;
for (Record record : message.getAnswers()) {
if (record.isAnswer(question)) {
expirationTime = record.getTtl();
break;
}
}
cache.put(question, message, expirationTime);
}
});
}
public static DNSResolver getInstance() {
return instance;
}
@Override
public List<SRVRecord> lookupSRVRecords(String name) {
List<SRVRecord> res = new LinkedList<SRVRecord>();
DNSMessage message = client.query(name, TYPE.SRV, CLASS.IN);
for (Record record : message.getAnswers()) {
SRV srv = (SRV) record.getPayload();
res.add(new SRVRecord(srv.getName(), srv.getPort(), srv.getPriority(), srv.getWeight()));
}
return res;
}
}