{"id":2748,"date":"2017-08-31T18:44:02","date_gmt":"2017-08-31T16:44:02","guid":{"rendered":"https:\/\/blog.mi.hdm-stuttgart.de\/?p=2748"},"modified":"2023-06-08T17:34:14","modified_gmt":"2023-06-08T15:34:14","slug":"developing-a-chat-server-and-client-in-the-cloud","status":"publish","type":"post","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/","title":{"rendered":"Developing a Chat Server and Client in the Cloud"},"content":{"rendered":"<h1>Introduction<\/h1>\n<p>During the Lecture &#8220;Software Development for Cloud Computing&#8221; I decided to develop a Cloud based Chat Application with the help of IBM&#8217;s <a href=\"https:\/\/www.ibm.com\/cloud-computing\/bluemix\">Bluemix<\/a>.<br \/>\nThe Application consists of 3 separate Applications:<\/p>\n<ul>\n<li>Chat Server: Allows Clients to connect to it, manages the Chat-Channels\/Users and relays messages sent from a client to the other clients in the same channel.<\/li>\n<li>Chat Client: The Client consists of a GUI where the User can connect to the Server and chat with other Users.<\/li>\n<li>Chat Backend Database: A simple Database which records and provides the chat history of a given Chat-Channel via REST.<\/li>\n<\/ul>\n<p><!--more--><br \/>\nThe following Image describes the connections\/interactions between the different applications. These will be described in more detail later.<\/p>\n<p><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/StudyChat.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2758\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/studychat\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/StudyChat.png\" data-orig-size=\"728,561\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"StudyChat\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/StudyChat.png\" class=\"wp-image-2758 alignleft\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/StudyChat-300x231.png\" alt=\"\" width=\"738\" height=\"568\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/StudyChat-300x231.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/StudyChat.png 728w\" sizes=\"auto, (max-width: 738px) 100vw, 738px\" \/><\/a><\/p>\n<p>The motivation behind this was that I always wanted to do a traditional Client-Server application and this Project was a good reason for it.<br \/>\nTo develop everything for the Cloud was an additional challenge since I had some experience with cloud based application but never really got into it.<\/p>\n<p>In the following paragraphs I will explain how these services were developed, what Problems arose and how IBM&#8217;s Bluemix performed.<br \/>\n(You can try out the client right <a href=\"http:\/\/studychatclient.mybluemix.net\/\" target=\"_blank\" rel=\"noopener\">here<\/a>.<br \/>\nIt should be working for at least another month of the time of this publishing, after that my trial runs out and I don&#8217;t know what&#8217;ll happen.)<\/p>\n<h2>Development<\/h2>\n<h3>Used Tools<\/h3>\n<p>All 3 applications were written in Java since I have the most experience with it and already knew some libraries I was going to use.<br \/>\nAs an IDE I used <a href=\"https:\/\/www.eclipse.org\/\" target=\"_blank\" rel=\"noopener\">Eclipse<\/a>, as Build Tool I used <a href=\"https:\/\/gradle.org\/\" target=\"_blank\" rel=\"noopener\">Gradle<\/a>.<br \/>\nA great tool to check for additional flaws or erros I used <a href=\"https:\/\/www.sonarqube.org\/\" target=\"_blank\" rel=\"noopener\">SonarQube<\/a> for code analysis which also has a plugin(SonarLint) for Eclipse.<br \/>\nAs a Build tool I chose Gradle since it is a lot more flexible due to its programmable nature.<br \/>\nAnd since groovy is very close to Java it&#8217;s quite easy to work with.<br \/>\nI chose <a href=\"https:\/\/git-scm.com\/\" target=\"_blank\" rel=\"noopener\">Git<\/a> as a Version Control System out of personal preference and experience.<br \/>\nThe Continuous Delivery Service of Bluemix supports Github Repositories which is an additional plus.<\/p>\n<h3>First Steps<\/h3>\n<p>When I first started developing on this project I started with the most important part, exchanging messages in a Server-Client structure.<br \/>\nNaivly I tried to use standard Java Sockets(java.net.Socket) which quickly failed for a reason:<br \/>\nWhen developing a Application in Bluemix usually only one single Port is open for use, which is mapped to the url of your application(in my case https:\/\/studychatclient.bluemix.net etc.).<br \/>\nIn my case the port defaulted to 8080 but others are possible.<br \/>\nSince each Java Socket connection needs its own port and I wanted\/needed multiple connections that option was qickly ruled out.<br \/>\nAfter that I tried to solve the issue by using REST calls, which worked ok at the time but obviously not fast enough.<br \/>\nOnly after a few weeks I found the oerfect(?) Solution for my problem: WebSockets.<br \/>\nWebSockets are based on TCP and work by sending an Upgrade request on an existing HTTP connection.<br \/>\nWhen this was succesful we have a full-duplex connection over an already used port and this isn&#8217;t limited to only one connection.<br \/>\nAfter this revelation I quickly searched for a fitting library and found org:java-websocket:Java-WebSocket(<a href=\"https:\/\/github.com\/TooTallNate\/Java-WebSocket\">https:\/\/github.com\/TooTallNate\/Java-WebSocket<\/a>) which provides two classes, WebSocketServer and WebSocketClient, which can easily be extended.<br \/>\nAn empty WebSocketServer extended class looks something like this:<\/p>\n<pre class=\"prettyprint lang-java\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">public class Server extends WebSocketServer\n{\n    public Server(final InetSocketAddress address)\n    {\n        super(address);\n    }\n\n    @Override\n    public void onOpen(final WebSocket conn, final ClientHandshake handshake)\n    {\n    }\n\n    @Override\n    public void onClose(final WebSocket conn, final int code, final String reason, final boolean remote)\n    {\n    }\n\n    @Override\n    public void onMessage(final WebSocket conn, final String message)\n    {\n    }\n\n    @Override\n    public void onError(final WebSocket conn, final Exception ex)\n    {\n    }\n}<\/pre>\n<p>The Client looks the same except for the Constructor, which needs an URI instead of an InetSocketAddress.<br \/>\nFor actually connection to the Server there exists the &#8220;connect()&#8221; and &#8220;connectBlocking()&#8221; methods, with the first one being run in the background.<br \/>\nAdditionally the WebSocket objects received as paramters in these methods can be used to send messages, either as a String, byte array or ByteBuffer.<br \/>\nWith this solution it is very easy to send messages between server and client but for a chat application there needed to be a few more things done.<\/p>\n<h3>Graphical User Interface<\/h3>\n<p>A chat application needs a GUI to be used efficiently, chatting via a command line interface would be quite bad and very limiting.<br \/>\nI started looking into a HTML+Javascript combination but quickly stopped due to my aversion and limited experience of JavaScript.<br \/>\nBut then I remembered <a href=\"https:\/\/vaadin.com\/home\">Vaadin<\/a>, which makes it possible to build web UIs in Java.<br \/>\nYou can try out their demos <a href=\"https:\/\/vaadin.com\/demo\" target=\"_blank\" rel=\"noopener\">here<\/a>.<br \/>\nIt&#8217;s based on the &#8220;javax.servlet.annotation.WebServlet&#8221; interface and provides similar functionality to the JavaFX framework, which I was already familiar with.<br \/>\nI had quite a few problems with settings it up and running it correctly but after many tries I settled on this:<\/p>\n<pre class=\"prettyprint lang-java\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">@Theme(\"valo\")\npublic class ChatUI extends UI\n{\n    @WebServlet(name = \"ChatUIServlet\", asyncSupported = true)\n    @VaadinServletConfiguration(ui = ChatUI.class, productionMode = false)\n    public static class ChatUIServlet extends VaadinServlet\n    {\n        private static final long serialVersionUID = -6216866496615055637L;\n    }\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(ChatUI.class);\n\n    private static final long serialVersionUID = 903938514945760669L;\n\n    @Override\n    protected void init(final VaadinRequest request)\n    {\n        final ChatView chatView = new ChatView();\n\n        this.setContent(chatView);\n        this.setPollInterval(500);\n        this.addDetachListener(event -&gt;\n        {\n            ChatUI.LOGGER.info(\"Closing View!\");\n            if (chatView.getClient() != null)\n            {\n                chatView.getClient().stopTimer();\n            }\n        });\n    }\n}<\/pre>\n<p>The UI class, which I extended here, represents the top most component in the Vaadin component hierarchy.<br \/>\nFor every instance of the Chat Client openend in a Browser a ChatUI Object will be created.<br \/>\nAs its content I created a ChatView, as you can see in the &#8220;init&#8221; method, which contains all the buttons, textfields and similar(usually in further subclasses).<br \/>\nThere exists a Graphical Designer to design a Vaadin UI in a Drag-and-Drop fashion but it isn&#8217;t available for free so I had to do it all in Code which is unfortunate but not the end of the world.<\/p>\n<h3>Server<\/h3>\n<p>The Server has effectively two responsibilities:<\/p>\n<ul>\n<li>Managing users<\/li>\n<li>Managing channels<\/li>\n<\/ul>\n<h4>Managing channels<\/h4>\n<p>Managing Channels contains relaying messages from one user to the rest of the channel and handling joining\/leaving of a user.<\/p>\n<h5>Channel registry<\/h5>\n<p>I had the idea of a single channel registry which controls\/manages all channels.<br \/>\nOriginally I wanted to add the ability to create custom channels but left it out because of time reasons and so the channel registry is a pretty lightweight class.<br \/>\nIt has a list containing all channels, in this case 6 fixed channels. It allows to access them by name or to send a list of all channels to a user.<br \/>\nI made this class a singleton, since there should be only every one instance of it.<\/p>\n<h5>Joining\/Leaving<\/h5>\n<pre class=\"prettyprint lang-java\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">    public boolean userJoin(final RemoteUser user)\n    {\n        LOGGER.debug(\"User {} wants to join Channel {}\", user.getName(), this.getName());\n        if (this.userList.size() &lt; this.maxUsers &amp;&amp; !this.userList.contains(user))\n        {\n            this.userList.add(user);\n            this.sendMessageToChannel(user, MessageType.CHANNEL_USER_CHANGE);\n            this.sendHistoryToUser(user);\n            return true;\n        }\n        return false;\n    }<\/pre>\n<p>When a User wants to join a channel, first the channel checks if the user can join and if so, notifies all other users that the user list has changed.<br \/>\nAfter that the chat history of that channel is retreived and sent to the new users client for display.<\/p>\n<pre class=\"prettyprint lang-java\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">    public boolean userExit(final RemoteUser user)\n    {\n        LOGGER.debug(\"User {} wants to exit Channel {}\", user.getName(), this.getName());\n        final boolean success = this.userList.remove(user);\n        this.sendMessageToChannel(user, MessageType.CHANNEL_USER_CHANGE);\n        return success;\n    }<\/pre>\n<p>A user leaving is almost the opposite, he\/she is removed from the list of users and another notification is sent so everyone else has the correct user list.<br \/>\nThe &#8220;sendHistoryToUser&#8221; method resolves to a relatively simple REST call which retreives the chat history and sends it to the user as a message.<\/p>\n<h5>Relaying messages<\/h5>\n<pre class=\"prettyprint lang-java\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">    public void sendMessageToChannel(final RemoteUser sender, final Message message)\n    {\n        final String messageType = message.getType();\n        LOGGER.debug(\"Sending message to channel {} with type {}\", this.getName(), messageType);\n        Message msg = null;\n        switch (messageType)\n        {\n        case MessageType.CHANNEL_USER_CHANGE:\n            msg = MessageBuilder.buildUserChangeMessage(this.userList, this);\n            break;\n        case MessageType.CHANNEL_MESSAGE:\n            msg = MessageBuilder.buildMessagePropagateAnswer(message.getMessage(), sender.getName());\n            this.addMessageToHistory(msg);\n            break;\n        default:\n            msg = new Message(\"{}\");\n            LOGGER.error(\"Tried to send message to channel with unknown type: {}\", msg.getType());\n            break;\n        }\n        for (final RemoteUser user : this.userList)\n        {\n            user.sendMessageToUser(msg.toJson());\n        }\n        LOGGER.debug(\"Message sent to channel {} with {} users, Content: {}\", this.name, this.userList.size(), message.toJson());\n    }<\/pre>\n<p>Relaying messages was pretty much a simple loop iterating over all joined users and sending them the given message.<br \/>\nIf it was of the type &#8220;CHANNEL_USER_CHANGE&#8221; it sends the whole list of currently joined users, if it was just &#8220;CHANNEL_MESSAGE&#8221; it sent the chat message around and uploaded it into the chat history.<\/p>\n<h4>Managing users<\/h4>\n<h5>User registry<\/h5>\n<p>As with the channels I created a user registry, managing all users.<br \/>\nWhen a user wants to join the server, he\/she has to send the username they want to use while chatting.<br \/>\nSince every username should be unique to avoid confusions, already used usernames were rejected.<br \/>\nAdditionally I assigned every user a unique and positive ID of the &#8220;long&#8221; datatype to make identification easy.<br \/>\nOut of the name and ID I created user objects which were stored in a Map with the ID as key and the user object as value.<br \/>\nThen of course I created methods for accessing and removing users.<\/p>\n<h3>Client<\/h3>\n<p><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2990\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/client\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client.png\" data-orig-size=\"1757,848\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"client\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client-1024x494.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client-1024x494.png\" alt=\"\" width=\"656\" height=\"316\" class=\"aligncenter size-large wp-image-2990\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client-1024x494.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client-300x145.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client-768x371.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/client.png 1757w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/a><br \/>\nThe client has a relatively simple GUI and, as written above, was built with the Vaadin framework.<br \/>\nI won&#8217;t go into too much detail of how the GUI itself was built, it&#8217;s mainly sticking pre-built blocks together.<\/p>\n<p>Vaadin has several containers such as &#8220;GridLayout&#8221;, &#8220;VerticalLayout&#8221; or similar.<br \/>\nThose containers can be filled with controls such Textfields for inputting text, buttons for pressing, so called &#8220;ListSelects&#8221; for displaying a list and many more.<br \/>\nWhen you look at the screenshot above you can see many of them in action.<br \/>\nI used a GridLayout as the base and then tried to group the different parts together in sub-layouts, i.e. the user list on the right is a VerticalLayout containing a Label for the title and a ListSelect for the user list.<br \/>\nThis splitting of parts helps a lot since they can be worked on seperately.<br \/>\nThe more interesting part is the WebSocketClient although it&#8217;s very similar to the WebSocketServer.<\/p>\n<h4>Detecting disconnected clients<\/h4>\n<p>One interesting problem with Vaadin is detecting when a user\/client disconnects under abnormal instances.<br \/>\nWhen he disconnects via the WebSocketClient it&#8217;s all fine and good but how is it detected if he closes the tab or even the Browser.<br \/>\nThe answer is unfortunately not easy.<br \/>\nVaadin provides several ways to detect this but I haven&#8217;t found a reliable solution.<br \/>\nYou can add a &#8220;DetachListener&#8221; to the Client but I found this to be called only around 30% of the time when I was closing a tab or window.<br \/>\nI then built in a custom &#8220;Heartbeat&#8221;, basically a periodically updating timestamp for each user on the server.<br \/>\nEach period a message would be sent to the respective client and he would (not) answer it and when he would fail to do so, the server would disconnect him.<br \/>\nBut since the closing isn&#8217;t detected very reliably more often than not there would be ghost users, sometimes I would find myself with 6 other users while testing, all of them created by me earlier.<\/p>\n<h3>Chat History Database<\/h3>\n<p>For the chat history service I chose to make it a REST based service with a NoSQL database attached.<br \/>\nMainly because I already knew how to work with REST APIs but never user a NoSQL database before.<br \/>\nIts service is also kind of detached from the server and client so if it fails at any point, the rest can still work.<br \/>\nIBM Bluemix provides such a database, namely the Cloudant NoSQL database, which I promptly connected with my application.<br \/>\nThis gives access to the database authentication via environment while running in the cloud.<br \/>\nCloudant also provides a nice library to use with this database.<\/p>\n<p>I used <a href=\"http:\/\/projects.spring.io\/spring-boot\/\" target=\"_blank\" rel=\"noopener\">SpringBoot <\/a>as the framework using a single controller with 3 methods:<\/p>\n<pre class=\"prettyprint lang-java\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">@RestController\n@RequestMapping(\"\/history\")\npublic class ResourceController\n{\n    @PostMapping(\"\/channel\/{channelName}\")\n    @ResponseStatus(HttpStatus.OK)\n    public String addMessage(@RequestBody final String input, @PathVariable final String channelName)\n    {\n        final JsonObject jo = MessageDatabase.addChannelMessageToDB(channelName, input);\n        return jo.toString();\n    }\n\n    @GetMapping(\"\/channel\/{channelName}\")\n    @ResponseStatus(HttpStatus.OK)\n    public String getChannelMessages(@PathVariable final String channelName)\n    {\n        return MessageDatabase.getMessageFromDB(channelName, new MessageList().getId());\n    }\n\n    @PostMapping(\"\/removeall\/{channelName}\")\n    @ResponseStatus(HttpStatus.OK)\n    public void removeDB(@PathVariable final String channelName)\n    {\n        MessageDatabase.removeDB(channelName);\n    }\n}<\/pre>\n<p>The methods are pretty self explanatory except the removeall POST mapping, which is only in there for development purposes.<\/p>\n<p>The database has a very simple structure:<br \/>\nIt is split into 6 documents, matching the 6 chat channels.<br \/>\nEach of those document contain the list of all messages sent to that channel, with the username who sent it.<br \/>\nThese then can be requested per channel and will be sent as a JSON message containing the array of messages.<\/p>\n<h3>Custom Message protocol:<\/h3>\n<p>For the Server and Client to reliably exchange messages I created custom, standardized JSON messages.<br \/>\nTheir base structure looks like this:<\/p>\n<pre class=\"prettyprint lang-json\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">{\n    \"version\" : &lt;versionNumber&gt;,\n    \"type\" : &lt;messageType&gt;,\n    \"content\" : {\n        &lt;additional Content, depending on messageType&gt;\n    }\n}<\/pre>\n<p>Explanation:<\/p>\n<p>The &#8220;version&#8221; field contains the Version of the chat protocol and serves to differentiate them, if there ever would be a conflict.<br \/>\nThe &#8220;type&#8221; field contains the type of the message, one of the following:<\/p>\n<ul>\n<li>USER_JOIN: A new Client wants to join a Server(not Channel)<\/li>\n<li>USER_HEARTBEAT: Periodic message to check if the client is still running<\/li>\n<li>CHANNEL_MESSAGE: A normal chat message to a channel<\/li>\n<li>CHANNEL_JOIN: A Client connected to the Server wants to join a Chat Channel<\/li>\n<li>ACK_CHANNEL_JOIN: Response to Client for succesful Channel join<\/li>\n<li>CHANNEL_USER_CHANGE: Send to all Clients of a Channel whenever the Userlist of that channel changes, contains the list of clients connected to the channel<\/li>\n<li>CHANNEL_CHANGE: Sends the currently available channels to a freshly connected client<\/li>\n<li>CHANNEL_HISTORY: Contains the Chat history of a channel, which is sent to a client on a channel join<\/li>\n<\/ul>\n<p>Example:<br \/>\nThis would be a message sent from the Client to the Server, containing a chat &#8220;message&#8221; from a Client with a given &#8220;userID&#8221;.<br \/>\nWith this ID the Server can find the User, the channel he\/she is in and send the message to the rest of the users of this channel.<\/p>\n<pre class=\"prettyprint lang-json\" data-start-line=\"1\" data-visibility=\"visible\" data-highlight=\"\" data-caption=\"\">{\n    \"version\" : 1,\n    \"type\" : \"CHANNEL_MESSAGE\",\n    \"content\" : {\n        \"userID\" : 1234567890L,\n        \"message\" : \"Hello World!\"\n    }\n}<\/pre>\n<h2>IBM Bluemix<\/h2>\n<p>Right from the start of the project I wanted to use a continuous delivery pipeline to make developing and testing much easier and comfortable.<br \/>\nLuckily Bluemix had in-built support for this with a (mostly) easy setup:<\/p>\n<p>When creating a Toolchain Bluemix provides several pre built templates to choose from. In this case the &#8220;Simple Cloud Foundry Toolchain&#8221; was sufficient.<\/p>\n<p><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2805\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-schablone\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone.png\" data-orig-size=\"1316,766\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-schablone\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone-1024x596.png\" class=\"aligncenter wp-image-2805 size-large\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone-1024x596.png\" alt=\"\" width=\"656\" height=\"382\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone-1024x596.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone-300x175.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone-768x447.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-schablone.png 1316w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/a>This toolchain is based around a Github repository and even provides a Web based IDE.<br \/>\n<a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2806\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-1\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1.png\" data-orig-size=\"1438,669\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1-1024x476.png\" class=\"aligncenter wp-image-2806 size-large\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1-1024x476.png\" alt=\"\" width=\"656\" height=\"305\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1-1024x476.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1-300x140.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1-768x357.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-1.png 1438w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/a>The toolchain for the Server(and the other two apps) looked like this in the end.<br \/>\n<a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-overview.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2807\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-overview\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-overview.png\" data-orig-size=\"774,424\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-overview\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-overview.png\" class=\"aligncenter wp-image-2807 size-full\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-overview.png\" alt=\"\" width=\"774\" height=\"424\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-overview.png 774w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-overview-300x164.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-overview-768x421.png 768w\" sizes=\"auto, (max-width: 774px) 100vw, 774px\" \/><\/a> I used the Github repository and configured the toolchain with it. This enabled me to use it as an input in the build steps.<br \/>\n<a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2808\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-githubconfig\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig.png\" data-orig-size=\"1173,556\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-githubconfig\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig-1024x485.png\" class=\"aligncenter wp-image-2808 size-large\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig-1024x485.png\" alt=\"\" width=\"656\" height=\"311\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig-1024x485.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig-300x142.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig-768x364.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-githubconfig.png 1173w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/a>I used the two pre-configured build Stages: &#8220;Build&#8221; and &#8220;Deploy&#8221;.<br \/>\nIn Build the unit tests are run and the application assembled while in Deploy the application is pushed to the cloud via the cloud foundry cli.<br \/>\n<a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2809\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-pipeline\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline.png\" data-orig-size=\"1132,651\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-pipeline\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-1024x589.png\" class=\"aligncenter wp-image-2809 size-large\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-1024x589.png\" alt=\"\" width=\"656\" height=\"377\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-1024x589.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-300x173.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-768x442.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline.png 1132w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/a>Each stage consists of one or more Jobs. In case of the Build stage there was a &#8220;Test&#8221; job and a &#8220;Build&#8221; job. As the names imply, the Test job ran the unit tests and the Build job assembled the application, all via Gradle tasks.<br \/>\nIn case of the unit tests, Bluemix can display the result of the tests so you can see where something went wrong.<br \/>\n<a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-job.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2810\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-pipeline-job\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-job.png\" data-orig-size=\"743,818\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-pipeline-job\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-job.png\" class=\"aligncenter wp-image-2810 size-full\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-job.png\" alt=\"\" width=\"743\" height=\"818\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-job.png 743w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-job-272x300.png 272w\" sizes=\"auto, (max-width: 743px) 100vw, 743px\" \/><\/a>In the Input Tab I configured the Stage to use the Git repository as an Input and more importantly set it to run whenever something is pushed to the repository on Github.<br \/>\n<a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-input.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2811\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-pipeline-input\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-input.png\" data-orig-size=\"770,698\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-pipeline-input\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-input.png\" class=\"aligncenter wp-image-2811 size-full\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-input.png\" alt=\"\" width=\"770\" height=\"698\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-input.png 770w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-input-300x272.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-pipeline-input-768x696.png 768w\" sizes=\"auto, (max-width: 770px) 100vw, 770px\" \/><\/a><br \/>\nThe Deploy stage is very simple, it configures the different Cloud-Foundry Variables(Organization, Space, Application Name etc.) and executes the command &#8220;cf push $CF_APP&#8221;. Additional configuration was stored per project in the &#8220;manifest.yml&#8221;.<br \/>\n<a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-deploy.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"2815\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2017\/08\/31\/developing-a-chat-server-and-client-in-the-cloud\/toolchain-deploy\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-deploy.png\" data-orig-size=\"763,731\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"toolchain-deploy\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-deploy.png\" class=\"aligncenter size-full wp-image-2815\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-deploy.png\" alt=\"\" width=\"763\" height=\"731\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-deploy.png 763w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2017\/08\/toolchain-deploy-300x287.png 300w\" sizes=\"auto, (max-width: 763px) 100vw, 763px\" \/><\/a><br \/>\nWhen the jobs of a stage have finished the next stage begins and runs its jobs and so forth.<br \/>\nThis whole process made testing the application very easy since all I needed to was develop something, push the changes and I could test them after 1 or 2 minutes live in the cloud.<br \/>\nBut not everything was great, the biggest problem was configuring a recent version of the JDK. As of this writing the standard version configured is the IBM JDK version 7 and I noticed this not until I tried to build a early version with Java 8 Lambdas. Then began the search on how to change to a Version 8 JDK, which took quite a while. I found the answer first on StackOverflow and later also in the official Documentation: Change the &#8220;JAVA_HOME&#8221; environment variable to $HOME\/java8 (&#8220;export JAVA_HOME=$HOME\/java8&#8221;).<br \/>\nOther Problems were with the UI of Bluemix itself but these were minor and some of them were solved over time.<\/p>\n<h2>Misc.<\/h2>\n<h3>Github Repositories<\/h3>\n<p>Here the list of Github repositories used for this project.<br \/>\nCode quality and documentation could use some improvement but these were not intended for further development.<br \/>\nStill, if there are questions about the code, the best option would be to create an issue on Github.<br \/>\n<a href=\"https:\/\/github.com\/westerwave\/StudyChatServer\">https:\/\/github.com\/westerwave\/StudyChatServer<\/a><br \/>\n<a href=\"https:\/\/github.com\/westerwave\/StudyChatClient\">https:\/\/github.com\/westerwave\/StudyChatClient<\/a><br \/>\n<a href=\"https:\/\/github.com\/westerwave\/StudyChatBackend\">https:\/\/github.com\/westerwave\/StudyChatBackend<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction During the Lecture &#8220;Software Development for Cloud Computing&#8221; I decided to develop a Cloud based Chat Application with the help of IBM&#8217;s Bluemix. The Application consists of 3 separate Applications: Chat Server: Allows Clients to connect to it, manages the Chat-Channels\/Users and relays messages sent from a client to the other clients in the [&hellip;]<\/p>\n","protected":false},"author":465,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,120,650,22],"tags":[],"ppma_author":[734],"class_list":["post-2748","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-cloud-technologies","category-scalable-systems","category-student-projects"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":21651,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/18\/deploy-random-chat-application-on-aws-ec2-with-kubernetes\/","url_meta":{"origin":2748,"position":0},"title":"Deploying Random Chat Application on AWS EC2 with Kubernetes","author":"dv029","date":"18. September 2021","format":false,"excerpt":"1. Introduction For the examination of the lecture \u201cSoftware Development for Cloud Computing\u201d, I want to build a simple Random Chat Application. The idea of this application is based on the famous chat application called Omegle. Omegle is where people can meet random people in the world and can have\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/image-19.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":7125,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/08\/21\/evaluating-and-visualizing-statistical-bot-data\/","url_meta":{"origin":2748,"position":1},"title":"Evaluating and Visualizing Statistical Bot Data","author":"zc001","date":"21. August 2019","format":false,"excerpt":"STAB Website Homepage The idea Video game streaming has taken over a big part of the commercial video game scene with Twitch being its biggest platform. Viewers are able to communicate with other viewers and streamers through the chat, or watch their previous streams or highlights. These highlights are made\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/chart.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/chart.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/chart.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":27618,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/02\/28\/crowdconnect-developing-a-scalable-live-chat-application-with-aws-cloud-services\/","url_meta":{"origin":2748,"position":2},"title":"CrowdConnect &#8211; Developing a Scalable Live Chat Application with AWS Cloud Services","author":"Jannik Scheider","date":"28. February 2025","format":false,"excerpt":"Imagine you're developing a live chat application in the cloud that needs to serve a growing number of users simultaneously and in real time across multiple chat rooms. Sounds like a challenge? It is. But with proven approaches and valuable insights from real-world experience, this task can be successfully and\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-14.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-14.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-14.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":22123,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2022\/02\/21\/scaling-a-basic-chat\/","url_meta":{"origin":2748,"position":3},"title":"Scaling a Basic Chat","author":"Max Merz","date":"21. February 2022","format":false,"excerpt":"Authors: Max Merz \u2014 merzmax.de, @MrMaxMerzMartin Bock \u2014 martin-bock.com, @martbock The idea of this project was to create a simple chat application that would grow over time. As a result, there would be more and more clients that want to chat with each other, what might lead to problems in\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/sent-vs-received_test-3.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/sent-vs-received_test-3.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/sent-vs-received_test-3.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/sent-vs-received_test-3.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":22530,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2022\/02\/28\/discord-monitoring-system-with-amplify-and-ec2\/","url_meta":{"origin":2748,"position":4},"title":"Discord Monitoring System with Amplify and EC2","author":"mk322","date":"28. February 2022","format":false,"excerpt":"Abstract Discord was once just a tool for gamers to communicate and socialize with each other, but since the pandemic started, discord gained a lot of popularity and is now used by so many other people, me included, who don't necessarily have any interest in video gaming. So after exploring\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/data-workflow.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/data-workflow.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/data-workflow.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":5175,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/02\/24\/benefiting-kubernetes-part-2-deploy-with-kubectl\/","url_meta":{"origin":2748,"position":5},"title":"Migrating to Kubernetes Part 2 &#8211; Deploy with kubectl","author":"Can Kattwinkel","date":"24. February 2019","format":false,"excerpt":"Written by: Pirmin Gersbacher, Can Kattwinkel, Mario Sallat Migrating from Bare Metal to Kubernetes The interest in software containers is a relatively new trend in the developers world. Classic VMs have not lost their right to exist within a world full of monoliths yet, but the trend is clearly towards\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"authors":[{"term_id":734,"user_id":465,"is_guest":0,"slug":"jk165","display_name":"Jan-Niklas Keck","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/1b6e91d7fc2622ece8b3308cd055c09cb3292f8ae0424f9a9799472c8314918b?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/2748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/users\/465"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/comments?post=2748"}],"version-history":[{"count":28,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/2748\/revisions"}],"predecessor-version":[{"id":24732,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/2748\/revisions\/24732"}],"wp:attachment":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/media?parent=2748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/categories?post=2748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/tags?post=2748"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/ppma_author?post=2748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}