Re: Business Logic Beanies
The "Struts with a Fruit Glaze" example has been updated to demonstrate filling option tags from a DBMS query, and changing another query using those options, along with inserting a new record. Still alpha, but available nonetheless if anyone is interested. Of course, it still also demonstrates an approach to using business logic beans in Struts. Right now, I'm defining a base data-bean, that is used by one or more query-beans -- and also by one or more form-beans. The action commutes the data-bean from the form to the query (along with a connection from the pool). The data-bean is not linked to Struts; the query-bean is only loosely linked through the ActionForm class (which is fairly generic anyway). The queries here are using prepared statements, and linked to host variables in the data-bean(s), so narrowing the query can by done automagically by changing options on the forms (which share the data-beans with the query-beans). http://husted.com/about/struts/
Re: Business Logic Beanies
A kind soul sent me this link to a Powered-by-Struts auction application, BrewTrade by Java-Genius - http://www.java-genius.com/ that uses a neat mechanism to abstract a database result into a generic list of fields (KeyValuePairs), which can then be used to populate a data bean. The method that gathers the database results packages each value with its column name, which the data bean can then use to match it up with one of its own properties. This comes very close to turning a result into an array of standard Java Beans, using the metadata to generate the "introspective" layer. Has anyone seen a type of factory that would do this; take a resultset and spit out a list of JavaBeans, where the column names automatically become "get" accessors.
Re: Business Logic Beanies
On 1/4/2001 at 8:00 AM Michael Gerdau wrote: The current approach is to have them hardwired in a helperclass which does provide these ... What I think one should have is a generic (XML ?) file that holds all these parameters very much like a resource bundle. How about a helper bean with properties that can be specified in the struts-config.xml? Something like what Craig mentioned here: form-bean name="SearchForm" type="com.mycompany.mypackage.SearchFormBean" set-property property="resource" value="...path to resource..."/ /form-bean If Martin Cooper gets the Digester running standalone, you should be able to write a utility that could plug into another Java application and read in the same helper beans! -- Ted Husted, Husted dot Com, Fairport NY USA. -- Custom Software ~ Technical Services. -- Tel 716 425-0252; Fax 716 223-2506. -- http://www.husted.com/
Re: Business Logic Beanies
Being able to autogenerate the "logical data beans" would be excellent! And very much in keeping with the rest of the Struts framework. Ideally, this would be a mechanism that could also be used in other applications (e.g. Swing-based). So, in general terms, it seems we're coming down to this: (data bean) :: (query bean) :: (action form) :: (action object) | JSP Where the DataBean is totally unaware of Struts, and the QueryBean might be only vaguely aware, through use of the GenericConnection and GenericDataSource classes. Sounds good. In my ignorance (and still being somewhat new to struts) I wasn't aware of the aforementioned generic classes. Of course the generic outline I just posted in another mail should be adjusted to use these. I would also say that the QueryBean should be able to read its base query from a resource file, so that these can be adjusted without recompiling (and centralized for control and documentation). Agreed. Talking about this I think struts also needs some kind of application configuration file. AFAICT the resources won't suffice as I might need configuration information inside my EJB etc. as well. Or is there something already which simply escaped me ? Best, Michael
Re: Business Logic Beanies
Ted Husted wrote: Being able to autogenerate the "logical data beans" would be excellent! And very much in keeping with the rest of the Struts framework. Ideally, this would be a mechanism that could also be used in other applications (e.g. Swing-based). So, in general terms, it seems we're coming down to this: (data bean) :: (query bean) :: (action form) :: (action object) | JSP Where the DataBean is totally unaware of Struts, and the QueryBean might be only vaguely aware, through use of the GenericConnection and GenericDataSource classes. You should program in terms of the javax.sql.DataSource interface, rather than hard coding GenericDataSource. That way, you will not be tying yourself to the Struts connection pool implementation. By the same reasoning, the thing you get back from DataSource.getCoinnection() is just a java.sql.Connection -- you do *not* want to be dependent on any particular underlying implementation. I would also say that the QueryBean should be able to read its base query from a resource file, so that these can be adjusted without recompiling (and centralized for control and documentation). If you do it this way, do you need more than one QueryBean? Couldn't you create a generic one that processes different kinds of query strings based on the name of the resource you told it to read? In my own work, I subclassed the QueryBean from ActionFormBean (in case I figure out how to read it from the struts-config file). Let's say your QueryFormBean has a property named "resource", with corresponding getResource() and setResource() methods. This should be configured by doing something like this in struts-config.xml: form-bean name="SearchForm" type="com.mycompany.mypackage.SearchFormBean" set-property property="resource" value="...path to resource..."/ /form-bean but it won't work until tonight's nightly build, when I make it legal to embed set-property/ inside a form-bean :-) In the meantime, I tried to give it a standard properties file to read the base SQL strings. No problem if I hardcode a system path, but no go if I try to find it on the classpath. To wit: public void resetQuery() throws IOException { // Must call setName first! Properties props = new Properties(); String name = "d:\\QueryFormBean.properties"; /* InputStream is = null; is = this.getClass().getClassLoader().getResourceAsStream(name); if (is != null) { props.load(is); is.close(); setQuery(props.getProperty(getName())); } */ FileInputStream in = new FileInputStream(name); props.load(in); setQuery(props.getProperty(getName())); in.close(); } The commented code was taken from the Struts PropertyMessageResource, but doesn't seem to work. (Not that I understand what it's doing - I'm just banging the rocks together!) If I hardcode the path, everything is hunky-dory. If you want to use ClassLoader().getResourceAsStream(name), the name you pass should look like a Java class name, but with periods changed to slashes. In other words, if your class is in package com.mycompany.mypackage, and your resource file name is "QueryFormBean.properties", the resource name is: com/mycompany/mypackage/QueryFormBean.properties This resource will be looked up along the runtime classpath for your web app, just like classes are looked up. A hacked example of all this, that works around the properties glitch, is available as a ZIP file at http://husted.com/about/struts as "Struts with a Fruit Glaze". Comments appreciated! -- Ted Husted, Husted dot Com, Fairport NY USA. -- Custom Software ~ Technical Services. -- Tel 716 425-0252; Fax 716 223-2506. -- http://www.husted.com/ Craig
Re: Business Logic Beanies
"Craig R. McClanahan" wrote: form-bean name="SearchForm" type="com.mycompany.mypackage.SearchFormBean" set-property property="resource" value="...path to resource..."/ /form-bean Oops, this really needs to include a reference to the custom ActionFormBean subclass to use. You can do this (again, as of tonight's nightly build) in one of two ways: * Set an initialization parameter named "formBean" on the controller servlet that names the class to be used for all form-bean elements. * On each individual formBean, include a "className" attribute that identifies the ActionFormBean subclass to use for this particular entry (so you can have different ones). Craig
Re: Business Logic Beanies
On 1/3/2001 at 11:06 AM Craig R. McClanahan wrote: If you do it this way, do you need more than one QueryBean? Couldn't you create a generic one that processes different kinds of query strings based on the name of the resource you told it to read? Now that you mention, it could be used a generic bean now; I've been using the name property as the key into the resource, which is meant to store all the queries used anywhere by the application. So that part is probably working already. I was subclassing it to provide a way to hand Struts a collection (based on the ResultSet) for the tags to play with. When we upgrade the tags for rowsets, I might be able to skip this step and use the rowset where I'm generate a collection now. Today, I'm just using the subclass to do something like public FruitSalesDetail[] fetchDetail(int from, int count) throws SQLException { // TODO - Generate exception if from 1 setFrom(from); // optimistic result setCountResult(count); // calculate where Prev would have been; but don't go negative if (fromcount) {setPrev(from-count);} else {setPrev(1);} FruitSalesDetail[] detail = new FruitSalesDetail[count]; // resultSet.absolute(from); // FIXME if 1 starts at 2 ? for (int i = 1; i from; i++) { result.next(); } for (int i = 0; i count; i++) { if (result.next()) { detail[i] = new FruitSalesDetail(); detail[i].setYear(result.getInt(1)); detail[i].setQuarter(result.getInt(2)); detail[i].setApples(result.getInt(3)); detail[i].setApplesales (result.getFloat(4)); detail[i].setOranges(result.getInt(5)); detail[i].setOrangesales (result.getFloat(6)); detail[i].setTopseller(result.getString(7)); from++; } else { setCountResult(i); break; } } if (result.next()) {setNext(from);} else {setNext(1);} return(detail); } The "detail" it returns gets inserted directly into the page context page.setAttribute("fruitSalesDetail",salesQuery.fetchDetail()); where iterate can snag it with logic:iterate id="row" name="fruitSalesDetail" length="length" scope="page" The next/prev stuff lets me call the JSP again for the next block of records, or rollback with if (action.equals("prev")) { sQuery.setNext(sQuery.getPrev()); } // where sQuery is a QueryBean property of my ActionForm. The 30,000 foot view is ActionForm - ActionDataForm - FruitSalesForm // Provides JDBC and PageContext hooks ActionFormBean - QueryFormBean - FruitSalesQuery // Implements JDBC calls; Maintains query state between requests. Action - FruitSalesAction // Resets FruitSalesQuery bean to start new round of requests. FruitSalesDetail // Generic bean to encapsulate fields returned by query // Inserted as an array into page context by FruitSalesForm Of course, suggestions for an alternate model would be appreciated! The endgame is just to provide something the iterate and option tags can use. A working example is available at http://husted.com/about/struts -- Ted Husted, Husted dot Com, Fairport NY USA. -- Custom Software ~ Technical Services. -- Tel 716 425-0252; Fax 716 223-2506. -- http://www.husted.com/
Re: Business Logic Beanies
I'm finishing up on a model for executing JDBC retrievals from a JSP, using a scriptlet like % FruitSalesForm fruitSalesForm = (FruitSalesForm) session.getAttribute("fruitSalesForm"); fruitSalesForm.setPageContext(pageContext); % to execute pooled JDBC connetions, and transfer the results into page-scope collections, for use by the iterate or option tags. To get there, I Setup straight "data beans" to represent the rows of a table (or a form option). Subclassed a "QueryFormBean" from ActionFormBean to encapsulate the query string, execute the query given a GenericConnection, and to track the last relative position in the result set. Subclassed QueryFormBean to return an array of data beans from the object's ResultSet (a RowSet would be better). This array is ultimately inserted directly into the page context, for use by an iterate or option tag. Subclassed a "ActionDataForm" from ActionForm, and added methods to expose key JSP and Struts resources via the page context, and a method for obtaining a GenericConnection from the servlet. Implemented the ActionDataForm with the subclassed QueryFormBean as a property. Overrode setPageContext to execute the QueryFormBean, and insert the databean array into the page context. I'm working on adding metadata and other convenience methods now. I'll post the working example soon. Just wondering what similar solutions others might have found to handling JDBC queries within Struts.
Re: Business Logic Beanies
[scriptlets to execute JDBC inside a JSP] I'm working on adding metadata and other convenience methods now. I'll post the working example soon. Just wondering what similar solutions others might have found to handling JDBC queries within Struts. The design I us works like this: - for each logical item of data write a trivial class with all the get/set methods (the Entity class). - for each such trivial data class write a likewise trivial class that does know how to map a ResultSet to the Entity class. Some SQL-Stmt merging code is added as well to tune the query (the Retriever class). - for each logical query add a more or less trivial class that does the actual JDBC stuff (the Controller class). For all of the above there exists base classes that make writing the code very simple. The Entity class can easily be exposed to Struts and used there. Th Controller class is invoked from Action; if there is some initialization to be done for a JSP create an action that's executed before the JSP is actually displayed. AFAICT the design outlined above does facilitate a better separation between the underlying physical data model and the way this data is represented to the user than can be achieved by using scriplets. If anyone is interested I'd be willing to share the code (though I'd have to check on copyright before). Best, Michael -- Vote against SPAM - see http://www.politik-digital.de/spam/ Michael Gerdau email: [EMAIL PROTECTED] Windows loading; please take a nap... PGP-keys available on request or at public keyserver
Re: Business Logic Beanies
Michael Gerdau wrote: [scriptlets to execute JDBC inside a JSP] I'm working on adding metadata and other convenience methods now. I'll post the working example soon. Just wondering what similar solutions others might have found to handling JDBC queries within Struts. The design I us works like this: - for each logical item of data write a trivial class with all the get/set methods (the Entity class). If we have any XSLT gurus in our midst, this sounds like it is something that could be auto-generated from an XML-based description of the "logical item", no? - for each such trivial data class write a likewise trivial class that does know how to map a ResultSet to the Entity class. Some SQL-Stmt merging code is added as well to tune the query (the Retriever class). As above, could such a "trivial" class be auto-generated? - for each logical query add a more or less trivial class that does the actual JDBC stuff (the Controller class). The EJB analogue for this would be to add a finder method that implemented the logical query. For all of the above there exists base classes that make writing the code very simple. The Entity class can easily be exposed to Struts and used there. Th Controller class is invoked from Action; if there is some initialization to be done for a JSP create an action that's executed before the JSP is actually displayed. AFAICT the design outlined above does facilitate a better separation between the underlying physical data model and the way this data is represented to the user than can be achieved by using scriplets. If anyone is interested I'd be willing to share the code (though I'd have to check on copyright before). I'd like to see design patterns like this available to the Struts community -- *especially* if we can create some tools that reduce the tedium of creating "trivial" classes. Best, Michael Craig McClanahan