Friday, April 4, 2014

Localized Data

Cousin Glen shared a way to put the weather on our form in his blog as well as in foxite last time and so when I decided that I finally needed one because we are working simultaneously on several road construction projects these days and the weather forecast will be helpful, I did not need to look far away and simply checked what he has shared which is via XMLHttpRequest.

What is XMLHttpRequest?

XMLHttpRequest (XHR) is an API available to web browser scripting languages such as JavaScript. It is used to send HTTP or HTTPS requests to a web server and load the server response data back into the script.  http://en.wikipedia.org/wiki/XMLHttpRequest

Using XMLHttpRequest has some (expected) peculiarities like it appears based on my observation that the previous request is compounding seeing my laptop which is doing the data fetching getting slower over time. Thus, I informed him of such and we decided to do these additional things:


  • Checking Current State of the Request.  Well, it is also better to perform a check to know the current state of the request operation via XMLHttpRequest's ReadyState property. Its value would be 4 when all the data has been received.  
  • Release the current request via XMLHttpRequest's abort method after transferring ResponseText value.
  • Clearing Cache - If you don't clear the cache after the processing of the request, chances are you'll get the same result over and over again. Glen gave me another Function called DeleteUrlCacheEntry to fix that. 
For a deeper understanding of XMLHttpRequest, check this link:  http://msdn.microsoft.com/en-us/library/ie/ms535874(v=vs.85).aspx


Processing Request Lags

We are almost set to get what we need.  However, another thing that we cannot remove is during when the HTTP request is being processed, that your unit will experience a lag which is more than a tick or two depending on the speed of your internet connection on your end.  And if so, during said HTTP request you may experience a somewhat short frozen state on your app until such time the whole request process is completed and response returned back to you.  And I dare say most users won't be happy with said lag.

Is there a way to avoid such then?

Avoiding Lags

There actually is no way to remove the HTTP request processing lag but we do can avoid that.  Remember this?  http://sandstorm36.blogspot.com.au/2012/11/run-vfp-app-like-service.html

So the trick to avoid such lags is to create another small app with, among its other jobs, is to send those HTTP requests and save the result to your local drive. Mine is set to get the info every 5 minutes.  Since this app is running on another thread of its own, then your main app won't be bothered by such request lags and all you need to do later is to fetch the data from the text file it generates/updates continuously.

Service Application

I called this as service application because it does service the needs of my main ERP app like performing compressed backup, cleaning, and other things on a specified time.  Now I added the XMLHttpRequest and so I will show here the portion that deals with that:

***************
bcService.prg
***************

*For reducing memory eaten by the process
Declare Integer SetProcessWorkingSetSize In kernel32 As SetProcessWorkingSetSize  ;
      Integer hProcess , ;
      Integer dwMinimumWorkingSetSize , ;
      Integer dwMaximumWorkingSetSize
Declare Integer GetCurrentProcess In kernel32 As GetCurrentProcess

* For Clearing URL Cache
Declare Integer DeleteUrlCacheEntry In wininet String lpszUrlName


On Error Wait Window '' Nowait

Set Classlib To Addbs(Home(2))+'Solution\Toledo\systray.vcx' 
Local loSysTray, loTimer
loSysTray = Createobject('myTray', 'systray.vcx')
loSysTray.AddIconToSystray()

*** Add the needed properties
Private oServices
oServices = Createobject('EMPTY')
AddProperty(oServices,'Folder',Addbs(Justpath(Sys(16,0))))
AddProperty(oServices,'GetURLCounter',0)  && So it will run outright the first run
AddProperty(oServices,'GetURLSet',300)   && 5 minutes interval
Set Default To (Fullpath(oServices.FolderData))

loTimer = Createobject( "myTimer" )
Read Events

Define Class myTray As systray
      IconFile    = Addbs(Justpath(Sys(16,0)))+"bcservice.ico"

      * Use Double-click to exit service
      Function iconDblClickEvent
            If Messagebox('Do you really want to stop this service?',4+32,'Oooppppssss!') = 6
                  Clear Events
            Endif
      Endfunc
Enddefine

Define Class myTimer As Timer
      Interval = 1000

      Function Timer
            * Get URL Requests based on parameter passed or default value
            oServices.GetURLCounter = oServices.GetURLCounter - 1
            If oServices.GetURLCounter <= 0
                  Local o As msxml2.xmlhttp, lcURL, lnloop, lcHTMLText, lcWord
                  lcHTMLText = 'Weather,PGKPHP,USDPHP,PGKINR,USDINR,PGKIDR,USDIDR,PGKUSD'
                  For lnloop = 1 To 8
                        lcWord = Getwordnum(m.lcHTMLText,m.lnloop,',')
                        If m.lnloop = 1
                              lcURL = [http://www.accuweather.com/en/pg/lae/258839/hourly-weather-forecast/258839]
                        Else
                              lcURL = [http://www.xe.com/currencyconverter/convert/?Amount=1&From=]+;
                                    LEFT(m.lcWord,3)+[&To=]+Right(m.lcWord,3)
                        Endif
                        o = Createobject("msxml2.xmlhttp")
                        o.Open("GET",m.lcURL,.F.)
                        o.Send(.Null.)
                       
                        Do While o.readyState <> 4  && Check if all data is received
                        ENDDO
                       
                        If !Empty(o.responseText)
                              Try
                                    lcFile = Addbs(oServices.Folder)+m.lcWord
                                    Strtofile(o.responseText,m.lcFile,0)
                                    Wait Window 'Update of '+m.lcWord+' Complete....' Nowait
                              Catch
                              Endtry
                        Endif
                        * Clean up
                        o.abort
                        o = Null
                        DeleteUrlCacheEntry(m.lcURL)
                  Next
                  oServices.GetURLCounter = oServices.GetURLSet
            ENDIF
           
            ***** Perform other more tasks

            * Reduce Memory
            SetProcessWorkingSetSize(GetCurrentProcess(),-1,-1)
      Endfunc
Enddefine

************ End 

Now, why in the heck did I named this post localized data?  

That is because my main app is actually working on files stored locally on my unit, never caring for the info coming from web or the lag it creates as the other (service) app takes care of that need.  And in this way, there is absolutely no lag on updating the latest data on my main ERP app and further disseminating those information across the LAN for my other users to see.   

Another reason why I decided to name this as localized data is because of the way I implemented my weather forecast widget.  The animated weather showing the current hour's weather forecast do not come from the web on every change of the weather.  Those are originally from the web which I downloaded and stored onto a table (not much records and won't change so I store in a table).  Then I fetch a set via an SQL SELECT based on the current weather and pick one randomly to be shown on my form.

Said animated weather image changes every 60 seconds in coordination with the current weather forecast, and the information changes as well based on whether an update has already been made by the service app.

Here is my BizCore ERP app's main screen/form:



Recap:

  • Create a separate app running on its own process to get the data from the web
  • Use the downloaded files to update your main app

I hope this gives others some ideas.

Cheers

3 comments:

  1. Thanks Mr. Jun Tangunan, a valuable Data information exchanged on Localize Data not to have "some ideas" but had a complete Way to GO.
    Zia Mughal

    ReplyDelete
  2. Thanks Zia. This is useful to me so I share so others who will be interested can do the same.

    ReplyDelete
  3. Thanks Mr. Jun,
    I have ssexcel class from you and it works well but the result file could not be opened in the tablet (iPad, iPhone). It's greate if you can improve it.

    ReplyDelete