Sansür, bir toplumun kendine olan güvensizliğini yansıtır ve otoriter rejimlerin belirgin bir özelliğidir.

--Potter Stewart

25.10.2012

PrimeFaces Datatable Column Custom Sorting

Popüler JSF kütüphanesi PrimeFaces'ın geliştiriciye yetenekli JSF bileşenleri sunduğu aşikar. Bu yeteneklerinin çoğunu showcase sayfasında sergilese de gözden kaçan gizli kalmış yeteneklerini de her zaman elinizin altında bulunması gereken kapsamlı dökümanını inceleyerek yakalayabilirsiniz.

Bunlardan biri de datatable bileşeninin sıralama yeteneğinde saklı. Basitçe kullanıcılarınızı ilk isimleri ile sıralamak istediğinizde işinize yarayacak aşağıdaki örnek, kullanıcının tam ismine göre sıralama yapmak istediğinizde elinizi bağlıyor:

<p:column width="100" sortBy="#{user.firstName}" >
 <f:facet name="header">
  <h:outputText value="Kullanici ismi" />
 </f:facet>

 <h:outputText value="#{user.firstName}" />
</p:column>

Yukardaki örnekte sortBy="#{user.firstName} #{user.lastName}" yapmamıza izin verilmiyor. Hemen akla kullanıcı tam ismini döndüren bir getter metot yazarak  sortBy="#{user.fullName}" yapmak akıllara gelebilir. Bu metot iki kolonu concat ederek bize tam ismi döndürmesi açısından kullanışlı olsa da ne var ki veri erişim katmanında Hibernate gibi bir kütüphane kullanıyorsanız buna da izin yok. Hibernate veritabanında ilişkilendirebileceği fullName isimli kolon bulamadığı için şikayet ediyor.

Bu aşamada yardımımıza datatable bileşeninin sortFunction yeteneği yetişiyor:

<p:column width="100" sortBy="#{user.firstName}" sortFunction="#{userBean.fullNameSorter}" >
 <f:facet name="header">
  <h:outputText value="Kullanici ismi" />
 </f:facet>

 <h:outputText value="#{user.fullName}" />
</p:column>

userBean managedbean'i içinde metodun gerçekleştirimi de şu şekilde basit bir compare işlemi ile halledilebilir:

public int fullNameSorter(User user1, User user2){
 Collator trCollator = Collator.getInstance(new Locale("tr","TR"));
 return trCollator.compare(user1.getFullName(), user2.getFullName());
}

Bol Javalar..

6.08.2012

Maven-Jetty Plugin ve EL ile Method Expression'lara Parametre Geçme

<plugin>
 <groupId>org.mortbay.jetty</groupId>
 <artifactId>jetty-maven-plugin</artifactId>
 <version>${jetty-maven-plugin.version}</version>
 <configuration>
  <scanIntervalSeconds>10</scanIntervalSeconds>
  <stopPort>8075</stopPort>
  <stopKey>STOP</stopKey>
 </configuration>
 <dependencies>
  <dependency>
   <groupId>org.glassfish.web</groupId>
   <artifactId>el-impl</artifactId>
   <version>2.2</version>
  </dependency>
 </dependencies>
</plugin>
Bu kadar..

26.07.2012

JSF MyFaces ve Spring Core

Uzunca bir süre projelerimizde ve JSF eğitimlerimizde JSF'in referans gerçekleştirimi olan Mojarra'yı kullandık. Referans gerçekleştirimi olmasına rağmen Mojarra'da yer alan hatalar ve MyFaces gerçekleştirimine kıyasla yavaş çalışması sonucu yeni projelerimizde MyFaces kullanmaya karar verdik.

Basitçe bu geçişi Mojarra'nın api ve impl .jar'larını MyFaces'inkilerle değiştirerek yapabiliyorsunuz. Lakin MyFaces, Mojarra'ya göre bazı noktalarda farklı davranabiliyor. Bu davranışı da web.xml'de ekleyebileceğiniz çeşitli context-param'larla düzenleyebiliyorsunuz.

MyFaces JSF'i Spring ile kullanırken karşılaştığımız bir farklılık da viewScope tanımlı managedBean niteliklerine bağımlılık aktarımı yapılan Spring bean'lerin ikinci istekte null değerler almasıydı. Bunun sebebi de MyFaces'in varsayılan olarak session'daki JSF state'ini her defasında serialize/deserialize etme çabasıydı. İkinci istek işlenirken deserialize yapılan JSF beanlerine Spring beanleri aktarılamadığı için NullPointerException hatası alıyorsunuz.


<context-param>
  <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
  <param-value>false</param-value>
 </context-param>


şeklinde yazılan context-param değeri bu sıkınıtının önüne geçiyor. Buna benzer MyFaces parametrelerin listesini buradan inceleyebilirsiniz..

4.06.2012

OmniFaces

