Well, the source of the study began. At present, the ANDROIDPN, limited to use it, ran a demo. Now start studying the source code.
(a) Entrance
When the server side starts, the console will print some log, in addition to spring and Hibernate,mina, in the last few lines, is the ANDROIDPN code, the first is the Xmppserver class.
In Xmppserver, load the spring configuration file. This seems to be the spring load configuration file is omitted, anyway, there is no Application*.xml file mentioned in Web. Xml.
(ii) Web process
When it starts, it also loads some of the actions in the configuration (SPRINGMVC, which is not known to be the same), and in the page, clicking on each connection will execute the action information. The main thing is the method of send.
PublicModelandview Send (httpservletrequest request, httpservletresponse response)throwsException {String broadcast=Servletrequestutils.getstringparameter (Request,"Broadcast", "Y"); String username=Servletrequestutils.getstringparameter (Request,"Username"); String title= Servletrequestutils.getstringparameter (Request, "title"); String message=Servletrequestutils.getstringparameter (Request,"Message"); String URI= Servletrequestutils.getstringparameter (Request, "uri"); String ApiKey= Config.getstring ("ApiKey", "" "); Logger.debug ("Apikey=" +ApiKey); if(Broadcast.equalsignorecase ("Y") { notificationmanager.sendbroadcast (ApiKey, title, message, URI); } Else{ notificationmanager.sendnotifcationtouser (ApiKey, username, title, message, URI); } modelandview Mav=NewModelandview (); Mav.setviewname ("Redirect:notification.do"); returnMav; }
The red font above, which is the method of execution, now begins to enter the subject.
(iii) Service flow
Broadcast code:
Public void sendbroadcast (String ApiKey, string title, String message, string uri) { log.debug ("Sendbroadcast () ..."); Log.debug (// IQ notificationiq = Createnotificationiq (apiKey, title, message, URI); for (Clientsession session:sessionManager.getSessions ()) { if (Session.getpresence ()). IsAvailable ()) { Notificationiq.setto (session.getaddress ()); Session.deliver (Notificationiq); }}}
Here, the first is to construct an IQ-type object, based on the XMPP protocol.
Then check from the server, whether there is a client presence, if there is client information, based on the client's information, the IQ is sent to the client. Then just look at how the client is generated.
(iv) Client connection
If you don't know where to look, you can test it with a real machine or simulator to see what's printed in the server log when the client connects.
When you first connect, there is a first record:
<org.androidpn.server.xmpp.net.XmppIoHandler>: sessioncreated () ...
Well, the gateway to the client connection is the Xmppiohandler class.
In fact, this thing, there is a configuration. When the xmppserver starts, load the Spring-config.xml file, in which there are two configurations:
<BeanID= "Xmpphandler"class= "Org.androidpn.server.xmpp.net.XmppIoHandler" /> <BeanID= "Ioacceptor"class= "Org.apache.mina.transport.socket.nio.NioSocketAcceptor"Init-method= "Bind"Destroy-method= "Unbind"> < Propertyname= "Defaultlocaladdress"value= ": 5222" /> < Propertyname= "Handler"ref= "Xmpphandler" /> < Propertyname= "Filterchainbuilder"ref= "Filterchainbuilder" /> < Propertyname= "Reuseaddress"value= "true" /> </Bean>
This is Mina, this thing has not been touched before. However, the communication connection between the client and the server is based on this framework. Baidu Encyclopedia has a very concise section of the introduction.
Xmppiohandler This class to implement several methods in the Iohandler interface. About these several methods, need to explain, otherwise really is confused, here quoted the information on the Internet:
Handler is used to handle Mina triggered i/o event. Iohandler is a core interface that defines all the behaviors required at the end of the filter chain. The Iohandler interface contains the following methods: sessioncreated sessionopened sessionclosed sessionidle exceptioncaught messageReceived Message Sentsessioncreated event when a new connection is created, the Sessioncreated event is triggered. For TCP, this event represents the establishment of a connection, and for UDP, it represents the receipt of a UDP packet. This method can be used to initialize the various properties of the session,
It can also be used to trigger some one-off behavior on a newly created connection. IThe/O processor thread calls this method, so when implementing the method, only a few more time-consuming operations are added, because i/O Processor threads are used to handle multi-session.
The sessionopened event triggers a sessionopened event when a connection is opened, which is always triggered after the sessioncreated. If the thread mode is configured, then this method is not/O Processor thread call.
The sessionclosed event triggers the Sessionclosed event when a session is closed. You can put the session cleanup operation in this method.
The Sessionidle event triggers the Sessionidle event when a session is idle. This method will not be called when UDP is used.
Exceptioncaught Event event is triggered when the user code or the Mina framework throws an exception. If the exception is a ioexception, then connection will be closed.
The messagereceived event triggers the Messagereceived event when a message is received. All business processing code should be written here, but be mindful of the type of message you want.
The Messagesent event triggers the Messagesent event (called Iosession.write () to send a message) when the message has been received by the remote.
From the server's background log can also be found, the order of creation of these events: sessioncreated ()--sessionopened ()--messagereceived ()--messagesent ()--- Exceptioncaught ().
In creating the session, there's nothing to do about it.
About Sessionopen:
Public voidSessionopened (iosession session)throwsException {log.debug ("Sessionopened () ..."); Log.debug ("Remoteaddress=" +session.getremoteaddress ()); //Create A new XML parserXmllightweightparser parser =NewXmllightweightparser ("UTF-8"); Session.setattribute (Xml_parser, PARSER); //Create a new connectionConnection Connection =NewConnection (session); Session.setattribute (CONNECTION, CONNECTION); Session.setattribute (Stanza_handler,NewStanzahandler (ServerName, connection)); }
In the Sessionopen, there are some things that have been done. First iosession this type, from the Eclipse auto-completion, you can see that there are many properties, including the source of the address listed in the session from the IP. In this, the author adds several attributes to it: Xml_parser,connection,stanza_handler. Each of the three is an object. About the Connection property, it should be needed for the server to send the message. The last field is the literal meaning of the XML node. In general, this method is for the connection information sent from the client, and another package, adding some information.
Messagereceived (), when the client connection, the server will have a message received, received by the client, to establish a connection message:
<to= "192.168.10.100" xmlns= "Jabber:client" Xmlns:stream = "Http://etherx.jabber.org/streams" version= "1.0">
Public voidMessagereceived (iosession session, Object message)throwsException {log.debug ("Messagereceived () ..."); Log.debug ("RCVD:" +message); //Get the stanza handlerStanzahandler handler =(Stanzahandler) session. getattribute (Stanza_handler); //Get The XMPP packet parser intHashcode =Thread.CurrentThread (). Hashcode (); Xmpppacketreader Parser=Parsers.get (hashcode); if(Parser = =NULL) {parser=NewXmpppacketreader (); Parser.setxppfactory (Factory); Parsers.put (hashcode, parser); } //The stanza handler processes the message Try{handler.process (String) message, parser); } Catch(Exception e) {log.error ("Closing connection due to error while processing message:" +message, E); Connection Connection=(Connection) session. getattribute (Connection); Connection.close (); } }
This method also does some things. The first is to get the Stanza_handler object added to the Sessionopen, and then get the parser for the XMPP packet. The following is the start of the Stanzahandler class process method, which begins to process the resulting XML information from something. This seems to be a big event, but also to polish the gun slowly to see, this method is a bit long, really tangled segment to see it:
Public voidprocess (String stanza, Xmpppacketreader reader)throwsException {BooleanInitialstream = Stanza.startswith ("<stream:stream"); if(!sessioncreated | |Initialstream) { if(!Initialstream) { return;//Ignore <?xml version= "1.0"?> } if(!sessioncreated) {sessioncreated=true; Mxparser Parser=Reader.getxppparser (); Parser.setinput (NewStringReader (stanza)); CreateSession (parser); } Else if(STARTEDTLS) {Startedtls=false; Tlsnegotiated (); } return; }
If the information sent, not beginning with <stream:stream, that directly on GG, returned to the Xmppiohandler class messagereceived method, everything over.
There are a lot of logical judgments, if the session is created or the resulting node information is the beginning of the <stream:stream, the two have a matching condition, it will enter the following judgment.
When the client and server are connected,if (! sessioncreated) This will determine execution because sessioncreated defaults to False. Here's what the client sends:
<to= "192.168.10.100" xmlns= "Jabber:client" xmlns: Stream= "Http://etherx.jabber.org/streams" version= "1.0">
This information, put in the Mxparser object (these are the openfire of the official things), and then called the CreateSession method, the method has the following code:
//Create the correct session based on the sent namespaceString namespace = Xpp.getnamespace (NULL); if("Jabber:client". Equals (namespace)) {Session=clientsession.createsession (ServerName, Connection, xpp); if(Session = =NULL) {StringBuilder sb=NewStringBuilder (250); Sb.append ("<?xml version= ' 1.0 ' encoding= ' UTF-8 '?> '); Sb.append ("<stream:stream from=\" "). Append (ServerName); Sb.append ("\" Id=\ ""). Append (RandomString (5)); Sb.append ("\" Xmlns=\ ""). Append (Xpp.getnamespace (NULL)); Sb.append ("\" Xmlns:stream=\ ""). Append (Xpp.getnamespace ("Stream")); Sb.append ("\" version=\ "1.0\" > "); //Bad-namespace-prefix in the responseStreamerror error =NewStreamerror (StreamError.Condition.bad_namespace_prefix); Sb.append (Error.toxml ()); Connection.deliverrawtext (Sb.tostring ()); Connection.close (); Log. Warn ("Closing session due to Bad_namespace_prefix in stream header:" +namespace); } }
The original comment says this is based on the sent namespace, to establish the correct session. That is the sentence:
Session = Clientsession.createsession (ServerName, Connection, xpp);
This is a static class, and when we enter this method, we can see a log message on the console output.
Here are some of the things that you do with connection, setting the language and the version information for XMPP. Then the real clientsession is created:
clientsession session = sessionmanager.getinstance () . Createclientsession (connection);