How to implement asynchronous notification in a three tier, web service backend, desktop application?
We have an ERP application. The server side is implemented as a series of Web services exposed with Hessian and Spring. The Web services make use of a DAO layer for all database operations. The DAOs are implemented using Hibernate. The client side is Java Swing. It makes use of the Web services for all the data related operations.
The problem is that there's a requirement to block certain rows from being edited if there's another client editing the same row at the same time. Also whenever a client is done editing a row, all the other clients shall update the row with the updated value. The solutio开发者_StackOverflow社区n has to take into consideration that the client might be displaying the same data but with a different view (for instance, the same data is filtered in one client, and non filtered in another).
A socket connection between clients is out of the question, since the application needs to work through firewalls with no additional configuration. Continuously polling the server for updates doesn't scale well, since we are looking into hundreds of concurrent clients here.
Looking at my options, I considered JMS but after spending 2 days trying to configure ActiveMQ with Spring, I finally gave up (I don't have previous experience with JMS, nor does the team). Still, it seemed way too complicated for what we need here. At the end, I implemented something using websockets using the excellent Java-WebSocket library, and after hacking a new table listener, cell editor and table model on the client, it's working.
Still I'm concerned that the client is responsible for keeping track of editable/non-editable cells, added and deleted rows, etc. From my perspective, this solution is too fragile. In any given time a message could be lost and all clients lose synchronization between their state.
My question is, how would you implement this requirement given the current architecture? If changing the backend is an option, what would you change to make this requirement easier to implement? It seems to me that the stateless nature of the Web services architecture, plus the fact we are using Hibernate and there's no way that I know of to be notified when a request is modifying a possibly detached object, is making things more complicated than they should be.
Due to mentioned stateless nature of web services there's nothing left but maintain and periodically query/update lock status of particular record (lock owner, lock type, timestammp, etc). And not forget about timeouts: "He's opened a record for editing and cut off his network cable or went on vacation". From my pov solution in the given layout actually does not matter if it does it's job. I'd go for JMS for example which would look into lock database and process lock/unlock/keepalive messages.
But when locking mechanism is not an integral part of ERP, the biggest question is not "how to lock", but rather "what to lock": Should I be able to edit purchase order's header when someone is adding new po entries? Should I be allowed to issue new account receivable while chief accountant edits customer's credit limit? Etc, etc. Implementing such logic, from top-level objects through business logic down to swing input field seems to me almost as hard as creating new ERP from scratch.
I think you are essentially staging yourself having to write your own messaging bus.
I don't understand why you would make the client responsible as the sole register of what it is modifying.
Normally, the client "checks out" the resources from the repository and it is the repository manager's responsibility to register who checked out what resources.
You have three tiers:
- the back-end data repository
- the mid-tier information controller
- the front-end client.
To make matters worse, let's presume you have a distributed data repository. What changed in Tokyo needs to be sync'd into London, Singapore, Shanghai and New York, in REAL TIME.
Real-time
First, you need to understand and define the meaning of "real-time". Real-time is the maximum time latency allowed that would prevent processes from getting out of phase. Or even, the max time latency within the amount of out-of-phaseness that your processes could tolerate.
Out-of-phase means you are receiving data from a previous process run/decision cycle to configure the current process run/decision cycle.
In fighter-jets, real-time means micro or nano seconds. In petroleum refinery, real-time could mean 10 miliseconds or even seconds. In world-wide manufacturing operations, real-time could mean one work shift of eight hours.
In your case, you have two sets of real-time latencies to define
- repository control processes with repositories.
- repository control processes with clients.
Let us presume, though irrelevant to the issue, that the real-timeness of your world-wide repository sync is four hours, i.e. the max time latency allowed between repositories and repository control processes is four hours, rather than seconds. Which would give you sufficient breathing space-time for your client-level sync.
Repository Kanban
I use the non-standard term kanban, to emphasize the role of the tokens, so that you could google on the term and understand its implications.
The repository control processes will be the kanban manager/register. The clients should not be the register of what resources have been checked out. There will be various types of kanban
- read kanban
- write kanban
- state-transition/event kanban
You would understand what read and write tokens are for, but what is a state-change token? In ERPs and MRPs, state-transitions and events form the backbone of the system's ability to monitor and manage process flow. Let us say a resource is on "vacation", the event "return-from-vacation" triggers a change in state for that resource.
Of course you are not using events and states to manage your ERP because you are keeping tabs of what other rows to lock while a row is being "edited". However, if you could rewrite your app to use events and states would be much better because your repository controller should only manage the lower levels of read-write synchronisation, leaving resource interlocking to the resource-event-state model.
So every client will check out kanbans for the resources they are perusing/persuing. Whenever a client commits an update, the kanban is returned to the controller, which then locates the slots of other kanbans that had been checked out - in order to send messages to those subscribers about the change.
Within the restraint of the real-time definition, you or your application would have to decide how many kanbans can be dispensed for a particular resource. One has to be realistic of how many subscribers you could notify so that the human-based and machine-based users will not make an untolerated out-of-phase decision. As well as how many client sockets a controller could manage.
If you are implementing a queued/cascaded state-transition model, you would also define how many state-transition kanbans a resource is allowed to dispense. I wish to emphasize again how helpful it would be to implement a resource-event/transition-state model rather than hard-coded if-then-else logic for an ERP. To do that, you would need to have played around with state-machines and be a state-machine geek. You might say, Hey a user simply just needs to update a price record. But you do not realise that very update created a change in state that must be propagated thro-out the network of resources.
What is the time-latency allowed to register that change and notify subscribers of that change - to prevent a machine or a human from firing a dependent event before receiving an update. Of course, the controller would reject out-of-phase requests for transition kanbans, but you need to minimise such occurrences for the sake of efficiency and user-friendliness.
Web services sync
A client would call a web service, with a request. The web service checks if the necessary kanbans for that resource is available. Bearing in mind, that a web service session will have to contend with other instances for kanbans. If you implemented the resource-event/transition-state model your app would know what kanbans to line up and whether multiple modifications could be cascaded to be checked out by different clients.
updateGrade(resourceA){
case (Extreme):
updatePrice(resourceA);
case (Premium):
notify(productMgrA)
case (Downgrade):
scrap (ProductA)
}
What if some client is waiting to make a disposition on some materials of ProductA and is planning to expend some resources/manpower to achieve that while scrap (ProductA) is potentially about to occur? First, your user's resource-event-state model definition, updateGrade would have requested the state-transition kanban for ProductA and any other process/client will fail to acquire a kanban to change the state of resources tagged with ProductA.
I am not sure if I have addressed your question, but I just had a whale of a time evangelizing the benefits of using state-machine modeling for your application and how well it would fit into your messaging needs. And that you should not use written source code or SQL to directly perform resource interlocking.
I also wish to say that I had whales and whales of time using state-transition diagrams and matrices training users how to define their processes. Which means you would have to enjoy doing that too.
精彩评论