Menu

31 Mart 2010 Çarşamba

Jsf 2.0 ile custom component olusturma

Makalemizde Jsf 2.0 ile custom component`lerin nasil olusturuldugu orneklerle beraber uygulamali olarak paylasmaya calisacam. Jsf `in 2.0`dan onceki surumlerinde de custom component olusturabiliyorduk ancak JSF2 ve facelets ile birlikte bu konu cok daha rahat bi sekilde hazirlanabiliyor. Bi sonraki yazimda, jsf2 ile gelen ozelliklerinden ve jsf2 ile eski surumlerin karsilastirilmasindan bahsedecem.

Simdi konumuza donersek, custom componentleri hangi durumlarda olusturuz, neden bole biseye ihtiyac duyariz derseniz, jsf`nin kendi componentlerinin yeterli olmadigi durumlarda, uygulamalarimiz icin kendi componentlerimizi olustururuz mesala bi ornek vermek gerekirse, h:datatable componentinde h:selectOneRadio componenti kullandigimizda cogumuz karsilasmisizdir, birden fazla satir secilebiliyor, ama radio butonlarin ozellikleri grub halinde calismalari ve o grub icinde yanliz birtane secilebilir olmalaridir. Ancak jsf componentinde birden fazla satir secebiliyoruz ve buda bizim hic istemedigimiz bir sonuc ortaya koyuyor, iste tam burada custom componentler yardimimiza kosuyor, ve biz kendi radio buton componentimizi istedigimiz sekilde olusturabiliyoruz. Bu sorunu 3.parti framevorklar kullanarak cozebiliyoruz ancak, onlarda sayfaya fazla bisekilde javascript-ajax atiyorlar. Bizim kendi olusturdugumuzu componentde ise hic bisekilde javascritpte yada ajax`a ihtiyacimiz olmayacak, Konuyu uzatmadan isterseniz hemen, nasil kendi componentlerimizi olusturabiliriz onan bakalim.

Ben uygulamarimda,

NetBeans 6.8 - glassfishv3 - j2ee 6 - jsf 2.0 ve facelets kullandim.

Simdi componentimizi olusturmaya baslayalim.

Bize gerekli olan classlar, SingleRowSelect, SingleRowSelectRenderer, RadioGroup, RadioGroupRenderer,

Simdi bu classlar ne isimize yarayacak,

SingleRowSelect classi bizim componentimizin propertylerinin olacagi class, bi nevi hangi attributelerinin olacagini burada gosteriyoruz, biz burada butun attributeleri tek tek olusturmakdansa var olanin uzerine bize gereken attributeleri ekleyelim, bunun icinde yanliz groupId attributemiz olsa bizim icin yeterli olacak. Classin icersi asagidaki gibi..



package net.aslan.faces.radiobutton;

import javax.faces.component.FacesComponent;


@FacesComponent(value = SingleRowSelect.COMPONENT_TYPE)
public class SingleRowSelect extends javax.faces.component.UIInput {

public static final String COMPONENT_FAMILY = "net.aslan.faces.component";
public static final String COMPONENT_TYPE = "net.aslan.faces.component.radiobutton.SingleRowSelect";
public static final String RENDERER_TYPE = "net.aslan.faces.component.radiobutton.SingleRowSelectRenderer";

public SingleRowSelect() {
super();
setRendererType(RENDERER_TYPE);
}

@Override
public String getFamily() {
return COMPONENT_FAMILY;
}

public void setGroupId(String groupId) {
getStateHelper().put("groupId", groupId);
}

public String getGroupId() {
return (String) getStateHelper().get("groupId");
}
}


Yukarida dikkat edecek olursak, classimizi UInput`dan extends ettik, cunku ayni seyleri tekrardan yazmakdansa bize gerekli olani var olani kullanarak onun uzerine eklemek daha rahat ve kolay olacaktir. UInput classinin icerisini incelemek bize cok fayada saglayacaktir.

Simdi yukaridaki classdaki kodlarin neler yaptigindan biraz bahsedecek olursak,

@FacesComponent, bu ozellikle jsf2 ile birlikte gelen annotationlar ile classin neyapacaginin neturden bi class olduguna karar veriyoruz,

