{"id":384,"date":"2012-07-15T15:35:41","date_gmt":"2012-07-15T10:05:41","guid":{"rendered":"http:\/\/ramkulkarni.com\/blog\/?p=384"},"modified":"2012-07-15T15:35:41","modified_gmt":"2012-07-15T10:05:41","slug":"webapprunner-run-your-web-applications-standalone","status":"publish","type":"post","link":"http:\/\/ramkulkarni.com\/blog\/webapprunner-run-your-web-applications-standalone\/","title":{"rendered":"WebAppRunner &#8211; Run your web applications standalone"},"content":{"rendered":"<p>Last week I wrote a <a href=\"http:\/\/wp.me\/p2g9O8-64\">blog post<\/a> about how Java objects can be passed to JavaScript code running in the SWT Browser control. I mentioned that I was working on an Eclipse RCP app that could run web apps as standalone apps in the SWT browser control.<\/p>\n<p>That application is now ready. If you want to give it a try, download it from following links. The application is about 21 MB in size.<\/p>\n<ul>\n<li><a href=\"http:\/\/ramkulkarni.com\/MyApps\/WebAppRunner\/WebAppRunner-Windows-64Bit.zip\">WebAppRunner (Windows 64Bit)<\/a><\/li>\n<li><a href=\"http:\/\/ramkulkarni.com\/MyApps\/WebAppRunner\/WebAppRunner-Windows-32Bit.zip\">WebAppRunner (Windows 32Bit)<\/a><\/li>\n<li><a href=\"http:\/\/ramkulkarni.com\/MyApps\/WebAppRunner\/WebAppRunner-Mac.zip\" target=\"_blank\">WebAppRunner (Mac)<\/a><\/li>\n<\/ul>\n<p><a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/index.html\" target=\"_blank\">JRE<\/a>\u00a0is not packaged in the above application. You will have to download and install it, if you don&#8217;t have it already.<\/p>\n<p>I have also created a sample app to show how a web page can call Java APIs. The application uses JDK File APIs to get list of files. Download FileListApp from <a href=\"http:\/\/ramkulkarni.com\/MyApps\/WebAppRunner\/SampleApps\/FileListApp.zip\" target=\"_blank\">here<\/a>. Below is a screen shot of this application &#8211;<\/p>\n<p><!--more--><\/p>\n<p><a href=\"https:\/\/i0.wp.com\/138.197.85.232\/blog\/wp-content\/uploads\/2012\/07\/FileListApp.jpg\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"385\" data-permalink=\"http:\/\/ramkulkarni.com\/blog\/webapprunner-run-your-web-applications-standalone\/filelistapp\/\" data-orig-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2012\/07\/FileListApp.jpg?fit=592%2C417\" data-orig-size=\"592,417\" 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=\"FileListApp\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2012\/07\/FileListApp.jpg?fit=300%2C211\" data-large-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2012\/07\/FileListApp.jpg?fit=525%2C370\" class=\"alignnone size-medium wp-image-385\" title=\"FileListApp\" alt=\"\" src=\"https:\/\/i0.wp.com\/138.197.85.232\/blog\/wp-content\/uploads\/2012\/07\/FileListApp-300x211.jpg?resize=300%2C211\" width=\"300\" height=\"211\" srcset=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2012\/07\/FileListApp.jpg?resize=300%2C211 300w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2012\/07\/FileListApp.jpg?w=592 592w\" sizes=\"(max-width: 300px) 100vw, 300px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>So what exactly can WebAppRunner do for you &#8211;<\/p>\n<ul>\n<li>It provides a container to run web applications as standalone desktop apps. It does not bundle any web browser, but uses IE browser on Windows and Safari on Mac.<\/li>\n<li>But is is not just a container for web apps. It lets you call Java APIs from JavaScript running in those apps. When you run web application in a standalone browser, your application cannot have access to local resources such as files. By letting you use Java APIs from JavaScript, WebAppRunner extend capabilities of HTML\/JS application by letting it call Java APIs.<\/li>\n<\/ul>\n<p>WebAppRunner can run application from a folder, or from a file packaged as ZIP. It looks for index.html in the root of the folder and opens it in the SWT browser control. So make sure that you have index.html in the root of the folder or zip file. The application can provide a few configuration information in manifest.mf. This file also has to be in the root of application folder\/zip. Currently following configuration properties are supported &#8211;<\/p>\n<p><strong>Manifest-Version<\/strong> &#8211; This is required.<br \/>\n<strong>Application-Name<\/strong> &#8211; Its value appears in the title bar.<br \/>\n<strong>Window-Width<\/strong> &#8211; Width of application window.<br \/>\n<strong>Window-Height<\/strong> &#8211; Height of application window.<br \/>\n<strong>Show-Menubar<\/strong> &#8211; true\/false. Specify if menus (and hence menu bar) of WebAppRunner be displayed when the application is opened.<br \/>\n<strong>Classpath<\/strong> &#8211; comma separated list of path of jar files that needs to be loaded. This is useful if you want to access custom Java Class from JavaScript<\/p>\n<p>Note that manifest.mf is optional. Also WebAppRunner loads all jar files in the application root. So you need not specify classpath in the manifest if all your jar files are in the application root. Here is how manifest.mf of <a href=\"http:\/\/ramkulkarni.com\/MyApps\/WebAppRunner\/SampleApps\/FileListApp.zip\" target=\"_blank\">FileListApp<\/a> looks like &#8211;<\/p>\n<p>Manifest-Version: 1.0<br \/>\nApplication-Name: File Browser App<br \/>\nWindow-Width: 600<br \/>\nWindow-Height: 400<\/p>\n<h3>Where can you use WebAppRunner:<\/h3>\n<p>The primary use case is to create desktop standalone applications, even if they don&#8217;t need web interface. It is easy to create powerful UI with HTML,JS and CSS. The main application logic can be in a jar packaged with your app. Or you can build complete standalone HTML5 application using local DB storage feature that uses SQLite\/IndexDB.<\/p>\n<p>You can also use it as a wapper for you existing browser based web apps, which can be enhanced by allowing access to local resources e.g. allowing (of course, trusted) web application to search files on your local disk.<\/p>\n<h3>JavaScript APIs to use Java Objects:<\/h3>\n<p>Following APIs are available for JavaScript code running in WebAppRunner &#8211;<\/p>\n<ul>\n<li><strong>createJava<\/strong>: For creating a new Java object.\n<ul>\n<li>Signature : createJava (className, constructor_args &#8230;, variableName)<\/li>\n<li>Arguments :\n<ul>\n<li>The first argument is Class name. It should be fully qualified name e.g. java.lang.String<\/li>\n<li>It is followed by arguments to the constructor<\/li>\n<li>The last argument is name of the variable in which you want to save the instance of this Java class<\/li>\n<\/ul>\n<\/li>\n<li>Returns : Name of the variable (sent as the last argument) , if Object is created successfully, else returns null.<\/li>\n<li>Example :<br \/>\nvar ret = createJava(&#8220;java.io.File&#8221;, path, &#8220;fileObj&#8221;);<br \/>\nif (!ret) {<br \/>\nalert(&#8220;Error creating file object&#8221;);<br \/>\n}<\/li>\n<\/ul>\n<\/li>\n<li><strong>executeJava<\/strong>: For calling method on a Java object\n<ul>\n<li>Signature : executeJava (objVariableName, methodName, methodArgs&#8230;,returnVariableName)<\/li>\n<li>Arguments:\n<ul>\n<li>The first argument is variable name, returned by createJava function described above.<\/li>\n<li>The second argument is method name<\/li>\n<li>It is followed by arguments to the method<\/li>\n<li>The last argument is return variable name. Evan if method does not return anything (void), you have to pass the last argument. It could be null for void methods.<\/li>\n<\/ul>\n<\/li>\n<li>Returns:Only basic data types e.g. String, numbers (int, float, double etc.) and boolean. Any other Java object is stored in a variable passed as the last argument. Note that if the Java method returns one of the basic data types, then executeJava returns the same and no return variable is created even if you specify valid variable name in the last argument.<\/li>\n<li>Example :<br \/>\nvar fileList = executeJava(&#8220;fileObj&#8221;, &#8220;listFiles&#8221;, &#8220;fileList&#8221;); \/\/calls listFiles method on fileObj, which is of type java.io.File, and is created using createJava method.<\/li>\n<\/ul>\n<\/li>\n<li><strong>getJavaProperty<\/strong>: For accessing object properties\/fields\n<ul>\n<li>Signature : getJavaProperty(objVarName, fieldName, returnVarName)<\/li>\n<li>Arguments:\n<ul>\n<li>The first argument is variable name, returned by createJava function described above.<\/li>\n<li>Second argument is the field name<\/li>\n<li>Third argument is return variable name. It is required, but can be null. See description of executeJava for more details.<\/li>\n<\/ul>\n<\/li>\n<li>Returns : Value of the field\/property in the given Java object. See return value description of executeJava above for more information.<\/li>\n<li>Example:<br \/>\nvar len = getJavaProperty(&#8220;fileList&#8221;, &#8220;length&#8221;, null);<\/li>\n<\/ul>\n<\/li>\n<li><strong>getJavaArrayAt<\/strong>: For getting array element from Java array\n<ul>\n<li>Signature : getJavaArrayAt(arrayVarName, index, returnVarName)<\/li>\n<li>Arguments:\n<ul>\n<li>First argument is variable name of array<\/li>\n<li>Second argument is index number<\/li>\n<li>Third argument is return variable name. It is required, but can be null.See description of executeJava above for more details.<\/li>\n<\/ul>\n<\/li>\n<li>Returns: Object at given index in the array. See return value description of executeJava above for more information.<\/li>\n<li>Example :<br \/>\ngetJavaArrayAt(&#8220;fileList&#8221;, i, &#8220;fileAtIndex&#8221;) ;\/\/ fileList points to Java array<\/li>\n<\/ul>\n<\/li>\n<li><strong>executeStaticJava : <\/strong>For calling static methods.\n<ul>\n<li>Signature : executeJava (className, methodName, methodArgs&#8230;,returnVariableName)<\/li>\n<li>Arguments:\n<ul>\n<li>The first argument is the fully qualified class name<\/li>\n<li>The second argument is method name<\/li>\n<li>It is followed by arguments to the method<\/li>\n<li>The last argument is return variable name. Evan if method does not return anything (void), you have to pass the last argument. It could be null for void methods.<\/li>\n<\/ul>\n<\/li>\n<li>Returns:Only basic data types e.g. String, numbers (int, float, double etc.) and boolean. Any other Java object is stored in a variable passed as the last argument. Note that if the Java method returns one of the basic data types, then executeJava returns the same and no return variable is created even if you specify valid variable name in the last argument.<\/li>\n<li>Example :<br \/>\nvar fileList = executeJava(&#8220;java.lang.System&#8221;, &#8220;getProperties&#8221;, &#8220;sysProperties&#8221;); \/\/calls getProperties method on class<br \/>\n\/\/java.lang.System and saves result in sysProperties variable<\/li>\n<\/ul>\n<\/li>\n<li><strong>setJavaProperty : <\/strong>For seting value if a object property\/field\n<ul>\n<li>Signature : setJavaProperty (varName, fieldName, value)<\/li>\n<li>Arguments:\n<ul>\n<li>The first argument is variable name, returned by createJava function described above.<\/li>\n<li>Second argument is the field name<\/li>\n<li>Third argument is value to be set<\/li>\n<\/ul>\n<\/li>\n<li>Example:<br \/>\nvar len = getSavaProperty(&#8220;empObj&#8221;, &#8220;name&#8221;, &#8220;Ram&#8221;);<\/li>\n<\/ul>\n<\/li>\n<li><strong>getApplicationPath<\/strong>: For getting path of the curently opened application with&#8221;Open File&#8221; or &#8220;Open Folder&#8221; method. This is useful when application is packaged as a zip and opened with WebAppRunner. Applications in Zip files are unzipped in a temporary folder before executing them. One of the usecase for getApplicationPath is that application is packaged as a zip file and you want to save application specific preferences in a property file in the same folder as the zip. With this API, you can get path of the folder where application zip file exists.\n<ul>\n<li>Signature : getApplicationPath()<\/li>\n<li>Returns : String contining full path of the folder that contains application\/zip file<\/li>\n<li>Example:<br \/>\nvar appPath &#8211; getApplicationPath();<\/li>\n<\/ul>\n<\/li>\n<li><strong>exitWebAppRunner<\/strong>: For closing WebAppRunner. Does not ask for the confirmation.\n<ul>\n<li>Example:<br \/>\nexitWebAppRunner();<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>If you want to pass already created Java object instance as an argument to any of the above functions then you need to prefix variable name with $, for example empVO (employee Value Object) points to an instance of a Java class and you want to pass that as an argument to addEmployee function, then you can pass it as &#8211;<\/p>\n<pre style=\"color: #000020; background: #f6f8ff;\">executeJava<span style=\"color: #308080;\">(<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">empMgr<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">addEmployee<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">$empVO<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span> <span style=\"color: #0f4d75;\">null<\/span><span style=\"color: #308080;\">)<\/span><span style=\"color: #406080;\">;<\/span><\/pre>\n<p>Checkout FileAPIs.js in the <a href=\"http:\/\/ramkulkarni.com\/MyApps\/WebAppRunner\/SampleApps\/FileListApp.zip\" target=\"_blank\">FileListApp<\/a>\u00a0and emp.js in <a href=\"http:\/\/ramkulkarni.com\/MyApps\/WebAppRunner\/SampleApps\/SQLiteApp.zip\">SQLiteApp <\/a>to see how above APIs can be used in a HTML\/JS application.<\/p>\n<h3>Executing applications using WebAppRunner:<\/h3>\n<p>You can pass folder path or zip file path as argument to WebAppRunner. You can also use &#8216;Open File&#8217; and &#8216;Open Folder&#8217; options under File menu if you want to load application when WebAppRunner is already opened.<\/p>\n<p>-Ram Kulkarni<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week I wrote a blog post about how Java objects can be passed to JavaScript code running in the SWT Browser control. I mentioned that I was working on an Eclipse RCP app that could run web apps as standalone apps in the SWT browser control. That application is now ready. If you want &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/ramkulkarni.com\/blog\/webapprunner-run-your-web-applications-standalone\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;WebAppRunner &#8211; Run your web applications standalone&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[38,20,1],"tags":[40,41],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2g9O8-6c","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/384"}],"collection":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/comments?post=384"}],"version-history":[{"count":0,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/384\/revisions"}],"wp:attachment":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/media?parent=384"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/categories?post=384"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/tags?post=384"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}