Sabtu, 25 April 2015

New Development Environment: Oracle 12c, APEX 4.2.6, APEX 5, ORDS 3.0 and Tomcat 8

APEX 5 now release into production with big impact and wow features, as part of continuous learning process, now I am preparing new development environment on my laptop (Windows 8.1 SL).
Oracle Database 12c enable to create separated environment with multiple APEX version in a single db instance. APEX 4.2.6 is my recent stable applications and APEX 5 as new learning development.

Dev Environment:
  • APEX 4.2.6 on PDB426
  • APEX 5 on PDB500


Installation
  • Create 2 PDB : PDB426 and PDB500
  • Uninstall apex on CDB
  • Install APEX 4.2.6 on PDB426 with images /i/
  • Install APEX 5 on PDB500 with images /i5/
  • Setup ORDS as APEX4 for APEX 4.2.6 container => change ords.war to apex4.war
  • Setup ORDS as APEX5 for APEX 5 container => change ords.war to apex5.war
ORDS installation Tomcat 8 :
  • Unzip Ords into temp directory : C:\temp\apex4 and C:\temp\apex5

  • Create separated config directory for each apex version : C:\Tomcat\apex4-config and C:\Tomcat\apex5-config.

  • Install ords for each version
  • Copy apex4.war and apex5.war to \tomcat-home\webapps

  • Copy APEX images to  \tomcat-home\webapps\ROOT don't forget to change images into i and i5 folder

  • Run Tomcat and enjoy :D
Now you have 2 APEX version in single instance
  • APEX 4.2.6 : http://localhost:8080/apex4/f?p=4550:1

  • APEX 5 : http://localhost:8080/apex5/f?p=4550:1

Selasa, 03 Februari 2015

How to use modal pop-up region

APEX telah menyediakan banyak contoh applikasi, salah satunya adalah Sample Dialog. Disitu kita akan belajar tentang bagaimana memakai dialog dengan teknik jQuery UI atau Custom Modal region untuk theme 25.

Namun untuk kasus modal region kita akan lihat bahwa modal dialog default adalah false. 
oh ya..saran saya jika kita memakai Theme 25 untuk membangun applikasi lebih baik kita bangun dialog dengan memakai region modal jangan memakai UI dialog biasa untuk pertimbangan estetika tampilan yg lebih oke. Untuk membuat modal dialog menjadi "true" maka tambahkan kode berikut saat memanggil regionnya.
function(){
  openModal('addDept');
  gBackground.off('click');
}
Untuk pemakaian dalam form process pop-up, nanti saya akan posting dengan kombinasi iFrame.

Note : Terima kasih buat bro Hoki yang telah men-debug dan mencarikan solusinya.

APEX 5 Tree Enhancement

APEX Early Adopter 3 telah release, kemaren telah terdaftar dan mencoba nya. Banyak sekali peningkatan yang signifikan dalam versi ini, yang paling ingin saya coba adalah universal theme.

Berikut beberapa ujicoba yang telah saya lakukan.

  • Mencoba implementasi jstree terbaru ke dalam APEX. dalam hal ini kita memperoleh feature
    • APEX dapat menerima file zip library dan otomatis di unzip kedalam Static Workspace Files.
    • Kita tidak perlu merubah referensi apapun di file CSS, tinggal pakai seperti halnya kita melakukan zip di file explorer.
  • Mencoba APEX tree.
    • Ada jenis tree baru yaitu : APEX Tree
    • APEX tree bisa memakai custom vector icon seperti font-awesome
    • Contoh query
    •  select case 
                when connect_by_isleaf = 1 then 0
                when level = 1             then 1
                else                           -1
              end as status 
            , level
            , m.description as title
            , case 
                when m.status = 'X' then 'fa-home fa-lg'
                when m.status = 'M' then 'fa-folder-open-o fa-lg'
                when m.status = 'F' then 'fa-book fa-lg'
                when m.status = 'R' then 'fa-table fa-lg'
                when m.status = 'T' then 'fa-tasks fa-lg'
                when m.status = 'C' then 'fa-bar-chart fa-lg'
                when m.status = 'S' then 'fa-cubes fa-lg'
              end as icon
            , m.id as value
            , m.tooltip as tooltip
            , 'f?p=&APP_ID.:&APP_PAGE_ID.:&SESSION.::::P3_ID,P3_SELECTED:'||m.id||','||m.id as link 
         from my_menu m
        start with m.status = 'X'
      connect by prior m.id = m.parent_id
        order siblings by m.SEQ
      

Sabtu, 17 Januari 2015

APEX AJAX and how to use apex.server.process

Pada kasus pemkaian dynamic biasanya kita telah terbiasa memakai fitur dari APEX yaitu Dynamic Action (DA). DA merupakan salah satu fitur terbaik yang dimiliki oleh APEX untuk melakukan proses AJAX dan hal lain dengan secara declarative dan bisa di gabunkan dengan kondisi dan sekuriti. Namun pada kasus-kasus khusus  nanti kita tetap perlu untuk membangun AJAX secara manual tanpa atau dikombinasikan dengan DA.

