четверг, 26 декабря 2013 г.

Интеграция ADF приложений (Библиотеки)


1. Создаем проект с BC и VC в котором будут находиться библиотечные компоненты. Важно правильно выставить зависимость проектов SharedVC от SharedBC


2. Для проекта SharedVC создаем профиль загрузки как ADF Lib Jar. Нужно проследить чтобы зависимость от SharedBC перенеслась правильно


Выбираем путь для хранения библиотеки

Проверяем, что нужные библиотеки и jar-ы в наличии.

4. Создаем проект в котором будем использовать библиотеки и подключам их как пользовательские

6. Убеждаемся, что в окошке приложения для нашего проекта библиотека видна и в ней нужные нам компоненты.


7. Теперь можно использовать библиотечные компоненты как родные


8. В свойствах либы нужно выставить указание, что передавать конеекцию только как имя(предполагается, что в майине используется такая же коннекция с таким же именем)
иначе обругает, "weblogic.common.ResourceException: Data Source rko already exists."


9. Если используется безопасность то:

В проекте либы лучше отключать секюрити. А в проекте майна не забыть поставить галочку "Показывать компоненты из библиотеки", чтобы выставить правильно безопасность на страницы, таскфлоу и прочую фуйню.




Integration in Oracle ADF Through ADF Libraries and ADF Task Flows
ADF Calling Bounded Task Flow Using URL

How-to integrate remote task flows in your ADF applications


четверг, 19 декабря 2013 г.

getCurrentDateTime()

/**
      * Get Current Date
      * @return
      */
public Date getCurrentDateTime()
    {
    return new Date(new java.sql.Timestamp(System.currentTimeMillis()));
    }

Безопасность в ADF





  • Включаем безопасность на приложении
Включаем безопасность на приложении
   Application->Security->Configure ADF Security
   AdfAutentification and Authorization
   Создаем login форму
   No Automatic Grants
   Выбираем страницу перехода по-умолчанию
 
Заводим пользователей и роли редактируя файл jazn-data.xml

из  oracle\middleware\modules

com.bea.core.weblogic.securiti.auth.....jar
com.bea.core.weblogic.securiti.identity......jar

из
c:\Oracle\Middleware123\wlserver_10.3\server\lib\wls-api.jar




Securing Fusion Web Applications
ADF Training - Oracle ADF 11g Security - Custom ADF Login (три библиотеки)
4 Adding Security to Your Application Fusion Middleware Tutorial
14 Developing Secure Applications Документация(!)

вторник, 17 декабря 2013 г.

Как добраться до свойства определенного в бине


Можно через функцию  JSFUtils.resolveExpression() например так:


RichCommandLink link = (RichCommandLink)JSFUtils.resolveExpression(
            "#{viewScope.ContractsTableBean.warningLink}");




Сама функция(метод JSFUtils) определена так:

/**
      * Method for taking a reference to a JSF binding expression and returning
      * the matching object (or creating it).
      * @param expression EL expression
      * @return Managed object
      */
     public static Object resolveExpression(String expression)
     {
       FacesContext facesContext = getFacesContext();
       Application app = facesContext.getApplication();
       ExpressionFactory elFactory = app.getExpressionFactory();
       ELContext elContext = facesContext.getELContext();
       ValueExpression valueExp = elFactory.createValueExpression(elContext, expression, Object.class);
       return valueExp.getValue(elContext);
     }

четверг, 12 декабря 2013 г.

воскресенье, 8 декабря 2013 г.

Форма для редактирования с кнопкой Edit

1) Добавляем во VO rowstatus





2) Добавляем во VO edit

