| Sessions |
| Sessions provide a user access class for finding and counting beans. As well as saving and removing beans and their dependent beans
|
|
BeanSession (com.javelin.beans.BeanSession) The BeanSession interface represents the machinery in the applications, where the Beans are the commodities passed about by the machinery. The BeanSession has a couple of methods to allow the Session to be aware of its context, The key represents the current key (User) on the system, this set on the Session before the session is got from the ClassContext. This key could be a Thread or User name and can be used by the Session to retrieve objects bound in its own context. public Object getKey(); The ClassContext represents the current ClassContex for the Session. Public ClassContext getClassContext(); |
|
AbstractBeanSession (com.javelin.beans.AbstractBeanSession) The AbstractBeanSession is a helper class that specific BeanSessions extend. The AbstractBeanSession has the following functionality: -
|
|
SessionInterfaceWriter (com.javelin.generator.beans.SessionInterfaceWriter) The SessionInterfaceWriter is responsible for writing out the BeanSession interfaces for every table. |
|
Instantiating Sessions BeanSessions are instantiated by the ClassContext. This is done to hide the implementation of the BeanSessions. BeanSessions are instantiated using the following syntax: - <ClassName>Session session = <ContextName>Context.getDefault().new<ClassName>Session(); <ClassName>Session session = <ContextName>Context.getDefault().get<ClassName>Session(); <ClassName>Session session = <ContextName>Context.getDefault()Get<ClassName>Session(Object key); To get a new AccountSession from the NorthwindContext, all you have to do is call : - AccountSession accountSession = NorthwindContext.getDefault().newAccountSession(); |
|
Finding Beans Finding Beans on a Session is at the center of a lot of rich application code. However it is often very expensive, in terms of writing code, to write lots of custom findBys. JGenerator provides lots of very powerful means of generating findBys Every BeanSession has a number of findBy methods created on it by default. The default findBy methods are: -
All findBy methods follow the EJB naming standard. FindBys either return a Bean, an Iterator or an Enumeration. The findBys by default return Iterators. It is possible to change the system wide setting so that Enumerations or Arrays are returned. To do this set: - indexType=Iterator In addition a findBy method is written out for every Index (see the Indexes section). Indexes provide a way of defining how you want to search for your data, so Indexes and findBys are very closely linked. Creating an Index does not mean that an Index is created on the database, as there is a concept of a pseudo index. For unique indexes the findBy methods return a single Bean for non-unique indexes the findBy methods returns either Iterators or Enumerations. This default to create a findBy for an Index can be switched off for any specific index using the following syntax: - <ClassName>.<IndexName>.find=false Alternatively the default to create findBys for Indexes for a whole table can be switched off using the following syntax:- <ClassName>Find=false Alternatively the default to create findBys for a Indexes for a whole database can be switched off using the following syntax:- find=true |
|
FindBy PrimaryKey The findByPrimaryKey is always created, where a primary key exists, and returns a single bean : - public <ClassName> findByPrimaryKey( Object <className>Key ) throws FinderException, ValidationException; |
|
FindBy All By default the findByAll is created. The findByAll return all the Beans, or up to a maximum row count. Public Iterator findByAll() throws FinderException, ValidationException; |
|
FindBy Query The findByQuery return all the Beans for a query, or up to a maximum row count. Public Iterator findByQuery( String query ) throws FinderException,
ValidationException; For SQL based queries, the findByQuery methods accept the query part of a piece of SQL following the table declaration for the Bean. The table declaration is given an alias which is the same name as the table so that it can be referenced. This means that another table declaration can be made, or the developer can start with the WHERE clause. The SELECT part of the query is pre-made For example, to find the first 1000 cars with a registration starting with the letter R: - carSession.findByQuery( "WHERE SUBSTRING( Car.registration, 0 ) == 'R'", 1000); Alternatively get all the cars with an engine capacity greater than 2000: - carSession.findByQuery( ", Engine Engine WHERE Car.engineKey=Engine.engineKey and Engine.engineCapacity >= 2000" ); Custom find by Queries can be created, that return Iterators, using the following syntax: - <ClassName>.findMethod.<index>=findBy<Name>(<arguments>) The example below creates a findByIndividual method on the ModelSession, the particular Jdbc or EJB Bean managed rendering uses the SQL to implement the query. Model.findMethod.0=findByIndividual(Object individualPK) This will create a findBy with the method described: - ModelSession.findByIndividual(Object individualPK) throws FinderException, ValidationException FindByQuery methods do not work for container managed EJB, as the servers wrap the SQL in single quote marks. |
|
FindBy ForeignKey By default indexes are not created for foreignKeys or primaryKeys on a table. However this feature can be switched on either across the whole database, on an individual table, for the all keys, all foreignKeys or just the primaryKey. See the section on Indexes for more information. By switching on the automatic creating of indexes for foreignKeys this triggers the automatic creation of findBys for foreignKeys. Indexes can be automatically created for all keys, primary keys or foreign keys for all tables by setting one of the following: - index=key Indexes can be automatically created for keys for specific tables by setting one of the following <ClassName>Index=key Creating a primaryKey Index or a foreignKey using this method does not create an Index on the database, as they are pseudo defined as indexes. Real Indexes can be created one at time for particular keys, and this gives control on whether the index is a real index or a pseudo index. See the section on Indexes for more information. For example a Wheel table may have a non-unique index on its car foreignKey column, this will create the following findBy method: - public Enumeration findByCar( Object carKey ) throws FinderException, ValidationException; Another example is an Engine table may have a unique index on its car foreignKey column, this will create the following findBy method: - public Engine findByCar( Object carKey ) throws FinderException, ValidationException; |
|
Custom FindBy Index JGenerator allows custom findBys to be created by creating custom Indexes. See the section on creating Custom Indexes for more details. For example the code below creates 2 indexes, with the following findByMethods. JGenerator knows the types of the columns. The SQL index that is created is the <IndexName>, however by default the find by method names are synthetically generated. UserProfile.index.0=Age(age) UserProfileSession.findByAge( int age ) throws FinderException,
ValidationException Synthetic findBy names can be overridden (except for the primary key) using the syntax: - <ClassName>.<IndexName>.longName=<name> For example: - MyTable.XYIdex(x,y) Will create the following: - MyTable.findBySillyName() throws FinderException, ValidationException |
|
FindBy Expressions More complex findBy can be also created, that have conditional expressions. By default default to the parameter in the findBy is == (equal). This means that a findBy does a straight forward match. The column name, in the index speciifcation (above) can also have the syntax: - propertyName[operator[expression]] Where an operator can be one of =,==,>,<,>=,<=,!= For example, this will create a findBy that uses the > operator: - UserProfile.index.0=AgeIdx(age>) UserProfilesession.findByGreaterAge(int age) It is also possible to define the expression used in the query. The following examples, will create a find bys that uses the >= , >, < and <= operators. The find by methods generated will not pass any parameters, as a constant value is used. The find by names are synthetically created, (and may need longname defined): - UserProfile.pseudoindex.0=OldAge(age>=60) Will create the following findBys: - UserProfile.findByAgeGEqualOldAge() throws FinderException,
ValidationException Where column are Strings it is more than often desirable to create partial matching using LIKE. LIKE Indexes are automatically created for indexes containing Strings when the findByLike property is set to true, at the index, table or database level. For example the following index property: - UserProfile.index=lastName(surname) will create the following findBys: - UserProfile.findByLastName(String surname) throws FinderException, ValidationException UserProfile.findByLikeLastName(String surname) throws FinderException, ValidationException if one of the following are set : UserProfile.lastName.findByLike=true UserProfile.findByLike=true findByLike=true
|
|
FindBy Sort Order Often the a defined (a fixed) sort order for a query may be needed. Columns for a index can be sorted using the syntax <ClassName>.<IndexName>.sortOrder=<propertyName>[DESC][, ...] For example: - Invoice.X10.sortOrder=dateSent DESC, clientName |
|
FindBy maxRows The maximum row count that can returned can be limited using the syntax <ClassName>.<indexName>.maxRows=<rows> For example: - Invoice.X10.maxRows=100
Alternatively the maximum number of rows can be set dynamically. This will add an argument to the findBy method allowing the maximum number fo rows to be passed. If the maxRows is 0 then an unlimited number of rows will be passed. This can be set using the following syntax: <ClassName>.<indexName>.maxRowsMethod=true|false For example Invoice.X10.maxRowsMethod=true |
|
maxRowsAllowed The maximum rows that can be created <ClassName>.maxRowsAllowed=<rows> For example: - Invoice.X10.maxRowsAllowed=2 This can be used to extend the maxRows so that they are limited to say a foreignKey. <ClassName>.maxRowsAllowedQuery=Java String for Count By Query For example to limit the number of addresses in a Line.<ClassName>.maxRowsAllowedQuery="Address.addressKey="+address.getAddressKey()
|
|
Singleton Beans Singleton Beans are Beans that have only one instance. This means that all the findBy's method signature will all return the Bean, and not a collection. Similar to saying maxRowsAllowed=1, but limits creation to 1. To specify singletons, use the following pattern: <ClassName>.singleton=true |
|
AutoCreate AutoCreate - is where there is one row automatically created, in the constructor for the Session. The defaults for the Bean that is created can be set using the default property. To specify autoCreate, use the following pattern: <ClassName>.autoCreate=true This can be used to automatically create Beans where they don't exist <ClassName>.autoCreateQuery=Java String findByQuery For example to create a new single row for each User.<ClassName>.autoCreateQuery="User.userId=\"UserUtil.getUser()\"" |
|
Counting Beans Applications often want to count the number of beans without having to return all the Beans and count them one by one. CountBys have same syntax as findBys except they return an int. For example: - public int countBySurname( String surname ) Counting beans is switched of by default. For every findBy there is an (optional) countBy method. One difference is that countBy methods, with an optional maxRows are not generated. The generation of these methods can be switched on using the following syntax:- <ClassName>.<IndexName>.count=true Alternatively to switch countBys on for a specific table use the following syntax:- <ClassName>Count=true Alternatively to switch countBys on for every table use the following syntax:- count=true In addition there is a countByQuery generated for every session and home that appends the findByQuery SQL to a SELECT COUNT(*) clause, instead of a SELECT * clause. |
|
Loading Beans Sessions expose the load method to allow a bean, and all it's dependent beans to be reloaded from the database. To load a single bean use the Home's load method. If the beans primary key is set then it is reloaded, otherwise an exception is thrown. The load method has the following pattern: - public void load( <Bean> <bean> ) throws LoadException, ValidationException For example: - public void load( Car car ) throws LoadException, ValidationException |
|
Saving Beans Unlike EJB the JBeans standard has a save method to save a bean, and all it's dependent beans. This method can be used to both create and store beans. The method must decide whether to call the create or store method on the underlying home class, based on the bean persisted property. This design is more Object-Oriented than the EJB pattern where bags of variable are marshaled around until creation time. The save method has the following patterns: - public void save( <Bean> <bean> ) throws CreateException, StoreException, ValidationException public void save( List beans ) throws CreateException, StoreException, ValidationException This example show how to save (create) a Car, with a mandatory engine: - CarSession carSession = AutoContext.getDefault().getCarSessionb=(); |
|
UndoOn Rollback By default all the changes made to beans during a transaction are rolled
back when that transaction fails. sessionUndoOnRollback=false For example: <className>.sessionUndoOnRollback=false
|
|
Removing Beans Sessions expose the remove method to allow a bean, and all it's dependent beans to be removed from the database. The Bean does not have a remove method. To remove a single bean use the Home remove method. The remove method has the following pattern: - public void remove( <Bean> <bean> ) throws RemoveException, ValidationException For example: - public void remove( Car car ) throws RemoveException, ValidationException |
|
Intercepting Sessions Sessions call a number of methods during transactions that can be overriden to give access to beans before and after the transactions. public void preLoad( List beans ) public void preSave( List beans ) public void detach( List beans ) throws ValidationException public void preRemove( List beans ) These methods can be overridden as follows: <Table>Session.method.0=public void postSave( Bean
bean, Exception e ) |
|
Standalone Sessions By default Sessions are created by specifying the $CREATE $CREATOR to create Entity Bean based Sessions. A Session can also be created that is not related to a bean, and only uses the Memory Session, this means that it has no find, create, store or remove methods; only custom methods, and no persistence. This is known as a standalone session. The example below creates a standalone session with 2 methods: - MyCalculationSession.method.0=public int add( int x, int
y ) MyCalculationSession.method.1=public String getDateTime() MyCalculation=$CREATE $STANDALONECREATOR |
|
Casading Transaction Dependent objects are also inserted, updated or deleted when a root bean is saved or deleted. In addtion any beans removed off lists are removed when the the root bean in the dependent tree is saved. JBeans keeps track of these beans. In addtion any associates that point to removed beans have their keys updated to null.
|
|
Transacting Lists It is possible to load or store a number of beans in lists and save or delete them in one go. Here is an example of loading beans List beans = new ArrayList(); bean1.listRelations( beans, Bean.DEPENDENTS );
|
|
Unit Of Work JGen Supports Units of Work. This means you can save or delete a number of beans anywhere on the stack all under the same transaction. You can only have one transaction open at a time in the same thread, and you must run the UserTransaction from the same thread. Each of the methods called from within the doUserTransaction() (e.g. doUpdateAnotherThing() ) get the Context, and save(bean) and delete(bean) just like normal, but they don't commit the transaction to the database until the commit() method is called in the finally clause. This is done using reference counting inside the WorkUserTransaction. import javax.transaction.UserTransaction public void doUserTransaction() throws Exception try doDeleteABean(); |
|
Example Session Here is an example of a (simple) Session Interfaces for Addresses to give a big picture of what is generated. /* package com.javelin.jcommerce; import java.util.*; /** public interface AddressSession extends BeanSession
/** /** /** /** /** /** /** /** } |