ve classimizi component olarak gosteriyoruz, value` degeri ise componentin bir butun olarak calisacagindan Component_Family belirtiyoruz,

public static final String COMPONENT_FAMILY = "net.aslan.faces.component";
public static final String COMPONENT_TYPE = "net.aslan.faces.component.radiobutton.SingleRowSelect";


kodlarimiz UInput classinin icindede var oldugunda biz bu propertyleri ovveride ediyoruz ve kendi component type`mizi ve family`ini gosteriyoruz, biz ovveride etmeseydik kendisi tanyacakti ama biz ona izin vermiyoruz (UIInput classinin icini incelemenizi tavsiye ederim.)


public SingleRowSelect() {
super();
setRendererType(RENDERER_TYPE);
}


burada ise yapilandiricimizda renderer olacagi classimi set ediyoruz, eger biz set etmesek kendi renderer classini kullanacaktir.

ve son olarak

public void setGroupId(String groupId) {
getStateHelper().put("groupId", groupId);
}

public String getGroupId() {
return (String) getStateHelper().get("groupId");
}




bizim icin gerekli olan attribute`i olusturuyoruz ve stateHelper ekliyoruz, stateHelper Map seklinde calisiyor, setGroupId`de map`a ekliyoruz ve istegimiz zaman getGroupId`de oldugu gibi cagirabiliyoru, StateHelper`i ilerki makalelerde UIInput incelerken gorecegiz.



Bundan sonra bizim icin gerekli olan ve en onemli kisimlardan birisi renderer clasimizi olusturmak. Yani componentimizin nasil davranacagini bu class yardimiyla belirtecegiz..



import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;

@FacesRenderer(componentFamily = SingleRowSelect.COMPONENT_FAMILY, rendererType = SingleRowSelect.RENDERER_TYPE)
public class SingleRowSelectRenderer extends javax.faces.render.Renderer {

@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
SingleRowSelect radio = (SingleRowSelect) component;
String clientId = component.getClientId();
String groupId = radio.getGroupId();
Object selectedItems = null;
RadioButtonGroup group = null;

if (groupId != null) {
group = (RadioButtonGroup) findComponent(radio, groupId);
if (group != null) {
selectedItems = group.getValue();
} else {
}
}

ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", component);
writer.writeAttribute("type", "radio", null);
writer.writeAttribute("id", clientId, null);

if (group != null) {
writer.writeAttribute("name", group.getClientId(), null);
} else {
writer.writeAttribute("name", clientId, null);
}
writer.writeAttribute("value", radio.getValue(), "value");

if (selectedItems != null) {
System.out.println("type is:" + radio.getValue().getClass().getName() + " / value:" + radio.getValue());
}
writer.endElement("input");
}

private UIComponent findComponent(UIComponent comp, String componentId) {
UIComponent parent = comp;
UIComponent found = null;
int i = 1;
while (parent != null) {
found = parent.findComponent(componentId);
if (found != null) {
return found;
}
parent = parent.getParent();
}
return null;
}
}


yukaridaki kod blogumuzu inceleyecek olursak,

@FacesRenderer ile classimizn renderer ozellikde davranacagini belirtiyoruz ve componentFamily ve rendererType`ni gosteriyoruz, ve classimizi Renderer`den extend ediyoruz, bize gerekli olan kisimlari ovveride edip gerekli degisiklikleri yaptiyoruz.

