Summary
In the XMPP communication process, Asmack provides the packet component is iq,message,presence three kinds: IQ is used for query messages for message passing presence for state interaction they are all packet subclasses, The essence is the XML format used to encapsulate messages into responses for data exchange, which has good scalability.
Brief introduction
We take the Open source project Androidpn as an example:
ANDROIDPN (Android push Notification) is a Java open source Android push Notification implementation based on the XMPP protocol. It contains the full client and server side.
The ANDROIDPN includes the server and client side, and the project name is Androidpn-server and androidpn-client.
In fact, Androidpn-server can support apps running on platforms such as Ios,uwp,windows,linux, not just Android, so you want to change the name of the project to XPN (Xmpp Push Notification) Seems to be more in line with its actual scene, we later involve Android Push notification collectively known as XPN.
XNP Current status
The project has ceased to be updated since January 2014, and the Asmack project has ceased to be updated, and the authors suggest using OpenFire's official smack4.0, but the jar will be particularly large and especially big. Of course, we've downloaded a newer stable version of asmack8.10.0 that can be used exclusively for learning and scaling.
Project related download site
Asmack-github.com-asmack Project Address
Asmack-asmack.freakempire.de-asmack Mirror Address
ANDROIDPN (XPN)-github.com-androidpn download Address
I. About packet Packets
Packet is a iq,message,presence parent class that implements the message component type.
Message semantics messages
A message is a basic push messaging method that does not require a response. It is mainly used in applications such as IM, groupchat, alert and notification.
The main properties are as follows:
Type property, which has 5 main types:
Normal: Similar to email, the main feature is not required response;
Chat: Similar to QQ friends instant chat, the main feature is real-time communication;
Groupchat: Like a group chat in a chat room;
Headline: For sending alert and notification;
Error: If send message error, found the wrong entity will use this category to notify the sender error;
To attribute: Identifies the recipient of the message.
From attribute: Refers to the sender's name or label. To prevent an address from leaking out, this address is usually filled by the sender's server instead of the sender.
Payload (payload): for example Body,subject
<message to= "lily@jabber.org/contact"
type= "chat" >
<body> Hello, are you busy </body>
</ Message>
Attend the information semantics presence
Presence is used to indicate the user's status, such as: online, Away, DND (Do Not Disturb). When you change your state, you insert a presence element in the context of the stream to indicate its state. To accept presence messages, you must go through a licensing process called presence subscription.
Property:
Type attribute, not required. There are the following categories
Subscribe: Subscribing to the status of other users
Probe: Request to get the status of another user
Unavailable: Not available, offline (offline) status
To attribute: Identifies the recipient of the message.
From attribute: Refers to the sender's name or label.
Load (payload):
Show
Chat: In Chat
Away: Leave temporarily
Xa:extend Away, long time to leave
DND: Don't Disturb
Status: Free format, readable text. Also known as rich presence or extended presence, it is often used to express the user's current mood, activities, listening songs, watching videos, the chat room, visiting pages, playing games, and so on.
Priority: Range -128~127. High-priority resource can accept messages sent to bare Jid, and low priority resource cannot. Priority is
<presence from= "ALICE@WONDERLAND.LIT/PDA" >
<show>xa</show>
<status>down the Rabbit hole!</status>
</presence>
IQ semantics
A request/response mechanism from which a request is sent from one entity and another entity receives the request and responds. For example, the client inserts an element into the context of the stream, requests a list of friends from the server, and the server returns one, which is the result of the request.
The primary property is type. Including:
Get: Gets the current domain value. Similar to the HTTP GET method.
Set: Sets or replaces the value of a get query. Similar to the HTTP put method.
Result: Indicates a successful response to a previous query. Similar to HTTP status code 200.
Error: Errors that occur in queries and responses.
<iq from= "ALICE@WONDERLAND.LIT/PDA"
Id= "Rr82a1z7"
To= "Alice@wonderland.lit"
Type= "Get" >
<query xmlns= "Jabber:iq:roster"/>
</iq>
Two. Custom packet
Because the server and the client use different packet, but the data format they interact with is XML, so this process we understand the XML implementation process.
1. Define Packet Package objects
Because of the limitations of Asmack label parsing, we cannot customize parsing unless we modify the source code, here for simplicity, only one of the existing tags can be inherited.
I do not follow the project code Notificationiq as an example, here did not inherit packet, but inherited the IQ
Import Org.jivesoftware.smack.packet.IQ;
/** * This class represents a Notifcatin IQ packet.
* * @author Sehwan Noh (devnoh@gmail.com) */public class Notificationiq extends IQ {private String ID;
Private String Apikey;
Private String title;
Private String message;
Private String URI; Public Notificationiq () {} @Override public String getchildelementxml () {StringBuilder buf = new StringBuilder
(); Buf.append ("<"). Append ("Notification"). Append ("Xmlns=\"). Append ("Androidpn:iq:notification"). Append ("\"
> ");
if (ID!= null) {buf.append ("<id>"). Append (ID). Append ("</id>");
} buf.append ("</"). Append ("Notification"). Append (">");
return buf.tostring ();
Public String GetId () {return id;
public void SetId (String id) {this.id = ID;
Public String Getapikey () {return apikey;
} public void Setapikey (String apikey) {this.apikey = Apikey; Public String GetTitle () {
return title;
public void Settitle (String title) {this.title = title;
Public String GetMessage () {return message;
public void Setmessage (String message) {this.message = message;
Public String GetURI () {return URI;
public void Seturi (String url) {this.uri = URL;
}
}
Where Getchildelementxml () is a subclass of IQ, which is used to splice the direct point under <iq>.
Public abstract class IQ extends Packet {private type type = Type.get;
Public IQ () {super ();
Public IQ (IQ IQ) {super (IQ);
Type = Iq.gettype ();
}/** * Returns the type of the IQ packet.
* * @return The type of the IQ packet.
*/Public Type GetType () {return type;
}/** * Sets the type of the IQ packet.
* * @param type of the IQ packet.
*/public void SetType (type type) {if (type = = null) {This.type = Type.get;
else {this.type = type;
} public String ToXML () {StringBuilder buf = new StringBuilder ();
Buf.append ("<iq");
if (Getpacketid ()!= null) {buf.append ("id=\" + getpacketid () + "\");
} if (Getto ()!= null) {buf.append ("to=\"). Append (Stringutils.escapeforxml ()). Getto ("\");
} if (Getfrom ()!= null) {buf.append ("from=\"). Append (Stringutils.escapeforxml ()). Getfrom ("\"); } if (type = null) {buf.append ("type=\" get\ ">");
else {buf.append ("type=\"). Append (GetType ()). Append (">");
}//Add the query section if there is one.
String queryxml = Getchildelementxml ();
if (queryxml!= null) {buf.append (queryxml);
}//Add the error sub-packet, if there is one.
Xmpperror error = GetError ();
if (Error!= null) {Buf.append (Error.toxml ());
} buf.append ("</iq>");
return buf.tostring (); }/** * Returns the sub-element XML section of the IQ packet, or <tt>null</tt> if there * isn ' t one. Packet extensions <b>must</b> is included, if any are defined.<p> * * Extensions of this class Mus
T override this method.
* @return the child element section of the IQ XML.
* * Public abstract String getchildelementxml (); /** * Convenience method to create a new empty {@link Type#result IQ. Type.result} * IQ based on a {@link Type#get IQ. Type.get} or {@link type#set IQ. Type.set} * IQ.
The new packet would be initialized with:<ul> * <li>the Sender set to the recipient of the originating IQ.
* <li>the recipient set to the sender of the originating IQ. * <li>the Type set to {@link Type#result IQ.
Type.result}. * <li>the ID set to the ID of the originating IQ.
* <li>no child element of the IQ element. * </ul> * @param iq @link Type#get IQ. Type.get} or {@link type#set IQ.
Type.set} IQ packet. * @throws illegalargumentexception If the IQ packet does not have a type of * {@link Type#get IQ. Type.get} or {@link type#set IQ. Type.set}. * @return A new {@link Type#result IQ.
Type.result} IQ based on the originating IQ. * public static IQ Createresultiq (final IQ request) {if (!) ( Request.gettype () = = Type.get | | Request.gettype () = = Type.set)) {throw new IllegalArgumentException ("IQ must is of Type ' SET ' or ' get '). OriginaL IQ: "+ request.toxml ());
Final IQ result = new IQ () {public String getchildelementxml () {return null;
}
};
Result.settype (Type.result);
Result.setpacketid (Request.getpacketid ());
Result.setfrom (Request.getto ());
Result.setto (Request.getfrom ());
return result; /** * Convenience method to create a new {@link type#error IQ. Type.error} IQ * Based on a {@link Type#get IQ. Type.get} or {@link type#set IQ. Type.set} * IQ.
The new packet would be initialized with:<ul> * <li>the Sender set to the recipient of the originating IQ.
* <li>the recipient set to the sender of the originating IQ. * <li>the Type set to {@link type#error IQ.
Type.error}. * <li>the ID set to the ID of the originating IQ.
* <li>the child element contained in the associated originating IQ.
* <li>the provided {@link xmpperror xmpperror}. * </ul> * @param iq the {@linkType#get IQ. Type.get} or {@link type#set IQ.
Type.set} IQ packet.
* @param error The error to associate with the created IQ packet. * @throws illegalargumentexception If the IQ packet does not have a type of * {@link Type#get IQ. Type.get} or {@link type#set IQ. Type.set}. * @return A new {@link type#error IQ.
Type.error} IQ based on the originating IQ. * * public static IQ Createerrorresponse (final IQ request, final Xmpperror error) {if (!) ( Request.gettype () = = Type.get | | Request.gettype () = = Type.set)) {throw new IllegalArgumentException ("IQ must is of Type ' SET ' or ' get ').
Original IQ: "+ request.toxml ());
Final IQ result = new IQ () {public String getchildelementxml () {return request.getchildelementxml ();
}
};
Result.settype (Type.error);
Result.setpacketid (Request.getpacketid ());
Result.setfrom (Request.getto ());
Result.setto (Request.getfrom ());
Result.seterror (Error);
return result;
} /** * A class to represent the type of the IQ packet. The types are: * * <ul> * <li>iq. Type.get * <li>iq. Type.set * <li>iq. Type.result * <li>iq.
Type.error * </ul> * public static class Type {public static final Type get = new Type (' get ');
public static final Type SET = new Type ("SET");
The public static final Type result = the new type ("result");
public static final Type ERROR = new Type ("error"); /** * Converts a String into the corresponding types.
Valid String values * that can is converted to types are: ' Get ', ' set ', ' result ', and ' error '.
* * @param type the String value to covert.
* @return the corresponding Type.
*/public static Type fromstring (String type) {if (Type = = null) {return null;
} type = Type.tolowercase ();
if (get.tostring (). Equals (type)) {return get; else if (set.tostring (). Equals (Type)){return SET;
else if (error.tostring (). Equals (type)) {return ERROR;
else if (result.tostring (). Equals (type)) {return result;
else {return null;
}} private String value;
Private Type (String value) {this.value = value;
Public String toString () {return value;
}
}
}
You can eventually generate data of the following structure
<iq from= "" >
<nofitication xlns= "" >
<iq>
Our use of the project is simple
xmppManager.getConnection().sendPacket(<NotificationIQ>niq)
Of course, the above just realized the object->xml, and then we realize xml->data
2. Realize Iqprovider
First look at the Iqprovider source
Public interface Iqprovider {
/**
* Parse the IQ sub-document and create an IQ instance. Each IQ must have a
* single child element. At the beginning of the "method" call, the XML parser * 'll be positioned at the
opening tag of the "the IQ child element." t the end
* is call, the parser <b>must</b> is positioned on the closing tag * of the child
element.
*
* @param parser an XML parser.
* @return A new IQ instance.
* @throws Exception If an error occurs parsing the XML.
* * Public
IQ Parseiq (Xmlpullparser parser) throws Exception;
}
Implementing a custom parsing tool
public class Notificationiqprovider implements Iqprovider {public Notificationiqprovider () {} @Override Public
IQ Parseiq (Xmlpullparser parser) throws Exception {Notificationiq notification = new Notificationiq (); For (Boolean = false;!done;)
{int eventtype = Parser.next ();
if (EventType = = 2) {if ("id". Equals (Parser.getname ())) {Notification.setid (Parser.nexttext ());
} if ("Apikey". Equals (Parser.getname ())) {Notification.setapikey (Parser.nexttext ());
} if ("title". Equals (Parser.getname ()) {Notification.settitle (Parser.nexttext ());
} if ("Message". Equals (Parser.getname ()) {Notification.setmessage (Parser.nexttext ());
} if ("uri". Equals (Parser.getname ()) {Notification.seturi (Parser.nexttext ());
} else if (EventType = 3 && "notification". Equals (Parser.getname ())) {done = true; } return notification;
}
}
How to use the project
Providermanager.getinstance (). Addiqprovider ("Notification",
"Androidpn:iq:notification",
New Notificationiqprovider ());
The following calls are made in the Packetparserutils class in Asmack
Object Provider = Providermanager.getinstance (). Getiqprovider (ElementName, namespace);
if (provider!= null) {
if (provider instanceof Iqprovider) {
Iqpacket = ((Iqprovider) provider). PARSEIQ (parser);
}
else if (provider instanceof Class) {
iqpacket = (IQ) packetparserutils.parsewithintrospection (ElementName,
(class<?>) provider, parser);
}