APEX telah menyediakan API untuk hal ini, namun sayang sangat ringkas sehingga perlu try-error untuk memahaminya. Tulisan Tom Petrus sangat mencerahkan dan detail untuk memahami hal ini. saya sangat merekomendasikan untuk membacanya untuk memahami gambaran besar APEX AJAX. 

Adapun hal yang harus diperhatikan adalah APEX AJAX adalah :
  • Gunakan documented API dalam hal ini (apex.server.process) untuk pembuatan proses AJAX supaya dalam perkembangannya jika aplikasi di migrasi ke versi yang terbaru tidak muncul masalah.
  • Dalam apex.server.process return default adalah JSON, jadi hati-hati karena meskipun kita telah membangun data dengan konstruksi JSON jika dilakukan lewat PL/SQL maka akan selalu menjadi string atau text, jadi untuk proses ini salalu gunakan opsi = dataType: "text". Setelah itu dalam proses JS kita bisa parsing kedalam JSON object memakai jQuery.parseJSON(pData)
  • Opsi = success agak membingunkan sering diartikan bahwa disitu untuk hadle proses sukses saja, namun sebenarnya adalah untuk funsi callback yang dilakukan setelah memperoleh return data dari proses pl/sql.
  • Cara melakukan passing parameter, item, value dan array.
Silahkan akses contoh pemakaiannya di demo ini disitu akan diperlihatkan contoh code javascript dan pl/sql yang digunakan. Selamat mencoba.

Miscellaneous Javascript APIs

  • $x(pNd)
  • Adalah sebuah padanan dari getElementById(). Dengan pNd adalah id dari DOM atau string "id". returnnya adalah DOM element atau false jika tidak ada.
    contoh : $x(P43_TEXT) atau $x("P43_TEXT").
    Pemakaian untuk get: $x("P43_TEXT").value, $x("P43_TEXT").name
    Pemakaian untuk set: $x("P43_TEXT").value="Test", $x("P43_TEXT").name="test"
    Namun tidak semua jenis item dapat dilakukan operasi tersebut seperti checkbox, selectlist dan shuttle.
  • $v(pNd), $v2(pNd), apex.item(pNd).getValue(),$f_SelectValue(pNd) dan $("#pNd").val()
  • Semuanya pada dasarnya adalah untuk mendapatkan value dari sebuah item, namun memiliki beberapa perbedaan. Pada test kasus item berikut :
    • Hidden, text, text area, date picker, popup lov (basis input) semua berhasil memperoleh value, khusus untuk display only $("#pNd").val() memakai $("#pNd").text()
    • selectlist, checkbox, radiogroup, list manager hanya $v(pNd) $v2(pNd) apex.item(pNd).getValue() dan $f_SelectValue(pNd) yang bisa memperoleh value
    • $v2(pNd) adalah shortcut untuk apex.item(pNd).getValue()
    • untuk kasus item multiple value perbedaan dari $v(pNd) dan $v2(pNd) adalah $v(pNd) mendapatkan nilai persis string dari item sedangkan $v2(pNd) dalam bentuk array
    • Kesimpulan yang dapat diambil adalah selalu gunakan APEX APIs $v(pNd) atau $v2(pNd) untuk mengambil nilai item.
  • $s(pNd, pValue, pDisplayValue, pSuppressChangeEvent), apex.item( pNd ).setValue(pValue, pDisplayValue, pSuppressChangeEvent), $x_Value(pNd,pValue) dan $("#pNd").val("pValue")
  • Sama halnya dengan kasus get selalu gunakan APEX APIs, $s(pNd, pValue, pDisplayValue, pSuppressChangeEvent) adalah shortcut untuk apex.item( pNd ).setValue(pValue, pDisplayValue, pSuppressChangeEvent). Kelebihan dari $s( pNd,pValue, pDisplayValue, pSuppressChangeEvent) adlah kita bisa melakukan pada semua jenis item dengan bisa mengatur pSuppressChangeEvent property ini berguna dalam urusan Dynamic Actions
  • Silahkan coba fungsi2 diatas pada page demo berikut

Jumat, 10 Oktober 2014

Get Yahoo Exchange Rate using PL/SQL

Setelah mencari api yang disediakan oleh Bank Indonesia atau bank-bank swasta/nasional indonesia tidak tersedia. maka dengan terpaksa kebutuhan exchange rate real time saya ambil dari yahoo api.

Melalui Yahoo Query Language kita dapat peroleh URI untuk exchange rate USD-IDR :

http://query.yahooapis.com/v1/public/yql?q=select * from yahoo.finance.xchange where pair in ("USDIDR")&env=store://datatables.org/alltableswithkeys

Lalu kemudian kita bangun fungsi didalam oracle untuk bisa dipakai dalam operasi sql pl/sql atau di APEX.

create or replace function get_yahoo_rate 
return number 
is

