I
think I have a better idea of what you are doing. I see you are using
entity beans. My comments would be:
1) As I mentioned in my earlier msg, you don't need to synchronize
your methods; the database resource manager will do this for you. There
are a number of ways of doing this, since you are using EJBs, the main
point is to implement an EJB Business Method that will replace the
functionality of lockKeywords. (Obviously you can wrap the call
to this EJB in a rewritten version of lockKeywords if you
must preserve the method signature for you clients).
2) You code would probably perform better and be simpler if you
created a new database table called something like Document_Lock, that would be
independent of your history table. This would carry the lock status in one
record for each mandant, and you would write history records out as each
entry in this table would be created or updated. (This is a
suggestion only. One downside is that either have to create the entry
representing the mandant at the time the document was created, or
create it the first time a user attempted to set the lock on the
document. I assume here that it has already been
created.)
3) You require a business method that is
transactional. (For simplicity, I ignore the possibility that
the document has already been locked, but you would take care of it as you do
now) It would include
Begin Transaction
Step
A: The execution of a find method on the Document_Lock
table, determining whether or not the document is already
locked.
Step
B: An update to the document entry in the Document_Lock
table, setting it to lock.
Step
C: The creation of a new entry in the keyword_table,
recording that the document has been locked.
Commit
Transaction.
4) The preceding could be implemented in a POJO using JDBC,
directly in a SSB, as an SSB invoking EB, or within an EB itself. And I
don't mean to suggest that you should use BMT if you use an EJB; the transaction
statements are just there to indicate the boundary.
5) The method unlocking the function works almost identically,
except that you probably do not need to do the Step A find. The
client knows the record already exists because they "own" the lock.
This method could also be used by an administrator to reset individual lock
entries as required.
Cheers, Jim W
P.S. I dimply use document, Document_Lock, etc. as an alias for a
media content object, or whatever it is your are referring to with the
mandant_id.
-----Original Message-----
From:
An interest list for Sun Java Center J2EE Pattern Catalog
[mailto:J2EEPATTERNS-INTEREST@JAVA.SUN.COM]On Behalf Of Rafal
Kedziorski
Sent: July 15, 2003 17:16 PM
To:
J2EEPATTERNS-INTEREST@JAVA.SUN.COM
Subject: Re: Design question
...
hi,
this is our
implementation for lockKeywords:
public synchronized
boolean lockKeywords(Long caller_user_id, Integer
mandant_id)
throws CreateException {
logger.debug("lockKeywords()
entered");
// get
lock
Long locked_user_id =
isKeyworsLocked(mandant_id);
// is allready locked
if
(caller_user_id.equals(locked_user_id))
{
logger.warn("lockKeywords() keywords for mandant_id=" + mandant_id + " is
allready
locked");
return true;
}
// keywords can't be
locked more than one time
if
(locked_user_id != null)
{
logger.warn("lockKeywords() keywords for mandant_id=" + mandant_id + " is
allready locked by other user_id=" +
locked_user_id);
return false;
}
// create
lock
keyword_historyLocalHome.create(caller_user_id, mandant_id,
getKeyword_History_Type_Id(Keyword_History_TypeHelper.LOCKED),
null);
return
true;
}
private Long
isKeyworsLocked(Integer mandant_id)
{
// get id for LOCKED
status
Integer
keyword_history_type_locked_id =
getKeyword_History_Type_Id(Keyword_History_TypeHelper.LOCKED);
try {
//
find all locks in
history
Iterator locked_keyword_historyIterator =
keyword_historyLocalHome.findAllByMandantIdAndKeywordHistoryTypeId(mandant_id,
keyword_history_type_locked_id).iterator();
// get last
lock
Object object =
null;
while (locked_keyword_historyIterator.hasNext())
{
object =
locked_keyword_historyIterator.next();
}
//
founded lock entry for given
mandant?
if (object != null)
{
// get id for UNLOCKED
status
Integer keyword_history_type_unlocked_id =
getKeyword_History_Type_Id(Keyword_History_TypeHelper.UNLOCKED);
Keyword_HistoryLocal locked_keyword_history = (Keyword_HistoryLocal)
object;
Long user_id =
locked_keyword_history.getUsers_id();
// find unlocks in history never than locked_keyword_history creation
date
Iterator unlocked_keyword_historyIterator =
keyword_historyLocalHome.findAllByMandantIdAndKeywordHistoryTypeIdAndCreationDate(mandant_id,
keyword_history_type_unlocked_id,
locked_keyword_history.getCreation_date()).iterator();
object =
null;
while (unlocked_keyword_historyIterator.hasNext())
{
object =
unlocked_keyword_historyIterator.next();
}
// founded unlock entry for given user and
keyword?
// no -> is locked by
user_id
if (object == null)
{
return
user_id;
}
else
{
Keyword_HistoryLocal unlocked_keyword_history = (Keyword_HistoryLocal)
object;
Timestamp locked_creation_date =
locked_keyword_history.getCreation_date();
Timestamp unlocked_creation_date =
unlocked_keyword_history.getCreation_date();
// unlock after lock
?
if (unlocked_creation_date.after(locked_creation_date))
{
return
null;
}
return
user_id;
}
}
else
{
return
null;
}
}
catch (FinderException fe)
{
logger.fatal("isKeyworsLocked() failed",
fe);
return null;
}
}
our client is communicating thru HTTP
protocol with out JBoss server. you have to call lock keywords bevore you want
edit keywords. after edit you have to unlock this module.
At 10:41
15.07.2003 -0400, you wrote:
Hi,
I might
not understand your requirements properly. However
-
A:
If your
lockKeywords method is simply trying to update the database entry to
"locked" status, and returns either success or failure, it should still be
capable of being made to work in a distributed environment. You don't
need to synchronize it, as your database resource manager should enforce
consistency through its locking mechanism. Provided you have your
isolation level set to READ_COMMITTED or higher.
The downside of this is that the status is
only available in the database, and you have to make a call to the database
each time a user needs to lock a module. If a large number of these
requests are being made, and a reasonable proportion of them result in
failure because the database is already locked, it might make sense to have
your update preceded by a read.
You could always wrap this in a stateless session
bean. Naturally you require some means of reseting the database if a
session locking the database crashes, or if a user fails to execute the
unlock process.
B:
The
alternative is to go to some kind of distrbuted solution using RMI. It
is not that difficult to implement, in the basic case,unless your
application has high availability requirements and you need to think about
failover. My feeling is that, unless your application usage
patterns are unusual as compared to that of a typical content management
solution, the RMI approach may not enhance performance enough to make it
worth the work. This would be especially true if you need to keep the
lock status in the database. On the other hand, if you can eliminate
the requriement to use the database, it solves the reset
issue.
C:
The
singleton approach that Martin suggests could also work. It is a
practical means of distributing read only data that is centrally maintained
(application configuration data, for instance). To use it in this kind
of situation with a database, you probably would want to have each Singleton
attempt to update the database directly, rather than relying on the
messaging backbone. So the process would work like
this.
1) The
client checks the singleton lock status for a particular
module.
2) If the
module is not locked by another user, the singleton attempts to update the
database (lock the module for the client). If this fails, the client
is informed the module is unavailable; if it suceeds, the client is allowed
to begin editing.
3) If the
lock attempt succeeds, some kind of process will be undertaken to notify the
other singleton instances in the cluster that the indicated module is now
locked. This could be done by having the locking singleton issues a
publish/subscribe msg via JMS. Or you could have a central message
producer activated by a trigger on the database.
The main
advantage of option C over A is that the probability of failure on the
locking call is reduced. This could be a significant issue if there is
a lot of contention among users for certain modules. Otherwise, it is
probably not worth the effort, unless there are additional uses for the
distributed singleton.
thanks. I will check, what is
the best for us.
Regards,
Rafal
Cheers, Jim
W
- -----Original Message----- "From: An interest list for Sun Java Center J2EE Pattern Catalog
[mailto:J2EEPATTERNS-INTEREST@JAVA.SUN.COM]On Behalf Of Martin
Zuzcak
- Sent: July 15, 2003 7:31 AM
- To: J2EEPATTERNS-INTEREST@JAVA.SUN.COM
- Subject: Re: Design question ...
- hi,
- see singleton in cluster, you can resolve your problem
similar way
- http://www.javaspecialists.co.za/archive/Issue052.html
- martin
- Rafal Kedziorski <rafcio@POLONIUM.DE>
- Odeslal: An interest list for Sun Java Center J2EE
Pattern Catalog <J2EEPATTERNS-INTEREST@JAVA.SUN.COM>
- 13.07.2003 13:09
- Odpovìzte prosím u¾ivateli An interest list for Sun Java
Center J2EE Pattern Catalog
-
-
Komu:
J2EEPATTERNS-INTEREST@JAVA.SUN.COM
-
Kopie:
-
Pøedmìt: Design question
...
- hi,
- I have a small design question for our problem which is working on a
single
- instance of an appicaltion server. we are working with JBoss
3.2.2.
- Our application - multimedia content management system - is an
modules
- based application. You can store media files with partient mata data.
You
- can admin category trees and keywords. If some user want for example
edit
- categories or keywords, this module will be locked for this user for
the
- duration of the edit session. our lock is working on a singe
instance
- without problems. how we do this. we have this method:
- public synchronized boolean lockKeywords(Long user_id, Integer
mandant_id,
- Long project_id)
- throws CreateException, ProjectException {
- ...
- }
- for each module we writes a history (created, changed, removed,
locked,
- unlocked, ...) to the db. this table we use for locking. we are
searching
- for the last unlock. id we found one, than the module can be locked
for the
- given user.
- but this wan't works in an cluster environment. are the a pattern,
which
- can we use to solve our problem? or should we user other
implementation?
- Best Regards,
- Rafal
- ====================================================================
- Community Web Site (Core J2EE Patterns Catalog - Online Version):
- http://java.sun.com/blueprints/corej2eepatterns
- Getting Started (Beta Version):
- http://developer.java.sun.com/developer/technicalArticles/J2EE/patterns/
- Get the book:
- http://www.amazon.com/exec/obidos/ASIN/0130648841/corej2eepatte-20
- List Archive:
- http://archives.java.sun.com/archives/j2eepatterns-interest.html
- Unsubscribing:
- email "signoff J2EEPATTERNS-INTEREST" to
listserv@java.sun.com