четверг, 8 апреля 2010 г.

Application Express: создание CSS-кнопки

Создание три кнопки вместо cтандартных в Apex:

  1. Home -> Application Builder -> Application 101 -> Shared Components -> Templates -> Button:

     1.1  Definition (для первой кнопки):
     <span class="buttons">  
     <a href="#LINK#" class="positive">  
      <img src="#IMAGE_PREFIX#themes/ThemeName/img/positive.png" alt=""/>  
       #LABEL#</a>  
     <span>  
    
     1.2 Definition (для второй кнопки):
     <span class="buttons">  
     <a href="#LINK#" class="negative">  
       <img src="#IMAGE_PREFIX#themes/ThemeName/img/negative.png" alt=""/>  
       #LABEL#</a>  
     </span>  
    
     1.3 Definition (для третьей кнопки):
     <span class="buttons">  
       <a href="#LINK#" class="regular">  
       #LABEL#</a>  
     </span>  
    
  2. Создать css-файл для описания кнопки:
     .buttons a, .buttons button{  
       display:block;  
       float:left;  
       margin:0 7px 0 0;  
       background-color:#f5f5f5;  
       border:1px solid #dedede;  
       border-top:1px solid #eee;  
       border-left:1px solid #eee;  
       font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;  
       font-size:12px;  
       line-height:130%;  
       text-decoration:none;  
       font-weight:bold;  
       color:#565656;  
       cursor:pointer;  
       padding:5px 10px 6px 7px; /* Links */  
     }  
     .buttons button{  
       width:auto;  
       overflow:visible;  
       padding:4px 10px 3px 7px; /* IE6 */  
     }  
     .buttons button[type]{  
       padding:5px 10px 5px 7px; /* Firefox */  
       line-height:17px; /* Safari */  
     }  
     *:first-child+html button[type]{  
       padding:4px 10px 3px 7px; /* IE7 */  
     }  
     .buttons button img, .buttons a img{  
       margin:0 3px -3px 0 !important;  
       padding:0;  
       border:none;  
       width:16px;  
       height:16px;  
     }  
     /* STANDARD */  
     button:hover, .buttons a:hover{  
       background-color:#dff4ff;  
       border:1px solid #c2e1ef;  
       color:#336699;  
     }  
     .buttons a:active{  
       background-color:#6299c5;  
       border:1px solid #6299c5;  
       color:#fff;  
     }  
     /* POSITIVE */  
     button.positive, .buttons a.positive{  
       color:#529214;  
     }  
     .buttons a.positive:hover, button.positive:hover{  
       background-color:#E6EFC2;  
       border:1px solid #C6D880;  
       color:#529214;  
     }  
     .buttons a.positive:active{  
       background-color:#529214;  
       border:1px solid #529214;  
       color:#fff;  
     }  
     /* NEGATIVE */  
     .buttons a.negative, button.negative{  
       color:#d12f19;  
     }  
     .buttons a.negative:hover, button.negative:hover{  
       background:#fbe3e4;  
       border:1px solid #fbc2c4;  
       color:#d12f19;  
     }  
     .buttons a.negative:active{  
       background-color:#d12f19;  
       border:1px solid #d12f19;  
       color:#fff;  
     }  
     /* REGULAR */  
     button.regular, .buttons a.regular{  
       color:#336699;  
     }  
     .buttons a.regular:hover, button.regular:hover{  
       background-color:#dff4ff;  
       border:1px solid #c2e1ef;  
       color:#336699;  
     }  
     .buttons a.regular:active{  
       background-color:#6299c5;  
       border:1px solid #6299c5;  
       color:#fff;  
     }  
    
  3. Загрузить данный файл на Web server (аналогично, тому как делается в Интеграции Oracle ApEx и extJS ).
  4. Загрузить следующие картинки в #IMAGE_PREFIX#themes/ThemeName/img:
    positive.png
    negative.png
  5. Получаются такие кнопки:


вторник, 6 апреля 2010 г.

Application Express: что такое Websheets? (на пошаговом примере приложения)

