Announcement Announcement Module
Collapse
No announcement yet.
[CLEAN DESIGN] Quest for best Architecture for a Rich-Client / Server application Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    For the DOM POJOs, I will have the Review maintain the reference to a 'Reviewable', which will be a tagging (empty) interface, implemented by all the objects that need to be reviewable.

    This reviewable reference will be resolved with the special lookup table you suggested, by using the field as the value in a HQL query parameter.

    I will resist the temptation to add a getReviews() to the Reviewable interface and therefore make the association bi-directional: this would be more OO, but would case A LOT of headaches with lazy initializion and object transfers, so I prefer to avoid this, and explicitly call the service layer for getting the reviews for a needed item, for example.

    Comment


    • #17
      Originally posted by omero
      Very true, and since this will be the most common way of navigating the association, I'm fine with it.

      Still, I prefer to leave the review.getReviewItem() on the review because I think it's the best thing to do, and avoid having the item.getReviews() instead, because that would force me to deal with lazy-initialization for associations to avoid to load and transfer a huge object graph even when it's not needed.
      I didn't mean to add that relation on an object level. I just meant that a lookup query could be created using a join operation.

      Anyway, fine that the solution seems fitting your needs
      Andreas

      Comment


      • #18
        Originally posted by omero
        I was just saying that i don't want intermediate CLASSES for mapping the hierarchy, like ReviewVote ItemVote UserVote, for representing a Vote on the different objects. I prefer a single 'Vote', with a polimorphic association with the needed object, which can be a different 'type' from time to time (a vote of a Review, a vote of an Item).
        Ah, I see. I agree with that.

        Regards,
        Andreas

        Comment


        • #19
          Originally posted by Andreas Senft
          I didn't mean to add that relation on an object level. I just meant that a lookup query could be created using a join operation.

          Anyway, fine that the solution seems fitting your needs
          Andreas
          Yeah, I wasn't saying that because you suggested to do that, but simply because *I* was doubtful about it. But that's not the case anymore.

          Comment


          • #20
            Adding some new info I found.

            From: http://www.hibernate.org/hib_docs/v3...pes-anymapping

            The <any> mapping element defines a polymorphic association to classes from multiple tables. This type of mapping always requires more than one column. The first column holds the type of the associated entity. The remaining columns hold the identifier.
            Wow, sounds right what we were speaking about Andreas, isn't it? Good to know there IS support in Hibernate for this

            I'm still wondering though if there are better ways to do this, since Hibernate warns and suggests to use the 'any' mapping only in extreme cases.

            It is impossible to specify a foreign key constraint for this kind of association, so this is most certainly not meant as the usual way of mapping (polymorphic) associations. You should use this only in very special cases (eg. audit logs, user session data, etc).
            Hum, the loss of the DB foreign key constraint is expected: after all I'm mapping an association to multiple tables, I wasn't expecting the db to support this.

            But the other warnings, suggesting not to use this, really make me doubtful if there are better way to model the DOM and/or to do the mappings in more standards way... after all it doesn't seems to me as my case is very rare or peculiar: seems like it could happen quite often to have polimorphic association.

            Still wondering.

            Comment


            • #21
              Thanks for the info concerning Hibernate support. Always good to know!

              Actually I hadn't yet such polymorphic associations, so I cannot tell anything out of experience. But concerning the warning I guess it is just intended for discouraging people from taking this as panacea (one size-fits all). For the discussed case I would see it indeed fitting, so I would suggest giving it a try. Unless someone else comes up with another compelling solution I would see this as adequate.

              Regards,
              Andreas

              Comment


              • #22
                Even better, I found out that I can use "Table per concrete class" with explicit polimorphism (opposed to implicit polimorphisms, as was with the <any> mapping), which is the nearly the same, but seems to be better, since it shares the ID through the subclasses tables, and therefore avoid to use a 'discriminator' column for telling which table to query.

                Read about this here: http://www.hibernate.org/hib_docs/v3...bleperconcrete

                You can even define the super-class as abstract, and this effectively eliminates the need for a common table, and is very very similar to our proposed approach (one table for each objecj), the only difference is that instead of using a discriminator value for looking up the object (which allows us to know the table to query in advance), they use a 'shared' ID, where an ID is unique across the N tables, and therefore the ID itself defines the linked object.

                Advantages:
                * Simpler approach, no discriminator column
                * full hibernate support (no limitations as with the <any> mapping, which limits several hibernate features as Polymorphic joins and Outer join fetching)

                Disadvantages
                * Performances (will have to query across the N involved tables I guess)
                * Shared ID (which is less optimal than a proper separate ID for each table)

                I'm now wondering if the fact that the DB will need to look for the needed IDs in three different tables, not knowing in advance which contains it, adds a lot of performance overhead to the join operations... will have to do some tests about it.
                Last edited by omero; Apr 27th, 2006, 02:02 PM.

                Comment


                • #23
                  I searched a bit more, and the union-subclass mapping seems to use SQL UNIONs when making up the query, and therefore uses a single (bigger) query to select the data from the union of the involved tables.

                  This is probably quite efficient, if the DB implements unions efficiently (as most do), and therefore the performance impact shouldn't be very harsh.

                  And we get to keep all the cool hibernate features! Good to know, and that's maybe because the <any> mapping was so discourages. It *IS* a 'last resort' feature after all ^_^

                  Comment


                  • #24
                    Still have a doubt about the explicit polimorphism approach through the union-subclass mapping.

                    Will this allow me to have a class defined as an union-subclass for several abstract classes?

                    Because my classes implements SEVERAL interfaces (at least two: Votable and Commentable), and I'll need to be able to use them in several union-subclass mapping, one for each of the interface they implement.

                    Will dig into the documentation to find out, if someone knows, please let us know as well

                    Comment


                    • #25
                      I have dug into the documentation and unluckily, it seems I was right.

                      The union-subclass mapping, as with all the *class mapping, can be used to map an entity only once, and an entity cannot belong to multiple *class mapping, as far as I know by reading the hibernate documentation.

                      Therefore the only applicable solution is using the <any> mapping, since I have several interface hierarchies that my classes must implement, and lose all the nice HQL queries features because of the <any> mapping limitations.

                      Still thinking if I can refactor the DOM somehow without impacting too much on my business model, and have an easier mapping as well.

                      Reversing the relationship is not an option, since will cause me to have to deal with the problem of lazy-loading remotely the possibly many instances of Comments/Reviews/Votes whenever loading an Item.

                      Another possibility could be not having a relationship at all in neither directions, but simple have several join tables (ReviewVotes, ReviewComments, etc...) and query against them through explicit business methods (getItemReviews(itemID), etc...) to get the needed objects explicitly.

                      This would allow me to avoid this 'difficult' mapping altogether, and keep the ability to extract the wanted objects when needed.

                      The drawback would be the inability to have a reference to the 'reviewed' object on the Review for example, and therefore I would have to think of a method to do this 'manually', like handing the interested object manually to the 'Review Sheet' when visualizing a single review, in order to keep the display of the reviewed item along with the review text.

                      It's not very clean, but would simplify mapping by a whole lot.

                      What do you think Andreas?

                      Comment


                      • #26
                        I guess, I still prefer the <any> approach here, as it is open to future extensions in the object model. And after some upfront work concerning queries, things would be done.

                        Having no relationship at all, but some standalone join tables doesn't look good to me. Filling them will be problematic since they are not mapped. Still you have to always create new tables if new types are created in your object model.

                        As of the different table mapping options: I know the table-per-type and table-per-hierarchy mappings. I would advise to use the table-per-hierarchy approach if possible, as I made bad performance experience on looking up elements of one (hierarchical) type from different tables.


                        Regards,
                        Andreas

                        Comment


                        • #27
                          Originally posted by Andreas Senft
                          I guess, I still prefer the <any> approach here, as it is open to future extensions in the object model. And after some upfront work concerning queries, things would be done.

                          Having no relationship at all, but some standalone join tables doesn't look good to me. Filling them will be problematic since they are not mapped. Still you have to always create new tables if new types are created in your object model.

                          As of the different table mapping options: I know the table-per-type and table-per-hierarchy mappings. I would advise to use the table-per-hierarchy approach if possible, as I made bad performance experience on looking up elements of one (hierarchical) type from different tables.
                          Thanks Andreas, I've decided to go after the <any> mapping after all.

                          A little bit of uneasiness in querying polimorphicly (which will seldom be done, anyway), but a much greater flexibility in future extensions to the DOM if they'll be needed (which is quite probable, after all).

                          Performances, given the inner implementation of the <any> mapping, should be on-par with similar simpler solutions, so we should be ok here.

                          You have been really really really helpful, thanks
                          Last edited by omero; May 1st, 2006, 01:59 AM.

                          Comment


                          • #28
                            Just wondering...

                            SERVER - Service Layer (exposed through httpInvoker remoting)
                            Exposing to the clients all the needed services to interact with the server and the community. This layer should be responsible of checking the user authorization, validating the clients requests and the involved data, and handle the logic for realizing the needed services, by accessing the DAO layer for data access.
                            Have you decided how you are going to do this yet, specifically the user authorization with httpInvoker?

                            Comment


                            • #29
                              Originally posted by mecode
                              Have you decided how you are going to do this yet, specifically the user authorization with httpInvoker?
                              Sort of.

                              I'm planning to use ACEGI ( http://www.acegisecurity.org/ ) which seems quite powerful and full-featured, and is completely integrated with Spring.

                              It seems to be compatible with Spring remoting, so I guess I should have no problem to integrate it with httpInvoker. Am I right? Haven't had time yet to check how to do it, since authorization and authentication is planned to be plugged-in later in the development process, as an AOP aspect ^_^

                              Comment


                              • #30
                                Omero,
                                I just ran across this thread, and find it extremely fascinating as I will be solving this exact problem sometime in the future (I'm referring to your original post). In my case, the user must be able to work in "offline" mode, and, as far as I can see, this forces us to have a DB local to the user. This also means I'm going to be replicating data between client and server. We use Swing/Spring rich on the client side and Spring/Hibernate (to PostgreSQL) on the server side with Acegi for security. This works well now, and I'd like to extend it to work with offline mode. In our case, we have many services and many different object models. Our architecture looks something like:

                                Server:
                                1. DB (PostgreSQL)
                                2. DAO layer (using Hibernate and POJOs) - one DAO per service
                                3. Service layer (typical stuff here - use case methods) - many services, each exposed separately
                                4. Security (Acegi)
                                5. Remote exposure of secured services: HttpInvoker for remote invocation and ActiveMQ (JMS) for firing events from server to client
                                Client:
                                1. Controller (handles interaction with remote services, security, etc)
                                2. Model (basically presents the base POJOs in a way more usable by the UI)
                                3. View (Swing, Spring Rich, etc)
                                Correlating with offline mode will be usability across the internet. Currently, this architecture runs on a LAN, and so the latency of remote service method invocations is not a problem. However, across the internet (and going through HTTP invocations), the latency becomes a problem. I'm thinking that in this case, the offline support can be leveraged as a cache. If the offline "cache" is kept in sync (in real time) while online, then one could always just work off the offline cache directly and avoid internet latency (the latency would be absorbed via the background live synchronization). This means that data would have to be synchronized both ways continuously between client and server. To me this suggests that either the client will be polling the server on a regular basis, or we are going to use some asynchronous messaging platform (ActiveMQ?).
                                For us, the whole synchronization thing is a little complicated by the fact that the offline DB on the user's machine must not contain information the user is not allowed to see or own (security wise). So, all synchronized data must be filtered by the user's security privileges. The user's local offline cache is a smaller "view" or subset of the actual DB.
                                Since we have so many services involved, I'd like to develop a generic solution. I'm thinking something at the Hibernate level. Maybe a Hibernate interceptor that detects any change (insert, update, delete) and asynchronously transmits those changes. Of course, it would also have to apply security filters - hmm... things get more complicated. Maybe a simple service that polls for new objects since the last update. That way Hibernate 3 filters could be leveraged for the security filtering.
                                One thing I'm curious about in your solution: are you synchronizing Hibernate objects or raw DB table row level data? The more I think about it, the more I like the idea of Hibernate objects from the perspective that the user's offline DB will not be the same as the server's DB (maybe hsqldb vs. PostgreSQL), so Hibernate gives us free DB independence (I don't have to translate raw row level data between DB dialects). However, the big issue with Hibernate objects is the object graph. If a single object is updated and I want to remote transmit that update, how do I encode the update in such a way that the entire object graph isn't sucked into the update data? For example, say I have a single object that is part of a large graph. That one single object gets updated (and no other part of the graph). If I used Java serialization to send the update from client to server (for synchronization), then all referenced objects (meaning the entire object graph in this example) gets serialized, wasting bandwidth and CPU. Collections are another example: if someone adds a single item to the collection, it would be nice to simply transmit a collection delta (add this one item), instead of a clone of the ENTIRE collection. All this is possible with Java, of course, but I don't see an easy or automatic way to make it happen. I'd hate to develop such a beast. Maybe Hibernate has some magical support for this that I'm not yet familiar with?
                                OK, enough food for thought. I'll stop here and see if anyone takes the time to read this and respond.

                                Comment

                                Working...
                                X