JSF ile haşır neşir olup da BalusC'yi duymayan yoktur herhalde. Forumlarda, özellikle stackoverflow.com'da yanıtlanmayan JSF sorusu kalmayacak diye inat etmiş Balus ve bir arkadaşı (Arjan Tijms) JSF'in eksikliklerini masaya yatırıp bunları nasıl yamarız diye düşünürlerken olsa gerek geçen günlerde OmniFaces'in ilk sürümünü yayınladılar.

Showcaselerinde PrimeFaces kullanan ekibin çalışmasına göz attığımda JSF'te can sıkan, baş ağrıtan belli başlı sorunlara pratik çözümler getirmelerinin yanı sıra bizim de "Bunları bir kütüphane haline getirsek de projelerde tekrar tekrar yazmasak" dediğimiz ama bir türlü fırsat bulamadığımız, her JSF projesinin olmazsa olmaz metotlarını da OmniFaces'a eklediklerini gördüm.

Session öldüğünde Ajax istemiyle geldiğinde alınan ViewExpiredException hatasına getirilen çözüm (FullAjaxExceptionHandler), script ve style dosyalalarını birleştirerek HTTP requestlerini azaltmayı hedefleyen CombinedResourceHandlerSelectItemsConverterRequiredCheckboxValidator, form validation mekanizmasına getirdikleri validateAllOrNonevalidateOneOrMore vb. yapılar, sıklıkla kullanılan işlevleri util sınıfı ve EL fonksiyonu olarak toparlamaları kütüphanenin ilk dikkat çeken özellikleri.

Kapattığı boşluklar ve karşıladığı küçük ihtiyaçlarla elimin altında olsun her JSF projesinde kullanırım diyeceğiniz bir çalışma olmuş. Göz atmanızda fayda var.

22.03.2012

PrimeFaces ve Security Kullanımı

Web projelerinde güvenlik olmazsa olmaz özelliklerden biri. Bu özelliği basitçe web.xml içerisinden yapılan güvenlik ayarlarıyla sunucunuz yardımıyla sağlayabileceğiniz gibi Spring Security benzeri çözümler de sundukları seçeneklerle daha çok tercih edilir durumda.

Her ne kadar erişim ayarları yapılırken tüm içeriğin giriş yapmayan kullanıcı için kısıtlanması tercih edilen yöntem ise de başta "giriş sayfası" olmak üzere benzer sayfalara ve bunların kullandığı kaynaklara erişim izni verilmesi gerekir. Giriş sayfasında PrimeFaces bileşeni kullanıyorsanız sayfanızın erişmeye çalışacağı ve erişim izni olmadığı için de kullanamayacağı başlıca adres "/javax.faces.resource/*" olacaktır.

PrimeFaces ile yazılmış bu gibi sayfaların kullanıcı giriş yapmadan düzgün bir şekilde görüntülenmesi için yukardaki adresin güvenlik ayarlarınızda erişime açılmış olması gerekmektedir.

web.xml içerisinde örnek bir güvenlik kısıtlaması şu şekilde yapılmalıdır:

 <security-constraint>
  <display-name>excluded</display-name>
  <web-resource-collection>
   <web-resource-name>All Access</web-resource-name>
   <url-pattern>/javax.faces.resource/*</url-pattern>
  </web-resource-collection>
 </security-constraint>
 
 <security-constraint>
  <display-name>Default Security Constraint</display-name>
  <web-resource-collection>
   <web-resource-name>Default</web-resource-name>
   <url-pattern>/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>ROLE_ADMINISTRATOR</role-name>
  </auth-constraint>
 </security-constraint>

Aynı şekilde Spring Security kullandığınız bir projede erişim ayarları şu şekilde yapılabilir:

        <intercept-url pattern="/javax.faces.resource/**" filters="none" />
        <intercept-url pattern="/**" access="ROLE_ADMINISTRATOR" />

Erişim kısıtlarını kendi geliştirdiğiniz bir yöntemle ele alıyorsanız PrimeFaces sayfaları için bu hususu umutmamanızda fayda var..

21.03.2012

JSF'te ActionListener / Action Çağrılma Sırası

JSF'e yeni başlayan birinin gün olur aklına düşen bir sorudur: commandButton ile ilişkilendirdiğim actionListener'lar ve action hangi sırada çağırılır.

Öncelikle, hatırlatma niteliğinde;

- Bir command bileşenine birden fazla actionListener yazabiliyorken sadece bir action yazabileceğinizi
- action ile bağlanan metotta döndürdüğünüz String ile sayfa yönlendirme işlemi yapabileceğinizi (void ya da "return null;" olursa aynı sayfada kalır) fakat actionListener metotlarında bu özelliğin olmadığını
- actionListener metodunun "ActionEvent" parametresi alabileceğini, action'a bağlanan metota ise el-2.2.jar'dan itibaren Expression Language ile istediğiniz parametreyi geçebileceğinizi

belirteyim.

Çağırılma sırasını ise Yiğit Darçın bizim için hemencecik test etmiş ve blogunda yayınlamış. Test edip deneyimlemekten üşenenler faydalanabilir ;)