What time is it Eccles?
Hold on a moment good fellow. I've got it written down on this piece of paper...
As any Spike Milligan devotee will testify, you have to commit things to documents. Sometimes even the time.
DPML allows resources in the virtual filesystem to be written to as well as read, and of course it's all done
with URI's.
The 1060 NetKernel is a concurrent processing environment. In the applications so far we've just assumed that it is taking
care of all the resource management for us and ensuring that contention for resources is handled. However in order to
write something to a resource we have to tell the operating system to ring fence it for us.
<irony>
Let's demonstrate with a really cool and up to date example. Wouldn't it be great if we could count the number of times
a resource is requested. Why don't we call such an application a 'Hit Counter'. You see this clever name gives it all away.
It's a counter which counts 'hits', which is another way of saying accesses to a resource. The resource being
an item for which a request has been made. So we'll make an 'Application which counts the
number of accesses to a Resource' or a 'Hit Counter' for short. It's such a good idea it's sure to catch on.
</irony> . "Humph, get on with it!!..."
View 'Hit Counter' application here
Try this application here
Not surprisingly this application increments a counter for every access. It is made safe for concurrent
requests by using the lock and unlock accessors. By requesting a lock on the operand URI the
developer is guaranteed synchronized access to the resource. Note however that lock and unlock are only a synchronization mechanism,
an application that requires transactional access to a resource must take care to catch exceptions and take care of error processing.
What do other application instances do if we've got a lock on a resource?
If another application concurrently requests
the same resource for reading it obtains the resource in whatever state it is currently in. There are no
guarantees what that state will be. If another application wishes to write to that resource it will be
unable to since we have a lock on it. The second application instance will block until we end the transaction.
Given that another application can read a resource whilst we're transacting it, it is generally a very good idea to
keep operations on a locked resource very short and never write any semi-processed state to the resource that would
cause problems for another application. As ever with concurrent design it is the application developers responsibility
to ensure the value of a resource is valid for concurrent access.
Looking in detail at this app, the first instruction locks the uri of .../counter.xml, our hit counter XML resource. The second
instruction uses STM which is Simple Tree Manipulation
language, we created it since we frequently needed a simple way to manipulate an XML document
without the complexity of XSLT. This STM operation uses the stm:set-xpath-eval operation to increment the value of the element /hits/counter, the result is
targeted at the .../counter.xml URI which instructs the NetKernel to write the result to the resource. The third instruction
releases the lock so that other application instances can access the resource. Finally the last instruction calls the expire accessor
with an operand of this:response and a target of this:response. If we did not expire
the response of this idoc it would be cached and subsequent results would obtain the cached value, therefore never executing the idoc and so
the hit counter would be a static value. A detailed discussion of the dependency based caching architecture is available
here
Argue all you like. It's a better MouseTrap
The observant will have noticed that the hit counter above is absolutely useless since it only counts
hits to the hit counter! What we need is a general purpose hit counter that can be accessed from
any application. Here's an application which uses a better hit counter.
Try this application here
As you can see we've finally reached parity with 1994's technology and have a splendid hit counter!
View the application here
View 'A Better Hit Counter' here
<instr> <type>dpml</type> <operand>app15b.idoc</operand> <hitcounter>mypage_counter.xml</hitcounter> <target>var:hits</target> </instr>
The first instruction of this basic application is calling the general purpose hit counter. It introduces
a new aspect of DPML, arguments.
We can see that the instruction is executing a sub-idoc, this time creatively called
'app15b.idoc', and that we are passing a named URI argument hitcounter .
The argument is exactly the same as any other resource reference. It can be either a URI or a literal - in this case it's a
relative URI to 'mypage_counter.xml'.
In the hit counter process the URI argument 'hitcounter' is obtained from the request by using the toURI accessor.
<instr> <type>toURI</type> <operand>this:param:hitcounter</operand> <target>var:hitcounter</target> </instr>
This looks at the request and obtains the URI for the given argument - the argument name is referenced in DPML with the parameter URI this:param:hitcounter . The result is returned
as a canoncial URI, referenced as curi:var:hitcounter and used exactly as though it were a direct URI - don't worry about this indirection
just now we'll discover more about curi: in the next section.
Arguments are very useful since they allow us to pass multiple resources to a DPML sub-idoc. They also allow us to build reusable
code libraries since the sub-idoc has no hard coded URI's it uses only arguments passed in with the call from the parent idoc.
She expired peacefully in her sleep
Finally, a hit counter, by definition, shows a different value each time it is accessed. We are using the expire
accessor, in order to make sure the NetKernel does not keep a cached copy of the idoc's result. This immediately
expires the this:response document ensuring that it will not be cached and so is regenerated each time with the new hit count value.
|