3) В xxxVOImpl.java вешаем метод для отмены изменений, примерно такой


    public void clearAllCache() {
      //dont ask
      ViewRowSetImpl drsi = super.getDefaultRowSetInternal();
      while(drsi.hasNext()) {
        Row item = drsi.next();
      }
      Iterator iter = super.getEntityDef(0).getAllEntityInstancesIterator(this.getDBTransaction());
      while(iter.hasNext()) {
        EntityImpl entityItem = (EntityImpl) iter.next();
        byte status = entityItem.getEntityState();
          String s = ((status == EntityImpl.STATUS_MODIFIED) ? " STATUS_MODIFIED" : "")
          + ((status == EntityImpl.STATUS_NEW) ? " STATUS_NEW" : "")
          + ((status == EntityImpl.STATUS_DELETED) ? " STATUS_DELETED" : "")
          + ((status == EntityImpl.STATUS_DEAD) ? " STATUS_DEAD" : "")
          + ((status == EntityImpl.STATUS_INITIALIZED) ? " STATUS_INITIALIZED" : "")
          + ((status == EntityImpl.STATUS_UNMODIFIED) ? " STATUS_UNMODIFIED" : "");
          System.err.println(" --- "+ s);
       
        if(status == EntityImpl.STATUS_NEW
          || status == EntityImpl.STATUS_DELETED) {
            entityItem.refresh(EntityImpl.REFRESH_REMOVE_NEW_ROWS
                | EntityImpl.REFRESH_UNDO_CHANGES);
        }
        if(status == EntityImpl.STATUS_MODIFIED) {
            entityItem.refresh(EntityImpl.REFRESH_WITH_DB_FORGET_CHANGES);
        }
        getViewObject().clearCache();

    }
 
4) В форму добавляем поле с кнопкой для редактирования


5) На кнопку вешаем PropertyListner   To: #{row.bindings.edit.inputValue}




) Свойство таблицы EditMode выставляем - onClickEdit

6) Добавляем на форму кнопку New с таким обработчиком событий:
#{bindings.CreateInsert.execute}. При этом нужно не забыть добавить action CreateInsert в binding!


7) Добавляем кнопку Save с обработчиком вызывающем такой метод:


    public void onSave(ActionEvent actionEvent) {
        // Add event code here...
        //System.out.println("--- onSave");
        ViewObject viewObject = getCurrentVO();
        RowSetIterator iterator = viewObject.createRowSetIterator(null);
        iterator.reset();
        while (iterator.hasNext()) {
        Row row = iterator.next();
        // process the row here
            row.setAttribute("edit",false);
        }
        iterator.closeRowSetIterator();
     
        super.onCommit(actionEvent);
    }


8) Добавляем кнопку Undo Changes обработчиком вызывающем такой метод:

    public void onRollback(ActionEvent actionEvent) {
        ((xxxVOImpl)getCurrentVO()).clearAllCache();
        getCurrentVO().executeQuery();
        
        if(getUpdComponent()!= null)
          AdfFacesContext.getCurrentInstance().addPartialTarget(getUpdComponent());
    }


9) Добавляем в xxxVORowImpl.java два метода, которые будут учитывать свойство edit записи:


    @Override
    public boolean isAttributeUpdateable(int i) {
        Boolean ed = this.getedit();
        if(ed == null) {
            return false;  
        }
        if(ed.equals(true)) {
            return super.isAttributeUpdateable(i);  
        } else {
            return false;
        }
    }

    @Override
    protected void create(AttributeList attributeList) {
        attributeList.setAttribute("edit", true);
        super.create(attributeList);
    }






------------------------------------------------------------------------------------------------------
Выделяем цветом редактируемые записи

inlineStyle="#{backingBeanScope.backing_ServiceTypesPriceV.cellColor}">
------------------------------------------------------------------------------------------------------


    /*
    * Управляем доступностью кнопок Edit, Delete
    */
    public void tableSelectionListener(SelectionEvent selectionEvent) {
        ADFUtil.invokeEL("#{bindings.PV_ViewObj2.collectionModel.makeCurrent}", new Class[] {SelectionEvent.class},
                             new Object[] { selectionEvent });
            // get the selected row , by this you can get any attribute of that row
            //Row selectedRow =
            //    (Row)ADFUtil.evaluateEL("#{bindings."+ iterator_name +".currentRow}"); // get the current selected row
            Row selectedRow = this.getCurrentRow();
            BigDecimal no = (BigDecimal) selectedRow.getAttribute("StatusId");
            if(no.intValue() == 1) {
                this.cb5.setDisabled(false);
                this.cb2.setDisabled(false);
                //System.out.println("--- cb5.setDisabled(false) " );
            } else {
                //this.cb5.setDisabled(true);
                //this.cb2.setDisabled(true);
                //System.out.println("--- cb5.setDisabled(true) " );
            }
    }

