OA Framework

switcher, работающий в hGrid
Видимо, это особенность совместимости switcher и hGrid. Решение:
1. Не изменяя SQL во VO, создать транзиторный атрибут с названием, например, swTran (Type: String, Updatable: Always);
2. В модуле VORowImpl изменить функцию-геттер так, чтобы она возвращала значение нашего параметра в зависимости от атрибута myCond:
public String getSwTran() {
        Number i = getmyCond();
        String cf = "";
     if (i.intValue() == 0){
        return cond1;
     }else{
        return cond2;
     }
}
hGrid не перерисовывется при фильтрации данных
Решение: перенести всю логику обертывания VO в условия в processRequest. И, как рекомендуется в гайде, после вызова одноименного метода родительского класса, прописать
OAHGridBean hGrid = (OAHGridBean)
     webBean.findIndexedChildRecursive("Grid");
if (hGrid != null) {
    hGrid.prepareForRendering(pageContext);
    hGrid.setAutoQuery(false);
}
использование атрибутов из VO разных уровней в атрибутах бина (например, построение Destination URI)
Необходимо соблюдение трех условий: 1) используемые атрибуты присутствуют во ВСЕХ уровнях, там, где они не имеют физического смысла, делаем Transient; 2) алиасы параметров должны быть идентичны с учетом регистра; 3) в атрибутах бина View Instance и View Attribute должен быть прописан любой уровень и параметр, имеющий физический смысл.
рекурсивное создание уровней hGrid
Если сущность завязана сама на себя по id = parent_id, то может потребоваться автоматическое достраивание уровней hGrid. Решение:
1. Создаем VL с отношением id = parent_id c отношением 0..1 to *;
2. Добавляем второй экземпляр VO нижнего уровня в AM через связь с созданным VL

3. Достраиваем в PG дерево hGrid:
Здесь CommentLevel - ветка нижнего уровня с View Instance = Comment3VO1, ChildCommentLevel - создаваемая рекурсивно ветка с View Instance = Comment3VO2, CommentsLevel - узел с View Link Instance = CommentRecursiveVL1. Особое внимание - на узел RecursiveLink, в котором View Link Instance = CommentRecursiveVL1. Для него необходимо также задать параметр Ancestor Node = /oracle/apps/.../путь к пакету/<имя_страницы>.<имя_узла> - это необходимо для зацикливания при построении новых уровней. В нашем случае <имя_узла> = CommentsLevel.
безусловный переход на страницу
pageContext.forwardImmediately(
"OA.jsp?page=/oracle/apps/xxx/xxx1/webui/MyPG",
null,
OAWebBeanConstants.KEEP_MENU_CONTEXT,
null,
null,
true, // retain AM
OAWebBeanConstants.ADD_BREAD_CRUMB_NO);
перерисовка страницы с hashmap
HashMap params = new HashMap(10);
params.put("wPrm1", pageContext.getParameter("prm1"));
params.put("wPrm2", pageContext.getParameter("prm2"));
params.put("wPrm3", pageContext.getParameter("prm3"));
pageContext.forwardImmediatelyToCurrentPage(
params,
false,
OAWebBeanConstants.ADD_BREAD_CRUMB_NO);
...
public void processRequest{
...
(OAPageContext pageContext, OAWebBean webBean)
pageContext.getParameter("wPrm1"));
...
}
обработка исключения
try{
OAApplicationModule am = pageContext.getApplicationModule(webBean);
OADBTransaction tran = (OADBTransaction)am.getTransaction();
prm = tran.getMyPRM();
}
catch (SQLException e) {
throw OAException.wrapperException(e);
}
invokeMethod с полными параметрами
OAApplicationModule am = pageContext.getApplicationModule(webBean);
Serializable[] prm_values = {myNum, myStr};
Class[] prm_classes = {Number.class, String.class};
am.invokeMethod("MyProc", prm_values, prm_classes);
оборачивание VO в ограничения
public void initQuery(Number Id, String Str) {
setWhereClause(null);
setWhereClauseParams(null);
setWhereClause("ent_id = :1 and ent_name = :2");
setWhereClauseParam(0, Id);
setWhereClauseParam(1, Str);
executeQuery();
}
программное изменение заголовка у webbean
String someTitle = "title1";
((OAPageLayoutBean)webBean).setTitle(someTitle); 
вызов DB процедуры
OADBTransaction tran = getOADBTransaction();
OracleCallableStatement cStmt = null;
StringBuffer callSt = new StringBuffer();
callSt.append("begin XXX_PKG.set_params(");
callSt.append("pv_name => :1, ");
callSt.append("pv_id => :2, ");
callSt.append("pv_date => :3)");
callSt.append("; end;");
try {
cStmt = (OracleCallableStatement)
tran.createCallableStatement(callSt.toString(),
tran.DEFAULT);
cStmt.setString(1, prmUser);
cStmt.setNUMBER(2, prmID);
cStmt.setString(3, prmDate);
cStmt.execute();
cStmt.close();
}
catch (SQLException sqle) {
throw OAException.wrapperException(sqle);
}
содержимое колонки по центру (hGrid)
private void getColCentered(OAPageContext pageContext, 
                          OAWebBean webBean, OAHGridBean hGrid)
 DataObjectList columnFormats = hGrid.getColumnFormats();
 DictionaryData columnFormat = null;
 int childIndex[] = 
     new int[] { pageContext.findChildIndex(hGrid, "Column1"), 
                 pageContext.findChildIndex(hGrid, "Column2"), 
                 pageContext.findChildIndex(hGrid, "Column3"), 
               };
 for (int i: childIndex) {
     columnFormat = (DictionaryData)columnFormats.getItem(i);
     columnFormat.put(COLUMN_DATA_FORMAT_KEY, ICON_BUTTON_FORMAT);
 }
} 
динамическое создание View Object
StringBuffer strBuf = new StringBuffer();
strBuf.append("select p from (select 0 p from dual ");
strBuf.append("union ");
strBuf.append("select 1 from dual)");
ViewObject myVO = am.createViewObjectFromQueryStmt("myVO", strBuf.toString());
myVO.setWhereClause("p = :1");
myVO.setWhereClauseParam(0, "0");
myVO.executeQuery();
myVO.first();
      
