direct printing 2
Library pencetak PDF menggunakan ‘pdfrenderer’.
Supaya Jasperreport mencetak PDF hasil ke suatu direktori di server gunakan method berikut: ‘JasperRunManager.runReportToPdfFile’
Umumnya aplikasi j2ee dijalankan dari dalam WAR atau EAR, maka supaya tersedia direktori tempat penyimpanan data harus disiapkan suatu direktori tersendiri di server. Definisikan path ke direktori tersebut menggunakan tag ‘<context-param>’ di ‘web.xml’ sbb:
<context-param> <param-name>jdevlab.REPORT_DIR</param-name> <param-value>f:/temp/adfupload</param-value> </context-param>
Untuk OS Linux, harus disesuaikan nama nama direktori. misalnya ‘/app/user/report’. Pastikan OAS mendapat hak akses untuk read write ke direktori tersebut.
Untuk memperoleh nilai direktori tersebut gunakan statement berikut di backing bean:
FacesContext context = FacesContext.getCurrentInstance();
ServletContext sc = (ServletContext) context.getExternalContext().getContext();
String strOutputFile = sc.getInitParameter("jdevlab.REPORT_DIR") + "/result.pdf";
Nama file report yang dihasilkan di beritahukan ke applet menggunakan applet parameter sbb:
<f:verbatim>
<applet archive="printpdf.jar" code="pdfrendererlab.PdfPrint"
codebase="../commonapplet/" height="35" width="75">
<param name="FILENAME"
value="${backing_report_testReport.outputFileName}"/>
</applet>
</f:verbatim>
Perhatikan EL yang digunakan menggunakan awalan ‘$’, bukan ‘#’ seperti umumnya pada aplikasi JSF/ADF. Pada Jdev 10.1.3.3 EL yang menggunakan awalan ‘#’ pada bagian content ‘f:verbatim’ tidak dievaluasi. Mungkin karena bagian yang terdapat dalam ‘f:verbatim’ dianggap sebagai JSP biasa.
Untuk menghandle request print dari Applet digunakan Servlet. Berikut configurasi servlet di ‘web.xml’:
<servlet> <servlet-name>ReportPdfServlet</servlet-name> <servlet-class>lab.view.servlet.ReportPdfServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ReportPdfServlet</servlet-name> <url-pattern>/reportdir/*</url-pattern> </servlet-mapping>
to be continued
direct printing 1
Tujuan: dari aplikasi web j2ee, server bisa mencetak pada printer yang terpasang pada komputer client. Misalnya pembuatan report dilakukan dengan jasperreport. Jasperreport dieksekusi di server lalu hasilnya langsung tercetak printer client.
Upaya pencarian melalui Google dan Yahoo menghasilkan pendapat umum sbb:
- PHP versi windows bisa mengerjakan hal tersebut. (Belum dibuktikan)
- Aplikasi web tidak diperbolehkan mengerjakan hal tersebut, karena itu berarti lubang pada security. Bayangkan ketika kita mengakses Yahoo lalu tiba-tiba server Yahoo bisa mencetak di printer kita.
- Ada beberapa solusi komersial non opensource dengan harga kira-kira $ 8000 per server.
- Belum ada solusi open source yang cukup memuaskan.
- Belum tahu apakah Javascript punya fasilitas direct printing
Setelah berdiskusi dengan Google dan Yahoo, diperoleh ide dasar untuk membuat solusi sederhana masalah ini sbb:
- Jasperreport menghasilkan report dalam format PDF di server
- Karena applet bisa mengakses printer, maka dibuat applet yang bisa membaca dari direktori server dan mengirimnya ke printer.
- Supaya applet bisa mengirim pdf ke printer, maka harus dicari library-library yang bisa melakukan pencetakan PDF
- Setelah selesai mencetak, bila diharuskan, hapus file PDF yang terletak di webserver
Ketika ditanya mengenai library java yang mencetak PDF, Google dan Yahoo sepakat memberikan alternatif:
- pdfbox
- icepdf
- pdfrenderer
- dll, maksudnya ada yang lain tetapi belum menarik untuk dieksplorasi lebih lanjut
Ketika framework j2ee yang digunakan untuk membangun aplikasi adalah ADF, isu-isu ini timbul:
- Bagaimana applet bisa memerintahkan server untuk mencetak report?
- Bagaimana ADF bisa memberitahu applet apa nama report yang dihasilkan dan dimana lokasinya. Pertanyaan dimana lokasinya juga terkait dengan kebiasaan ADF menggunakan nama folder ‘faces’ yang merupakan folder virtual. Contoh : http://nama_server/nama_app/faces/thepage.jspx Apakah ini akan menimbulkan masalah???
- Bagaimana kalau aplikasi tersebut dijalankan dari dalam WAR atau EAR? Apakah proses penulisan file akan tetap normal seperti bila dijalankan dari exploded app?
change second soc value
Misalkan ada suatu bean :
class EntryForm
{
String name;
Double brandId;
Double brandTypeId;
}
Baik ‘brandId’ dan ‘brandTypeId’ akan dipilih menggunakan selectOneChoice. Nilai pilihan yang tersedia misalnya dalam format (id -> description) :
pilihanBrandId{ 46122 -> honda, 46125 -> yamaha, 46126 -> suzuki, 46127->kawasaki, 46128->’belum memiliki’}
pilihanBrandTypeId{ 46123->sport, 46129->matic, 46130->bebek, 46131->’belum memiliki’}
Skenario yang diminta, bila brandId dipilih ‘belum memiliki’ maka brandTypeId secara otomatis diset ke ‘belum memiliki’.
Untuk memfasilitasi pembuatan SelectOneChoice dibuat suatu managed bean dengan scope ‘session’, diberi nama DoubleSocHelper.java. File ini bisa dilihat dalam source yang disertakan. DoubleSocHelper ini memperoleh data dari pageDef yang diinsert melalui faces-config.xml.
Supaya nilai ID brandId dan brandTypeId tidak perlu dihardcode ke file java, maka nilai-nilai yang menyebabkan perubahan value di selectOneChoice ke dua disimpan dalam managed bean sbb :
<managed-bean>
<managed-bean-name>doubleSocMap</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<map-entries>
<key-class>java.lang.Double</key-class>
<value-class>java.lang.Double</value-class>
<map-entry>
<key>46128</key>
<value>46131</value>
</map-entry>
</map-entries>
</managed-bean>
Berikut dua soc yang digunakan :
<af:selectOneChoice label="brand"
value="#{bindings.brandId.inputValue}"
binding="#{backing_doublesoc_createDocdata.socBrand}"
id="socBrand"
valueChangeListener="#{backing_doublesoc_createDocdata.brandValueChangeListener}"
immediate="true" autoSubmit="true">
<f:selectItems value="#{doubleSocHelper.brandSelectItems}"
binding="#{backing_doublesoc_createDocdata.selectItems1}"
id="selectItems1"/>
</af:selectOneChoice>
<af:selectOneChoice label=”brand type”
value=”#{bindings.brandTypeId.inputValue}”
binding=”#{backing_doublesoc_createDocdata.socBrandType}”
id=”socBrandType” immediate=”true”
partialTriggers=”socBrand”>
<f:selectItems value=”#{doubleSocHelper.brandTypeSelectItems}”
binding=”#{backing_doublesoc_createDocdata.selectItems2}”
id=”selectItems2″/>
</af:selectOneChoice>
SelectOneChoice pertama menggunakan valueChangeListener sbb:
public void brandValueChangeListener(ValueChangeEvent vce)
{
Double dblNewValue = (Double) vce.getNewValue();
Double dblSoc2Target = (Double) JSFUtils.getManagedBeanValue(“doubleSocMap[" + dblNewValue.toString() + "]“);
if (dblSoc2Target == null)
{
// do nothing
}
else
{
socBrandType.setValue(dblSoc2Target);
}
}
May the source be with you. download, rename jadi zip lalu extract.
toplink mapping 1
Membuat mapping Toplink dengan objective sbb:
- bisa menampilkan attribute dari object yang direferensi.
- bisa melakukan persistEntity dan mergeEntity secara benar
- bisa membatalkan seluruh transaksi bila ternyata nilai object yang direferensi tidak ditemukan
- nilai bisa diset dengan selectOneChoice, selectOneRadi
Untuk mendemonstrasikan mapping, dibuat 3 table sbb:
- person(id int, code varchar, name varchar, birthdate)
- position(id int, parent_id int, code varchar, name varchar, description varchar)
- employee(id int, code varchar, person_id int, position_id int, entrydate date, permanentdate date)
Seperti biasa seluruh ke-3 table menggunakan field ID sebagai primary key. Table employee mempunyai foreign key ke table person dan position.
Objective 1:
Buat kelas baru misalnya bernama EmployeeView2 sebagai turunan dari class Employee. Langkah-langkah pembuatan mapping sbb :
- klik kanan di toplinkMap structure editor. pilih Inherited Field -> Map to SuperClass
- Associated Table pilih table Employee
- lakukan mapping per field secara manual. field id, code, entrydate, permanentdate di map ‘direct to field’. Pilih field di database secara manual.
- field person dan position di map sebagai ‘One-To-One’. Pilih table Person dan table Position sebagai target map.
Buka class EmployeeView2. Tambahkan dua attribute berikut:
private String personName;
private String positionName;
Generate accessor untuk kedua attribute diatas.
Kembali buka toplinkMap.
- buka structure editor
- klik kanan di class EmployeeView2
- pilih ‘Advanced Properties –> Multitable Info’
- tekan tombol Add di bawah textfield Additional Table.
- tambahkan table Person dan Position. Foreign key yang digunakan akan langsung terpilih secara otomatis.
- kembali ke Structure Editor
- map field personName sebagai ‘Direct To Field’ ke field PERSON.NAME. tick checkbox ReadOnly.
- map field positionName sebagai ‘Direct To Field’ ke field POSITION.NAME. tick checkbox ReadOnly.
Pada tahap ini, lakukan ‘Create Data Control’. Buat satu jspx, buat table dengan drag drop findAllEmployeeView2. Lihat bahwa isi field personName dan positionName tampil dengan sendirinya.
.. to be continued ..
source. Download, ubah extension jadi zip, lalu extract. WordPress tidak mengizinkan attachment berextension ‘zip’.
adf constructor form langsung refresh
ADF menyediakan fasilitas create form menggunakan constructor. Cara paling sederhana adalah membuat JSPX baru, lalu ke tab Data Control, pilih salah satu dari constructor yang tersedia disitu. Untuk proses simpan tinggal drag drop tombol dari function persistEntity di DataControl.
Default tingkah laku form yang dihasilkan, tetap menampilkan data yang lama setelah dilakukan proses save (persistEntity). Adakalanya diperlukan langsung mengosongkan form setelah proses persist. Form sekarang siap untuk menerima data baru. Hal tersebut dapat dilakukan dengan mudah.
Berikut adalah salah satu contoh PageDef yang dihasilkan dengan menarik constructor dari DataControl :
<executables>
<invokeAction Binds="Position" id="invokePosition" Refresh="renderModel" RefreshCondition="${!adfFacesContext.postback and empty bindings.exceptionsList}"/>
<methodIterator DataControl="SessionEJB"
BeanClass="toplinklab.model.Position"
Binds="Position.result" id="PositionIter"
Refresh="renderModel"
RefreshCondition="${!adfFacesContext.postback and empty bindings.exceptionsList}"/>
<variableIterator id="variables"/>
</executables>
Untuk membuat form langsung kosong setelah melakukan persistEntity, hilangkan RefreshCondition dari ‘invokeAction’. PageDef menjadi sbb:
<executables>
<invokeAction Binds="Position" id="invokePosition" Refresh="renderModel" />
<methodIterator DataControl="SessionEJB"
BeanClass="toplinklab.model.Position"
Binds="Position.result" id="PositionIter"
Refresh="renderModel"
RefreshCondition="${!adfFacesContext.postback and empty bindings.exceptionsList}"/>
<variableIterator id="variables"/>
</executables>
Selamat mencoba
get jdbc connection via datasource
Misal dalam OC4J sudah terdapat suatu Managed Data Source, misalkan namanya labDS dengan alamat JNDI : jdbc/labDS.
Bila diperlukan JDBC connection, maka connection tersebut bisa diperoleh dari Managed Data Source dengan code sbb:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public String cbExecuteJdbc_action()
{
DataSource ds = null;
Connection con = null;
// memperoleh koneksi lewat data source
try
{
InitialContext ic = new InitialContext();
ds = (DataSource) ic.lookup("jdbc/labDS");
con = ds.getConnection();
}
catch (SQLException e)
{
}
catch (NamingException e)
{
}
// gunakan Connection yang diperoleh untuk melakukan sesuatu
// berkaitan dengan database. Disini sekedar contoh
// untuk menjalankan suatu query
try
{
if (con != null)
{
String sql = " select code, name, address from i_customer where id = 46059 ";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
rs.next();
itCode.setValue(rs.getString("code"));
itName.setValue(rs.getString("name"));
itAddress.setValue(rs.getString("address"));
rs.close();
stmt.close();
}
}
catch (SQLException e)
{
}
// close connection
if (con != null)
{
try
{
con.close();
}
catch (SQLException e)
{
}
}
return null;
}
reset adf search page
terdapat satu form pencarian dengan satu parameter strName.
misalkan pagedef pencarian sbb:
<executables>
<variableIterator id=”variables” Refresh=”ifNeeded”>
<variable Type=”java.lang.String” Name=”findAllICustomerLikeName_strName”
IsQueriable=”false”/>
</variableIterator>
<methodIterator id=”findAllICustomerLikeNameIter”
Binds=”findAllICustomerLikeName.result”
DataControl=”IseriesLab” RangeSize=”10″
BeanClass=”lab.model.iseries.ICustomer”
Refresh=”ifNeeded”/>
</executables>
<bindings>
<methodAction id=”findAllICustomerLikeName”
MethodName=”findAllICustomerLikeName”
RequiresUpdateModel=”true” Action=”999″
IsViewObjectMethod=”false” DataControl=”IseriesLab”
InstanceName=”IseriesLab.dataProvider”
ReturnName=”IseriesLab.methodResults.IseriesLab_dataProvider_findAllICustomerLikeName_result”>
<NamedData NDName=”strName” NDType=”java.lang.String”
NDValue=”${bindings.findAllICustomerLikeName_strName}”/>
</methodAction>
<attributeValues id=”strName” IterBinding=”variables”>
<AttrNames>
<Item Value=”findAllICustomerLikeName_strName”/>
</AttrNames>
</attributeValues>
</bindings>
Untuk membuat page tersebut selalu refresh ketika ditampilkan pertama kali tambahkan code berikut di backing bean. Jangan lupa sebelumnya jadikan bindings sebagai managed property di faces-config.xml
/**
strName adalah nama variable pencarian
findAllICustomerLikeName adalah nama method pencarian
*/
public void setBindings(BindingContainer bindings)
{
AdfFacesContext afc = AdfFacesContext.getCurrentInstance();
if (!afc.isPostback())
{
ADFUtils.setBoundAttributeValue(bindings, “strName”, “”); // lakukan ini sesuai jumlah parameter
OperationBinding ob = bindings.getOperationBinding(“findAllICustomerLikeName”);
Object result = ob.execute();
}
this.bindings = bindings;
}
sesuaikan dengan search form anda
<variableIterator id=”variables” Refresh=”ifNeeded”>
<variable Type=”java.lang.String” Name=”findAllICustomerLikeName_strName”
IsQueriable=”false”/>
</variableIterator>
<methodIterator id=”findAllICustomerLikeNameIter”
Binds=”findAllICustomerLikeName.result”
DataControl=”IseriesLab” RangeSize=”10″
BeanClass=”lab.model.iseries.ICustomer”
Refresh=”ifNeeded”/>
</executables>
<bindings>
<methodAction id=”findAllICustomerLikeName”
MethodName=”findAllICustomerLikeName”
RequiresUpdateModel=”true” Action=”999″
IsViewObjectMethod=”false” DataControl=”IseriesLab”
InstanceName=”IseriesLab.dataProvider”
ReturnName=”IseriesLab.methodResults.IseriesLab_dataProvider_findAllICustomerLikeName_result”>
<NamedData NDName=”strName” NDType=”java.lang.String”
NDValue=”${bindings.findAllICustomerLikeName_strName}”/>
</methodAction>
<attributeValues id=”strName” IterBinding=”variables”>
<AttrNames>
<Item Value=”findAllICustomerLikeName_strName”/>
</AttrNames>
</attributeValues>
<table id=”findAllICustomerLikeName1″
IterBinding=”findAllICustomerLikeNameIter”>
<AttrNames>
<Item Value=”address”/>
<Item Value=”city”/>
<Item Value=”code”/>
<Item Value=”id”/>
<Item Value=”name”/>
</AttrNames>
</table>
</bindings>
tinggalkan komentar