Archived

This forum has been archived. Please start a new discussion on GitHub.

Ice and Object Persistence

Hi, I'm really new to ICE and have some problems understanding some things.

Anyway, here's the scenario:

I have a little application which stores books and authors in an object oriented database. Now, I already have the model, and the beans (Author.java and Book.java) This works well from a pure java approach. Nonetheless I want to be able to use these objects with a c++ program too. Here's where ICE comes into the game.

Now, Author and Book don't really have anything special to them. Their attributes are strings and booleans. All of them can be correctly mapped to c++. So my questions are:

- What's the best approach on this case?
- Should I generate interfaces or classes or tie classes or what?
- The database exists, so I can't create new Objects, I must use the ones I already have... Is that possible?
- How would my ICE file would look like?
- How can I use a hypothetical AuthorPrx to manage the existing Author?
- Is this possible?

Thanks :)

Comments

  • matthew
    matthew NL, Canada
    What you are asking is entirely possible, yes :) However, your questions seem to be a bit random in that they are mixing implementation questions (do I use tie classes?) with design questions (what should the slice look like?).

    Without knowing exactly what things you don't understand, its very hard to provide advice. What you should do is first model your database in Slice, and then next provide an implementation of that. If you get stuck with a specific question, please ask here!
  • I'll try to be more specific tomorrow...

    But part of the problem is that the database is already in use, there's already a model and I have to adapt slice to it.

    Right now I'm a little bit stuck as of how should I interact with the database. See, normally I would have something like:
    public class Author
    
    public String getName()...
    public void setName()...
    public List<Book> getBooks()...
    public void setBooks(List<Books> books)...
    
    ...
    

    Where "Book" is also an object, obviously. Now, if I wanted to implement database-related methods, such as:
    ...
    
    public void save()...
    public void delete()...
    public List<Author> get(Author author)...
    

    I wouldn't know how to do it... I'm talking about the get() part. If I understand well, I can't define something like that in slice:
    sequence<Author> AuthorSeq;
    class Author {
    ...
    idempotent AuthorSeq get(Author* a);
    }
    

    So that's one of my problems. I figured that I can have a separate interface to do that. Some "finder" interface, which would implement queries for all of the persistent objects.

    Then another question arises... How should I implement the queries?

    - idempotent AuthorSeq getAuthor(Author* a);
    - idempotent void getAuthor(Author* a, out AuthorSeq);
    - sequence<Author*> AuthorSeq;
    idempotent AuthorSeq getAuthor(Author* a);
    - sequence<Author*> AuthorSeq;
    idempotent void getAuthor(Author* a, out AuthorSeq);

    There's where I begin getting lost! How do I get my list of Authors?

    Note.- All my "sequences<Type>" are mapped to java.util.list<E>... I just didn't write that on the code to make it a little bit smaller. :)
  • matthew
    matthew NL, Canada
    It looks to me like you are quite confused about the difference between pass by proxy, and pass by value. I would recommend reading my article "Proxies" in http://www.zeroc.com/newsletter/issue23.pdf. You might also want to look in more detail about the Ice object model in the Ice manual.
    public void save()...
    public void delete()...
    public List<Author> get(Author author)...
    

    What does get do? At any rate, you would probably have a query interface. Perhaps something like:
    interface Book
    {
    };
    sequence<Book*> BookPrxSeq;
    
    interface Library
    {
       sequence<BookPrxSeq> getBookByAuthor(string author);
    };
    

    You might want to look at the Oracle demos in the C++ distribution for more ideas on how to access and abstract a database using Ice.
  • Read your article :) It did help me, now I know that there's no problem at all --and in fact makes a lot more sense-- to return proxies on my queries. So, in my "finder" interface, I can define something like:
    interface Finder {
     idempotent AuthorPrxSeq getAuthors(Author* a);
    }
    

    Where AuthorPrxSeq is defined as:
    sequence<Author*> AuthorPrxSeq;
    

    And Author as:
    class Author {
     idempotent String getName();
     idempotent String getLastName();
     idempotent BookPrxSeq getBooks();
     idempotent void setName(String name);
     idempotent void setLastName(String lastName);
     idempotent void setBooks(BookPrxSeq books);
    }
    

    ** BookPrxSeq is:
    sequence<Book*> BookPrxSeq;
    

    Now what I haven't figured out is how do I get my Author servant (AuthorI) to deliver an AuthorPrxSeq (or, in java, as I defined it: List<AuthorPrx>.) Should I create a new AuthorPrx on the server side, and return that to the client? Because, there's got to be a way of filling up that List<AuthorPrx> with Author Proxies... And the same goes for the BookPrxSeq embedded in each AuthorPrx
  • YaY! It works!

    I don't know if it's the best way to do it though... So, anyway, in my servant code I created a new Author ice-object:
    Author author = new AuthorI();
    

    Yesterday I was stuck right there, because I was giving that to the client, which, obviously, couldn't really use. Because it's not a prx, and it doesn't point anywhere! and, well... anyway, I let that part as is and then:
    AuthorPrx prx = AuthorPrxHelper.checkedCast(adapter.addWithUUID(author));
    

    Then that's what I give my client and it works! :D YAY!

    Thanks for all your help! I'll keep in touch :) (Surely I'll have more and more questions)
  • matthew
    matthew NL, Canada
    Glad to hear you are getting along with your project!

    What you should probably do is use a servant id that is representative of the database object (for example, use the database id), and then use a default servant. This allows you do use a single servant instance for all database objects of a given type.

    I would also encourage you to design your interfaces in such a way as to not require multiple invocations to get your object data. This is a very good way to get bad performance. For example, in your above interface you have:
    class Author {
     idempotent String getName();
     idempotent String getLastName();
     idempotent BookPrxSeq getBooks();
     idempotent void setName(String name);
     idempotent void setLastName(String lastName);
     idempotent void setBooks(BookPrxSeq books);
    }
    

    It would be better to do:
    struct AuthorDesc {
      string name;
      string lastName;
      BookPrxSeq books
    };
    class Author {
      AuthorDesc describe();
      idempotent void setName(String name);
      idempotent void setLastName(String lastName);
      idempotent void setBooks(BookPrxSeq books);
    };