Re: Newbie: connected user

From: Andrus Adamchik (andru..bjectstyle.org)
Date: Mon Jan 10 2005 - 10:05:10 EST

  • Next message: Andrus Adamchik: "Re: cross-vm cache - group name?"

    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