С выходом Apex 4.0 Early Adopter Phase II (EA2) стал доступен один из новых компонентов Apex 4.0 - Websheets. Данная функциональность позволяет конечным пользователям (быстро и просто) вводить, безопасно "расшарить" и предоставлять информацию. С помощью Web-браузера пользователь может создавать (если есть на права) страницы, секции страницы, таблицы и отчёты.


Рассмотрим возможности WebSheets на примере приложения.

  1. Создаём приложение типа WebSheets:
  2. Вводим название приложения (например: WebSheets Demo):
  3. Подтверждаем создание приложения:
  4. Запускаем приложение:
  5. Входим в приложение текущим пользователем Apex (по-умолчанию механизм аутентификации Application Express Account)
  6. Домашняя страница:
  7. Изменим текст региона на домашней странице:
  8. Для работы с текстом используется полноценный WYSIWYG-редактор:
  9. Создадим новую таблицу (DataGrid):
  10. Выбираем тип создаваемой страницы (в нашем случае - From Scratch):
  11. Определяем наименование таблицы и колонки:
  12. Таблица создана:
    Конечный пользователь может изменять свойства таблицы, колонок, добавлять колонки, валидацию, группировку и т.п.
  13. Добавим данные в таблицу:
  14. Получаем по-сути интерактивный отчёт с возможностью изменения структуры таблицы:
  15. Вернёмся на домашнюю страницу и создадим новый регион:
  16. Выбираем тип региона - Data:
  17. Выбираем источник данных:
  18. Завершаем создание региона:
  19. Аналогично добавим регион типа Chart:
  20. Добавим аннотации - один файл, один тэг и одну заметку:
  21. Получилась следующая страница:
  22. Теперь настроим авторизацию. Переходим в меню "Administration" -> "Access Control":
  23. Создаем новую запись(entry):
  24. Создадим ещё одну запись(entry). Получаем:
  25. Теперь зайдя в приложение под пользователем reader (он предварительно должен быть создан) видим что есть только права на просмотр страниц:

Application Express: использование всплывающих модальных окон из фреймворка jQuery

Варианты реализации:

Предлагаю два способа:
  • с использованием плагина SimpleModal;
  • с использованием стандартных диалоговых окон входящих в состав jQuery UI.

На мой взгляд второй вариант предпочтительнее, за счёт использования стандартного функционала Apex 4.0 (jQuery UI) и большей функциональности.