Как отменить изменения только в одном VO

Rollback не годится, т.к. сбрасывает изменения во всём модуле для всех VO. Поэтому чтобы  справиться с задачей модифицируем класс xxxVOImpl добавив в него метод


    public void clearAllCache() {
      //dont ask
      ViewRowSetImpl drsi = super.getDefaultRowSetInternal();
      while(drsi.hasNext()) {
        Row item = drsi.next();
      }
      Iterator iter = super.getEntityDef(0).getAllEntityInstancesIterator(this.getDBTransaction());
      while(iter.hasNext()) {
        EntityImpl entityItem = (EntityImpl) iter.next();
        byte status = entityItem.getEntityState();
          String s = ((status == EntityImpl.STATUS_MODIFIED) ? " STATUS_MODIFIED" : "")
          + ((status == EntityImpl.STATUS_NEW) ? " STATUS_NEW" : "")
          + ((status == EntityImpl.STATUS_DELETED) ? " STATUS_DELETED" : "")
          + ((status == EntityImpl.STATUS_DEAD) ? " STATUS_DEAD" : "")
          + ((status == EntityImpl.STATUS_INITIALIZED) ? " STATUS_INITIALIZED" : "")
          + ((status == EntityImpl.STATUS_UNMODIFIED) ? " STATUS_UNMODIFIED" : "");
          System.err.println(" --- "+ s);
       
        if(status == EntityImpl.STATUS_NEW
          || status == EntityImpl.STATUS_DELETED) {
            entityItem.refresh(EntityImpl.REFRESH_REMOVE_NEW_ROWS
                | EntityImpl.REFRESH_UNDO_CHANGES);
        }
        if(status == EntityImpl.STATUS_MODIFIED) {
            entityItem.refresh(EntityImpl.REFRESH_WITH_DB_FORGET_CHANGES);
        }
       
      }
      getViewObject().clearCache();
    }


 Идея заключается в том, что проходим по всем записям VO и в зависимости от их состояния делаем refresh.

ссыль

четверг, 5 декабря 2013 г.

Как сделать кнопку активной/пассивной в зависимости от записи в таблице

Можно задать свойство disabled для этой кнопки


Кнопка будет доступна когда значение статуса равно 'N'
#{bindings.Status.inputValue eq 'N' ? 'false' : 'true'} 

четверг, 7 ноября 2013 г.

CheckBox в таблице связанный с INTEGER полем базы

В БД есть поле do_flg типа INTEGER со значениями 0(ложь), 1(истина), которое нужно отображать в таблице интерфейса в виде чекбокса.


  • Создаем в xxxEO транзиентный(!) атрибут flg типа Boolean всегда изменяемый.
  • Добавляем flg в xxxVO где ставим его ControlType CheckBox
  • В классе xxxEOImpl.java переопределяем методы доступа к flg так, чтобы они были привязаны к полю do_flg
    public Boolean getFlg() {
        Number n = (Number)getAttributeInternal(DOFLG);
        if( n != null && n.longValue()== 1) {
            return new Boolean(true);
        }
        return new Boolean(false);
    }

    public void setFlg(Boolean value) {
        if(value == null || !value.booleanValue())
            setAttributeInternal(DOFLG, new BigDecimal(0));
        else 
            setAttributeInternal(DOFLG, new BigDecimal(1));
        setAttributeInternal(FLG, value);
    }