OAMessageChoiceBean mcBean = (OAMessageChoiceBean)webBean.findChildRecursive("Test");
mcBean.setValue(pageContext, (String)myVO.getCurrentRow().getAttribute(0));

myVO.remove();  
конвертирование строки в объект oracle.jbo.domain.Date
import java.text.SimpleDateFormat;
import java.text.DateFormat;
import oracle.cabo.ui.data.DataObjectList;
import oracle.cabo.ui.data.DictionaryData;

public void dateTest(){
  String dateStr = "11.01.2013";
  DateFormat df; 
  df = new SimpleDateFormat("dd.MM.yyyy");
  java.util.Date tmp = null;
  tmp = df.parse(dateStr);
  oracle.jbo.domain.Date resDate = new oracle.jbo.domain.Date(new java.sql.Date(tmp.getTime()));
}
очистка датасета VO (итератор)
public void clearVO(){
  MyVOImpl MyVO = getMyVO1();
  int rowCount = MyVO.getRowCount();
  RowSetIterator deleteIter = MyVO.createRowSetIterator("deleteIter");
  if (rowCount > 0) { 
     deleteIter.setRangeStart(0); 
     deleteIter.setRangeSize(rowCount);
     for (int i = rowCount - 1; i > -1; i--) {
         MyVORowImpl row = (MyVORowImpl)deleteIter.getRowAtRangeIndex(i);
         row.remove();
      }
  }
  deleteIter.closeRowSetIterator();
} 
очистка датасета VO (метод)
singleVO.executeEmptyRowSet();
поиск записи в VO
CausesVOImpl causeVO = getCausesVO1();
if (!causeVO.isPreparedForExecution()){
  causeVO.setMaxFetchSize(0);
}
causeVO.executeQuery();
causeVO.setRangeStart(0);
causeVO.setRangeSize(causeVO.getRowCount());
Number causeId = new Number(1);
        
