Hi Koka,
Before we look at the PK generator issue, there is a deeper problem. It is
in the way Cayenne access stack is built - you can not use the advise for
a single user desktop client app in a multiuser web application
environment. At least not directly.
Look at this picture from the user guide:
http://objectstyle.org/cayenne/images/access-layer.gif
Web user sessions have dedicated DataContexts. Everything underneath it is
shared. So if you override a DataSource at the DataNode level from within
a session, you have a race condition with other sessions.
There are a few solutions to that.
1. More Cayenne-centric (already mentioned in this thread) is to use a
separate DataDomain for each login id. DataDomains are designed to isolate
access stacks, so that no DataNodes or object cache is shared. However
DataDomains work best if you have a small number of access "groups" (e.g.
a few independent online stores served off of the same app). In your case
every user is a "group" and will require a separate DataDomain... Unless
you have a limited number of users, this is too wasteful and will consume
too much memory.
2. Custom DataSource. This is a hack that I came up with last night. I
haven't tried it yet, but it looks least invasive of all and might work
without fighting any of the Cayenne design assumptions. Looks pretty clean
to me... The idea is to implement a custom DataSource that will create
connections based on user credentials attached to the current request
thread. Here is the steps involved:
- Implement your own javax.sql.DataSource, e.g. "UserDS". Its
"getConnection()" method should use user credentials bound to the current
thread (see java.lang.ThreadLocal). You can inherit from
org.objectstyle.cayenne.conn.DriverDataSource to simplify the
implementation.
- Implement your own org.objectstyle.cayenne.conf.DataSourceFactory to
instantiate UserDS, e.g. "UserDSFactory".
- In the Modeler select DataDomain and uncheck "use shared cache" to
disable sharing data between the users.
- In the Modeler select DataNode and type "UserDSFactory" (or whatever
your factory class is called) for DataSource Factory. In the Location Hint
field you can type any informatio your custom factory needs and
understands (e.g. driver name, DB url, etc.)
- Finally you need to bind user credentials to the current thread for each
request. It is up to you how you do that. For instance you can look at the
ServletFilter example in Cayenne Examples
(http://objectstyle.org/cayenne/examples/index.html)
I hope this doesn't look more complicated than it is...
Andrus
> Thanks for prompt answers even on weekend.
>
> All works fine using the link provided by Andrus except that I found
> that sequence based PK generation SQLs ("select
> schemaName.sequenceName.nextVal from dual") are NOT prefixed with
> schemaname automatically (while the normal queries are), so one needs
> not to forget to add schema name to sequence name directly into the XML
> or GUI modelling tool... Maybe one should adjust
> OraclePkGenerator ...
>
> However, either I'm too unlucky or something's wrong with sequences in
> Cayenne / Oracle. I found that if I try to register
> (registerNewObject) new entities in a loop, commitChanges fails with
> primary key violated error if number of new objects exceeds sequence's
> cache parameter (default usually is 20) !? Looking at the neigbouring
> thread about ordering sequence generated IDs I suspect the problems are
> caused by multithreading and it could be Oracle fault in my case (Oracle
> 9).
> Any ideas?
> Koka
This archive was generated by hypermail 2.0.0 : Mon Jan 10 2005 - 10:05:12 EST