Всё. Теперь все изменения flg будут приводить к изменению do_flg/


вторник, 29 октября 2013 г.

Запись изменений VO в базу без commit

Для автоматической записи в БД всех изменений происходящих на уровне WLS
можно выставить  this.setAutoPostChanges(true); в объекте VOImpl.

ВАЖНО:
1. запись будет происходить только  в момент выполнения ExecuteQuery()
2. на измененных записях таблицы выставляется блокировка




What you may need to know about DBTransaction::postChanges()


// Get VewRowImpl someVewRowImpl from VO  
    someVewRowImpl.setAttribute( "SomeAttrib","New Value");  
    EntityImpl someEOImpl = someVewRowImpl.getEntity(0);  
    DBTransaction txn = getDBTransaction();  
    txn.validate();  
    txn.postChanges();  
    txn.removeTransactionPostListener(someEOImpl); 
 
    //The below two lines may cause your EO to skip 
    // beforeCommit() and afterCommit() call backs.
    //Normally you can skip the below two lines, 
    // use it if you need to clear the EO cache once data is posted to DB
    // This makes sense if you have millions of rows in an update and
    // and you want to get rid of the cached rows without any delay
    txn.removeTransactionListener(someEOImpl); 
    txn.clearEntityCache(null);



Как получить текст запроса для поисковой формы


Хотим получить запрос выполняющийся в поисковой форме (Query) элементе
для этого переопределяем метод executeQueryForCollection объекта ViewObjectImpl

    protected void executeQueryForCollection(Object qc, Object[] params,
        int numUserParams) {
            System.out.println("--- numUserParams "+numUserParams);
            System.out.println("--- getQuery "+getQuery());
            for(int i=0;i<numUserParams;i++) {
                Object[] o = (Object[])params[i];
            System.err.println(o[0] + " " + o[1]);
        }
        super.executeQueryForCollection(qc, params, numUserParams);
    }

Получаем что-то такое:


SELECT * FROM
(SELECT /*+ FIRST_ROWS */ IQ.*, ROWNUM AS Z_R_N FROM
(SELECT TrInOperationsEO.ID,         TrInOperationsEO.INOUT_DATA_LOG_ID,
...
TrInOperationsEO.CLIENT_CODE
FROM TR_IN_OPERATIONS TrInOperationsEO
WHERE (ROWNUM <= :bndMaxRows)
AND ( ( ( (TrInOperationsEO.ID = :vc_temp_1 )
AND (TrInOperationsEO.INOUT_DATA_LOG_ID = :vc_temp_2 ) ) ) ) ORDER BY id DESC
) IQ  WHERE ROWNUM < :Bind_RangePage_High
) WHERE Z_R_N > :Bind_RangePage_Low

Надо заметить, что параметры Bind_RangePage_High, Bind_RangePage_Low возникают из постраничного вывода VO, остальные имеют имена vc_temp_1, vc_temp_2, и т.д. в соответствии с тем, какие параметры отмечены в форме.

Список параметров выглядит примерно так:


bndMaxRows 100
vc_temp_1 15613
vc_temp_2 23
vc_temp_3 R

Первая переменная bndMaxRows добавлена в запрос VO вручную, остальные формируются по полям автоматически. 




  

четверг, 24 октября 2013 г.

Таблицы с постраничный выводом


Настраиваем VO для работы с многостраничными запросами



В свойствах итератора выставляем то же  количество записей:





Для таблицы с постраничным выводом количество записей получается через функцию
getEstimatedRowCount()  объекта ViewObjectImpl