С использованием плагина SimpleModal

  1. Загрузить плагин SimpleModal с сайта: http://www.ericmmartin.com/projects/simplemodal
  2. Создаем две страницы в приложении (одна из которой открывается всплывающее модальное окно, вторая - собственно само содержимое всплывающего окна; в нашем случае страницы №1 и №2 соответственно)
  3. На странице №1 в свойствах установить в закладке "HTML Header and Body Attribute" значение "HTML Header":
     <style type="text/css">  
     body {height:100%; margin:0;}  
     h3 {color:#5f87ae; font-size:1.6em; padding:0; margin:0;}  
     #basic-modal-content {display:none;}  
     /* Overlay */  
     #simplemodal-overlay {background-color:#000; cursor:wait;}  
     /* Container */  
     #simplemodal-container {height:320px; width:600px; color:#bbb; background-color:#333; border:4px solid #444; padding:12px;}  
     #simplemodal-container code {background:#141414; border-left:3px solid #65B43D; color:#bbb; display:block; margin-bottom:12px; padding:4px 6px 6px;}  
     #simplemodal-container a {color:#ddd;}  
     #simplemodal-container a.modalCloseImg {background:url(../img/basic/x.png) no-repeat; width:25px; height:29px; display:inline; z-index:3200; position:absolute; top:-15px; right:-16px; cursor:pointer;}  
     #simplemodal-container #basic-modal-content {padding:8px;}  
     </style>  
     <script type="text/javascript" src="http://simplemodal.googlecode.com/files/jquery.simplemodal-1.3.4.js"></script>  
    
    здесь мы импортируем JavaScript-плагин SimpleModal на страницу, а так же CSS-стили для него:
  4. На странице №1 в свойствах установить в закладке "JavaScript" значение "Function and Global Variable Declaration":
     function modalOpen(pageNumber){  
      var newURL = window.location.protocol + "//" + window.location.host + "/apex/f?p=" +$v('pFlowId')+":"+pageNumber+":"+$v('pInstance')+":::::";  
      apex.jQuery.modal('<iframe src="' + newURL + '" height="100%" width="100%" style="border:0">', {  
      closeHTML:'',  
      containerCss:{  
       backgroundColor:"#fff",  
       borderColor:"#BDBDBD",  
       padding:0,  
       height:200,  
       width:200  
      },  
      overlayClose:false  
      });  
     }  
     function modalClose(){  
       apex.jQuery.modal.close();  
     }  
    
  5. На странице №1 создаём регион и добавляем туда кнопку по нажатие на которую будет открываться всплывающее модальное окно. Для этого в свойствах кнопки в закладке "Action When Button Clicked" установить значения полей:
    Action: Redirect to URL
    URL Target: javascript:modalOpen(2)

    ,где параметр функции есть номер страницы открываемой во всплывающем окне.
  6. Запускаем страницу №1 и нажимаем на кнопку:

С использованием стандартных диалоговых окон входящих в состав jQuery UI

  1. Создаем две страницы в приложении (одна из которой открывается всплывающее модальное окно, вторая - собственно само содержимое всплывающего окна; в нашем случае страницы №1 и №2 соответственно)
  2. На странице №1 в свойствах установить в закладке "JavaScript" значение "Function and Global Variable Declaration":
     var modalDialog=null;  
     function modalOpen(pageNumber,windowTitle,windowWidth,windowHeight){  
      var newURL = window.location.protocol + "//" + window.location.host + "/apex/f?p=" +$v('pFlowId')+":"+pageNumber+":"+$v('pInstance')+":::::";  
      modalDialog=apex.jQuery('<div></div>').html('<iframe src="' + newURL + '" height="100%" width="100%" style="border:0" frameborder="0">').dialog({autoOpen: false,modal: true,height: windowHeight,width: windowWidth,title: windowTitle});  
      modalDialog.dialog('open')  
     }  
     function modalClose(){  
      if (modalDialog!=null){  
       modalDialog.dialog('close');  
       modalDialog=null;  
      }  
     }  
    
  3. На странице №1 создаём регион и добавляем туда кнопку по нажатие на которую будет открываться всплывающее модальное окно. Для этого в свойствах кнопки в закладке "Action When Button Clicked" установить значения полей:
    Action: Redirect to URL
    URL Target: javascript:modalOpen(2,'Testing modal windows!!!',220,220)

    ,где первый параметр функции есть номер страницы открываемой во всплывающем окне, второй - наименование окна, третий - ширина окна, четвертый - высота окна.
  4. Запускаем страницу №1 и нажимаем на кнопку:

Дополнительные материалы:

среда, 31 марта 2010 г.

Зарисовка архитектуры приложения с использованием Application Express

Зарисовка архитектуры приложения, которому требуется интеграция с корпоративными информационными системами через интерфейсы Web-сервисов и Java API

Основная идеология:    В данной архитектуре вынесен "во вне" интеграционный слой - его задачи выполняет прослойка в виде JavaEE-сервера приложения (например: WebLogic, OC4J, JBoss и т.п.). Взаимодействие между ApEx-ом и сервером приложений построено на основе очередей сообщений Oracle Advanced Queuing, т.е. встроенным в СУБД механизмом организации очередей сообщений. Что даёт возможность некоторой балансировки нагрузки на сервер приложений. В нашем случае очередей сообщений две: "для запросов" и "для ответов". На стороне сервера приложения развернуты Message Driven Beans (MDB), которые слушают очередь сообщений "для запросов" и при появлении в ней сообщения обрабатывают его (парсинг; возможен вариант обработки сообщения в Session Bean). В зависимости от результата обработки вызывается метод Session Bean-а, который в свою очередь вызывает Java API или Web-Service корпоративного приложения. После получения ответа данный Session Bean отправляет ответ в очередь сообщений "для ответов", а по появлении в ней сообщения срабатывает процедура обработки в базе данных. Например, вызов Java API (аналогично и для Web-Service) корпоративного приложения:

  1. по нажатию на кнопку в ApEx(может быть любое другое действие) - вызывается хранимая процедура в СУБД;
  2. данная процедура формирует сообщение и отправляет его в очередь сообщений "для запросов";
  3. MDB-компонент слушает очередь сообщений и когда в ней появляется сообщение забирает его из очереди "для запросов" и обрабатывает его;
  4. в зависимости от результата обработки вызывается метод Session Bean-а, который в свою очередь вызывает Java API корпоративного приложения;
  5. по полученому ответу(от корпоративного приложения) данный Session Bean формирует сообщение и отравляет его в очередь сообщений "для ответов";
  6. на стороне базы данных для очередь "для ответов" выполняется процедура обработки сообщения и согласно результатам выполняется какое-либо действие (например: изменяются данные с таблице).

Плюсы данного подхода:    Интеграционная часть вынесена из базы данных. Что даёт возможность:

  • Вынесение интеграционного слоя в том числе на отдельную машину;
  • Распределения нагрузки между СУБД и сервером приложений.
  • Возможность использования всех интеграционных возможностей платформы Java EE

Минусы данного подхода:

  • Требуется дополнительное программное обеспечение ввиде сервера приложения;
  • Требуется разработка EJB-компонентов (MDB и Session Beans) на языке Java.

суббота, 6 марта 2010 г.

Установка и интеграция Oracle Application Express 3.2 и Oracle e-Business Suite R12

Установка Oracle Application Express

  1. Скачиваем дистрибутив Oracle Application Express по ссылке:
    http://www.oracle.com/technology/products/database/application_express/download.html

  2. Распаковываем скаченный zip-архив (apex_3.2.zip):
     $ unzip apex_3.2.zip  
    
  3. Переходим в директорию apex (которая создастся после распаковки архива)
     $ cd  apex  
    
  4. Запускаем SQL Plus и соединаемся с БД как sys as sysdba
     $ sqlplus /nolog  
     SQL> CONNECT SYS as SYSDBA  
    
  5. В SQL Plus выполняем команду в формате:
     SQL> @apexins tablespace_apex tablespace_files tablespace_temp images  
    
    Например :
     SQL> @apexins APEX_TBS APEX_TBS APEX_TBS_TEMP /i/  
    
  6. После завершения выполнения предыдущего пункта – запускаем SQL Plus и соединяемся с БД как sys as sysdba (см. Шаг 4).
  7. В SQL Plus выполняем команду:
     SQL> @apxchpwd  
    
    Устанавливаем пароль для администратора Application Express (пользователь ADMIN)
  8. Необходимо перестартовать инстанс БД и процесс прослушивателя (listener).
  9. Запускаем SQL Plus и соединяемся с БД как sys as sysdba (см. Шаг 4).
  10. В SQL Plus выполняем команду:
     SQL> ALTER USER APEX_PUBLIC_USER ACCOUNT UNLOCK  
    
  11. Выполняем следующую команду:
     SQL> ALTER USER APEX_PUBLIC_USER IDENTIFIED BY new_password  
    
    где new_password – заменить на пароль для APEX_PUBLIC_USER
  12. Скачать дистрибутив Oracle HTTP Server для соответствующей версии СУБД используемой в Oracle e-Business Suite. Например: для Oracle 11g R1 на платформе AIX по ссылке:
    http://www.oracle.com/technology/software/products/database/oracle11g/111060_aixsoft.html

  13. Установить Oracle HTTP Server используя Oracle Universal Installer
  14. Скопировать директорию apex/images (которая создастся после распаковки архива) в директорию ORACLE_HTTPSERVER_HOME/ohs:
     $ cp –rf apex/images ORACLE_HTTPSERVER_HOME/ohs  
    
    где ORACLE_HTTPSERVER_HOME – директория, где установлен Oracle HTTP Server.
  15. Используя текстовый редактор изменям файл конфигурации Oracle HTTP Server - ORACLE_HTTPSERVER_HOME/ohs/modplsql/conf/dads.conf:
     $ vi ORACLE_HTTPSERVER_HOME/ohs/modplsql/conf/dads.conf  
    
  16. Добавляем в данный файл следующий фрагмент в конец файла:
     Alias /i/ "ORACLE_HTTPSERVER_HOME/ohs/images/"  
     AddType text/xml xbl  
     AddType text/x-component htc  
     <Location /pls/apex>  
     Order deny,allow  
     PlsqlDocumentPath docs  
     AllowOverride None  
     PlsqlDocumentProcedure wwv_flow_file_mgr.process_download  
     PlsqlDatabaseConnectString host:port:service_name ServiceNameFormat  
     PlsqlNLSLanguage AMERICAN_AMERICA.AL32UTF8  
     PlsqlAuthenticationMode Basic  
     SetHandler pls_handler  
     PlsqlDocumentTablename wwv_flow_file_objects$  
     PlsqlDatabaseUsername APEX_PUBLIC_USER  
     PlsqlDefaultPage apex  
     PlsqlDatabasePassword apex_public_user_password  
     PlsqlRequestValidationFunction wwv_flow_epg_include_modules.authorize  
     Allow from all  
     </Location>  
    
    Необходимо изменить в данной фрагменте значения ORACLE_HTTPSERVER_HOME, host, port, service_name и apex_public_user_password на соответствующие Вашей системе. И в случае наобходимости значение параметра PlsqlNLSLanguage

  17. Перезапустить Oracle HTTP Server выполнив последовательно две команды:
     ORACLE_HTTPSERVER_HOME/opmn/bin/opmnctl stopproc ias-component=HTTP_Server  
     ORACLE_HTTPSERVER_HOME/opmn/bin/opmnctl startproc ias-component=HTTP_Server  
    
  18. Если СУБД - Oracle RDBMS 11g, то выполняем скрипт в SQL Plus (от sys as sysdba):
     DECLARE  
      ACL_PATH VARCHAR2(4000);  
      ACL_ID RAW(16);  
     BEGIN  
      -- Look for the ACL currently assigned to '*' and give APEX_030200  
      -- the "connect" privilege if APEX_030200 does not have the privilege yet.  
      SELECT ACL  
      INTO ACL_PATH  
      FROM DBA_NETWORK_ACLS  
      WHERE HOST   = '*'  
      AND LOWER_PORT IS NULL  
      AND UPPER_PORT IS NULL;  
      -- Before checking the privilege, ensure that the ACL is valid  
      -- (for example, does not contain stale references to dropped users).  
      -- If it does, the following exception will be raised:  
      --  
      -- ORA-44416: Invalid ACL: Unresolved principal 'APEX_030200'  
      -- ORA-06512: at "XDB.DBMS_XDBZ", line ...  
      --  
      SELECT SYS_OP_R2O(extractValue(P.RES, '/Resource/XMLRef'))  
      INTO ACL_ID  
      FROM XDB.XDB$ACL A,  
       PATH_VIEW P  
      WHERE extractValue(P.RES, '/Resource/XMLRef') = REF(A)  
      AND EQUALS_PATH(P.RES, ACL_PATH)       = 1;  
      DBMS_XDBZ.ValidateACL(ACL_ID);  
      IF DBMS_NETWORK_ACL_ADMIN.CHECK_PRIVILEGE(ACL_PATH, 'APEX_030200', 'connect') IS NULL THEN  
       DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(ACL_PATH, 'APEX_030200', TRUE, 'connect');  
      END IF;  
     EXCEPTION  
      -- When no ACL has been assigned to '*'.  
     WHEN NO_DATA_FOUND THEN  
      DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('power_users.xml', 'ACL that lets power users to connect to everywhere', 'APEX_030200', TRUE, 'connect');  
      DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('power_users.xml','*');  
     END;  
     /  
     COMMIT;  
    
  19. Если СУБД - Oracle RDBMS 11g, то выполняем скрипт в SQL Plus (от sys as sysdba):
     DECLARE  
      ACL_PATH VARCHAR2(4000);  
      ACL_ID RAW(16);  
     BEGIN  
      -- Look for the ACL currently assigned to 'localhost' and give APEX_030200  
      -- the "connect" privilege if APEX_030200 does not have the privilege yet.  
      SELECT ACL  
      INTO ACL_PATH  
      FROM DBA_NETWORK_ACLS  
      WHERE HOST   = 'localhost'  
      AND LOWER_PORT IS NULL  
      AND UPPER_PORT IS NULL;  
      -- Before checking the privilege, ensure that the ACL is valid  
      -- (for example, does not contain stale references to dropped users).  
      -- If it does, the following exception will be raised:  
      --  
      -- ORA-44416: Invalid ACL: Unresolved principal 'APEX_030200'  
      -- ORA-06512: at "XDB.DBMS_XDBZ", line ...  
      --  
      SELECT SYS_OP_R2O(extractValue(P.RES, '/Resource/XMLRef'))  
      INTO ACL_ID  
      FROM XDB.XDB$ACL A,  
       PATH_VIEW P  
      WHERE extractValue(P.RES, '/Resource/XMLRef') = REF(A)  
      AND EQUALS_PATH(P.RES, ACL_PATH)       = 1;  
      DBMS_XDBZ.ValidateACL(ACL_ID);  
      IF DBMS_NETWORK_ACL_ADMIN.CHECK_PRIVILEGE(ACL_PATH, 'APEX_030200', 'connect') IS NULL THEN  
       DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(ACL_PATH, 'APEX_030200', TRUE, 'connect');  
      END IF;  
     EXCEPTION  
      -- When no ACL has been assigned to 'localhost'.  
     WHEN NO_DATA_FOUND THEN  
      DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('local-access-users.xml', 'ACL that lets power users to connect to everywhere', 'APEX_030200', TRUE, 'connect');  
      DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('local-access-users.xml','localhost');  
     END;  
     /  
     COMMIT;  
    
  20. Установка завершена

Интеграция с аутентификацией Oracle e-Business Suite

  1. Создать функцию (или пакет содержащий данную функцию):
     FUNCTION ebiz_suite_auth(  
       p_username IN VARCHAR2,  
       p_password IN VARCHAR2)  
      RETURN BOOLEAN  
     AS  
     BEGIN  
      IF fnd_web_sec.validate_login(p_username, p_password) = 'Y' THEN  
       RETURN true;  
      ELSE  
       RETURN false;  
      END IF;  
     END;  
    
  2. Создать новую схему аутентификации:
    1. Перейти из приложения в “Shared Components”->”Authentication Schemes”.
    2. Нажать кнопку “Create”.
    3. Выбрать тип создаваемой темы как “From scratch”. Нажать “Next”.
    4. Ввести имя схемы аутентификации, например: “eBusiness Suite Authentication”. Нажать “Next”.
    5. Оставить все значения полей по-умолчанию в шагах: Page Sentry Function, Session Verify Function, Invalid Session Target, Invalid Session Target.
    6. На шаге “Authentication Function” выбрать “Use my custom function to authenticate” и ввести в поле: “return ebiz_suite_auth;”. Нажать “Next”.
    7. Оставить все значения полей по-умолчанию в шагах: Post Authentication Process, Cookie Attributes.
    8. На шаге “Logout URL” ввести: “wwv_flow_custom_auth_std.logout?p_this_flow=&APP_ID.&p_next_flow_page_sess=&APP_ID.:1:&SESSION.”. Нажать “Next”.
    9. На следующем шаге нажать “Create Scheme”. Схема создана
  3. Необходимо изменить два параметра созданной схемы:
    1. Перейти из приложения в “Shared Components”->”Authentication Schemes”.
    2. Выбрать созданную схему. В нашем случае это “eBusiness Suite Authentication”.
    3. Изменить значение поля “Session Not Valid Page” на 101 (это номер страницы логина), а значение поля “-Or- Session Not Valid URL” должно быть пустым.
    4. Нажимаем “Apply Changes”.
  4. Сделать созданную схему аутентификации активной:
    1. Перейти из приложения в “Shared Components”->”Authentication Schemes”.
    2. Перейти на вкладку “Change Current”.
    3. Выбрать для пункта “Available Authentication Schemes” наименование созданной схемы аутентификации. В нашем случае это “eBusiness Suite Authentication”. И нажать “Next”.
    4. Нажать “Make current.”