34,333
edits
Changes
Created page with "Having established the importance of the role that an app server plays when working with upstream Firebase Cloud messages, it is now time to take a look at an example server...."
Having established the importance of the role that an app server plays when working with upstream Firebase Cloud messages, it is now time to take a look at an example server. The server outlined in this chapter will be used in the next chapter in the implementation of a simple instant messaging app designed to allow users to exchange messages.
This chapter will explain how to load the app server project into Android Studio before providing a guided tour of the key elements of the code that enable the server to communicate with the Firebase Cloud Connection Server (CCS) and to receive and send messages.
== About the FCM App Server Project ==
The app server covered in this project is written in Java and is based on code examples provided by Google for the Google Cloud Messaging service (the precursor to Firebase Cloud Messaging). The code examples were used by Wolfram Rittmeyer as the basis for a simple app server which was subsequently updated for Firebase Cloud Messaging by Nimrod Dayan. For the purposes of this book, the server has been further modified to include persistent storage of user identities and registration IDs and to support the sending of messages between devices.
The project code is contained within the fcm-app-server folder of the sample code download that accompanies this book which may be downloaded from the following URL:
[http://www.ebookfrenzy.com/web/firebase_android http://www.ebookfrenzy.com/web/firebase_android]
Launch Android Studio, select the Open an Existing Android Studio Project option and locate and open the fcm-app-server project.
== Project Dependencies ==
As previously mentioned, the app server is written entirely in Java. The server code also makes use of the following open source libraries which can be found listed under the libs folder in the Android Studio project tool window:
• '''Smack''' – Smack is an open source Java library providing an API for communicating with XMPP servers. This API is used to communicate between the app server and the CCS.
• '''Smackx''' – The Smack Extensions library. Although the app server code does not make direct use of this library, it is a requirement for the main Smack library.
• '''Moshi''' – JSON library for Android and Java. This library is used by the app server to parse JSON to and from Java objects. The app server implements custom Moshi-based type adaptors to work with both upstream and downstream messages.
• '''Okio''' – A library used to process input and output data. While it is not used directly by the app server it is a requirement for other libraries.
• '''XML Pull''' – Used by the Smack library to parse streaming XML.
== CcsClient.java ==
The CcsClient class implements a simple client for communicating with the Firebase CCS. It is responsible for reading the configuration settings from a property file, establishing the connection to the CCS using the Smack API and then handling incoming messages. The class also includes a send method which takes as an argument a JSON request and sends it to the CCS.
The key methods of the class are as follows:
• '''main()'' – The entry point into the app server when it is started from the command-line. This method reads server key and sender ID values from a properties file and initiates the connection to the CCS.
• '''connect()''' – Called by the main() method to establish the CCS connection. Once the connection has been established, the method also adds a listener to the connection to report the loss of a connection and attempt to reconnect. The method also adds a packet listener to detect the arrival of new messages from the CCS. This listener converts the incoming packet to JSON and passes it to the handleMessage() method.
• '''handleMessage()''' – This method examines the incoming JSON message and identifies the message type. If the message is an ACK or NACK from the CCS output is sent to the logger identifying the corresponding message ID. If the message is determined to be an upstream message from a client app, an ACK message is sent to the CCS and the message passed to the handleIncomingDataMessage() method.
• '''handleIncomingDataMessage()''' – This app server is designed to handle two types of upstream message. A registration message contains the registration ID from the client and the email address of the user. These need to be stored for reference later when sending messages to specific users. The second message type contains the email address of a recipient and the message to be sent to that user. The task of determining how the message is to be treated is handled by the getProcessor() method of the ProcessorFactory class.
== PayloadProcessor.java ==
The PayloadProcessor class is responsible for deciding which type of processor is needed to handle an upstream message. When upstream messages are sent from the client app, the data payload contains an action key set to a value of either “REGISTER” or “MESSAGE”. The CcsClient handleIncomingDataMessage() method extracts the value assigned to the action key and passes it to the getProcessor() method a PayloadProcessor object which, in turn, returns an instance of either the PayloadProcessor or RegisterProcessor class to handle the message.
== RegisterProcessor.java ==
When the client app is launched it sends a registration type upstream message containing the user’s email address. By default an upstream message also contains the app’s registration token. The RegisterProcessor handleMessage() method uses an instance of the AccountStore class to store this data in a HashMap which is saved to a file.
== AccountStore.java ==
A rudimentary storage class designed to store user email and registration token data as properties in a data file:
• '''readFile()''' – Checks whether or not the properties file exists. If it exists, the data is read into a HashMap.
• '''addRegistration()''' – Called when a client sends a registration upstream message. The email address and corresponding registration token are added to the HashMap and the writeFile() method called.
• '''writeFile()''' – Converts the HashMap to a Properties object and writes it to the properties file.
• '''getRegistrationIdForAccount()''' – When passed an email address, this method returns the corresponding registration token.
• '''getUniqueMessageId()''' – Returns a string based on a random long number to act as a message ID when sending outbound messages.
== MessageProcessor.java ==
When the client app sends an upstream message containing a message to be sent to another user, the handleMessage() method of this class is called. This method extracts the email address of the destination user from the message payload and uses it to obtain the corresponding registration token from the account store together with a unique message ID. A JSON message is then constructed and the send() method of the CcsClient instance called to send it to the CCS for delivery to the recipient’s device.
== Building and Running the Server ==
The server can be built and run on any system that supports Java and has access to the internet via port 5236. In this example, the server can be executed from within the Android Studio environment and the log output viewed within the Run tool window. Before starting the server, however, the fcm-app-server.properties file needs to be configured with the server key and sender ID associated with the Firebase Examples project.
As previously outlined, both the cloud messaging server key and sender ID for the project are available within the Firebase console. Within the console, select the Firebase Examples project, click on the gear icon next to the Overview heading and select the Project settings menu option. On the Settings screen, select the Cloud Messaging tab and locate the Server key and Sender ID fields in the Project credentials section.
Edit the fcm-app-server.properties file which is located in the top level directory of the fcm-app-server project folder and enter the credentials into the appropriate fields.
Build the project by selecting the Build -> Make Module ‘fcm-app-server’ menu option. If the menu provides two options to build the module, be sure to select the second one as highlighted in Figure 31-1:
[[File:]]
Figure 31-1
After the server has built, click on the toolbar run button to start the server. Refer to the Run tool window and verify that the server has started without any errors:
[[File:]]
Figure 31-2
Assuming that no errors occurred, the server is now connected to the CCS and is listening for incoming messages.
The Smack library also includes a debugging user interface window (Figure 31-3) that displays all of the packets sent and received over the XMPP connection.
[[File:]]
Figure 31-3
By default, the window shows three panels listing sent, received and interpreted packets (the latter being messages that have been parsed by the Smack library as opposed to raw messages passed directly to the server). Tabs along the top of the window can be used to focus solely on one category of packet. At this point the interpreted panel should show the successful authentication of the app server with the CCS. If an error occurred (such as an invalid server key), the panel will include details of the failure.
The debug window is useful for monitoring the packets travelling between the CCS and app server, both to aid in resolving problems and as a way to learn how the XMPP protocol works. To disable the debug window (an important step if the app server is to be run on a headless server), edit the CcsClient.java file and modify the following variable declaration so that it reads as follows:
<pre>
private boolean mDebuggable = false;
</pre>
With the app server now running, the next step is to develop a client app so that it can be put to use.
== Summary ==
Upstream Firebase cloud messaging requires the presence of an app server continuously connected to the Firebase CCS. The app server contains the logic that defines what happens when upstream messages are sent from client devices. This chapter has outlined the structure and basic logic of a simple app server that will be used in the next chapter to implement an example instant messaging app.
This chapter will explain how to load the app server project into Android Studio before providing a guided tour of the key elements of the code that enable the server to communicate with the Firebase Cloud Connection Server (CCS) and to receive and send messages.
== About the FCM App Server Project ==
The app server covered in this project is written in Java and is based on code examples provided by Google for the Google Cloud Messaging service (the precursor to Firebase Cloud Messaging). The code examples were used by Wolfram Rittmeyer as the basis for a simple app server which was subsequently updated for Firebase Cloud Messaging by Nimrod Dayan. For the purposes of this book, the server has been further modified to include persistent storage of user identities and registration IDs and to support the sending of messages between devices.
The project code is contained within the fcm-app-server folder of the sample code download that accompanies this book which may be downloaded from the following URL:
[http://www.ebookfrenzy.com/web/firebase_android http://www.ebookfrenzy.com/web/firebase_android]
Launch Android Studio, select the Open an Existing Android Studio Project option and locate and open the fcm-app-server project.
== Project Dependencies ==
As previously mentioned, the app server is written entirely in Java. The server code also makes use of the following open source libraries which can be found listed under the libs folder in the Android Studio project tool window:
• '''Smack''' – Smack is an open source Java library providing an API for communicating with XMPP servers. This API is used to communicate between the app server and the CCS.
• '''Smackx''' – The Smack Extensions library. Although the app server code does not make direct use of this library, it is a requirement for the main Smack library.
• '''Moshi''' – JSON library for Android and Java. This library is used by the app server to parse JSON to and from Java objects. The app server implements custom Moshi-based type adaptors to work with both upstream and downstream messages.
• '''Okio''' – A library used to process input and output data. While it is not used directly by the app server it is a requirement for other libraries.
• '''XML Pull''' – Used by the Smack library to parse streaming XML.
== CcsClient.java ==
The CcsClient class implements a simple client for communicating with the Firebase CCS. It is responsible for reading the configuration settings from a property file, establishing the connection to the CCS using the Smack API and then handling incoming messages. The class also includes a send method which takes as an argument a JSON request and sends it to the CCS.
The key methods of the class are as follows:
• '''main()'' – The entry point into the app server when it is started from the command-line. This method reads server key and sender ID values from a properties file and initiates the connection to the CCS.
• '''connect()''' – Called by the main() method to establish the CCS connection. Once the connection has been established, the method also adds a listener to the connection to report the loss of a connection and attempt to reconnect. The method also adds a packet listener to detect the arrival of new messages from the CCS. This listener converts the incoming packet to JSON and passes it to the handleMessage() method.
• '''handleMessage()''' – This method examines the incoming JSON message and identifies the message type. If the message is an ACK or NACK from the CCS output is sent to the logger identifying the corresponding message ID. If the message is determined to be an upstream message from a client app, an ACK message is sent to the CCS and the message passed to the handleIncomingDataMessage() method.
• '''handleIncomingDataMessage()''' – This app server is designed to handle two types of upstream message. A registration message contains the registration ID from the client and the email address of the user. These need to be stored for reference later when sending messages to specific users. The second message type contains the email address of a recipient and the message to be sent to that user. The task of determining how the message is to be treated is handled by the getProcessor() method of the ProcessorFactory class.
== PayloadProcessor.java ==
The PayloadProcessor class is responsible for deciding which type of processor is needed to handle an upstream message. When upstream messages are sent from the client app, the data payload contains an action key set to a value of either “REGISTER” or “MESSAGE”. The CcsClient handleIncomingDataMessage() method extracts the value assigned to the action key and passes it to the getProcessor() method a PayloadProcessor object which, in turn, returns an instance of either the PayloadProcessor or RegisterProcessor class to handle the message.
== RegisterProcessor.java ==
When the client app is launched it sends a registration type upstream message containing the user’s email address. By default an upstream message also contains the app’s registration token. The RegisterProcessor handleMessage() method uses an instance of the AccountStore class to store this data in a HashMap which is saved to a file.
== AccountStore.java ==
A rudimentary storage class designed to store user email and registration token data as properties in a data file:
• '''readFile()''' – Checks whether or not the properties file exists. If it exists, the data is read into a HashMap.
• '''addRegistration()''' – Called when a client sends a registration upstream message. The email address and corresponding registration token are added to the HashMap and the writeFile() method called.
• '''writeFile()''' – Converts the HashMap to a Properties object and writes it to the properties file.
• '''getRegistrationIdForAccount()''' – When passed an email address, this method returns the corresponding registration token.
• '''getUniqueMessageId()''' – Returns a string based on a random long number to act as a message ID when sending outbound messages.
== MessageProcessor.java ==
When the client app sends an upstream message containing a message to be sent to another user, the handleMessage() method of this class is called. This method extracts the email address of the destination user from the message payload and uses it to obtain the corresponding registration token from the account store together with a unique message ID. A JSON message is then constructed and the send() method of the CcsClient instance called to send it to the CCS for delivery to the recipient’s device.
== Building and Running the Server ==
The server can be built and run on any system that supports Java and has access to the internet via port 5236. In this example, the server can be executed from within the Android Studio environment and the log output viewed within the Run tool window. Before starting the server, however, the fcm-app-server.properties file needs to be configured with the server key and sender ID associated with the Firebase Examples project.
As previously outlined, both the cloud messaging server key and sender ID for the project are available within the Firebase console. Within the console, select the Firebase Examples project, click on the gear icon next to the Overview heading and select the Project settings menu option. On the Settings screen, select the Cloud Messaging tab and locate the Server key and Sender ID fields in the Project credentials section.
Edit the fcm-app-server.properties file which is located in the top level directory of the fcm-app-server project folder and enter the credentials into the appropriate fields.
Build the project by selecting the Build -> Make Module ‘fcm-app-server’ menu option. If the menu provides two options to build the module, be sure to select the second one as highlighted in Figure 31-1:
[[File:]]
Figure 31-1
After the server has built, click on the toolbar run button to start the server. Refer to the Run tool window and verify that the server has started without any errors:
[[File:]]
Figure 31-2
Assuming that no errors occurred, the server is now connected to the CCS and is listening for incoming messages.
The Smack library also includes a debugging user interface window (Figure 31-3) that displays all of the packets sent and received over the XMPP connection.
[[File:]]
Figure 31-3
By default, the window shows three panels listing sent, received and interpreted packets (the latter being messages that have been parsed by the Smack library as opposed to raw messages passed directly to the server). Tabs along the top of the window can be used to focus solely on one category of packet. At this point the interpreted panel should show the successful authentication of the app server with the CCS. If an error occurred (such as an invalid server key), the panel will include details of the failure.
The debug window is useful for monitoring the packets travelling between the CCS and app server, both to aid in resolving problems and as a way to learn how the XMPP protocol works. To disable the debug window (an important step if the app server is to be run on a headless server), edit the CcsClient.java file and modify the following variable declaration so that it reads as follows:
<pre>
private boolean mDebuggable = false;
</pre>
With the app server now running, the next step is to develop a client app so that it can be put to use.
== Summary ==
Upstream Firebase cloud messaging requires the presence of an app server continuously connected to the Firebase CCS. The app server contains the logic that defines what happens when upstream messages are sent from client devices. This chapter has outlined the structure and basic logic of a simple app server that will be used in the next chapter to implement an example instant messaging app.