Пройти по всем записям можно через два цикла, первый - цикл по страницам, второй по записям на каждой странице, примерно так:


    public void onLoop(ActionEvent actionEvent) {
        long row_count = getVoImpl().getEstimatedRowCount();
        long rows_per_page = getVoImpl().getRangeSize();
        long page_count = row_count / rows_per_page + 1;
        System.out.println("total rows:" + row_count + "  rows at page:" +    rows_per_page + "  numb of pages:" + page_count);
        int m = 1;
        for(int i=1;i<=page_count;i++) {
            System.out.println("--- Page: " + i);
            getVoImpl().scrollToRangePage(i);
                for(int j=0; j<rows_per_page && m<=row_count; m++, j++) {
                    Row row = getVoImpl().getRowAtRangeIndex(j);
                    System.out.println(m +"  "+ row.getAttribute(0)+ "  " + row.getAttribute(2) );
                }
        }
    }



Тестовое приложение TestHr1.rar






вторник, 22 октября 2013 г.

Стандартные иконки


Иконки находится в jar файле oicons.jar

У меня они в двух местах:

C:\Oracle\Middleware123\jdeveloper\ide\lib\
C:\Oracle\Middleware123\oracle_common\modules\oracle.adf.model_11.1.1\oicons.jar

Oracle ADF Useful Links and Resources Resource Links

понедельник, 21 октября 2013 г.

Pagination in ADF 11.1..2....


Оракл убрал привычный постраничный вывод таблиц в ADF 11.1..2.... Изумлению пользователей, судя по отзывам в блогах, нет предела, тем не менее факт свершившийся.)


Будем искать обходные маневры:
Custom Table Pagination Using EJB Native Query


В принципе, постраничная организация вывода в новом ADF работает, только это осуществляется "прозрачным" для пользователя способом. Хорошо или плохо это, не знаю.


Ограничения, связанные с постраничным выводом:

Нельзя открыть итератор по записям, возникнет ошибка: "JBO-25083: Cannot create a secondary iterator on row set {0} because the access mode is forward-only or range-paging"

"In order to be able to iterate a view object rowset using a secondary iterator, the view object
access mode in the General | Tuning section must set to Scrollable. Any other access
mode setting will result in a JBO-25083: Cannot create a secondary iterator on row set {0}
because the access mode is forward-only or range-paging error when attempting to create a
secondary iterator. To iterate view objects configured with range paging, use the range paging
view object API methods. Specifically, call getEstimatedRangePageCount() to determine
the number of pages and for each page call scrollToRangePage(). Then determine
the range page size by calling getRangeSize() and iterate through the page calling
getRowAtRangeIndex()."
                                                  Oracle JDeveloper 11gR2 Cookbook



"Падучая" болезнь Weblogic-а при деплойменте


Weblogic оказался подвержен "падучей" при деплойменте приложений. Каждая третья попытка кладет его по OutOfMemory, превышен Permgen.

Нашел статью с рекомендацией "Java. Сборщики мусора" .с рекомендацией включить очистку  Permgen-а. Для этого в опциях java машины нужно добавить два параметра
+CMSPermGenSweepingEnabled +CMSClassUnloadingEnabled

(редактируем startWebLogic.cmd)
@REM МОИ ДОПОЛНИТЕЛЬНЫЕ НАСТРОЙКИ для очистки Permgen
set EXTRA_JAVA_PROPERTIES= -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled
set MEM_ARGS=%MEM_ARGS% %EXTRA_JAVA_PROPERTIES%


Не знаю поможет или нет.
UPD:
Отчасти помогло, WLS стал работать устойчивее, но всё-же не до конца, его по-прежнему . можно завалить "деплоями".


Полезные ссылки:

Java. Сборщики мусора. Часть первая.
Java. Сборщики мусора. Часть вторая.

пятница, 18 октября 2013 г.

Напоролся на JBO-25200


Оказывается если использовать ViewCriteria с виндинг-переменной в WHERE конструкции например WHERE ROWNUM <= :bndMaxRows) , то при выполнении можно поиметь исключение JBO-25200. Выглядит так, словно модуль потерял коннекцию к базе. Причем, это происходит только в том случае, если переменная отображается в списке критериев поиска, если же у неё своиство display hint сделать Hide то ошибка исчезает.


