Apache Jakarta and Beyond: A Java Programmeramp;#039;s Introduction [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Apache Jakarta and Beyond: A Java Programmeramp;#039;s Introduction [Electronic resources] - نسخه متنی

Larne Pekowsky

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







10.7. Lazy Evaluation


As mentioned previously, based on the setting of auto-load in the mapping file, collections and objects can be loaded either eagerly or lazily. Eager evaluation makes it easy to write application code because the code can always assume that cascaded data will be present. However, eager evaluation may load a lot more data than the application uses, impacting both performance and memory usage.

There are two different ways in which evaluation of a collection may be lazy: at the collection level or at the object level. Laziness at the collection level means that a stub List will be provided when the parent object is first loaded. The methods in this List will load the data if necessary before performing the usual List action. For example, the first time get() or iterate() is called, the List will first run the necessary query and populate itself. This means the same total number of queries will be executed, as in eager evaluation, but they will be delayed until needed. On the other hand, this means that as soon as any element of the List is accessed, all elements will be read into memory.

Object-based laziness implies that when the parent object is loaded a List is prepared with stubs for each of the children, and each individual child is loaded as it is accessed. This may mean many more queries will be executedone for the parent, one to find out how many children there are, and one for each child. The benefit is that only the data that is used by the program will be loaded.

One approach to collection-level lazy evaluation would be to manually load collections, either in the application code or in the bean. Album data could be handled in the Artist bean with code like the following:


private Collection albums = null;
public Collection getAlbums() {
if(albums != null) return albums;
Album a = new Album();
a.setArtistId(getArtistId());
Query qry = new QueryByIdentity(a);
PersistenceBroker broker =
PersistenceBrokerFactory.defaultPersistenceBroker();
albums = broker.getCollectionByQuery(query);
return albums;
}

Note the use of the new broker method getCollectionByQuery(). This would need some effort to make it produce a List, properly handle exceptions, and other such details.

While this approach would certainly work, it is far from ideal because it makes the job of writing persistable beans much more difficult. Even if most of the work in the preceding method were abstracted into a method in a base class, it inexorably ties the beans to the persistence model, which is undesirable.

The most salient feature of the preceding code snippet is the the conditional right at the top. The implication of this test is that the data will be loaded the first time it is needed, when the albums are first requested. This test can be moved from the bean into the Collection class, which is what OJB does. To enable this kind of lazy evaluation, it is just necessary to add proxy= "true" to the collection-descriptor, as in


<collection-descriptor
name="albums"
element-class-ref="com.awl.toolbook.chapter10.Album"
orderby="year_released"
sort="ASC"
proxy="true"
<
<inverse-foreignkey field-ref="artistId"/>
</collection-descriptor>

Note that auto-update and auto-delete have been removed.It is possible to leave these features enabled, but note that doing so will cause the entire collection to be read from the database when a save or delete operation occurs.

Object-level lazy evaluation is somewhat more difficult. What is needed is a means for OJB to automatically detect that an object is being used without requiring the user to add any code. Note that, to be as lazy as possible, simply accessing albums.get(3) should not cause the third album to be read. This should only happen when member data is used, as in albums.get(3).getName() or artist getAlbum(3). getYearReleased().

This is asking rather a lot of OJB because the calls to the Album methods do not invoke OJB at all. One way OJB could intercept the calls to these methods is to use a

proxy, a class that sits between OJB and the Artist bean, which provides the same methods and performs the special handling required by lazy collections. An outline of such a class is shown here.


public class AlbumProxy {
private Album theAlbum = null;
public int getYearReleased() {
if(theAlbum == null) {
loadAlbum();
}
return theAlbum.getYearReleased();
}
}

The loadAlbum() method would do essentially the same thing as the getAlbums()from the previous example. Any calls to a broker that result in an Album being generated would instead return an AlbumProxy.

So far this solution looks even worse than putting the code in the getAlbum()method. The same code must be written, plus more, and all application code must be changed to use AlbumProxy instead of Album. A little of this burden could be avoided by using an interface that defines the Album methods and having both Album and AlbumProxy implement this interface. At least then application code could use one type name consistently.

Now a remarkable feature of Java enters the picture. As of JDK 1.3 it is possible for a class to declare that it implements an interface at runtime. This feature is relatively unknown. Readers who have not previously encountered it may wish to read more details in Appendix A.

The practical upshot of this feature is that once the interface has been defined, no more code needs to be written! OJB can declare that a generalized proxy implements the interface. This general proxy will then intercept all method calls and will automatically load collections that have not yet been loaded.

This feature is enabled in the descriptor for the class rather than any collection that may use the class. It will therefore impact all references to the class, whether in collections, backpointers, or anywhere else. A typical definition is as follows:


<class-descriptor
proxy="dynamic "
table="Album"
>
<!-- field definitions, as before -->
</class-descriptor>


/ 207