Monday 13 August 2007

Multiple DWR Call - DWREngine Hook ve Batch Kullanımı

Bazen, ekrandaki bir form alanında bir değişiklik, js tarafında birden fazla işlemi tetikleyebiliyor. Mesela, bir select'ten seçilen değere göre iki farklı combo'yu doldurmak gerekiyor. Ve bu comboların dinamik gelmesi için de server tarafına gitmek gerekiyor.

Bu işlem için DWR uygun görünüyor. Biz de burada DWR kullandık diyelim. Bu sefer de, iki DWR'ı peşpeşe çağırmak gerekiyor. Ya da tek DWR çağırıp her iki select'in opsiyonlarını tek seferde de serverdan çekebiliriz. ilk seçeneği uyguladım ben. Ama beklenmedik bir durumla karşılaştım.

DWR çağrıldığı zaman, kullanıcıya o an işlem yapıldığını dolayısıyla ekrandaki alanları değiştirmemesi gerektiğini belirtecek bir mesaj gösterilmesi gerekiyor, ya da form alanlarını disable yapmak gerekir. Bunu DWR çok pratik bir şekilde sunmuş. DWR çağrıldığı zaman DWREngine içerisindek preHook fonksiyonu çağrılıyor. DWR'dan response döndüğü zaman da postHook fonksiyonu çağrılıyor. Bunun için şu alttaki satırları eklememiz yeterli oluyor:

DWREngine.setPreHook(function() {
$('DWRwaiting').style.visibility = 'visible'; });
DWREngine.setPostHook(function(data) {
$('DWRwaiting').style.visibility = 'hidden'; });

Buradaki DWRwaiting isimli HTML objesi bir DIV. Bu isimli bir DIV oluşturdum ve içine, DWR işlem yaparken kullanıcıya ne gösterilmek isteniyorsa onu koydum. Benim DWRwaiting div'imin içerisinde şunlar var. Örnek olması açısından ekliyorum:

<div id="DWRwaiting" name="DWRwaiting"
style="Z-INDEX:3;LEFT:40px;POSITION:absolute;
TOP:115px;width:950;height:50;
visibility:hidden;background-color:white;filter:
alpha(opacity=60);border:solid 2px #000000;">
<table width=950>
<tr>
<td width=5%> </td>
<td width=5% valign=center> <img src="loading.gif" width="25" height="25"> </td>
<td width=90% align="left" class="loadingMessage">Bilgiler
getiriliyor. Lütfen bekleyiniz ...</td>
</tr>
</table>
</div>

Böylece, bir dwr metodunu çağırdığımda ekranda yukarıdaki div görünüyor, dwr response döndüğünde ise bu div kayboluyor.

Buraya kadar herşey çok güzel, fakat peşpeşe iki tane dwr çağırmışım ve ikisi birbirinden bağımsız iki thread halinde server'a gitmiş. Bu durumda, yukarıdaki DIV mesajı ilk çağrılan dwr metodu ile birlikte görünür oluyor. Ama çağırdığım iki dwr metodundan hangisi önce gelirse, onun postHook fonksiyonu bu DIV mesajını tekrar görünmez yapıyor. Oysa, benim diğer DWR çağrım hala devam ediyor. Bu da kullanıcıyı şaşırtıyor. Beklemesi gerekirken, dwr'ın işlemini bitirdiğini zannedip işlem yapmaya başlıyorlar.

Burada, bir çözüm üretmek için düşünüyordum. Bunun için, html'de, her iki dwr metodunu temsil eden global iki javascript değişkeni koyacak, postHook fonksiyonu içinde her iki değişken de kontrol edip ona göre DIV mesajımı gizleyecektim. Ama tabi ki, böyle bir case'i de DWR düşünmüş. Bunun için DWREngine.beginBatch ve DWREngine.endBatch fonksiyonlarını kullanmak yeterli oluyor.

Örnek vereyim. Bir select değiştiğinde çağrılan fonksiyon XYZFunc fonksiyonu olsun. Önceden;

