FireRender is the Xmarc technology for enabling Fire to function as an internet data server. FireRender can serve HTML pages and mime-typed images, such as GIF and JPEG.
It comprises:
a Java Servlet (Service Broker - actually named Broker) that manages a set of Fire map servers, and relays requests and responses between Fire and a client.
a set of Fire commands that allow Fire to communicate with the client via the Service Broker, serving data to the client, e.g. HTML pages and mime-typed images.
The service broker, FireRender, is a Java servlet that runs behind an HTTP server, and is accessed via a URL in the form:
http://<your-http-server>/xmarc/Broker...
or
http://<your-http-server>/xmarc/FireRender...
depending on your web server servlet container.
The Java Servlet technology is currently supported in most HTTP servers on most platforms, and, thus the Service Broker is considered platform-independent.
The Service Broker manages a set of named services, known as logical services. Each logical service can have multiple instances of Fire performing the same function, i.e. running the same application. Loads on a service are automatically balanced among servers. A server is allocated to a request if it's the first free, or the least loaded server.
When there are multiple requests queued on a server, requests are synchronized and processed one at time by the server. This means that a server is not required to be multithreaded, and the scalability is achieved by running multiple instances (servers) of a logical service.
The Service Broker communicates with Fire through TCP/IP socket on a designated port. Fire can run on any machine as long as there is an open port from the HTTP server machine to the machine hosting Fire. This configuration fits well with some web sites where the HTTP server and other application servers are required to run on the opposite sides of the corporate firewall.
The Service Broker automatically detects and removes "bad" Fire instances (for example, services which have possibly hung or have prematurely terminated), and will start new instances when required, which will immediately join the rest of the Fire instances available to the broker.
The Service Broker can support stateful connections between a client and a Fire instance. A client can lock down a Fire instance exclusively and unlock it when a unit of processing expanding multiple requests is finished.
The following figure shows how a request initiated from a browser travels through an HTTP server and the broker servlet, and reaches a back-end Fire data server.
http://www.server.com/xmarc/Broker&service=ID
When Fire is to be used as a back-end data server, it must be started as a service in one of 2 ways:
For both methods, Fire requires the following parameters:
-appstart=<app>where <app> is the name of a .fsc or .xml file with application configuration details. Refer to Building An Application for details of how to create applications.
-env=<install_dir>where <install_dir> is the directory containing the Fire installation, e.g. c:/Xmarc/es6.1/fire. If you only have one Fire version installed, then this parameter is usually not necessary, but it does no harm to include it to be sure.
For the manual registration method, the registration url is specified by the following option:
-url="http://<webhost>/xmarc/Broker/register?service=<serviceID>\ [&host=<host>]&pwd=<password>[&key=<secret_key>]\ &timeout=<request-timeout>[:<server_timeout>]"
where
<webhost> is the name of the machine running the Service Broker.
<serviceID> is the name of the service which a client will use to connect to. This is known as the Logical Service name.
<host> is the name of the machine on which the Fire service is to run. This is typically omitted, in which case Fire will use the value of ~global.host_name.
<pwd> is the name of the password giving access to the Service Broker.
<secret key>: An optional secret key. This is an extra level of protection which can be set for a service to restrict client access.
<request-timeout>[:<server-timeout>] can specify how long a request to a service is queued if all servers of that service is busy, and how long to wait for a response from a server once a request has been forwarded. The default values are both are 30 seconds.
Note: You require an fxrender license to run Fire as a service.
Services running under the Service Broker can be managed remotely from a browser, via the Service Manager screen. Functions available within the Service Manager include:
For further information and use on this html-based application, and how to install the Service Manager refer to Service Manager.
How does a Fire application communicate with a client via the Service Broker ?
Assuming you are familiar with both the Fire language and writing Fire applications, there are 3 concepts to learn
Fire provides several global identifiers, all prefixed with firerender_, to provide the connection details between Fire and the Service Broker. These identifiers are created automatically for you when Fire starts. They in turn access an internal atable named firestation, which you should not need to reference.
To initialize a FireRender application you should register the application with the following Fire statement:
unless (fire_render_register()) { firerender_destroy }
This bit of code does the actual registration with the Service Broker, sending the url which was on the Fire command line. The Service Broker now knows that the service has started. You will typically do this in your applications start.cmd macro, with a test as shown to handle failure.
Your application would then typically wait for client requests via the command poll.
When a client makes a request to the service, the service broker will relay it to your Fire application invoking the callback/handler firerender_request.
You must implement your own version of this handler to process the client request, i.e.
firerender_request = { args names=string[], values=string[] # Add your own code in here }
This should also be done in your application's start.cmd macro before calling firerender_register
All client requests are of the form name=value, name=value ... etc. and qualify what the client wants from the request. Your application should be aware of these. The Service Broker strips these off the client's request url and passes them to Fire, along with some standard name/value pairs such as service name, host, port. You can ignore these standard ones if you like.
When the client sends an HTTP GET request, then the name/value pairs are those on the URL submitted by the client. Additionally, when an HTTP POST request is sent, the Serice Broker analyses the body of the request, and if it is a form-type (typically sent by a Submit from a client HTML page) then the name/value pairs within the body are also passed to Fire. If the body is any other text content then the body is passed as a single text value with the name "__POST". If the body is not text content the Service Broker ignores it and does not passed it to Fire.
Your implementation of firerender_request should analyse the name/value pairs and decide what response to send back to the client. This is discussed in the next section.
Data is returned to client via the channel assigned to you in the initialization phase. You can use any of the following Fire commands to send data down this channel.
Calls to these commands should be made during execution of the firerender_request handler in response to the particular client request. Returned data is buffered up until the handler finishes execution, at which point the data is sent to the Service Broker, which in turn pushes it to the client.
When a Fire application is started by the Service Manager, it is launched via a subsidiary program known as an "agent". This allows for the situation where you want Fire to run on a different host from the Service Broker. The Service Manager is responsible for adding the -url parameter to the Fire invocation command, so when launching a Fire service, you only need to supply the -appstart parameter and any others specific to your service.
The agent is also responsible for logging service activity, e.g. when client requests are received, application errors etc.
A Fire application can add messages to the agent log, using the Fire svclog command. Typically, such messages are added to the start.cmd and stop.cmd macros to echo service initialization and termination, e.g.
svclog 0,<"Service started: ",firerender_service_name>
As you can see, this message makes use of the global identifier firerender_service_name which maintains the name of the logical service.
svclog takes an leading integer parameter to specify the type of message. This should be one of the following:
0 - System errors and service start/stop messages
1 - Client connect and disconnect messages
2 - Application errors
3 - Command monitoring
4 - Debug messages
Within the Service Manager, the agent log can be inspected. In addition the log level can be set to increase or decrease the amout of information held in the agent log. Fire gets notified whenever the log level is changed. Initially the log level is 1. Messages of type 0 are always sent to the agent log, others will be sent only if the type is less than or equal to the current log level.
A FireRender Application conforms to the same rules and conventions as a standard Fire application with the addition of the liaison with the firerender variables as described above.
When creating a Fire application to run as a service, the developer needs to keep in mind that the application will not be interactive or visible.
You will typically have to set up HTML pages on your web-server for display in a browser. These pages will typically have some links with associated URLs to hit the FireRender service.
For example the URL
http://mars/xmarc/Broker?service=MapSvc¢er=Portland&radius&500
would pass to firerender_request:
names: <service,port,host,center,radius>
values: <MapSvc,12345,myhost,Portland,500>
This might return an image for display in the client's web page.
Note: The order of name/value pairs in the array is not guaranteed.
To re-iterate, a Fire server application should implement the firerender_request() callback procedure, and properly process the request based on input parameters. As the result, the application should either generate an HTML page using the writefile command or a mime-typed image using the rasdump command. Sending both an HTML page and an image for a single request will result in an error.
Within firerender_request, the channel identifier firerender_channel can be used as the channel to send data back to the client. In addition there is a string identifier firerender_service_name which has the logical service name given to the service in the registration URL, and a string firerender_broker which has the name of the broker to which the service was registered.
A partial example of some start.cmd code for an application is as follows:
atable myapp # The request handler firerender_request = { args names=string[] args values=string[] tell <'Got ',names.alength,'Name/Value Pairs'> numeric cidx=aindex('center',names) numeric ridx=aindex('radius',names) if (cidx && ridx) { string center = values[cidx] numeric radius = ^(values[ridx]) # Add some code which displays an image in window "mywin" # ....... (beyond the scope of this document) # Return it to the client ... # First we add some stuff to the http header to tell the client # (typically a browser) what the content is and a name with which # it can be saved write firerender_channel,'Content-Type: image/jpeg' write firerender_channel,'Content-Disposition: inline; filename=map.jpg' # Then we compute and send the meat, i.e. the image rasdump -iw=mywin,-ch=firerender_channel,-jpg } else { # We could return an error html page here write firerender_channel,'Content-Type: text/html' writefile firerender_channel,bad_params.html } } # Register with the Service Broker unless (firerender_register) { message "Could not contact the Service Broker" firerender_destroy } # Add "start service" message to the agent log svclog 0,<"Service started: ",firerender_service_name> # Wait for events poll
As written above, registering the application is normally done as the last step in the application initialization because it makes it ready to receive client requests.
The Fire command line for the manual registration of such an application would be something like:
fire -appstart="http://uranus/apps/mapsvc.fsc" \ -url="http://mars/xmarc/Broker/register?service=MapSvc&pwd=fred"
where uranus is a machine hosting the Fire application, and mars is the machine hosting the Service Broker servlet. These may of course be on the same machine depending on your system configuration.