/******************************************************************************
   NAME:       get_yahoo_rate
   PURPOSE:    get latest USD-IDR rate from Yahoo finance exchange

   REVISIONS:
   Ver        Date        Author           Description
   ---------  ----------  ---------------  ------------------------------------
   1.0        10/10/2014   Lutfi Hedir     1. Created this function.

******************************************************************************/
  l_xml xmltype;
  l_yahoo_uri constant varchar2(500) := 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22USDIDR%22)&env=store://datatables.org/alltableswithkeys';
  l_rate      varchar2(500);
  l_rate_n    number(10);
begin
  -- get xml data
  l_xml := xmltype(utl_http.request(l_yahoo_uri));
  -- extract rate value from xml data  
  select extractvalue(l_xml, '/query/results/rate/Rate/text()') into l_rate
    from dual;  
  -- convert to number   
  l_rate_n := to_number(REGEXP_SUBSTR(l_rate,'[0-9]+'));
  
  return l_rate_n;
  
end get_yahoo_rate;
/


Catatan :
  • Jangan lupa setting ACL untuk 11g supaya bisaakses internet.
  • Jika akses SSL buatlah wallet terlebih dahulu
  • Jika akses proxy modifikasi utl_http.request dengan signature proxy dan wallet

Selasa, 23 September 2014

How to create executable package/procedure on URL

Posting ini sebenarnya pernah saya bahas, namun sekarang saya akan membahasnya lebih spesifik pada download file dengan web server apex listener.

Adapun hal yang harus diperhatikan pada bagian
  1. Package/procedure
    • Contoh
    • create or replace PACKAGE BODY web_utils IS
        -- retrieves image from blob in product info
        PROCEDURE display_bu_logo (p_id number, p_product_name varchar2) 
        IS
          l_mime        varchar2 (255);
          l_length      number;
          l_file_name   varchar2 (2000);
          lob_loc       blob;
        begin
          if p_id is not null then
            select mimetype
                 , filename
                 , nvl(product_image, empty_blob()) blob_content
                 , dbms_lob.getlength(product_image)
              into l_mime
                 , l_file_name
                 , lob_loc 
                 , l_length
              from demo_product_info
             where product_id = p_id;    
          elsif p_product_name is not null then
            select mimetype
                 , filename
                 , nvl(product_image, empty_blob()) blob_content
                 , dbms_lob.getlength(product_image)
              into l_mime
                 , l_file_name
                 , lob_loc 
                 , l_length
              from demo_product_info
             where lower(product_name) = lower(p_product_name);     
          end if;
      
      
         owa_util.mime_header (nvl (l_mime, 'application/octet'), false);
      
         -- set the size so the browser knows how much to download
         htp.p ('Content-length: ' || l_length);
         -- the filename will be used by the browser if the users does a save as
         htp.p (   'Content-Disposition:  attachment; filename="'
                || replace (replace (substr (l_file_name,
                                             instr (l_file_name, '/') + 1
                                            ),
                                     chr (10),
                                     null
                                    ),
                            chr (13),
                            null
                           )
                || '"'
               );
      
         -- close the headers
         owa_util.http_header_close;
         -- download the BLOB
         wpg_docload.download_file (lob_loc);
      
        END display_bu_logo;
      END web_utils;
      
    • Tambahkan nvl(lob_column, empty_blob())
    • Gunakan htp.p
    • Untuk kasus image jika ingin tampil inline, lakukan comment pada bagian
    • --   htp.p (   'Content-Disposition:  attachment; filename="'
      --          || replace (replace (substr (l_file_name,
      --                                       instr (l_file_name, '/') + 1
      --                                      ),
      --                               chr (10),
      --                               null
      --                              ),
      --                      chr (13),
      --                      null
      --                     )
      --          || '"'
      --         );
      
  2. Security
    • Anda harus tahu environment server apa yang dipakai, apakah EPG, OHS atau APEX Listener
    • Untuk APEX Listener/OHS anda cukup grant APEX_PUBLIC_USER
    • Untuk OHS grant APEX_PUBLIC_USER dan daftarkan procedure yang akan dipanggil di APEX_XXXXXX.wwv_flow_epg_include_mod_local
    • Untuk EPG anda grant ke ANONYMOUS dan aktifkan procedure di APEX_XXXXXX.wwv_flow_epg_include_mod_local
  3. Cara memanggil dengan signature parameter.
    • mulai dengan ? pisahkan dengan &
    • Posisi tidak penting namun harus disebutkan semua kecuali punya default value
    • Untuk kasus APEX listener parameter signature akan selalu dirubah dengan menjadi lowercase, hati-hati jika memakai parameter non-case-sensitive seperti BI Publisher web service
    • contoh
    • http://localhost:8888/ords/hr.web_utils.display_bu_logo?p_product_name=Blouse&p_id=
      
    • contoh array parameter
    • http://localhost:8888/ords/!hr.web_utils.display_bu_logo?p_product_name=Blouse&p_id=
      
Catatan :
  • APEX Listener / ORDS 2.0.8.163.10.40