function XYZFunc(fld){
DWRCode.firstSubCombo(fld.value, fillFirstCombo);
DWRCode.SecondSubCombo(fld.value, fillSecondCombo);
}

bu şekildeydi. Çok basit bir şekilde Batch'i ekliyorum:

function XYZFunc(fld){
DWREngine.beginBatch();
DWRCode.firstSubCombo(fld.value, fillFirstCombo);
DWRCode.SecondSubCombo(fld.value, fillSecondCombo);
DWREngine.endBatch();
}

Böylece, DWR her iki sorguyu birlikte server'a götürüyor. Ve her ikisinin sonucunu alıp response'ları geri getiriyor. iki sorgu arasında bir kopukluk olmuyor ve yukarıda bahsettiğim DIV mesajım doğru zamanda gösterilip doğru zamanda kayboluyor.

Burada dikkat edilmesi gereken ufak bir nokta var. Gönderilen iki ya da daha fazla dwr çağrısı, batch içinde birbirini beklediği için, herhangi bir dwr çağrısının uzun sürmesi ya da takılması durumunda ekranın fazla beklememesi için ya da timeout'a düşmemesi için bu dwr batch'ine bir timeout süresi koymak faydalı olabilir. Buna örneği de DWR'ın kendi sitesinden alayım:

DWREngine.endBatch({ timeout:3000});

4 comments:

Unknown said...

Selam ben de dwr kullanmaya yeni başladım ama okuduğum kadarıyla tekniklerimiz farklı, ben server üzerindeki obje üreten metodlarımı çağırıp bu metodlardan dönen stringleri önceden idleri ile hazırladığım divlere innerhtml olarak gönderiyorum ve bu şekilde birden çok combo box ı rahatlıkla kontrol edebiliyorum.

Ancak takıldığım bir konu var ve yardımcı olabileceğinizi düşünüyorum bana java'ya sanki sayfa yenileniyormuşçasına dönebilecek bir request lazım ve ben parametrelerimi normal kullanımındaki gibi (request.getParameter) alabilir miyim? yardımcı olursanız sevinirim. kolay gelsin....

Mahir Tarlan said...

Merhaba,

tam olarak anlayamadim ama anladigim kadariyla cevap vereyim.

dwr ile gittiginiz method'da request icine istediginizi set edebilirsiniz. method'da request'i almak icin asagidakine benzer bir satir kullanilabilir.

HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();

kolay gelsin

Unknown said...

Öncelikle cevabınız için teşekkürler..
Bu şekilde bir request oluşturunca requestin jsp arayüzündeki inputlarla bi alakası olmuyor mesela sayfada şöyle bir inputum var
input type='hidden' name='hiddeninput' value='hello world'
dwr kullanarak girdiğim javasayfasında
HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();
System.out.println("hidden input value = "+request.getParameter("hiddeninput"));
komutunu yazınca
hiddeninput = null
çıktısını alıyorum ancak bana valuesu yani Hello World lazım dwr kullanarak bunu yapabilmenin bir yolu var mı acaba?
ilginiz için teşekkürler...

Mahir Tarlan said...

Tekrar merhaba,
Şimdi anladım galiba ne yapmaya çalıştığınızı. fikirlerimi yazayım.
Formu submit etmediğimizden dwr metodunun içinde request'ten form alanlarının değerlerini alamayız. değerlerin null gelmesi doğaldır. Ekrandan girilmiş değerlere ihtiyacımız varsa dwr'a bu değerleri parametre olarak geçebiliriz ya da ekrandaki form bir obje ise (struts'taki actionForm gibi), o objeyi dwr.xml'e bean olarak tanımlayıp dwr metodunda ihtiyacımız olabilecek alanları javascriptle bu objedeki ilgili alanlara set ederek dwr'a tüm objeyi parametre olarak geçebiliriz.

buna benzer bir konuyla ilgili bir mailleşmeyi de göndereyim belki işinize yarar:
http://osdir.com/ml/java.dwr.user/2007/msg02701.html