OADBTransaction transaction = getOADBTransaction();
Key keyCauseId = new Key(new Object[] {causeId});
// 1 - макс. количество возвращаемых записей
Row causes[] = causeVO.findByKey(keyCauseId, 1);
if (causes != null && causes.length > 0) {
  CausesVORowImpl causeRowVO = (CausesVORowImpl)causes[0];
  ...
}
построение мастер-детали в компоненте table
1) добавляем атрибут Expand типа String во VO-родитель и в запросе устанавливаем его константой 'N'. Детализация будет отображена только для строк, где (Expand is not null). N - по умолчанию деталь свернута, Y - развернута;
2) создаем View Link (MyVL), которым будут связаны данные, добавляем его и связь с дочерней таблицей в Application Module;
3) родительская таблица: параметр Detail View Attribute = Expand;
4) создаем бин детализации: правый клик по бину родительской таблицы - New - detail. В иерархии table components - detail создаем table layout, в нем создаем table. Можно и без первого, но он может потребоваться для добавления управляющих элементов в деталь;
5) дочерняя таблица: параметр Detail View Attribute = <имя атрибута, через который связывается родительская таблица>, View Link Instance = <имя экземпляра VL из Application Module>
Альтернативный метод связывания мастера и детали программно:
public void setMasterDetailLink(OAPageContext pageContext, OAWebBean webBean) {
OATableBean masterTable = (OATableBean)webBean.findChildRecursive("MasterTable");
if (masterTable != null) {
   masterTable.setAttributeValue(CHILD_VIEW_ATTRIBUTE_NAME, "DetailId");
   masterTable.setAttributeValue(VIEW_LINK_NAME, "MyVL1");
   masterTable.setAllDetailsEnabled(true);
}
        
OATableBean detailTable = (OATableBean)webBean.findChildRecursive("DetailTable");
if (detailTable != null) {
   detailTable.setAttributeValue(CHILD_VIEW_ATTRIBUTE_NAME, "MasterId");
   detailTable.setAttributeValue(VIEW_LINK_NAME, "MyVL1");
   detailTable.clearCache(pageContext);
}
}
форматирование с помощью интерфейса Formatter
private void setColumnsFormat(OAPageContext pageContext, OAWebBean webBean, OAHGridBean hGrid){
    int i;
    String format = "#,##0;-#,##0";
    ArrayList<OAMessageStyledTextBean> columns = new ArrayList<OAMessageStyledTextBean>();
    Formatter formatter = new OADecimalValidater(format, format); 
    String columnNames[] = new String[] {"Col1", "Col2", "Col3"};

    for (String str: columnNames){
        OAMessageStyledTextBean col = (OAMessageStyledTextBean)
               webBean.findChildRecursive(str);
        if (col != null) columns.add(col);
    }

    for (i = 0; i<columns.size(); i++){
        OAMessageStyledTextBean col = columns.get(i);
        col.setAttributeValue(ON_SUBMIT_VALIDATER_ATTR, formatter);           
    }
}
очистка VO при использовании retainAM=Y
Часто возникает проблема: при использовании retainAM (сохранение состояния модуля приложения) мастер-деталь в табличных бинах не отражает текущего состояния данных. Для очищения датасетов во всех VO, связанных с AM, имеет смысл использовать метод
am.clearVOCaches(null,Boolean.TRUE);
содержимое колонки по центру (table)
private void alignCenter(OAPageContext pageContext, OAWebBean webBean) {
OATableBean versionTable = (OATableBean)webBean.findChildRecursive("SearchVO1");
versionTable.prepareForRendering(pageContext);
DataObjectList columnFormats = (DataObjectList)versionTable.getColumnFormats();
DictionaryData columnFormat = null;
//
int childIndex = pageContext.findChildIndex(versionTable, "imgEdit");
columnFormat = (DictionaryData)columnFormats.getItem(childIndex);
columnFormat.put(COLUMN_DATA_FORMAT_KEY, ICON_BUTTON_FORMAT);
// 
childIndex = pageContext.findChildIndex(versionTable, "imgRemove");
columnFormat = (DictionaryData)columnFormats.getItem(childIndex);
columnFormat.put(COLUMN_DATA_FORMAT_KEY, ICON_BUTTON_FORMAT);
}