@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {


Renderer classinin encodeEnd metodunu ovveride ettik cunku bizim icin componentimizin en son nasil davranacagini burada belirttik, metodu icinde kullandiklarimiza gelince.

SingleRowSelect radio = (SingleRowSelect) component

-burada componentimizi daha once olusturdugumuz SingleRowSelect custom component`i tipinde olusturduk. Burada kullandigimiz clientId componentimizin clientId`sini aldik, groupId ile`de bizim olusturdugumuz attribute`in degerin aldik. RadioGroup birazdan bizim olusturacagimiz class, bu classida component gibi olusturduk, cunku radiobutonlarimizdaki degerleri grub halinde kullanip radio butondaki degeri Object turunde almak icin.


ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", component);
budan sonraki kisimlarda ise componentimizi hangi propetylerinin oldugunu degerlerin nasil alinacagini gosteriyoruz, bu bolumleri derinlemesi baska bi makalede paylasacagiz.

Ve RadioGroup ve RadioGroupRenderer clasinin yaziyoruz, bu bolumlerin uzerine fazla deyinmeden gececem, makaleyi cok fazla uzatmamak icin, sorusu olan arkadaslara formda yardimci olmaya calisirim.



=============

package net.aslan.faces.radiobutton;


import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.render.FacesRenderer;


@FacesRenderer(componentFamily = RadioButtonGroup.COMPONENT_FAMILY, rendererType = RadioButtonGroup.RENDERER_TYPE)
public class RadioButtonGroupRenderer extends javax.faces.render.Renderer {

public RadioButtonGroupRenderer() {
super();
}

@Override
public void decode(FacesContext context, UIComponent component) {

RadioButtonGroup group = (RadioButtonGroup) component;
String clientId = group.getClientId(context);
Object[] submittedValue = context.getExternalContext().getRequestParameterValuesMap().get(clientId);
group.setSubmittedValue(submittedValue);
}
}


====================

package net.aslan.faces.radiobutton;


import javax.faces.component.FacesComponent;
import javax.faces.component.UIInput;


@FacesComponent(value = RadioButtonGroup.COMPONENT_TYPE)
public class RadioButtonGroup extends UIInput {

public static final String COMPONENT_FAMILY = "net.aslan.faces.component";
public static final String COMPONENT_TYPE = "net.aslan.faces.component.radiobutton.RadioButtonGroup";
public static final String RENDERER_TYPE = "net.aslan.faces.component.checkbox.RadioButtonGroupRenderer";

public RadioButtonGroup() {
super();
setRendererType(RENDERER_TYPE);
}

@Override
public String getFamily() {
return COMPONENT_FAMILY;
}
}


Bizim icin gerekli olanlar classlar bukadar, bunda sonra yapmamiz gereken, componentimiz icin bi taglib olusturmak ve xml`de gostermek, daha sonrada kullanmak :).



Bunda sonra yapacaklarimiz cok kolay, oncelikle taglib`imizi olusturalim.



net-aslan-taglib.xml





http://www.aslan.net/jsf/component


inputRadiobutton

net.aslan.faces.component.radiobutton.SingleRowSelect


radioGroup

net.aslan.faces.component.radiobutton.RadioButtonGroup




sonra web.xml icerisinde gosterelim..



javax.faces.FACELETS_LIBRARIES/WEB-INF/net-aslan-taglib.xml



uygulamadaki dizin yapisi asagidaki sekilde






hepsi bukadar, simdide facelets page`imde kullanmaya basliyalim.


DataBean.java


import accr.beans.Person;
import accr.beans.PersonRemote;
import java.io.Serializable;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;


@ManagedBean
@SessionScoped
public class DataBean implements Serializable {

@EJB
PersonRemote pr;
private Person selectedPerson;
Object selectedItem[];

public List getPersons() {
return pr.findAll();
}

public String actionEdit() {
String id = (String) selectedItem[0];
selectedPerson = pr.getPerson(new Long(id));
System.out.println("Per : " + selectedPerson.getName());
return "edit";
}

public Object[] getSelectedItem() {
return selectedItem;
}

public void setSelectedItem(Object[] selectedItem) {
System.out.println("Set edildi -----=== ");
this.selectedItem = selectedItem;
}

public Person getSelectedPerson() {
return selectedPerson;
}

public void setSelectedPerson(Person selectedPerson) {
this.selectedPerson = selectedPerson;
}
}


index.xhtml



































edit.xhtml






Edit Person











uygulamanin tamamini, proje halinde dosyalar bolunde bulubilirsiniz.

Yorum ve dusuncelerinizi bekliyorum, Faydali olmasi dilegiyle.

Bir sonraki makaledeki, Jsf 2.0 ile gelen yeniliklerden bahsedecegim..

Degiserek gelismenin dilegilyle...



Ertugrul Aslan

R.I.S.K Company

Baku / Azerbaycan

27 Mart 2010 Cumartesi

Java Ile Asal Sayi

Asagidaki ornekde java ile asal sayilarin nasil bulundugu gosteren bi ornegimiz var
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

public static void main(String[] args) throws IOException {
int a;
System.out.println("Kaca kadar olan asal sayılar bulunsun :");
BufferedReader nesne = new BufferedReader(new InputStreamReader(System.in));
int sayı = Integer.parseInt(nesne.readLine());
for (int i = 2; i < sayı; i++) {
a = 1;
for (int j = 2; j < i; j++) {
if (i % j == 0) {
a = 0;
}
}
if (a == 1) {
System.out.println("" + i);
}
}
}
}