Полезная ссылка:
oracle.jbo.NotConnectedException: JBO-25200 While using View Criteria

воскресенье, 13 октября 2013 г.

Динамическое отображение колонок в таблице


Задача: изменять видимость колонок таблицы в в коде программы, в зависимости от некоторых условий.


  • создаем HashMap отвечающий за отображение колонок в бине InOperationsB (область ViewScope). Инициализируем  его в конструкторе, либо в момент первого использования


    private HashMap viewColumns;

    public InOperationsB() {
        super();
        
        if(viewColumns == null) {
            viewColumns = new HashMap();
            viewColumns.put("Payid",Boolean.TRUE);
        }
        ...
    }


  • вешаем на форму кнопочку Test с обработчиком onTest()  в InOperationsB
    public void onTest(ActionEvent actionEvent) {

       //-- сюда вставляем логику отображения, у меня просто "вкл-выкл"
 
        Boolean b = (Boolean)viewColumns.get("Payid");
        if(b != null) {
            if( b.booleanValue()) {
                viewColumns.put("Payid",Boolean.FALSE);
            } else {
                viewColumns.put("Payid",Boolean.TRUE);
            }
        }
        //-- refresh table  getVoImpl().executeQuery(); 
  }



  • правим свойство Visible у колонки в отображаемой таблице на EL выражение "#{viewScope.InOperationsB.viewColumns['Payid']}" где  'Payid' у меня имя атрибута в колонке(но это не суть важно)
  • тестируем. По нажатию кнопки колонка то появляется, то исчезает



Получение бина области viewScope в коде


Алгоритм примерно такой:



  1. получаем текущий Инстансе из FacesContext
  2. из него получаем контекст EL  и контекст ExpressionFactory
  3. в котором открываем ValueExpression для требуемого бина, через выражение  "#{viewScope.YourBeanName}"
  4. и получаем объект бина функцией getValue()


 Всё офигенно просто.)))

Пример:

private TreeTableStateBean getTreeTableStateObject(){
        TreeTableStateBean stateBean = null;
     
        FacesContext fctx = FacesContext.getCurrentInstance();
        ELContext elctx = fctx.getELContext();
        ExpressionFactory elFactory = fctx.getApplication().getExpressionFactory();
     
        ValueExpression ve = elFactory.createValueExpression(
                                elctx,
                                "#{viewScope.treeTableStateBean}",
                                Object.class);
     
        stateBean = (TreeTableStateBean) ve.getValue(elctx);      
        return stateBean;
      }

Ссылка:
ADF Code Corner 84. Dynamically show or hide af:treeTable columns dependent on the disclosed node

Работа с критериями поиска ViewCriteria


Полезные ссылки:


ViewObject (VO) - Выводимый Объект (ВО)
ViewCriteria(VC) - Критерий Поиска (КП)

Похоже, Критерии Поиска довольно мощный и гибкий механизм. Суть в том, что на один VO можно навесить несколько разных критериев, а затем, использовать один и тот же VO в нужном контексте. 

Примерная последовательность действий:
  • Добавляем несколько КритериевПоиска в интересующий ViewObject
  • Создаем таблицу "t1" в форме на основе VO
  • Добавляем в форму popup элемент в который вставляем query(Запрос с Параметрами) на основе NamedCriteria   для нашего VO.  Можно создать Запрос с Параметрами на основе конкретного Критерия Поиска, но потом всё-равно можно перемещаться выбирая другие КП.
  • Для каждого КП можно декларативно определить выводимые параметры на основе атрибутов VO
----------------------------------------------------------------------------------------------------------

Программное изменение использования атрибута в запросе критерия

В классе ViewObjectImpl определяем метод:


public void setQuerable(String attributeName, Boolean isQuerable) {  
   
     int indx = this.getAttributeIndexOf(attributeName);  
   
     ViewAttributeDefImpl attr = (ViewAttributeDefImpl)this.getAttributeDef(indx);  
   
     attr.setQueriable(isQuerable);  
   
   }