Richard,

Maybe you could explain the difference between an "array of structures" as you call it 
and a
"graph of business objects". I often return arrays of more complex object graphics 
where the
reporting requirements are more complex then the simple example of employee salaries.

If java didn't support introspection, then you might be able to argue that the 
ResultSet
approach is superior. However, we have a simple reflection library that handles the 
interface
between the client developer's code and the data structures. Our objects are far from 
fragile.

In fact we have considered using XML hierarchies instead of serialized objects, but 
haven't
made the transition because object methods provide us great flexibility in defining 
properties

for the client developers.

For most entities, the object graph is fairly constant. What changes from use case to 
use case

is how much of that graph is actually returned. The structure doesn't change and hence 
isn't
any more fragile than a ResultSet which is missing the required data for a give use.

--Victor Langelo


Richard Monson-Haefel wrote:

> Hi Victor,
>
> Thanks for the e-mail.  There is a big difference between sending an array of 
>structures
> and a graph of business objects.  What you advocate is an array of structures that
> represent a subset of the entities data.  I'm not against that as long as the subset 
>is no
> more then is needed. In fact, I have advocated this approach in my book and on my 
>web site
> (http://www.ejbnow.com/ejbtips/ejbtip_4.html).
>
> However, the ResultSet approach IMO is still superior since you can add and remove 
>data as
> requirements change without impacting the developer's interlace to the data.  With an
> array of structures you are dealing with a fairly fragile structure that must change 
>as
> the data requested changes. In addition, the use of structures does not provide for 
>as
> much reuse as a ResultSet interface.
>
> Thanks,
>
> Richard
>
> Victor Langelo wrote:
>
> > Richard,
> >
> > I think you've take William's argument to the extreme. While you may not have seen 
>an
> > approach where object graphs are used work, I have. In the case where all 
>employee's
> > salaries are really what's needed (and I'm referring to IBM or Sun here) then a
> > specialized bean the returns just employee name and salary is appropriate. I'd 
>have to
> >
> > argue that this is a rather extreme example. Getting the salaries for a department 
>of
> > 20-50 people is more likely. In this case we could still use strategy 1. However 
>there
> >
> > are some optimizations needed.
> >
> > For instance, the Employee bean should use lazy instantiation of referenced
> > collections. Since you're only interested in the salary and name, the Employee bean
> > should have a method the gets only basic employee information. This method wouldn't
> > need to query for children, addresses and possibly job titles.
> >
> > As we all know as soon as you show a real user a list of employees salaries, 
>they're
> > going to ask you for other related data like insurance, whether they are married,
> > etc...
> >
> > We provided methods in our entity beans that allow the user to select only the 
>subset
> > of the object graph of interest to the given use case. Sure, more data is returned
> > than your strategy 2, but the increased reuse is more than offset the small extra
> > network bandwidth.
> >
> > --Victor Langelo
> >
> > Richard Monson-Haefel wrote:
> >
> > > Hi William,
> > >
> > > Having worked extensively on both ends of the front (GUI and ServerSide) I have
> > > to follow practical lessons I have learned and respectively reject your approach
> > > to the problem.
> > >
> > > What follows is an embarrassingly long e-mail that I found myself compelled to
> > > write.  I don't suspect that I'll change your mind, William, because you seem
> > > rather stubborn about it.  So I have written this for the hundreds of other EJB
> > > developers that subscribe to this e-mail list. I beseech you to read this
> > > thoroughly before deciding to adopt William's ideas.  William's hart is in the
> > > right place, but his way simply doesn't work.  I've seen his design implemented
> > > many times in the past by some pretty smart people, but I have never seen it
> > > succeed.  I have seen my own strategy succeed in various forms in some pretty
> > > big projects, and so I know it works.  You will have to decide for yourself.
> > >
> > > I probably will not follow up with this discussion because I feel that I have
> > > been as concise and detailed as possible.  In addition, it simply is too time
> > > consuming to continue on this thread.  But I'll be listening and if anything
> > > compelling is said I promise to respond.
> > >
> > > -------------
> > >
> > > Its more appropriate to provide data to the client that is as close to its final
> > > user's representation as possible.  Requiring the client to navigate the
> > > relationships of a complex object graph (as you propose) requires a few
> > > assumptions about the client: A) Its a fat client that can afford memory and
> > > processing cycles to deal with the navigation of complex object graphs.  B) A
> > > great deal of the business logic is to be housed in the client.  These are the
> > > assumptions that prospered under the two-tier architectures of the late 80's and
> > > early 90's.  Since that time, however, we have been introduced to World Wide Web
> > > and discovered that a client applications can have many forms including GUI
> > > clients, HTML (via Servlets), hand-held devices, etc.   My experience has been
> > > that an application that services a large community will eventually require at
> > > least two different kinds of client (frequently GUI and HTML).  Only the fat
> > > client application can afford the resources to house the business logic.
> > > Placing the business logic in the client, means you have to duplicate that logic
> > > in other clients.  These are the primary motivates for a three tier architecture
> > > and thin clients.
> > >
> > > If I want to provide my client(s) with a list of all the employees and their
> > > salaries I could go about this in two ways:  1) I could provide my clients with
> > > a graph of employee objects (William's solution).  OR (2) I could provide them
> > > with a serializable ResultSet (my solution).
> > > *******************************
> > > Strategy 1 (William's strategy):
> > >
> > > The EmployeeDetail Object might be defined as follows:
> > >
> > > public class EmployeeDetail {
> > >     private int id;
> > >     private String lname;
> > >     private String fname;
> > >     private Address [] addresses;
> > >     private DepartmentDetail department;
> > >     private EmployeeDetail manager;
> > >     private [] JobTitle;
> > >     private double salary;
> > >     private HealthInsurance hInsruance;
> > >     private LifeInsurance lInsurance;
> > >     private Person spouse;
> > >     private Person [] children;
> > > }
> > >
> > > In order to obtain this information I might use a session object as follows:
> > >
> > > public class PayRollBean implements javax.ejb.SessionBean [
> > >
> > >     public Enumeration getEmployeeSalaries( ){
> > >         Vector vect = new Vector( );
> > >         InitialContext cntx = new InitialContext( );
> > >         Object ref = cntx.lookup("java:comp/env/ejb/employee");
> > >         EmployeeHome empH = (EmployeeHome)PortableRemoteObject.narrow(ref,
> > > EmployeeHome.class);
> > >         Enumeration enum = empH.findAllEmployees( );
> > >         while( enum.hasMoreElements( )){
> > >             Employee emp =
> > > (Employee)PortableRemoteObject.narrow(enum.nextElement(),Employee.class);
> > >             EmployeeDetail detail = emp.getDetialObject();
> > >             vect.add(detail);
> > >         }
> > >         return vect.elements();
> > >     }
> > >     ...
> > > }
> > >
> > > The EmployeeDetail object would be constructed by each EmployeeBean as follows:
> > >
> > > public class EmployeeBean implements javax.ejb.EntityBean {
> > >
> > >     public int id;
> > >     public String lname;
> > >     public String fname;
> > >     public Address [] addresses;
> > >     public DepartmentDetail department;
> > >     public EmployeeDetail manager;
> > >     public [] JobTitle titles;
> > >     public double salary;
> > >     public HealthInsurance hInsruance;
> > >     public LifeInsurance lInsurance;
> > >     public Person spouse;
> > >     public Person [] children;
> > >
> > >     public EmployeeDetail getDetailObject( ){
> > >         EmployeeDetail detail = new EmployeeDetail( );
> > >         detail.id = id;
> > >         detail.lnam = lname;
> > >         detail.fname = fname;
> > >         detail.address = address;
> > >         detail.department = department;
> > >         detail.manager = manager;
> > >         detail.titles = titles;
> > >         detail.salary = salary;
> > >         detail.hInsurance = hInsurance;
> > >         detail.lInsurance = lInsuracne;
> > >         detail.spouse = spouse;
> > >         detail.children = children;
> > >         return detail;
> > >     }
> > >     ..
> > > }
> > >
> > > The client application would use all this as follows:
> > >
> > > public class MyClient {
> > >
> > >     public static void main(String [] args){
> > >
> > >         InitialContext cntx = new InitialContext();
> > >         PayRollHome home =
> > > 
>(PayRollHome)PortableRemoteObject.narrow(cntx.lookup("java:comp/env/ejb/payroll"),
> > > PayRollHome.class);
> > >         PayRoll payRoll = home.create( );
> > >         Enumeration enum = payRoll.getEmployeeSalaries( );
> > >         while(enum.hasMoreElements()){
> > >             EmployeeDetail detail = (EmployeeDetail)enum.nextElement();
> > >             System.out.println(detail.lname+", "+detail.fname+"
> > > "+detail.salary);
> > >         }
> > >     }
> > > }
> > >
> > > Looks pretty good, doesn't it? but its anything but efficient.
> > >
> > > First, in order to get the data we have to use an ejbFinder method to get a
> > > remote reference to an entity bean for every employee in the enterprise.  This
> > > alone would cause so much latency as to be prohibitive, but that's William's
> > > strategy since he has advocated keeping everything in an object like
> > > representation.  Anyway, after we finish loading every single employee record in
> > > the data base into hundreds (possibly hundreds of thousands) of Employee beans
> > > we then proceed to create thousands of EmployeeDetial beans to send back to the
> > > client.  Once the client gets the EmployeeDetail objects from the PayRoll bean,
> > > it will extract the data it needs and produce the output (in this case a
> > > System.out but it could be a GUI table if you like).
> > >
> > > Notice that only a portion of the data in the EmpolyeeDetail bean is needed?
> > > Yet we create and serialize the entire graph including complex relationships
> > > with the employee's manager, insurance benefit information, address, etc.
> > >
> > > This is an example of the worst EJB design possible, yet people persist in
> > > taking this rout to preserve the "OO" design of the system. Hogwash!  All you
> > > have done is created a system that will not run fast enough to service your
> > > client population and will require an enormous amount of resources (many
> > > clustered servers, huge platforms, lot and lots of memory).
> > >
> > > **********************************
> > > Strategy 2: Here is my strategy to the problem:
> > >
> > > public class PayRollBean implements javax.ejb.SessionBean [
> > >
> > >     public EJBResultSet getEmployeeSalaries( ){
> > >
> > >         DataSource dataSource =
> > > (DataSource)cntx.lookup("java:comp/env/jdbc/db");
> > >         Connection con = dataSource.getConnection( );
> > >         Statement stmt = con.createStatement( );
> > >         ResultSet set = stmt.executeQuery("select LNAME, FNAME, SALARY from
> > > EMPLOYEE");
> > >
> > >         CustomResultSet customSet = new CustomResultSet(set);
> > >         return (EJBResultSet)customSet;
> > >
> > >     }
> > >     ...
> > > }
> > >
> > > The EJBResultSet return type for the method is an interface that can have many
> > > different implementation.  One implementation might be a wrapper to a
> > > CachedRowSet, while another might be a custom ResultSet that is a lightweight
> > > serializable object containing only the data needed.  I have personally created
> > > the custom implementation which is used today in production in a very large
> > > CORBA banking system.
> > >
> > > The implementation for CachedRowSet would make sense when using a JDBC 2.0
> > > driver that supported that type.  The nice part about EJBResultSet is that all
> > > implementations use the EJBResultSet interface so the client is unaware of the
> > > different implementations. (Encapsulation & Polymorphism).  The result set is
> > > read only because we don't want the client attempting to update the database
> > > directly.  The EJBResultSet should contain cached data and be immutable. (This
> > > can be done with a CachedRowSet also be setting the properties to be read-only.)
> > >
> > > Below is a partial definition of the EJBResultSet (limited for brevity).
> > >
> > > public interface EJBResultSet extends Serializable {
> > >
> > >     public boolean next( ) throws QueryException;
> > >     public Properties getMetaData( ) throws QueryException;
> > >     public int getRowCount() throws QueryException;
> > >     public boolean getBoolean(int columnIndex) throws QueryException;
> > >     public boolean getBoolean(String columnName) throws QueryException;
> > >     public byte getByte(int columnIndex) throws QueryException;
> > >     public byte getByte(String columnName) throws QueryException;
> > >     public java.util.Date getDate(int columnIndex) throws QueryException;
> > >     public java.util.Date getDate(String columnName) throws QueryException;
> > >     public double getDouble(int columnIndex) throws QueryException;
> > >     public double getDouble(String columnName) throws QueryException;
> > >     public float getFloat(int columnIndex) throws QueryException;
> > >     public float getFloat(String columnName) throws QueryException;
> > >     public int getInt(int columnIndex) throws QueryException;
> > >     public int getInt(String columnName) throws QueryException;
> > >     public long getLong(int columnIndex) throws QueryException;
> > >     public long getLong(String columnName) throws QueryException;
> > >     public Number getNumber(int columnIndex) throws QueryException;
> > >     public Number getNumber(String columnName) throws QueryException;
> > >     public Object getObject(int columnIndex) throws QueryException;
> > >     public Object getObject(String columnName) throws QueryException;
> > >     public short getShort(int columnIndex) throws QueryException;
> > >     public short getShort(String columnName) throws QueryException;
> > >     public String getString(int columnIndex) throws QueryException;
> > >     public String getString(String columnName) throws QueryException;
> > > }
> > >
> > > [Note: An alternative is to use the RowSet interface which is certainly more
> > > standard then EJBResultSet or possibly the java.sql.ResultSet interface itself.
> > > I use the EJBResultSet to limit my API to the read only methods and simply the
> > > API for the developer]
> > >
> > > The client application would use the EJBResultSet just like a JDBC ResultSet.
> > > The advantage to using this design is that the underling data can change (e.g.
> > > add the person's department) but the client code stays the same.  This means
> > > that a change in my requirements has very little impact on my client or server.
> > > The EJBResultSet is lightweight with out the business object baggage which is
> > > not necessary for listing behavior.  As a result it can be easily used in a
> > > variety of client types form heavy GUI to Servlets, to smaller devices.
> > >
> > > In addition, the EJBResultSet is standard across all quires and provides
> > > meta-data so that it can be used by tools and builders without developer
> > > intervention.  This is not possible with the object graph approach that William
> > > proposes because the type of objects and their graphs change for each kind of
> > > query. In the case of the EJBResultSet it can be used to peruse Employee
> > > salaries as easily as it can be used to peruse Hotel Reservation data.  The
> > > programming interface is familiar to developers (pretty much the same as
> > > java.sql.ResultSet) and its an API that used consistently across all listing
> > > operations.  Developer's learn how to use it once.  The interface never changes,
> > > just the data.
> > >
> > > Below is an example of how the EJBResultSet interface is used:
> > >
> > > public class MyClient {
> > >
> > >     public static void main(String [] args){
> > >
> > >         InitialContext cntx = new InitialContext();
> > >         PayRollHome home =
> > > 
>(PayRollHome)PortableRemoteObject.narrow(cntx.lookup("java:comp/env/ejb/payroll"),
> > > PayRollHome.class);
> > >         PayRoll payRoll = home.create( );
> > >         EJBResultSet set = payRoll.getEmployeeSalaries( );
> > >         while(set.next()){
> > >             System.out.println(set.getString("lname")+",
> > > "+set.getString("fname")+" "+set.getDouble("salary"));
> > >         }
> > >     }
> > > }
> > >
> > > The EJBResultSet solution I use grew out of my CORBA experience before the days
> > > of EJB. Admittedly, we didn't have serialization back then but we managed to
> > > fake it.  Anyway its a proven technique that works and was popular with server
> > > side and gui developers because its simple, consistent, and lightweight.
> > >
> > > This strategy has also been independently recognized by the folks at Sun
> > > Microsystems.  In fact that need for this type of functionality was the
> > > motivation behind the CachedRowSet and RowSet types introduced in JDBC 2.0.
> > >
> > > *******************
> > >
> > > This discussion has focused on listing behavior and is specific to only that
> > > topic.  The fact that I use JDBC directly is not a condemnation of entity beans.
> > > I'm a big advocate of Entity beans because they are extremely vital part of the
> > > EJB model. They are used extensively when updating entities and leveraging their
> > > behavior to accomplish tasks.
> > >
> > > Listing behavior is only a subset of the scenarios we have to deal with when
> > > designing EJB solutions, but its one area where we can can model the data as its
> > > used, in Tabular format. In my case I like the EJBResultSet design but I have
> > > also used multidimensional String arrays and arrays of structures.  See this EJB
> > > design Tip for mote detail (http://www.ejbnow.com/ejbtips/ejbtip_4.html).
> > >
> > > Thanks,
> > >
> > > Richard
> > > --
> > > Richard Monson-Haefel
> > > Author of Enterprise JavaBeans, 2nd Edition
> > > Published by O'Reilly & Associates
> > > http://www.EjbNow.com
> > >
> >
> > ===========================================================================
> > To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
> > of the message "signoff EJB-INTEREST".  For general help, send email to
> > [EMAIL PROTECTED] and include in the body of the message "help".
>
> --
> Richard Monson-Haefel
> Author of Enterprise JavaBeans, 2nd Edition
> Published by O'Reilly & Associates
> http://www.EjbNow.com
>
> ===========================================================================
> To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
> of the message "signoff EJB-INTEREST".  For general help, send email to
> [EMAIL PROTECTED] and include in the body of the message "help".

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff EJB-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to