Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    ISC_FileLoader for perfect caching on StartUp of login screen

    Hello everyone,

    in the Quick Start Guide, Chapter "Authentication and Authorization", Isomorphic suggests that one caches files while displaying the login-screen.

    I tried to set this up and I think I succeeded now and wanted to share my approach.

    Basic setup:

    The login HTML looks like:
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>Login</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" href="stylesheet.css" />
    
    <script type="text/javascript" language="javascript">var isomorphicDir = "myApp/sc/";</script>
    <script type="text/javascript" language="javascript" src="myApp/sc/modules/ISC_FileLoader.js"></script>
    <script type="text/javascript" language="javascript">FL.modulesDir = "modules/"; FL.defaultSkin = "Enterprise"; FL.cacheISC();</script>
    </head>
    <body>
    <div id="box">
    <form method="post" action="j_security_check"> 
            <label>Name:</label>
                <input type="text" name="j_username" />
            <label>Password:</label>
                <input type="password" name="password" />
                <input type="password" name="j_password" style="display: none;" />
                <input type="submit" value="Login" name="submit" class="submit" />
                <input type="reset" value="Cancel" class="submit" />
    </form>
    </div>
    <SCRIPT>//'"]]>>isc_loginRequired
    //
    // Embed this whole script block VERBATIM into your login page to enable
    // SmartClient RPC relogin.
    
    while (!window.isc && document.domain.indexOf(".") != -1) {
        try {
    	
            if (parent.isc == null) {
                document.domain = document.domain.replace(/.*?\./, '');
                continue;
            } 
            break;
        } catch (e) {
            document.domain = document.domain.replace(/.*?\./, '');
        }
    }
    
    var isc = top.isc ? top.isc : window.opener ? window.opener.isc : null;
    if (isc.Canvas) isc.RPCManager.delayCall("handleLoginRequired", [window]);
    </SCRIPT>
    </body>
    </html>
    When starting with an empty cache, the ISC_FileLoader will issue requests to e.g. http://myserver.com/myapp/sc/modules..._2014-03-30.js. Note the version in the query parameter. This is added automatically by the ISC_FileLoader.js from its own version.
    When calling again with "URL bar"->Enter, for my config the *.js files won't be loaded again, as I configured a 1 year expiry in Apache httpd (see below).

    2nd is the main jsp file:
    Code:
    <!DOCTYPE html>
    <%! 
    /** Ant task extractsgwtversion sets the version of the lib here **/
    String regex_replaced = "v9.1p_2014-03-30";
    String version = "?isc_version=" + regex_replaced + ".js";
    %>
    
    <html>
      <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <meta name="gwt:property" content="locale=de">
        <% /** <!-- Any title is fine -->**/ %>
        <title>My title</title>
        <% /** <!-- IMPORTANT : You must set the variable isomorphicDir to [MODULE_NAME]/sc/ so that the SmartGWT resource are 
    	  correctly resolved --> **/ %>	
    	
    	<script type="text/javascript">var isomorphicDir = "myApp/sc/";</script>
    
      <% /** <!-- Needed here as SuperDev Mode can't use "include" in gwt.xml -->**/ %>
    	<script type="text/javascript" src="myApp/sc/modules/ISC_Core.js<% out.print(version); %>"></script>
    	
    	<script type="text/javascript" src="myApp/sc/modules/ISC_Foundation.js<% out.print(version); %>"></script>
    	<script type="text/javascript" src="myApp/sc/modules/ISC_Containers.js<% out.print(version); %>"></script>
    	<script type="text/javascript" src="myApp/sc/modules/ISC_Grids.js<% out.print(version); %>"></script>
    	<script type="text/javascript" src="myApp/sc/modules/ISC_Forms.js<% out.print(version); %>"></script>
    	<% /** Unused so far
    	<script type="text/javascript" src="myApp/sc/modules/ISC_RichTextEditor.js"></script>
    	<script type="text/javascript" src="myApp/sc/modules/ISC_Calendar.js"></script>
      **/ %>
    	<script type="text/javascript" src="myApp/sc/modules/ISC_DataBinding.js<% out.print(version); %>"></script>
    	<script type="text/javascript" src="myApp/sc/skins/Enterprise/load_skin.js<% out.print(version); %>"></script>
      <% /**
        <!--                                           -->
        <!-- This script loads your compiled module.   -->
        <!-- If you add any GWT meta tags, they must   -->
        <!-- be added before this line.                -->
        <!--                                           -->
      **/ %>
      <script type="text/javascript" src="myApp/myApp.nocache.js"></script>
      </head>
      <% /**
      <!--                                           -->
      <!-- The body can have arbitrary html, or      -->
      <!-- you can leave the body empty if you want  -->
      <!-- to create a completely dynamic UI.        -->
      <!--                                           -->
      **/ %>
      <body>
        <% /** <!--load the datasources--> **/ %>
        <script type="text/javascript" src="myApp/sc/DataSourceLoader?dataSource=.........................................long list..............."></script>
        <% /** <!-- OPTIONAL: include this if you want history support --> **/ %>
        <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
      </body>
    </html>
    Note that this uses JSP-comments that are not present in the final HTML in order to keep the result better looking.
    In order to have the ISC_*.js-files served from the cache, the URL must look exact the same as in the login screen. While in the login screen the FileLoader takes care of the version-string, you have to do it on your own this time. As this is easily forgotten when done manually, I created an Ant-task for it:
    Code:
    ...
    	<path id="catalina-ant-classpath">
    		<fileset dir="${tomcat-dir}/lib">
    			<include name="catalina-ant.jar" />
    			<include name="tomcat-coyote.jar" />
    			<include name="tomcat-util.jar" />
    		</fileset>
    		<fileset dir="${tomcat-dir}/bin">
    			<include name="tomcat-juli.jar" />
    		</fileset>
    		<fileset dir="${sgwtee.sdk}/../ant/">
    			<include name="xmltask.jar" />
    		</fileset>
    	</path>
    ...
    ...
    	<!-- Used in Ant Task extractsgwtversion -->
    	<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpathref="catalina-ant-classpath" />
    ...
    ...
    	<target name="extractsgwtversion" description="Extract version from SmartGWT library">
    		<xmltask>
    			<fileset file="${sgwtee.sdk}/maven/pom/smartclient-eval.xml" />
    			<copy path="//*[local-name()=&quot;version&quot;]/text()" property="sgwtee.buildversion" />
    			<!--
    			Weird XPath stuff because of the namespace in the POM-file. See:
    			http://www.oopsconsultancy.com/software/xmltask/#usage.print
    			http://stackoverflow.com/questions/21928260/xpath-query-local-name-fetch-tag-based-on-other-tags-value
    			http://www.xml.com/pub/a/2004/02/25/qanda.html
    			-->
    		</xmltask>
    		<fail message="You must provide a file to extract the SGWT version from.">
    	    <condition>
    	        <not>
    	            <resourcecount count="1">
    	                <fileset id="fs" dir="${sgwtee.sdk}/maven/pom" includes="smartclient-eval.xml"/>
    	            </resourcecount>
    	        </not>
    	    </condition>
    			</fail>
    		<fail unless="sgwtee.buildversion" message="You must supply a correct XPath expression in order to extract the version." />
    		<echo>${sgwtee.sdk}/maven/pom/smartclient-eval.xml</echo>
    		<echo>${sgwtee.buildversion}</echo>
    		<replaceregexp file="war/myApp.jsp" match="String regex_replaced.*" replace="String regex_replaced = &quot;${sgwtee.buildversion}&quot;;" byline="true" />
    	</target>
    The task tries to take one of the SmartGWT-maven-pom files and extract the version from it. Hopefully it's the same version as in ISC_FileLoader.js. If there is a better way to extract the version number from the framework, any pointers are appreciated.
    This way, after building and deploying a war, the browser should download the needed JS-files once on start-up and then never again.
    My Apache httpd virtual host cache configuration looks like this:
    Code:
    <VirtualHost *:80>
        ServerAdmin webmaster@mydomain.com
    #   DocumentRoot /var/www/centos.mydomain.com/public_html
        DocumentRoot /usr/share/apache-tomcat-7.0.52/myapp_centos
        RedirectMatch ^/$ /centos/MyApp.jsp
        RedirectMatch ^/centos$ /centos/MyApp.jsp
        RedirectMatch ^/centos/$ /centos/MyApp.jsp
        ServerName centos.mydomain.com
        TraceEnable Off
        ErrorLog  /var/www/centos.mydomain.com/logs/error_log
        CustomLog /var/www/centos.mydomain.com/logs/access_log combined
    
        <IfModule mod_jk.c>
    	JkMount /centos/j_security_check worker1
    	JkMount /centos/*.jsp worker1
    	JkMount /centos/myapp/sc/IDACall worker1
    	JkMount /centos/myapp/sc/DataSourceLoader worker1
    	JkMount /centos/myapp/sc/HttpProxy worker1
    	JkMount /centos/myapp/sc/ worker1
    	JkMount /centos/ServletLogin worker1
    	JkMount /centos/ServletLogout worker1
        </IfModule>
    
    #   <Directory /var/www/centos.mydomain.com/public_html>
        <Directory /usr/share/apache-tomcat-7.0.52/myapp_centos>
            AllowOverride FileInfo AuthConfig Limit
            Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
    		#SetOutputFilter DEFLATE
    		AddOutputFilterByType DEFLATE text/plain text/html application/json text/xml text/css text/javascript
    		
            <Limit GET POST OPTIONS>
                    Order allow,deny
                    Allow from all
            </Limit>
    		<Files *.cache.*>
    		  ExpiresActive on
    		  ExpiresDefault "now plus 1 year"
    		</Files>
    		<Files *.js>
    		  ExpiresActive on
    		  ExpiresDefault "now plus 1 year"
    		</Files>
    		<FilesMatch "\.(gif|jpe?g|png)$">
    		  ExpiresActive on
    		  ExpiresDefault "now plus 1 year"
    		</FilesMatch>
    		<Files *.css>
    		  ExpiresActive on
    		  ExpiresDefault "now plus 1 year"
    		</Files>
    		<Files *.nocache.*>
    		  ExpiresActive on
    		  ExpiresDefault "now"
    		  Header merge Cache-Control "public, max-age=0, must-revalidate"
    		</Files>
    		<Files *.html>
    		  ExpiresActive on
    		  ExpiresDefault "now"
    		  Header merge Cache-Control "public, max-age=0, must-revalidate"
    		</Files>
    		# Correct, but done in some other way by Tomcat
    		<Files *.jsp>
    		  ExpiresActive on
    		  ExpiresDefault "now"
    		  Header merge Cache-Control "public, max-age=0, must-revalidate"
    		</Files>
    	</Directory>
    </VirtualHost>
    This way, for me everything besides Compression of the DataSourceLoader servlet result is now working in the best (?) possible way.

    Best regards, I hope this HowTo helps someone,
    Blama
    Last edited by Blama; 4th Apr 2014, 07:21.

    #2
    Hi all,

    I missed something above:
    The URLs of the ISC_FileLoader calls end in "?isc_version=v9.1p_2014-03-30.js". The maven xml file contains "4.1-p20140330". Besides prefix and suffix, which is set in the main jsp file, also the version differs in format and system (SmartClient vs SmartGWT).

    So one has to adapt here as well. See http://stackoverflow.com/questions/1...n-ant-property for this.

    My solution using Ant-contrib looks like this (should be working for SmartGWT 4.*/5.* prod/dev):

    Code:
    	<path id="catalina-ant-classpath">
    		<fileset dir="${tomcat-dir}/lib">
    			<include name="catalina-ant.jar" />
    			<include name="tomcat-coyote.jar" />
    			<include name="tomcat-util.jar" />
    		</fileset>
    		<fileset dir="${tomcat-dir}/bin">
    			<include name="tomcat-juli.jar" />
    		</fileset>
    		<fileset dir="${sgwtee.sdk}/../ant/">
    			<include name="xmltask.jar" />
    			<include name="ant-contrib-1.0b3.jar" />
    		</fileset>
    	</path>
    
    	<taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" classpathref="catalina-ant-classpath" />
    	<taskdef name="start" classname="org.apache.catalina.ant.StartTask" classpathref="catalina-ant-classpath" />
    	<taskdef name="stop" classname="org.apache.catalina.ant.StopTask" classpathref="catalina-ant-classpath" />
    	<taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" classpathref="catalina-ant-classpath" />
    	<!-- Used in Ant Task extractsgwtversion -->
    	<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpathref="catalina-ant-classpath" />
    	<taskdef name="propertyregex" classname="net.sf.antcontrib.property.RegexTask" classpathref="catalina-ant-classpath" />
    ...
    ...
    	<target name="extractsgwtversion" description="Extract version from SmartGWT library">
    		<xmltask>
    			<fileset file="${sgwtee.sdk}/maven/pom/smartclient-eval.xml" />
    			<copy path="//*[local-name()=&quot;version&quot;]/text()" property="sgwtee.buildversion" />
    			<!--
    			Weird XPath stuff because of the namespace in the POM-file. See:
    			http://www.oopsconsultancy.com/software/xmltask/#usage.print
    			http://stackoverflow.com/questions/21928260/xpath-query-local-name-fetch-tag-based-on-other-tags-value
    			http://www.xml.com/pub/a/2004/02/25/qanda.html
    			
    			<print path="//*[local-name()=&quot;project&quot;]/*" comment="project" />
    			<print path="//*[local-name()=&quot;version&quot;]/text()" comment="v3" />
    			-->
    		</xmltask>
    		<fail message="You must provide a file to extract the SGWT version from.">
    			<condition>
    				<not>
    					<resourcecount count="1">
    						<fileset id="fs" dir="${sgwtee.sdk}/maven/pom" includes="smartclient-eval.xml" />
    					</resourcecount>
    				</not>
    			</condition>
    		</fail>
    		<fail unless="sgwtee.buildversion" message="You must supply a correct XPath expression in order to extract the version." />
    		<echo>${sgwtee.sdk}/maven/pom/smartclient-eval.xml</echo>
    		<echo>${sgwtee.buildversion}</echo>
    		<!--
    		See http://forums.smartclient.com/showthread.php?p=118344#post118344 and 
    		http://stackoverflow.com/questions/1176071/replacing-characters-in-ant-property
    		-->
    		<propertyregex property="sgwtee.buildversion" override="true" input="${sgwtee.buildversion}" regexp="^4\." replace="v9." global="true" />
    		<propertyregex property="sgwtee.buildversion" override="true" input="${sgwtee.buildversion}" regexp="^5\." replace="v10." global="true" />
    		<propertyregex property="sgwtee.buildversion" override="true" input="${sgwtee.buildversion}" regexp="-p" replace="p_" global="true" />
    		<propertyregex property="sgwtee.buildversion" override="true" input="${sgwtee.buildversion}" regexp="-d" replace="d_" global="true" />
    		<propertyregex property="sgwtee.buildversion" override="true" input="${sgwtee.buildversion}" regexp="([0-9]{4})([0-9]{2})([0-9]{2})" replace="\1-\2-\3" global="true" />
    		<echo>${sgwtee.buildversion}</echo>
    		<replaceregexp file="war/myApp.jsp" match="String regex_replaced.*" replace="String regex_replaced = &quot;${sgwtee.buildversion}&quot;;" byline="true" />
    	</target>
    Best regards,
    Blama

    Comment


      #3
      For all interested parties:

      Additional caching of the result of the DataSourceLoader call is discussed here.

      Best regards
      Blama

      Comment

      Working...
      X