СТАТЬЯ
16.11.01

Как сделать так, чтобы библиотека dxejb.jar работала без ошибок?

© Александр Лейтес
Статья опубликована на сайте www. Jbuilder.ru

Появление на рынке нового JBuilder 5.0 принесло разработчикам EJB-приложений долгожданное облегчение. Новая библиотека dxejb.jar с набором компонентов: SessionBeanConnection, EjbClientDataSet, EntityBeanProvider и EntityBeanResolver обеспечивает довольно удобное взаимодействие клиентской и серверных частей при помощи специальных компонентов-переходников, представляющих собой stateless session beans. Раньше, разработчику приходилось писать свои источники данных. Это было довольно неудобно и отнимало много времени. Теперь, разработчику нужно написать только переходник на сервере, и он сможет воспользоваться стандартным EjbClientDataSet для подключения визуальных компонентов к EJB-источнику данных. Данные передаются в виде массивов, что также ускоряет работу клиентского приложения.

Я не буду подробно останавливаться на архитектуре библиотеки dxejb.jar и примерах ее использования. Эту информацию читатель легко найдет в документации, поставляемой с JBuilder 5.0. Здесь, мне бы хотелось привлечь внимание к тем ошибкам и неточностям, которые допущены в этой библиотеке, а также показать, как их исправить.

1. Метод storeDataRowToEntityBean() в файле EntityBeanresolver.java не проверяет столбцы на значение NULL. Это приводит к тому, что вместо NULL в таблицу подставляются конкретные числовые значения, например, вместо целого NULL. подставляется 0. Это может вызвать проблемы, если столбец ссылается на другую таблицу и допускает значение NULL. В этом случае, присваивание столбцу 0 не всегда возможно, так как в таблице на которую он ссылается может отсутствовать запись с первичным ключом 0. Понятно, что из этой ситуации всегда можно выкрутиться, добавив соответствующие “нулевые” записи однако, это нельзя считать нормальным положением дел. Этот недостаток можно легко исправить добавив в исходный текст проверку на NULL:

int storeDataRowToEntityBean(DataRow dataRow, int index, EJBObject entityRemote) {
try {
Column column = dataRow.getColumn(index);
if ( !column.isReadOnly() ) {
String columnName = column.getColumnName();
if ( columnName.indexOf('.') == -1 ) {
Method setterMethod = methodsDesc.findSetterMethod("set" + column.getColumnName());
if ( setterMethod != null ) {
if(dataRow.isNull(columnName))
{
setterMethod.invoke(entityRemote, new Object[] {null});
return 1;
}

}

}
catch(Exception ex) {…}
...
}

Оператор if () проверяет значение поля и если оно равняется null, то вызывается соответствующий метод с параметром null.

2. Метод provideDataSets() из SessionBeanConnection.java содержит серьезную ошибку: не выделяется память под объекты parameterRowDataArray[i] и masterRowDataArray[i] , после чего вызываются методы этих объектов! Если в случае с masterRowDataArray[i] это не так страшно (связь master-detail в настоящее время не используется), то необходимость передавать параметры запроса на сервер возникает очень часто. Понятно, что такая попытка заканчивается исключением NullPointerException. В этом случае нужно просто сделать то, что забыли сделать разработчики, а именно: выделить память под элементы массива:

if ( parameterArray != null ) {
parameterRowDataArray = new RowData[parameterArray.length];
for (int i = 0; i < parameterArray.length; i++) {
if ( parameterArray[i] != null ) {
parameterRowDataArray[i] = new RowData();
parameterRowDataArray[i].load(parameterArray[i]);
}
}
}
if ( masterArray != null ) {
masterRowDataArray = new RowData[masterArray.length];
for (int i = 0; i < masterArray.length; i++) {
if ( masterArray[i] != null ) {
masterRowDataArray[i] = new RowData();
masterRowDataArray[i].load(masterArray[i]);
}
}
}

2. Однако, даже после этих исправлений, передать параметр серверу оказывается не так то просто: передается только значение последней колонки ParameterRow, остальные значения оказываются пустыми! Дело в том, что класс ParameterRow ведет себя, на мой взгляд, достаточно странно: он требует, чтобы разработчик сначала сформировал все столбцы вызовами метода addColumn(), и только после этого присваивал им значения! Видимо, разработчики класса RowData.java не догадывались об этой маленькой особенности ParameterRow (или его предков), поэтому написали очень естественный код, который написал бы каждый нормальный человек на их месте:

public ParameterRow extract() {
ParameterRow parameterRow = new ParameterRow();
for (int i = 0; i < values.length; i++) {
parameterRow.addColumn(names[i], values[i].getType());
parameterRow.setVariant(names[i], values[i]);
}
return parameterRow;
}

Но, разработчики ParameterRow по-видимому не желали своим коллегам легкой жизни! На самом деле, в свете вышесказанного, код должен выглядеть следующим образом:

public ParameterRow extract() {
ParameterRow parameterRow = new ParameterRow();
for (int i = 0; i < values.length; i++) {
parameterRow.addColumn(names[i], values[i].getType());
}
for (int i = 0; i < values.length; i++) {
parameterRow.setVariant(names[i], values[i]);
}
return parameterRow;
}

После исправления этих ошибок я пересобрал библиотеку и заменил исходный файл dxejb.jar своим. Теперь, библиотека работает нормально.

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Обсудить на форуме Inprise/Borland
Отправить ссылку на страницу по e-mail


Interface Ltd.
Тel/Fax: +7(095) 105-0049 (многоканальный)
Отправить E-Mail
http://www.interface.ru
Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 16.11.01