{"id":378,"date":"2015-11-18T11:17:02","date_gmt":"2015-11-18T11:17:02","guid":{"rendered":"http:\/\/smartfoxserver.com\/blog\/?p=378"},"modified":"2022-05-17T08:11:03","modified_gmt":"2022-05-17T08:11:03","slug":"http-request-and-extensions-integration","status":"publish","type":"post","link":"https:\/\/smartfoxserver.com\/blog\/http-request-and-extensions-integration\/","title":{"rendered":"HTTP Request and Extensions integration"},"content":{"rendered":"\n<p>In this new recipe&nbsp;we&#8217;re going to&nbsp;take a look at how we can integrate regular HTTP calls with the SmartFoxServer runtime and specifically how to communicate with Extension code via HTTP GET\/POST requests.<\/p>\n\n\n\n<p>Common applications of the HTTP\/Extension interoperability are debugging interfaces and administration UIs. With this approach developers can easily&nbsp;build a simple web interface&nbsp;that reports that game state, monitors data structures, users etc&#8230; allowing to quickly debug problems while testing, triggering events and so on.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 id=\"a-working-example\">\u00bb&nbsp;A working example<\/h2>\n\n\n\n<p>Let&#8217;s take a look at a simple use case that illustrates how to work with servlets (Jetty) and extensions (SFS2X). We will start by building our simple SFS2X Extension and implementing the <strong>handleInternalMessage(&#8230;)&nbsp;<\/strong>method, which is at the&nbsp;bridge between the two worlds.<\/p>\n\n\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage sfs2x.test.http.ext;\n\nimport com.smartfoxserver.v2.extensions.SFSExtension;\n\npublic class SimpleSumExtension extends SFSExtension\n{\n\t@Override\n\tpublic void init()\n\t{\n\t\ttrace(&quot;Simple Sum Extension -- Ready&quot;);\n\t}\n\n\t@Override\n\tpublic Object handleInternalMessage(String cmdName, Object params)\n\t{\n\t\tObject result = null;\n\n\t\ttrace(String.format(&quot;Called by: %s, CMD: %s, Params: %s&quot;, Thread.currentThread().getName(), cmdName, params));\n\n\t\tif (cmdName.equals(&quot;numbers&quot;))\n\t\t{\n\t\t\tString[] nums = ((String) params).split(&quot;\\\\,&quot;);\n\n\t\t\tint sum = 0;\n\n\t\t\tfor (String item : nums)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tsum += Integer.parseInt(item);\n\t\t\t\t}\n\t\t\t\tcatch(NumberFormatException nfe)\n\t\t\t\t{\n\t\t\t\t\t\/\/ Skip and continue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult = sum;\n\t\t}\n\n\t\treturn result;\n\t}\n}\n<\/pre>\n\n\n\n<p>The <strong>handleInternalMessage(&#8230;)<\/strong> method is very&nbsp;generic, allowing us to send a &#8220;command&#8221; string and a parameter object. The latter could be anything from a number to an array or collection of specific objects. Similarly the return value could be any object.<\/p>\n\n\n\n<p>In our case we define a command called <em>&#8220;numbers&#8221;&nbsp;<\/em>and expect a String containing comma separated numbers. We&#8217;ll take these numbers, sum them all together and return the result back to the servlet.<\/p>\n\n\n\n<p>This will allow us to use a simple url request such as<\/p>\n\n\n\n<p><strong>http:\/\/localhost:8080\/servlet?numbers=1,2,3,4<\/strong><\/p>\n\n\n\n<p>send the data to the Extension, obtain the result back and output it to our HTML page, integrating it with other dynamic data, JSP pages, template engines etc&#8230;<\/p>\n\n\n\n<p>In order to build the Extension we will export a jar file from our IDE of choice and deploy it under <strong>extensions\/HTTPSumExtension\/SumExtension.jar<\/strong><\/p>\n\n\n\n<p>Then we open the <strong>AdminTool <\/strong>&gt;<strong> Zone Configurator<\/strong>, select our Zone of choice (e.g. BasicExamples) and activate the Extension:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/SumExt.png\"><img loading=\"lazy\" width=\"887\" height=\"297\" src=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/SumExt.png\" alt=\"SumExt\" class=\"wp-image-383\" srcset=\"https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/SumExt.png 887w, https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/SumExt-300x100.png 300w, https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/SumExt-624x209.png 624w\" sizes=\"(max-width: 887px) 100vw, 887px\" \/><\/a><\/figure><\/div>\n\n\n\n<p><strong>\u00bb The servlet<\/strong><\/p>\n\n\n\n<p>Next we proceed with the creation of the simple servlet that will act as the bridge between the browsers&#8217;s requests and the SFS2X&#8217;s Extension.<\/p>\n\n\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage sfs2x.test.http;\n\nimport java.io.IOException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.smartfoxserver.v2.SmartFoxServer;\nimport com.smartfoxserver.v2.extensions.ISFSExtension;\n\n@SuppressWarnings(&quot;serial&quot;)\npublic class ExtensionHTTPFacade extends HttpServlet\n{\n\tprivate final static String CMD_NUMBERS = &quot;numbers&quot;;\n\n\tprivate SmartFoxServer sfs;\n\tprivate ISFSExtension myExtension;\n\n\t@Override\n\tpublic void init() throws ServletException\n\t{\n\t\tsfs = SmartFoxServer.getInstance();\n\t\tmyExtension = sfs.getZoneManager().getZoneByName(&quot;BasicExamples&quot;).getExtension();\n\t}\n\n\t@Override\n\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException\n\t{\n\t\tObject result = null;\n\t\tString numbers = req.getParameter(CMD_NUMBERS);\n\n\t\tif (numbers != null)\n\t\t\tresult = &quot;RES: &quot; + myExtension.handleInternalMessage(CMD_NUMBERS, numbers);\n\t\telse\n\t\t\tresult = &quot;Please pass a list of comma separated values called 'numbers'. Example ?numbers=1,2,3,4&quot;;\n\n\t\tresp.getWriter().write(result.toString());\n\t}\n}\n<\/pre>\n\n\n\n<p>All of the &#8220;magic&#8221; happens in the <strong>init()&nbsp;<\/strong>method were we obtain a reference to the SmartFoxServer instance. From there we proceed by accessing the Zone we want to work with.<\/p>\n\n\n\n<p>As you may already know, each Zone represents a different application running in the server so the Zone is the top level object from which we can access the user&#8217;s list, room lists, the Zone Extension, the database manager etc&#8230;<\/p>\n\n\n\n<p>In this case we just reference the Zone&#8217;s Extension so that we can later invoke its&nbsp;<strong>handleInternalMessage(&#8230;)<\/strong> method.<\/p>\n\n\n\n<p>The <strong>doGet(&#8230;)<\/strong> implementation simply acts as a paper-pusher by taking the &#8220;<em>numbers<\/em>&#8221; parameter, handing it over to the Extension and finally outputting the result to the client.<\/p>\n\n\n\n<h2 id=\"putting-it-all-together\">\u00bb&nbsp;Putting it all together<\/h2>\n\n\n\n<p>Before we can test the solution we need to deploy the servlet.&nbsp;If you&#8217;re using an IDE such as Neatbeans or Eclipse you can generate a&nbsp;.war file with a few clicks and deploy it under <strong>SFS2X\/www\/<\/strong>.&nbsp;Otherwise you can do the same manually by creating this folder structure under <strong>SFS2X\/www\/&nbsp;<\/strong><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/servlet-test-deploy.png\"><img loading=\"lazy\" width=\"382\" height=\"177\" src=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/servlet-test-deploy.png\" alt=\"servlet-test-deploy\" class=\"wp-image-384\" srcset=\"https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/servlet-test-deploy.png 382w, https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/servlet-test-deploy-300x139.png 300w\" sizes=\"(max-width: 382px) 100vw, 382px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>The ExtensionTest folder must contain the usual <strong>WEB-INF\/<\/strong> with the compiled classes and the deployment descriptor (web,xml), which looks like this:<\/p>\n\n\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;\n&lt;web-app\n   xmlns=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee&quot;\n   xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;\n   xsi:schemaLocation=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\/web-app_3_1.xsd&quot;\n   metadata-complete=&quot;false&quot;\n   version=&quot;3.1&quot;&gt;\n\n\t&lt;display-name&gt;SFS2X Test&lt;\/display-name&gt;\n\n\t&lt;servlet&gt;\n\t\t&lt;servlet-name&gt;ExtensionTest&lt;\/servlet-name&gt;\n\t\t&lt;servlet-class&gt;sfs2x.test.http.ExtensionHTTPFacade&lt;\/servlet-class&gt;\n\t&lt;\/servlet&gt;\n\t&lt;servlet-mapping&gt;\n\t\t&lt;servlet-name&gt;ExtensionTest&lt;\/servlet-name&gt;\n\t\t&lt;url-pattern&gt;\/ExtensionTest&lt;\/url-pattern&gt;\n\t&lt;\/servlet-mapping&gt;\n&lt;\/web-app&gt;\n<\/pre>\n\n\n\n<p>Time to restart the server and test locally in the browser with this url:<\/p>\n\n\n\n<p><strong>http:\/\/localhost:8080\/ExtensionTest\/ExtensionTest?numbers=100,60,50,112,88<\/strong><\/p>\n\n\n\n<p>&nbsp;which will yield this:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/serlvet-res.png\"><img loading=\"lazy\" width=\"607\" height=\"141\" src=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/serlvet-res.png\" alt=\"serlvet-res\" class=\"wp-image-386\" srcset=\"https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/serlvet-res.png 607w, https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/11\/serlvet-res-300x70.png 300w\" sizes=\"(max-width: 607px) 100vw, 607px\" \/><\/a><\/figure><\/div>\n\n\n\n<h2 id=\"class-loader-woes\">&nbsp;\u00bb&nbsp;Class loader&nbsp;woes<\/h2>\n\n\n\n<p>The simple example shown so far uses simple objects found in the JDK such as String, Integer etc&#8230; no big deal. When working with custom data, however, you may encounter class loading issues due to the fact that classes defined in an Extension are visible only under their class loader.<\/p>\n\n\n\n<p>Attempting to pass these objects between servlet and Extension will not work out of the box,&nbsp;and depending on the specific case it will require special attention at the deployment process.<\/p>\n\n\n\n<p>We have already discussed in many articles various ways to deploy Extension classes that are visible at the top class loader. Here are some links to learn more:<\/p>\n\n\n\n<ul><li><a href=\"http:\/\/docs2x.smartfoxserver.com\/AdvancedTopics\/advanced-extensions#classLoading\" target=\"_blank\" rel=\"noopener\">Doc article: class loading architecture&nbsp;in SFS2X<\/a><\/li><li><a href=\"http:\/\/smartfoxserver.com\/blog\/?p=149\" target=\"_blank\" rel=\"noopener\">Blog article: how to maintain global state across reloads<\/a> (hence useful for servlets too)<\/li><li><a href=\"http:\/\/smartfoxserver.com\/blog\/?p=144\" target=\"_blank\" rel=\"noopener\">Blog article: global singleton visibility<\/a><\/li><\/ul>\n\n\n\n<p>Finally there can be situations in which it is more convenient to serialize the objects that need to be passed around, avoiding more complex deployment schemes.<\/p>\n\n\n\n<h2 id=\"when-this-is-not-a-good-idea\">\u00bb When this is not a good idea<\/h2>\n\n\n\n<p>We mentioned in the opening that there are can be a few concerns when exposing Extension calls via HTTP, namely:<\/p>\n\n\n\n<ol><li><strong>Security:<\/strong>&nbsp;SmartFoxServer always knows who is sending a&nbsp;request because clients are recognized via their TCP socket. Using HTTP removes this identification leaving ample room for identity spoof attacks.<\/li><li><strong>Scalability:&nbsp;<\/strong>HTTP is much slower and heavier than the SFS2X protocol. If the HTTP requests being sent&nbsp;are going to be fast and copious it is likely that we&#8217;ll&nbsp;hit a bottleneck at relatively low CCU counts.<\/li><\/ol>\n\n\n\n<p>While the former&nbsp;problem can be solved in several ways, the latter is much more of a concern and a reminder that this feature should be used sparingly and for debugging\/monitoring purposes more than anything else.<\/p>\n\n\n\n<p>In regards to issue #1 a good way to strengthen the security would be to send&nbsp;the unique session token obtained by the User after connecting to SmartFoxServer. The token can be used to identify the sender and also to double check his identity against the HTTP request&#8217;s source address.<\/p>\n\n\n\n<p>By matching this two pieces of data we can&nbsp;be reasonably sure that no spoofing is going on.<\/p>\n\n\n\n<p>The session token can be obtained from the client side via the&nbsp;<strong>SmartFox.SessionToken<\/strong> property, available across all supported languages.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this new recipe&nbsp;we&#8217;re going to&nbsp;take a look at how we can integrate regular HTTP calls with the SmartFoxServer runtime and specifically how to communicate with Extension code via HTTP GET\/POST requests. Common applications of the HTTP\/Extension interoperability are debugging interfaces and administration UIs. With this approach developers can easily&nbsp;build a simple web interface&nbsp;that reports [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[31,49,48,7,24],"_links":{"self":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/378"}],"collection":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/comments?post=378"}],"version-history":[{"count":11,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/378\/revisions"}],"predecessor-version":[{"id":2243,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/378\/revisions\/2243"}],"wp:attachment":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/media?parent=378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/categories?post=378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/tags?post=378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}