Announcement Announcement Module
Collapse
No announcement yet.
Generic User Management conflicts with Rich Domain Model Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Not really. I can choose.
    I meant that if you have to bind setter and getter methods, you don't have much of a choice. ;-)

    One more thing. The DAO abstraction spring provides, and how it is commonly put to use with a data mapper (especially Hibernate). Too me it actually sounds exactly what Evans describes as a Repository. A object that is responsible for reconstructing and persisting entities. I'm just courious.
    I don't think that this a DAO abstractation is a repository. By definition a DAO is mostly stupid. It does not have an inner state (shouldn't have). I would say that the objects using the concrete DAO implementations might act like repositories. But saidly I didn't checked the Evans' Repository definition. I will do it tomorrow.


    That reminds me, I didn't reacted to the discussion UserManager vs UserRepository/Registry.

    No it would not change. If the functionality would be the same. But it UserManager would execute business specific logic (like calculating shipping or the like) and UserRepository would not, i'd not go so far calling UserRepository a business service.
    The problem is the term business service. It is difficult, I guess. But I think that a true UserRepository is part of the domain model. It solves the task of permanently storing user accounts and retrieving them. So at the end the user registry is part of a solution of a business related use-case. And there is no doubt that the user registry is a service. But there might be questions about how the registry is visible to other business objects.

    And what is business logic by the way? The only definition I found was a german one: "Im oo-Designkontext als Programmteil zu verstehen, welcher die durch die Use Cases ergebende Logik und die zugehörige Architektur definiert ist." http://www.hta-bi.bfh.ch/Projects/vs...html/g780.html

    The definition says nothing more than every logic which results of a use-case and which defines the appropriate architecture is considered business logic. But this definition is highly questionable. What is a use-case in this context? What is architecture here? I use 'business logic is all logic directly required by a business process'... .

    So does anyone have reliable definitions for business service, business logic, business object etc.? I don't like to fuzz with these words.


    Cheers,

    Martin (Kersten)[/quote]

    Comment


    • #17
      I don't think that this a DAO abstractation is a repository. By definition a DAO is mostly stupid. It does not have an inner state (shouldn't have). I would say that the objects using the concrete DAO implementations might act like repositories.
      Hmm. My DAOs seem to match all the criterias a Repository has:

      - reconstitution of model objects
      - saving
      - no transactions (inserts, deletes, updates but does not commit)
      - globally accessible
      - acts like a in memory collection (you don't know about the persistence, it just seems like all the objects are there up front).

      And internally my DAOs do delegate to the DataMapper or could use Query Objects to build the model objects.

      My DAO would never ever return a DTO. Yet this would be possible - so i guess the name "DAO" is correctly choosen for the framework. But my Dao implementation using Hibernate (in Spring terms) is actually acting as a Repository.

      Code:
      public class GroupDao extends Dao implements IGroupDao {
      
      	private Class groupImplClazz = Group.class;
      
      	public IGroup loadGroup(Long uid) throws DataAccessException {
      		return (IGroup) getHibernateTemplate().load(groupImplClazz, uid);
      	}
             // list of IGroup objects
      	public List getGroups() throws DataAccessException {
      		return (List) getHibernateTemplate().loadAll(groupImplClazz);
      	}
      
      	public void storeGroup(IGroup group) throws DataAccessException {
      		getHibernateTemplate().saveOrUpdate(group);
      	}
      }
      This is a simple example of a DAO i use. Group is a Entity in my model. So this could also look like this:

      Code:
      public class GroupRepository {
      
             Cache cache = new Cache();
      
      	public IGroup loadGroup(Long uid)  {
                    if group object with uid is in cache return it
                    else run jdbc query
                      parse result set into Group object
                      put group objet to cache
      		  return Group object;
      	}
      ....etc for store find and the like
      So this would still be a true Repository - as i understand it. But if i have a method say "public GroupDTO loadGroup(Long uid)" it would not be a Repository anymore, but more a DAO (http://java.sun.com/blueprints/corej...essObject.html). So, a Repository would be a subset of a DAO dealing with the model only - not with DTOs or other objects.

      So bringin it down to the essential differences: a Repository returns exclusively entities/aggregate roots whereas a DAO returns all kind of objects (DTOs, RowSets, whatever). They both accept different kinds of objects as input (i.e primitives, model objects, etc.) Internally they're doing the same: Encapsulate the persistence implementation.

      I'm not 100% sure if this is correct though.

      The problem is the term business service. It is difficult, I guess. But I think that a true UserRepository is part of the domain model. It solves the task of permanently storing user accounts and retrieving them. So at the end the user registry is part of a solution of a business related use-case.
      After rethinking about it, I think business service is more a concept than a concrete class. Let's say "transfer money from and Accoutn to an Account" would be a business service. It acutually does not matter where it appears technically (Account Class, TransferMoneyService class, etc.) - well it does in a concrete model or implementation, but still it's a business service.

      I would not categorize a UserRepository as service. But i agree that it is part of the domain model. Whereas the implementation details may be not part of the domain model but an "interface" to another model, the relational model or xml or whatever. The domain does not care how the data gets persisted/restored. The Repository hides that mechanism and pretends the objects being in-memory. So i disagree on the statement that storing/loading of persistent entities is a concern of the model (in my case, that is).

      I use 'business logic is all logic directly required by a business process'...
      I agree. The business logic are the rules and tasks applied during a business process. So i'd say in the case of the "transfer money" use-case, everything required to transfer the money is the logic of the business. So this might be all kinds of stuff from checking balance to acutually do the transfer.

      Business object hmm i think that's hard to describe and depends on the language used in the domain. but the most close definition i'd dare to sepak out loud is maybe "any object somehow related to the domain" like a value or entity but not a Hibernate session for exmaple.

      -andi

      Comment


      • #18
        I also found this BLOG entry which seems to say the same:
        http://abc.truemesh.com/archives/000464.html

        "The Repository pattern described by Evans is different to Fowler's Mappers. The difference is mainly in the intent. Fowler's Mappers are a way of transforming objects into database records whilst Evans's Repositories are a way to separate out whatever persistence mechanism you've chosen from the domain model. A Repository implementation might use Mapper or any of the object-relational mapping patterns behind the scenes."

        or here:
        http://bookshelved.org/cgi-bin/wiki....inDrivenDesign

        "when it came out and have used the Repository pattern on production projects I found that Evans made me see it anew. Why? Because he shows the reader how that pattern can be combined with the notions of Aggregate, Entities and Aggregate Roots to tackle complex domains. Repository (in combination with Specification) goes from being a clever trick to hide your object-relational mapping choices to a fundamental technique that frees the development team to actually model the domain without worrying too much about their choice of a persistence strategy."

        So the DAO support spring provides is basically a Repository support where you can build DAOs or Repositories upon.

        -andi

        Comment


        • #19
          So this would still be a true Repository - as i understand it. But if i have a method say "public GroupDTO loadGroup(Long uid)" it would not be a Repository anymore, but more a DAO (http://java.sun.com/blueprints/corej...essObject.html). So, a Repository would be a subset of a DAO dealing with the model only - not with DTOs or other objects.
          Maybe there is a problem with the word repository. For me a repository is a concept (since it is represented by a noun, a concept must exist). The repository is about a collection of objects (i also mean non-physical objects here) being stored/maintained somewhere. Depot might be quite a synonym for repository.

          By using the money transfer example: A bank manages a collection of bank accounts. In the early days, a bank account was something like a safe deposit box is today. You put the things in it and it got locked away. Today money is used and a concrete 100 EUR note is worth the same like another 100 EUR note. So there is no need to store the money physically and guarantee that the same note you gave the bank is the same note you get from the bank when you draw money out of your account.

          Never the less the amount of money 'stored in' your account is guaranteed. Maybe it is just quite abstract but I guess a bank account can be seen as a special kind of a repository (depot) for storing money. Like a repository of datas is just a place where you can store your datas.

          In this case the repository aspect is part of the modeled elements and quite following from the aggregation concept.

          I also reread the repository related sections in "Domain Driven Design" (page 152ff). There isn't much of a problem. I guess from this standing building a repository using a DAO support is correct. I agree with it. But I wouldn't relate this repository to be a real DAO implementation. I would say it is a domain object.

          I guess we should just turn to page 164 and check out figure 7.1. This diagram represents the model of the shipping domain. Now lets turn to page 172. In figure 7.4 are the repositories introduced. Here we find the repositories to provide access to the domain model objects.

          The question I have is, wether these repositories are part of the system's domain model or not (I would say yes). I have learned that a model of an application includes such repositories (like a document repository).

          Also if you let your use-cases to condense on such a repository containing model, it is much likely that the repositories also change faces by attracting more responsibilities. Often it comes to a more competent object to serve the model better, just like a UserRegistry does a better job instead of having a UserRepository + a UserFactory + others to deal with modifications made on a collection of users (like one user got a granted right and that effects the right of all of the people in his temporary team, which has not been modeled explicitly)).

          If we call it a UserDAO, we talk about data. Every business logic using the userDAO has to be aware that by retrieving a user object, datas has to be accessed. The name-postfix DAO is mostly a problem, I guess.

          The DAO in the name prevents such an object to be subject of change and to attract additional responsibilities. And the goal is to use as abstract objects as possible and to implement as concrete as possible (simplify usage + simplify implementation). Often I fought with a DAO layer, when there simply shouldn't be one there... .


          So bringin it down to the essential differences: a Repository returns exclusively entities/aggregate roots whereas a DAO returns all kind of objects (DTOs, RowSets, whatever).
          Or better a Repository related to the domain speaks domain language, whereas a DAO just talks everything needed. I consider a DAO to be a facade to interconnect the domain layer and the persistence layer. (I will drop talking about persistence layer anymore. I find the four layer model presented by Evans better (but I question the application layer, any thoughts?).


          They both accept different kinds of objects as input (i.e primitives, model objects, etc.) Internally they're doing the same: Encapsulate the persistence implementation.
          The use-cases of the DAO and the repository is quite different for me. Actually if I would use the DAO pattern I would implement a repository just as this:

          Repository -- uses --> ConcreteDAO. You know a DAO is like a strategy to retrieve objects form a persistence store being plugged into the concrete repository. Thats the picture I have of the DAO pattern (because of the data in the name, and if you check the Sun's pattern description a persistence related language is used to describe it). But thinking about the term Data Access Object even a graphic driver would fall under this definition. I don't know if this is suitable?

          Also just watch your system (architecture+design+implementation), when you change the system requirement: "The domain model should be persisted into a database" to "The domain model should only exist in memory". If the domain layer is well designed, only implementations of the domain model objects should change and the public method signatures should be stable. Any object that changes in case of a method signature would indicate a problem.

          It depends on the style of programming, but I often found that DAO interface are not quite stable according to a change of the persistence related requirements. That's why I actually consider a DAO to be a implementation detail (requires to move it to a sub package for instances).

          Also even if you call something UserDAO but implement something I would call UserRegistry, it brings a problem with the test-suite. I don't know but when I write tests for a DAO it looks quite different compared to the tests I write for a domain objects like a user registry.


          After rethinking about it, I think business service is more a concept than a concrete class.
          The problem with the term concept comes, when talking about totally abstract classes. Every designed object seams to reflect at least one concept. Every object in a designed system solves one or more tasks. To solve a task a concept must exist (classes are realisations of concepts and interfaces/totally abstract classes represent concepts).


          I would not categorize a UserRepository as service.
          But it serves client object(s). Maybe I would not call a user repository a business service but it provides a service (finding users) for every object in the domain layer. Like a warehouse, which provides also a service (storing products).


          So i disagree on the statement that storing/loading of persistent entities is a concern of the model (in my case, that is).
          It is the fun of the onion model. The higher onion layer may delegate the requirements but for the outside the higher layer is the only one to be responsible for ensuring the requirements are meet. Maybe I expressed it in the wrong manor.


          Business object hmm i think that's hard to describe and depends on the language used in the domain. but the most close definition i'd dare to sepak out loud is maybe "any object somehow related to the domain"
          The question goes, what a domain? Business domain? Is the business domain the same domain as of the domain layer (what happens to the use-cases here?)? Is the domain model more than just a representation of the business domain? What does a domain model additionally need to implement a business domain model?

          Some posts before I used 'business object is every object which takes part in a business process'. But I read some pages in the internet and learned that every method might have business objects, too. Just an objects that apply to the domain (bounded context) of the particular method. I think people are intermixing this. Maybe this is just another term getting lost by overusing it - just like the term refactoring... .


          like a value or entity but not a Hibernate session for exmaple.
          I agree.


          I have to say thank you. This is a very a interesting and highly productive discussion for me. It seams that I simply had to take Evans' book form my book shelf. I will reread most of the chapters, I guess. It seams that I missed some details here.

          My problem with the DAO pattern seam to be just related to the D in DAO + the focus of towards the persistence aspect. Since I am used to Analysis Patterns (writing my own pattern languages, when I analyse a domain/problem (provides great reuse value, I guess)), I never stumbled accross a DAO object after all, so it always felt wrong (especially when I found myself fighting with such an implementation once it got more complicated).


          So the DAO support spring provides is basically a Repository support where you can build DAOs or Repositories upon.
          I agree. But this implementation I wouldn't like to call DAO anymore ;-). So it is more like a general Hibernate persistence support. Indeed a very interesting thought. You are right.


          Cheers,

          Martin (Kersten)

          Comment


          • #20
            Maybe there is a problem with the word repository. For me a repository is a concept (since it is represented by a noun, a concept must exist). The repository is about a collection of objects (i also mean non-physical objects here) being stored/maintained somewhere. Depot might be quite a synonym for repository.
            Yes, depot might fit too. I agree with your definition of the collection. It appears as such a collection. And the implementation of the repository maps it to whatever is required (database, xml, memory). This mapping part is not part of the business - the business (usually) does not care how data is stored/retrieved - of course it depends on the business. It is part of the domain, just like a factory.

            This makes it much more comfortable to use it in the model directly. Instead if i'd use a DAO in say, my User object, it'd feel klunky. But that might be due to the interpretation of what is a DAO. Using Evans' Repository to abstract persistence of my model makes much more sense to me than using a Sun DAO.

            In fact, all the sudden my Repositories (formerly "DAO Layer") are now a part of my model, not a part of my infrastructure (hiernate is infrastructure which is carefully hidden by the Repositories). This promotes even cleaner an more cohesive packaging. Which all makes perfectly sense now. The only thing that bleeds through from the infrastructure layer are the exceptions (DataAccessExceptions). But i can live with that as it is perfectly fine for me to catch them in a service class or even in the web tier.

            Never the less the amount of money 'stored in' your account is guaranteed. Maybe it is just quite abstract but I guess a bank account can be seen as a special kind of a repository (depot) for storing money. Like a repository of datas is just a place where you can store your datas.
            I see where you coming from. The account would be a repository in a business sense (a place where you can store data = repository). So if the bank people talk about repository they mean a bank account. If a developer talks about a repository he thinks of something else. This would conflict with the Language of the business people, i guess. But i doubt that the bank business guys would call an Account a "repository". So there are two languages conflicting here. A repository has a special meaning the the model but it is also concept that goes along with the implementation details. However this overlapping of language could occur with any business i guess.

            But I wouldn't relate this repository to be a real DAO implementation. I would say it is a domain object.
            Yes, this might be an option. But i don't see a big gain introducing a another layer between the Repository and Hibernate (or JDBC, or XML, or...). Depends of the requiremens of course. If your dao neets to spit out DTOs it makes sense (even this could be handled a layer higher in a service class).

            I guess we should just turn to page 164 and check out figure 7.1. This diagram represents the model of the shipping domain. Now lets turn to page 172. In figure 7.4 are the repositories introduced. Here we find the repositories to provide access to the domain model objects.
            Yep. But he does not use those repositories within aggregates. They are used by the client to coordinate things (see P158 Figure 6.23). Now what is a client? On p156 he states (second bullet): "leave transaction control to the client". this makes it clear what a client in my project is: a service (my UserService). I think a client is whoever uses the domain model, which could basically everything except the entities/values. that's how i'd define it.

            The question I have is, wether these repositories are part of the system's domain model or not (I would say yes). I have learned that a model of an application includes such repositories (like a document repository).
            Hmm, your document repository is that a part of your domain (on p172 fig 7.4, your document repository would be direct interchangable with, say "Cargo" ... of course it would not in the shipping business, but you know what i mean). Is that the case? Then your document repository is part of the domain model, but it is not the same thing like a CargoRepository - which your case would be a DocumentRepositoryRepository. Huh, i hope it is understandable, what i want to say.

            To get back to Evans example, the cargo example in fig 7.4. I'm thinking out lout: say i.e. the CustomerRepository is an implementation detail of the problem domain, which makes it somehow a part of the domain model. how so? well, let's ask us if the need to "find a customer by id" is an itrinsic part of the shipping problem domain? i'd say yes and no. but, how can you ship a cargo when you don't know where to ship it to. to get this information we need user interaction. somehow the address must be provided. this could be by querying a database or by using a factory to build a address value. so if your address would have been built by a factory would you say the factory is part of a the business domain model? no, because the factory is a implementation detail.

            however, i'm really not 100% sure about this either.

            ust like a UserRegistry does a better job instead of having a UserRepository + a UserFactory + others to deal with modifications made on a collection of users (like one user got a granted right and that effects the right of all of the people in his temporary team, which has not been modeled explicitly)
            You could have both (Registry+ Factory) and combine them in a service which also may apply a transactional boundary or something else.

            If we call it a UserDAO, we talk about data. Every business logic using the userDAO has to be aware that by retrieving a user object, datas has to be accessed. The name-postfix DAO is mostly a problem, I guess.
            I agree, DAO does implies persistence somehow. whereas REPOSITORY not necessarily does. It's more abstract and leaves the concrete actions to the implementation. A when using a repository you really don't care and do not know anything about if the objects "in the repository" are coming from a database, a xml file, held in memory, are loaded by each method call or not, are cached or not, are retrieved and reconstructed from 3 different sources... If a need a specific object i just ask a repository to give it to me. That's so cool imho.

            Often I fought with a DAO layer, when there simply shouldn't be one there... .
            Right, i think theres no need for such thing as a "DAO Layer". I have my Repsository that takes care of it. The closes thing to a DAO would be Hibernate in my case. It's part of the infratructural layer and i don't need to pull out responsibilities for persistence up another layer. Makes no sense.

            Or better a Repository related to the domain speaks domain language, whereas a DAO just talks everything needed.
            Exactly. But in such a model, there's no need for a DAO layer talking anything needed by using the database. I really don't see the need for that. If i need data in a DTO or other form i use a service to assemble that data from my domain entities/values.

            I consider a DAO to be a facade to interconnect the domain layer and the persistence layer.
            Hmm. I'd say a DAO is a facade that connects the "persistence layer" (hibernate, jdbc, ibatis) to anything else. But do i really want that? I don't. Because i don't want something or somebody messing around with infromation in between the model and the database because this could violate essential business rules. say a dao allows to insert a Cargo to the database (by using a persistence mechanism) and by passing in a DTO (or manually created cargo object) with some, maybe invalid, cargo data. this would bypass all my business rules that might apply if i'd create a new cargo using a factory or a service that assembles me a valid cargo object.
            I'd even go so far now and say that a DAO has nothing to do in a rich domain model. At least what data manipulation concerns.

            (I will drop talking about persistence layer anymore. I find the four layer model presented by Evans better (but I question the application layer, any thoughts?).
            I think his Application layer is basically a facade to the domain service layer (see p107). It's just a more fine grained seperation that might make sense when serveral domain services need to be combined in one application service call. maybe to apply transactions to a series of domain service calls or just in case there's a rich client that needs to communicate to the domain service using the app service.

            Repository -- uses --> ConcreteDAO. You know a DAO is like a strategy to retrieve objects form a persistence store being plugged into the concrete repository
            I see you point. But in which case you would need the ConcreteDAO? What are the pros of using another layer vs Hibernate (or a query QueryObject) to retrieve/store the domain object? To me this is another abstraction ob the infrastructure layer that does not make any sense.

            "The domain model should be persisted into a database" to "The domain model should only exist in memory". If the domain layer is well designed, only implementations of the domain model objects should change and the public method signatures should be stable.
            Absolutely. Customer findCustomerById(id) would ever stay the same, but the implementation my now using the repository internal in memory cache to retrieve the cusomer. Then again your ConcreteDAO would fall under the shelf and have been a waste of time writing it. Or you change the DAO to be a cache wrapper.

            Also even if you call something UserDAO but implement something I would call UserRegistry, it brings a problem with the test-suite. I don't know but when I write tests for a DAO it looks quite different compared to the tests I write for a domain objects like a user registry.
            I assume, that is because your DAO tests actually test if the persistence mechanism is working correctly. But if you test a Repository you test if the repository is working correctly, no matter which persistence mechanism you use. It still woul yield failure if your persistence mechanism is faulty. But then something is wrong with the infrastructure - and domain model tests should not be responsible for testing infrastructure. If i want to test the UserRegistry it's simply a mock to an in memory storage (simple collection or so).

            But it serves client object(s). Maybe I would not call a user repository a business service but it provides a service (finding users) for every object in the domain layer
            Yes, I agree. Here we have the clash of language a gain (like with the document repository above). It provides the means to finding users.

            I think people are intermixing this. Maybe this is just another term getting lost by overusing it - just like the term refactoring... .
            That's true, and i don't exclude myself here. Even in the course of this thread my terminology changed a bit. Evans has his part here since i'm reading the book at the moment. I think it really depends on the language of the project. But that's also a problem with many stuff on the internet. The definitions are omitted or not 100% clear. Then i read somthing where the word "process" occurs and the context makes it clear to say 70%, and theres still 30% that is in the dark or interpretable.

            I have to say thank you. This is a very a interesting and highly productive discussion for me. It seams that I simply had to take Evans' book form my book shelf. I will reread most of the chapters, I guess. It seams that I missed some details here.
            Yeah, this is really a great book. I found it especially useful in combination with Fowlers Pattern reference in Patterns of Enterprise Application Architecture. Those two books should belong togther all the time.

            My problem with the DAO pattern seam to be just related to the D in DAO + the focus of towards the persistence aspect.
            My problem with the DAOs were that they just felt like something that does not fit in the design. They stand apart somewhere and are used to put a wrapper around the persistence implementation. But i could not tell why. And i needed persistence. All the examples on the web almost all used the DAOs and the "just getter/setter" model beans persisted using DAOs.
            I did not want to put DAOs in my Entities or uses them in my web controllers directly. Evans book really helped me focusing on the important stuff and getting my model clean and straight forward.



            Since I am used to Analysis Patterns (writing my own pattern languages, when I analyse a domain/problem (provides great reuse value, I guess)), I never stumbled accross a DAO object after all, so it always felt wrong (especially when I found myself fighting with such an implementation once it got more complicated).
            Yeah, the DAOs just poped up and seem to be a must have in the J2EE world. But they make no sense in a well designed model, imho. That becomes more and more obvious to me.

            But this implementation I wouldn't like to call DAO anymore . So it is more like a general Hibernate persistence support. Indeed a very interesting thought. You are right.
            Indeed. The dao-packages spring provide a good deal of help in implementing (not connecting!) infrastructure that provides persistence under a consistent interface. They're sort of an "interface" to all persistence solutions out there (or at least that are supported by spring). So the name *DAO* does not express the richness of those support packages. Acutally they are named after a _possible_ concrete target implementation, instead of what they really provide.

            They would much better display as i.e. *PersistenceSupport and PersistenceException or something that is less limiting. Maybe something the spring people want to think about (though it would break with Rods book).

            -andi

            Comment


            • #21
              Hi thyrell,

              Wow this is a long reply, thanks for your afford!

              Hmm, your document repository is that a part of your domain (on p172 fig 7.4, your document repository would be direct interchangable with, say "Cargo" ... of course it would not in the shipping business, but you know what i mean). Is that the case? Then your document repository is part of the domain model, but it is not the same thing like a CargoRepository - which your case would be a DocumentRepositoryRepository. Huh, i hope it is understandable, what i want to say.
              You are understandable, don't worry. But why do you think this repository is part of the domain? I usally follow a step by step process:

              1. Identify the requirements and the responsibilities for the business objects (including domain objects).

              2. Introduce another collection of objects needed by the business objects to do there tasks. This is mostly where the domain model takes shapes for me, thats why I think repositories are domain model objects unless they are not business objects (not required to talk about the business domain).

              3. Introduce other objects needed to implement the domain model related stuff, these are implementation details like DAO stuff or String objects... .

              It is quite obvious that there is a difference between the User of the business domain model and the User of the actual implemented domain model. This is why I always express this by using an interface for the business domain user and a concrete implementation for the domain model User.

              And the DocumentRepository is just something being introduced to model the fact that the documents are stored. I guess it is the onion model that tricks us here. I like to model the whole lifecycle of any object that appears to be dynamic during the lifecycle of the system (if a system uses persistence data, the system just lives on, if the hardware is shut down).


              Yes, depot might fit too. I agree with your definition of the collection. It appears as such a collection. And the implementation of the repository maps it to whatever is required (database, xml, memory).
              I don't know but I like depot even more. You know for me a depot is actively managed where as a repository appears to be passive itself (just like a list). But maybe this is just a picture in my mind ;-).


              Yep. But he does not use those repositories within aggregates. They are used by the client to coordinate things (see P158 Figure 6.23). Now what is a client? On p156 he states (second bullet): "leave transaction control to the client". this makes it clear what a client in my project is: a service (my UserService). I think a client is whoever uses the domain model, which could basically everything except the entities/values. that's how i'd define it.
              That is the problem by using the term client, I guess. Every unit of the system is designed to exist for a given purpose. And the only purpose a system might have is to be senseful (in a designed system, not in a real world). And to be senseful, you have to perform a task for someone (other system, other unit or what else). You know client used here is just meaning everything. The question is where does the client ends? How about the client of the client?

              But following the onion model it is quite clear. The domain layer (Evans term) serves the application layer, which serves the user interface layer which serves the outside. So the reason of existence of the system is the existence of the outside.

              This is quite obvious when you remember that all functional requirements come from the outside and travel towards the next layer (deeper). So the reason for existence just travels in the opposite direction than the requirements go (requirements define which solution is senseful). And if two things travel in opposite directions, it is quite likely that both are related somehow. (like of every money transaction, where the decrease of the money counter of one account directly opposites the increase of money of the other one).

              so if your address would have been built by a factory would you say the factory is part of a the business domain model? no, because the factory is a implementation detail.
              The problem with this factory thinking is that a factory is nothing more then a valid starting point of the lifecycle of an object. The body of my mother factored me. But I am not likely to model such biological reality when talking about user registries. So a hypothetical factory just replaces the biological factory and so users can be created out of thin air. So a factory mostly substitutes a world detail that is not modeled (just a detail left out).

              So a value object called address is an expression of a real address which was created by the postal dudes. ;-)


              You could have both (Registry+ Factory) and combine them in a service which also may apply a transactional boundary or something else.
              Which would be a manager. A manager is something that can manage a lifecycle of objects. That's why I would like to express this aspect within the domain model.


              I agree, DAO does implies persistence somehow. whereas REPOSITORY not necessarily does.
              The problem is that both are implementation details. Mostly a repository is used to support a very limited count of business objects (or even domain model elements). So I am not sure if this is interchangeable.


              A when using a repository you really don't care and do not know anything about if the objects "in the repository" are coming from a database, a xml file, held in memory, are loaded by each method call or not, are cached or not, are retrieved and reconstructed from 3 different sources... If a need a specific object i just ask a repository to give it to me. That's so cool imho.
              Well just use interfaces to define all your public objects (visible to the outside) and all you will say is cool ;-). That's why we all try to program against as abstract objects as possible, and there is nothing more abstracter than a well defined interface. ;-)


              I have my Repsository that takes care of it.
              But check if there is an even more comprehensive object possible. For example, why should I create a special repository 'layer' if an implementation of the user manager can take care of it. Everything that work is related to becomes just an implementation detail. For the outside the client of the repositories are responsible. Don't add repositories just to have repositories - I don't think you are doing that, but this is what happens to most users of the DAO, there has to be a DAO object... .

              Hmm. I'd say a DAO is a facade that connects the "persistence layer" (hibernate, jdbc, ibatis) to anything else. But do i really want that? I don't.
              Someone has to abstract and play the role of a facade. Just check your business objects. They are facades to hide all the implementation stuff the business objects use themselves to delegate the work. On package level the parent package is a facade of its child packages, if not you screwed you packaging up ;-).

              I think his Application layer is basically a facade to the domain service layer (see p107). It's just a more fine grained seperation that might make sense when serveral domain services need to be combined in one application service call.
              I would say the Application layer extends the domain layer with additional logic needed by the UI interfaces... . So it is like an extension of the domain layer (but a application specific one).


              I see you point. But in which case you would need the ConcreteDAO? What are the pros of using another layer vs Hibernate (or a query QueryObject) to retrieve/store the domain object? To me this is another abstraction ob the infrastructure layer that does not make any sense.
              If you don't use repositories, it is the task of the DAO to take care for the services the repositories provide... .


              If i want to test the UserRegistry it's simply a mock to an in memory storage (simple collection or so).
              Depends on the implementation of the registry. You know someone has to be adding Hibernate or what every to the picture. So if you don't have a DAO you might end up with a repository to speak the hibernate language internally. That's when you have to test it. Another thing is the mock issue. There is at least an acceptance test to take care for the integration of the things you mock in one test-suite. The question is, if it is suitable for an acceptance test to do this work. I am currently against it to mock-test the domain objects directly delegating there work towards the persistence layer.


              Yeah, this is really a great book. I found it especially useful in combination with Fowlers Pattern reference in Patterns of Enterprise Application Architecture. Those two books should belong togther all the time.
              Yeah they both fit my book shelf very well (beside others...). What kind of books did you read lately? Anything I should also read?


              They would much better display as i.e. *PersistenceSupport and PersistenceException or something that is less limiting. Maybe something the spring people want to think about (though it would break with Rods book).
              Yeah I also have the same thinking. But I guess this isn't that urgent. Maybe you can raise and issue and ask for it to be a matter of consideration when Spring 2.0 is planned.


              Cheers,

              Martin (Kersten)[/quote]

              Comment


              • #22
                You are understandable, don't worry. But why do you think this repository is part of the domain? I usally follow a step by step process:
                Oh, i understood it that way. I guess I misunderstood it.

                And the DocumentRepository is just something being introduced to model the fact that the documents are stored. I guess it is the onion model that tricks us here. I like to model the whole lifecycle of any object that appears to be dynamic during the lifecycle of the system (if a system uses persistence data, the system just lives on, if the hardware is shut down).

                Yep, and the repository would take care of it if the requirements determine such a persistence behavior.

                I don't know but I like depot even more. You know for me a depot is actively managed where as a repository appears to be passive itself (just like a list). But maybe this is just a picture in my mind .
                Hmm, yeah maybe. CVS repository is that kind of thing i guess. Whereas a perforce repository is actively managed imho. But then again, different language different thing. To me the word "Repository" is quite neutral. I drop and pull things there and don't care much what's happening and trust on the repository that everyhting is fine. Though, english is not my native language and Repository is possibly valued different by natives.

                You know client used here is just meaning everything. The question is where does the client ends? How about the client of the client?
                Hehe now it becomes philosophical.

                But following the onion model it is quite clear. The domain layer (Evans term) serves the application layer, which serves the user interface layer which serves the outside. So the reason of existence of the system is the existence of the outside.
                I think that's quite reasonable thinking. I think the problem here is to draw a clean line between the UI Layer and the "application" that solves problems.

                But check if there is an even more comprehensive object possible. For example, why should I create a special repository 'layer' if an implementation of the user manager can take care of it.
                It's not an additional layer i create. I replaced the former DAO Layer with the Repository which now is part of the implementation of my model and not a mere connector to my persistence infrastructure. I'll post some sketeches wenn i'm through finished the project. So then it becomes more clear i guess.

                Someone has to abstract and play the role of a facade. Just check your business objects. They are facades to hide all the implementation stuff the business objects use themselves to delegate the work. On package level the parent package is a facade of its child packages, if not you screwed you packaging up .
                Heheheh. Yeah, the Repository is a facade to the persistence infrastructure. So I'm fine. But i don't see a need putting another facade in between:

                Code:
                UserRepository {
                   User findUserById(id) {
                        return userDao.gerUserById(id);
                   }
                }
                instead i prefer:

                Code:
                UserRepository {
                  IUser findUserById(Id) {
                        return (IUser) getHibernateTemplate().load(User.class, id); 
                  }
                }
                I would say the Application layer extends the domain layer with additional logic needed by the UI interfaces... . So it is like an extension of the domain layer (but a application specific one).
                Agreed.

                If you don't use repositories, it is the task of the DAO to take care for the services the repositories provide... .
                Ok, and then on the other hand if i use Repositories i don't have a need for DAOs.

                Yeah they both fit my book shelf very well (beside others...). What kind of books did you read lately? Anything I should also read?
                Hmm, i read the Spring book (J2EE development witout EJB) which actually brought me to spring. Spring in Action (pretty basic, more for spring beginners, i did not really read it through though) and "Hibernate in Action", also very good. As well as "The Design of Sites" which is more a web-designer's patterns book, more of a reference to look things up. But very handy if you design UIs.

                Yeah I also have the same thinking. But I guess this isn't that urgent. Maybe you can raise and issue and ask for it to be a matter of consideration when Spring 2.0 is planned.
                Yeah absolutely, it's nothing urgent.

                Now, back to the code... before i loose interest That's a big problem, I like it much more to lab things out than to do the actual coding work

                -andi

                Comment


                • #23
                  It's not an additional layer i create. I replaced the former DAO Layer with the Repository which now is part of the implementation of my model and not a mere connector to my persistence infrastructure. I'll post some sketeches wenn i'm through finished the project. So then it becomes more clear i guess.
                  I am looking forward. But I don't know, I just think a repository is just very limited as an object (single responsibility). I like seeing objects comming to life and to demand additional responsibilities. And I don't know but repositories doesn't look being that smart. Anyways, lets see how your code envolves. Hopefully you will keep me up to date! ;-)


                  Ok, and then on the other hand if i use Repositories i don't have a need for DAOs.
                  Sure! I also agree with that.

                  Hmm, i read the Spring book (J2EE development witout EJB) which actually brought me to spring. Spring in Action (pretty basic, more for spring beginners, i did not really read it through though) and "Hibernate in Action", also very good. As well as "The Design of Sites" which is more a web-designer's patterns book, more of a reference to look things up. But very handy if you design UIs.
                  Hibernate and 'J2EE without EJB' I already own. I also have a copy of 'Pro Spring', which is quite good and I learned something new from it. Lately I got my hands on 'Agile Documentation' (which isn't that useful for me, but a good read anyways), McConnell's 'Software project survival guide' and 'Code Complete 2nd Edition' are great books and 'Death March' is quite entertaining and also worth reading. There were some more books but they don't made it on my recommendation list. (like Sun's JMX and Java performance tuning book and those books of the 'software metrics series')

                  'The Design of Sites' book looks like a good book but Amazon (de) does not provide it yet. I will put it on my wishlist and hopefully I can get a copy of this book. Thanks for the tip.


                  Cheers,

                  Martin (Kersten)

                  Comment


                  • #24
                    'The Design of Sites' book looks like a good book but Amazon (de) does not provide it yet. I will put it on my wishlist and hopefully I can get a copy of this book. Thanks for the tip.
                    http://www.amazon.de/exec/obidos/ASIN/020172149X/

                    That's the one. It does not show up if you search by it. Very strange.

                    -andi

                    Comment


                    • #25
                      Well thanks andi, I brought a copy and I am looking forward to read it.


                      Cheers,

                      Martin (Kersten)

                      Comment


                      • #26
                        Hi Andi,

                        got a grip on that book. It's quite well and very interesting but the patterns are quite coarse-grained. To much stuff for a single pattern, if you ask me. Anyways quite a great information source. Thanks for the tip.

                        Another issue: I am doing some work related to Public Key Infrastructres and I learned a new word there: Depositories. Never ran across it before. It seams to be a combination of depot and repositories and refers to a banking save or just a secure place you store things at. Might this a nice word to describe a secure or manager like repository. What do you think?


                        Cheers,

                        Martin (Kersten)

                        PS: Boy I scrolled this second page all the way down. I guess this is one of the longest pages this forum has seen so far ;-).

                        Comment


                        • #27
                          Hi Martin,

                          it's more for a designer than a developer and different style. I come from both worlds so i'm used to it anyway. matter of taste i guess..

                          depository sounds interesting. i'm going with repository though and i refactored them a bit now they look like:

                          Code:
                          UserRepository {
                             private RepositoryStrategy strategy;
                          
                             setStrategy(...);  // i.e. HibernateRepositoryStrategy
                          
                             User findUserByName(String name) {
                                  Criteria specs = strategy.getCriteria();
                                  specs.add(Restrictions.eq("name", name));
                                  return (User) strategy.soleMatch(specs);
                            }
                          }
                          The specs are currently the hibernate Criteria api, which is somewhat unclean to use them in the Repository directly. But that works perfectly for now and refactoring towards my own Specification API will be straigt forward. All my persistence code is in one pluggable class "HibernateRepositoryStrategy" and nicely hidden. repositories are clean and working fine. Now I'm happy

                          I also ditched coding my model classes (like User, TimeInterval, Name) to interfaces (i mean "interface" contracts). Refactoring became a mess. Maybe I need to add them later, but currently there's no need and just complicates things.

                          Yeah, the thread is quite long. I hope it is useful for others than us too...

                          -andi

                          Comment


                          • #28
                            it's more for a designer than a developer and different style. I come from both worlds so i'm used to it anyway. matter of taste i guess..
                            I also like to read books from the other side of the edge. But I don't like the way they used to write down those patterns. Some of the pattern fun is missing and I had to add it myself. If you abstract all those patterns you get a concept collection that helps you in nearly every area. That's what I missed most (beside the forces section), but anyway a great knowledge source.


                            All my persistence code is in one pluggable class "HibernateRepositoryStrategy" and nicely hidden. repositories are clean and working fine. Now I'm happy Smile
                            That's nice to hear. Do you use the same class with diffrent persistance strategies or do you use this strategy 'just for' organisation of your logic?

                            In my current situations, I didn't like the strategy pattern that much. I simply had an iBatis implementation and that is all? I will fall back for those strategy pattern once, I need it.

                            Also I miss the addUser method in your repository :-). How is the repository finally be used? Where is the user added and removed? Where are the update methods? Can you please outline the dependencies of this repository? You know, who uses it and for what... .


                            Cheers,

                            Martin (Kersten)

                            PS: I brought 'JavaServer Faces in Action' lately - just to keep me in touch with JSF. Do you know of a good book about JDO? This is next on my 'to investigate' list.

                            Comment


                            • #29
                              Hi Martin,

                              Code:
                              That's nice to hear. Do you use the same class with diffrent persistance strategies or do you use this strategy 'just for' organisation of your logic?
                              Currently i use it with hibernate only. But the idea is to make a switch as smooth as possible. So, basically it's currently only 'just' for organization.

                              Code:
                              Also I miss the addUser method in your repository . How is the repository finally be used? Where is the user added and removed? Where are the update methods? Can you please outline the dependencies of this repository? You know, who uses it and for what...
                              I did not refactor all the repositories to the strategy pattern. The example is not the whole code just typed it on the fly. Also i still do not have diagrams in digital form (i'm lazy...).

                              The following repository is working though (used to store/lookup hashes for the user enrollment, the name will change eventually):

                              Code:
                              public class RegistrationTicketRepository {
                              
                              	/**
                              	 * The persistence strategy used for this repository
                              	 */
                              	private RepositoryStrategy strategy;
                              
                              	/**
                              	 * Private construcor. This class should never be instantiatet manually.
                              	 */
                              	private RegistrationTicketRepository() {}
                              
                              	// ~ Bean setters/getters --------------------------------------------------
                              
                              	public void setStrategy(RepositoryStrategy strategy) {
                              		this.strategy = strategy;
                              	}
                              
                              	// ~ Methods ---------------------------------------------------------------
                              
                              	public RegistrationTicket findTicket(String hash)  {
                              		// This is OK but not very clean since the hibernate
                              		// criteria api bleeds into the repository that should not be
                              		// A domain criteria specification object wwhich the strategy is
                              		// aware of should be passed to the strategy here
                              		// nevertheless this code is easie to refactor if the persistence
                              		// layer would change.
                              		Criteria crit = strategy.createCriteria(RegistrationTicket.class);
                              		crit.add(Restrictions.eq("hash", hash));
                              		return (RegistrationTicket) strategy.soleMatch(crit);
                              	}
                              
                              	public void storeTicket(RegistrationTicket ticket) {
                              		strategy.save(ticket);
                              	}
                              
                              	public void removeTicket(RegistrationTicket ticket) {
                              		if (!ticket.isValid()) {
                              			strategy.remove(ticket);
                              		} else {
                              			// TODO-HIGH: convert to business exception
                              			throw new RuntimeException("Can't remove a valid ticket. Please invalidat first.");
                              		}
                              	}
                              
                              }
                              The ticket classes
                              Code:
                              /**
                               * An abstract Ticket. A <em>Ticket</em> is basically a object that holds a
                               * world wide unique and random hash &#40;GUID&#41;. A Ticket should be subclassed to
                               * provided case specific behavior and data.
                               *
                               * @author  Andreas Aderhold
                               * @version $Revision$
                               */
                              public abstract class Ticket extends Entity implements Serializable &#123;
                              
                              	private String  hash = "";
                              	private boolean valid = false;
                              	private Date created = new Date&#40;&#41;;
                              
                              	Ticket&#40;&#41; &#123;&#125;
                              
                              	public String getHash&#40;&#41; &#123;
                              		return hash;
                              	&#125;
                              
                              	protected String buildNewHash&#40;&#41; &#123;
                              		this.hash = AnotherGuid.getInstance&#40;&#41;.genNewGuid&#40;&#41;;
                              		this.valid = true;
                              		return getHash&#40;&#41;;
                              	&#125;
                              
                              	public void invalidate&#40;&#41; &#123;
                              		this.valid = false;
                              	&#125;
                              
                              	public boolean isValid&#40;&#41; &#123;
                              		return this.valid;
                              	&#125;
                              
                              	public Date created&#40;&#41; &#123;
                              		return this.created;
                              	&#125;
                              
                              &#125;
                              
                              public class RegistrationTicket extends Ticket &#123;
                              
                              	public static final RegistrationTicket EMPTY_TICKET = new RegistrationTicket&#40;&#41;;
                              
                              	private User user;
                              
                              	RegistrationTicket&#40;&#41; &#123; super&#40;&#41;;	&#125;
                              
                              	private RegistrationTicket&#40;User user&#41; &#123;
                              		this.user = user;
                              		buildNewHash&#40;&#41;;
                              	&#125;
                              
                              	public User getUser&#40;&#41; &#123;
                              		return user;
                              	&#125;
                              
                              	public void validateUser&#40;&#41; &#123;
                              		if &#40;isValid&#40;&#41;&#41; &#123;
                              			if &#40;!user.isEnabled&#40;&#41;&#41; &#123;
                              				user.setEnabled&#40;true&#41;;
                              			&#125;
                              			invalidate&#40;&#41;;
                              		&#125;
                              	&#125;
                              
                              	public static RegistrationTicket newTicketForUser&#40;User user&#41; &#123;
                              		if &#40;user == null&#41; &#123;
                              			throw new IllegalArgumentException&#40;"The user can't be null."&#41;;
                              		&#125;
                              		return new RegistrationTicket&#40;user&#41;;
                              	&#125;
                              
                              	public boolean equals&#40;Object o&#41; &#123;
                              	    if &#40;this == o&#41; return true;
                              	    if &#40;!&#40;o instanceof RegistrationTicket&#41;&#41; return false;
                              	    final RegistrationTicket ticket = &#40;RegistrationTicket&#41; o;
                              	    if &#40;!getHash&#40;&#41;.equals&#40;ticket.getHash&#40;&#41;&#41;&#41; return false;
                              		if &#40;!getId&#40;&#41;.equals&#40;ticket.getId&#40;&#41;&#41;&#41; return false;
                              	    return true;
                              	&#125;
                              
                              	public int hashCode&#40;&#41; &#123;
                              		return this.getHash&#40;&#41;.hashCode&#40;&#41;;
                              	&#125;
                              
                              	public String toString&#40;&#41; &#123;
                              		return "RegistrationTicket &#40;HASH= "+ getHash&#40;&#41; +"&#41;";
                              	&#125;
                              
                              &#125;

                              The repository is used by a service:

                              Code:
                              public interface IRegistrationService &#123;
                              
                              	/**
                              	 * Register a new User with the system.
                              	 * <p>
                              	 * This method should throw an &#123;@link UserExistsException&#125; if the user is
                              	 * already in the database and a &#123;@link EmailAddressExistsException&#125; if
                              	 * the Email addess of the user is already taken by another user.
                              	 * <p>
                              	 * This methdod is also responsible for sending a email to the user that
                              	 * the enrollment process started.
                              	 * <p>
                              	 * This can be done by a advisor wich sends a email to the user. It can
                              	 * also be done programatically by sending the mail directly within the
                              	 * implementation. Maybe the preffered choice.
                              	 * <p>
                              	 *
                              	 * @param  user The configured User to sign up.
                              	 * @throws BusinessException in case of errors
                              	 * @return <code>true</code> if the registration completed;
                              	 *         <code>false</code> otherwise
                              	 */
                              	abstract boolean registerUser&#40;User user&#41; throws BusinessException;
                              
                              	/**
                              	 * Enroll a registered user.
                              	 * <p>
                              	 * Completes the final enrollment of a user by checking against a hash.
                              	 * If the hash can be found in the pending enrollemnts the corresponding
                              	 * User is set active and the pending enrollment is deleted.
                              	 * <p>
                              	 * This methdod is also responsible for sending a email to the user that
                              	 * the enrollment process successfully completed.
                              	 * <p>
                              	 * This can be done by a advisor wich sends a email to the user. It can
                              	 * also be done programatically by sending the mail directly within the
                              	 * implementation. Maybe the preffered choice.
                              	 *
                              	 * @param  hash
                              	 * @throws BusinessException
                              	 * @return The enrolled <code>User</code>
                              	 *
                              	 */
                              	abstract User enroll&#40;String hash&#41; throws BusinessException;
                              &#125;
                              Implementations
                              Code:
                              	public boolean registerUser&#40;User user&#41; &#123;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"Starting signup for user " + user.getUsername&#40;&#41;&#41;;
                              		&#125;
                              
                              		if &#40;userRepository.findUserByUsername&#40;user.getUsername&#40;&#41;&#41; != null&#41; &#123;
                              			throw new UserExistsException&#40;&#41;;
                              		&#125;
                              		if &#40;userRepository.findUserByEmail&#40;user.getEmail&#40;&#41;&#41; != null&#41; &#123;
                              			throw new EmailAddressExistsException&#40;&#41;;
                              		&#125;
                              
                              		Role roleEveryone = roleRepository.findRole&#40;ROLE_EVERYONE&#41;;
                              		Role roleCustomer = roleRepository.findRole&#40;ROLE_CUSTOMER&#41;;
                              		Group groupUsers = groupRepository.findGroup&#40;GROUP_USERS&#41;;
                              
                              		user.addToRole&#40;roleEveryone&#41;;
                              		user.addToRole&#40;roleCustomer&#41;;
                              		user.addToGroup&#40;groupUsers&#41;;
                              
                              		userRepository.storeUser&#40;user&#41;;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"Creating validation ticket..."&#41;;
                              		&#125;
                              
                              		RegistrationTicket ticket = RegistrationTicket.newTicketForUser&#40;user&#41;;
                              		ticketRepository.storeTicket&#40;ticket&#41;;
                              
                              		String hash = ticket.getHash&#40;&#41;;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"Ticket created and saved with hash&#58; " + hash&#41;;
                              		&#125;
                              
                              		// TODO&#58; USE SCHEDULER, fire and forget the mail to a scheduler
                              		//       mail sending should not happen in transactional context
                              		try &#123;
                              
                              			MimeMessage mm = mailSender.createMimeMessage&#40;&#41;;
                              			MimeMessageHelper msg = new MimeMessageHelper&#40;mm, "UTF-8"&#41;;
                              			msg.setFrom&#40;"[email protected]"&#41;;
                              			msg.setTo&#40;user.getEmail&#40;&#41;&#41;;
                              			msg.setSubject&#40;"Welcome..."&#41;;
                              			msg.setText&#40;"Hallo please click here&#58; " + hash&#41;;
                              			mailSender.send&#40;msg.getMimeMessage&#40;&#41;&#41;;
                              
                              		&#125; catch &#40;MessagingException ex&#41; &#123;
                              			logger.error&#40;"Error sending mail", ex&#41;;
                              			throw new RuntimeException&#40;"Could not complete request, sending email failed", ex&#41;;
                              		&#125;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"Successfully sent confimation mail to&#58; " + user.getEmail&#40;&#41;&#41;;
                              		&#125;
                              
                              		if &#40;logger.isInfoEnabled&#40;&#41;&#41; &#123;
                              			logger.info&#40;"New registration pending for validation &#40;user=" + user.getName&#40;&#41;.toString&#40;&#41; +"/id=" + user.getId&#40;&#41; + "&#41;"&#41;;
                              		&#125;
                              
                              		return true;
                              	&#125;
                              
                              	public User enroll&#40;String hash&#41; &#123;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"Looking up hash&#58; " + hash&#41;;
                              		&#125;
                              
                              		RegistrationTicket ticket = ticketRepository.findTicket&#40;hash&#41;;
                              
                              		if &#40;ticket == null || !ticket.isValid&#40;&#41;&#41; &#123;
                              			throw new ConfirmRegistrationException&#40;"User already confirmed or confirmation sequence does not exist"&#41;;
                              		&#125;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"Found valid hash&#58; " + hash&#41;;
                              		&#125;
                              
                              		ticket.validateUser&#40;&#41;;
                              		User user = ticket.getUser&#40;&#41;;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"Got associated user&#58; " + user.toString&#40;&#41;&#41;;
                              		&#125;
                              
                              		ticketRepository.removeTicket&#40;ticket&#41;;
                              
                              		// TODO&#58; Need programmatic transaction here or put in advisor
                              		// ALSO&#58; USE SCHEDULER, fire and forget the mail to a scheduler
                              		// mail sending should not happen in transactional context
                              		try &#123;
                              			MimeMessage mm = mailSender.createMimeMessage&#40;&#41;;
                              			MimeMessageHelper msg = new MimeMessageHelper&#40;mm, "UTF-8"&#41;;
                              			msg.setFrom&#40;"[email protected]"&#41;;
                              			msg.setTo&#40;user.getEmail&#40;&#41;&#41;;
                              			msg.setSubject&#40;"Registration complete"&#41;;
                              			msg.setText&#40;"it worked Hallo please click here to login..."&#41;;
                              			mailSender.send&#40;msg.getMimeMessage&#40;&#41;&#41;;
                              		&#125; catch &#40;MessagingException ex&#41; &#123;
                              			logger.error&#40;"Error sending mail", ex&#41;;
                              			throw new ConfirmRegistrationException&#40;ex&#41;;
                              		&#125;
                              
                              		if &#40;logger.isDebugEnabled&#40;&#41;&#41; &#123;
                              			logger.debug&#40;"User confirmed successfully&#58; " + user.toString&#40;&#41;&#41;;
                              		&#125;
                              		return user;
                              	&#125;
                              Reg.Service is used in a controller .. i.e.:

                              Code:
                              public class RegistrationEnrollController extends ParameterizableViewController implements InitializingBean &#123;
                              
                              	// ~ Instance fields =======================================================
                              
                              	private IRegistrationService regService;
                              
                              	// ~ Methods ===============================================================
                              
                              	public void setRegistrationService&#40;IRegistrationService service&#41; &#123;
                              		this.regService = service;
                              	&#125;
                              
                              	public void afterPropertiesSet&#40;&#41; throws Exception &#123;
                                      if &#40;regService == null&#41; &#123;
                                          throw new IllegalArgumentException&#40;"A registration service is required"&#41;;
                                      &#125;
                                  &#125;
                              
                              	protected ModelAndView handleRequestInternal&#40;HttpServletRequest request, HttpServletResponse response&#41; throws Exception &#123;
                              		String hash = RequestUtils.getRequiredStringParameter&#40;request, "enroll"&#41;;
                              		User user = regService.enroll&#40;hash&#41;;
                              		Map model = new HashMap&#40;&#41;;
                              
                              		if &#40;user.isEnabled&#40;&#41;&#41; &#123;
                              			model.put&#40;"username", user.getName&#40;&#41;.first&#40;&#41;&#41;;
                              		&#125;
                              	    return new ModelAndView&#40;getViewName&#40;&#41;, model&#41;;
                              	&#125;
                              
                              &#125;

                              The strategy classes
                              Code:
                              /**
                               * This <em>Layer Supertype</em> is an attempt to unify repository strategies.
                               *
                               * <p>The motivation behind this is to reduce code duplication in combination
                               * with persistence strategies used in different repositories. Most
                               * repositories perform CRUD operations all the time. They expose their
                               * functions with <em>intetion revealing interfaces</em> that underneath
                               * calling the appropriate strategies to manage persitence.</p>
                               *
                               * <p>However, the intention revealing interfaces are duplicated from the
                               * Respositories down to the strategies resulting in seperate strategies for
                               * seperate Repositories. Though the strategies are mostly doing CRUD or other
                               * common operations the intent is to unify the strategy in one that works
                               * for all repositories.</p>
                               *
                               * <p><strong>This class &#40;and implementations&#41; should be considered highly
                               * experimental at this stage and must be used soly for experimentation.</strong></p>
                               *
                               * @author  Andreas Aderhold
                               * @version $Revision$
                               */
                              public interface RepositoryStrategy &#123;
                              
                              	// cirteria should NOT be hibernate specific
                              	Collection matching&#40;Criteria specs&#41;;
                              	Object soleMatch&#40;Criteria specs&#41;;
                              
                              	void save&#40;Object object&#41; throws DataAccessException;
                              	void update&#40;Object object&#41; throws DataAccessException;
                              	void refresh&#40;Object object&#41; throws DataAccessException;
                              
                              	void evict&#40;Object object&#41;;
                              
                              	void remove&#40;Object role&#41; throws DataAccessException;
                              
                              	String getObjectId&#40;Object role&#41; throws DataAccessException;
                              
                              
                              	void removeById&#40;Class clazz, Serializable id&#41; throws DataAccessException;
                              	Object findById&#40;Class clazz, Serializable id&#41; throws DataAccessException;
                              
                              
                              	Criteria createCriteria&#40;Class clazz&#41;;
                              	
                              &#125;
                              
                              public class HibernateRepositoryStrategy extends HibernateDaoSupport implements RepositoryStrategy &#123;
                              
                              	public void evict&#40;Object object&#41; &#123;
                              		getHibernateTemplate&#40;&#41;.evict&#40;object&#41;;
                              	&#125;
                              
                              	public Object findById&#40;Class clazz, Serializable id&#41; throws DataAccessException &#123;
                              		return getHibernateTemplate&#40;&#41;.load&#40;clazz, id&#41;;
                              	&#125;
                              
                              	public String getObjectId&#40;Object object&#41; throws DataAccessException &#123;
                              		return getSession&#40;&#41;.getIdentifier&#40;object&#41;.toString&#40;&#41;;
                              	&#125;
                              
                              	// cirteria that come in should NOT be hibernate specific
                              	public Collection matching&#40;Criteria specs&#41; &#123;
                              		return specs.list&#40;&#41;;
                              	&#125;
                              
                              	public void refresh&#40;Object object&#41; throws DataAccessException &#123;
                              		getHibernateTemplate&#40;&#41;.refresh&#40;object&#41;;
                              	&#125;
                              
                              	public void remove&#40;Object object&#41; throws DataAccessException &#123;
                              		getHibernateTemplate&#40;&#41;.delete&#40;object&#41;;
                              	&#125;
                              
                              	public void removeById&#40;Class clazz, Serializable id&#41; throws DataAccessException &#123;
                              		getHibernateTemplate&#40;&#41;.delete&#40;findById&#40;clazz, id&#41;&#41;;
                              	&#125;
                              
                              	public void save&#40;Object object&#41; throws DataAccessException &#123;
                              		getHibernateTemplate&#40;&#41;.saveOrUpdate&#40;object&#41;;
                              	&#125;
                              
                              	public Object soleMatch&#40;Criteria specs&#41; &#123;
                              		List objs = specs.list&#40;&#41;;
                              		if &#40;objs.iterator&#40;&#41;.hasNext&#40;&#41;&#41;
                              			return objs.iterator&#40;&#41;.next&#40;&#41;;
                              
                              		return null;
                              	&#125;
                              
                              	public void update&#40;Object object&#41; throws DataAccessException &#123;
                              		getHibernateTemplate&#40;&#41;.update&#40;object&#41;;
                              	&#125;
                              
                              	public Criteria createCriteria&#40;Class clazz&#41; &#123;
                              		return getSession&#40;&#41;.createCriteria&#40;clazz&#41;;
                              	&#125;
                              &#125;

                              Hope this gives you the picture. The comments are not always proper, i'm lazy here too...

                              Comment


                              • #30
                                Hope this gives you the picture. The comments are not always proper, i'm lazy here too...
                                Great thanks! This was a very interesting read. Looks really smooth and well done. I understood nearly everything what's going on. Very good coding style, indeed.

                                The only thing I noticed was this:

                                Code:
                                 /**
                                    * The persistence strategy used for this repository
                                    */
                                   private RepositoryStrategy strategy;
                                I would prefer a more descriptive name:

                                Code:
                                 
                                   private RepositoryStrategy persistenceStrategy;

                                But never the less, the picture is now clear. I also did some fine adds to my little iBatis research project. I declared a service interface 'UserManager' and it's implemented by a concret class called 'PostgreUserManager'.

                                It turned out that the iBatis API only adds a minor amount of lines of code to the implementation. So I feel that there is no need to exclude these minor lines and define a common 'DAO' interface etc. I guess using a XML mapping file to specify the DAO related logic (SQL and mapping) works like a DAO itself. Just a quite different language than Java.

                                Also I guess the Hibernate solution would require a slightly different implementation in the service object itself. So having only one service object implementing the binding for a given database directly, feels very good and straight. There isn't no replication of tests going on, like it would have been when using a DAO centered solution.

                                But I will take a closer look when adding the document repository. This repository is a domain model element and has a lot of responsibilities (managing workflow informations, document history, conversion of documents etc). I think the code metrics will demand something like a persistence strategy or a real DAO or a deligate or even a split in the inheritance hierarchy or whatever.

                                I will keep you informed about my findings and the turn overs.


                                Cheers and thanks for the code snippets,


                                Martin (Kersten)

                                PS: Boy, just scroll down this page and you know we both were quite busy writing all this... . ;-)

                                Comment

                                Working...
                                X