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

--Potter Stewart

23.10.2008

Char Tipi ve Hibernate

Bir veritabanına erişirken Char tipinde tanımlanmış bir kolona
rastladım. Birkaç ufak takla atma, alan nesnesinde kolona karşılık
gelen niteliği String tanımalama gibi girişimlerim sonuç vermeyince
Google başvurmak kaçınılmaz oldu. Hibernate'in sitesinde yer alan bir sayfada
UserType arayüzünden gerçekleştirilmiş bir sınıfın bu işi çözeceği
belirtilmiş. Sınıfı aşağıdaki annotationlar ile denediğimde artık Char
tipine sorunsuz ulaşabildim:

(Burada Char.class, UserType’tan gerçekleştirilmiş sınıfımız)

@Entity
@Table(name="ABONE_DURUM")
@TypeDef(name = "char", typeClass = Char.class)
public class AboneDurum{

@Id

@Column(name="ABONE_DURUM_KODU")
private Long id;

@Column(name="ACIKLAMA")
private String aciklama;

@Type(type="char")
@Column
(name="KISA_ACIKLAMA", length=3)
private String kisaAciklama;

...



13.08.2008

POJO vs. EJB 3.0

POJO ve EJB, Java EE geliştiriminde tercih edilen iki ayrı programlama modeli. Bu iki teknoloji, EJB 3.0'ın öğrenilmesi zor ve karmışık programlama modelini terkederek POJO tabanlı bir model seçmesiyle aynı eksende ilerleyecek gibi duruyor. Ama hala göz ardı edilemeyecek farklılıklar mevcut. POJO programlama modelini temel alan Spring çatısını kendine örnek alan EJB ile POJO'yu kıyaslarken elde ettiğim sonuçları özetlemeye çalıştım:


POJO

EJB 3

Basitlik

Mimarinin geliştiriminde göz önünde tutulan nesne yönelimli ilkeler sayesinde öğrenilmesi ve kullanılması kolay bir yapıya sahip. Basitlik ve tutarlılık ön planda.

Getirdiği mimari artılarına karşın EJB 1.0 sürümünden bu yana değişen programlama modeli ve öğrenim maliyeti projeler için dezavantaj oluşturuyor.

Test Edilebilirlik

POJO yapısı sayesinde Bağımlılık aktarımı (Dependency Injection) örüntüsü kullanılarak bileşenlerin kolay ve hızlı test edilebilirliğine imkan sağlıyor. Testler containerdan bağımsız yapılabiliyor.

Bağımlılık aktarımının sadece JNDI nesneleri ile yapılabilmesi, Session ve message-driven beanlerinin POJO olmalarına rağmen EJB Container’a ihtiyaç duymaları sebebiyle test edilebilirlik kısıtlanıyor. Bu da geliştirim sürecini olumsuz etkiliyor.

Geliştirim Ortamı

Tomcat gibi hafif (lightweight) containerlarla geliştirilen web uygulaması hızlıca çalıştırılabiliyor.

Geliştirilen uygulamanın çalıştırılabilmesi için ağır uygulama sunucularına ihtiyaç duyuyor. Projenin ihtiyaç duymadığı özellikler de uygulama sunucusu ile ayağa kaldırılıyor.

Collections Desteği

Hibernate çatısı ile persistence katmanında Set<String>, Set<Integer> gibi entity beanlerden oluşmayan collectionlara doğrudan destek sağlıyor.

Persistence katmanında sadece entity beanleri için collection desteği sağlıyor. Set<String>, Set<Integer> gibi collectionlara doğrudan destek sağlamıyor.

Konfigürasyon

Spring Bean configuration dosyalarına ihtiyaç duyuyor. Annotation desteği sunuyor.

Spring Bean configuration dosyalarından daha karmaşık bir yapıya sahip EJB descriptor dosyalarına ihtiyaç duyuyor. Annotation desteği sunuyor.

Persistence API

Kendine ait bir persistence api olmamasına karşın Template örüntüsü ile desteklenen; Hibernate, Ibatis, JPA gibi popüler çatılarla ve JDBC ile kolayca entegrasyona izin veren bir mimari sağlıyor.

EJB 3 ile Entity beanlerin yerini Hibernate, Toplink, JDO gibi persistence API’lerden devşirilen JPA belirtimi alıyor. Belirtim olması sebebiyle belirtimin yetersiz kaldığı yerlerde geliştirim sağlayıcısına bağımlı kalınabilmektedir.

Transactions

Dağıtık transaction mimarisini JTA ile destekliyor. Spring AOP çatısı ile annotationlar kullanılarak 7 farklı Propagation-bazlı transaction tanımlanabiliyor. Transactionlar XML konfigürasyon dosyalarında ya da aspect yaklaşım kullanılarak tanımlanıyor. Spring JDBX, Hibernate ve JTA ile entegre olabiliyor.

Dağıtık transaction mimari geliştirimine olanak sağlıyor. Session beanlerin tüm public metodlarına transaction mantığı otomatik olarak uygulanıyor. Annotation tabanlı bir transaction yönetimi bulunuyor. Sadece JTA’yı destekliyor. JTA Tomcat gibi hafif containerlarda çalışmıyor.

Güvenlik

ACEGI güvenlik çatısıyla hem nesne method çağrımı hem de HTTP istemlerinde doğrulama ve yetkilendirme yapılabiliyor. Rol-bazlının yanı sıra ACL-bazlı yetkilendirme de sağlıyor. Uygulama sunucusundan bağımsız standart bir güvenlik katmanı sağlıyor.

Tanımlı method-düzeyi rol-bazlı yetkilendirme, programatik rol belirleme özelliklerine sahip. EJB belirtiminin yeterli olmaması sebebiyle, güvenlik gerçekleştirimini uygulama sunucusuna bırakıyor. Böylece güvenlik katmanı uygulama sunucuna bağımlı hale geliyor.
















































Summation of Persistence Comparison Between Spring and EJB 3.0.

Feature

Spring

EJB 3.0

Simple ORM Persistence

√

√

Implementation

Hibernate, JPA, JDO, TopLink, iBatis

JPA (providers include Hibernate, Kodo and Toplink)

JDBC Support

√

--

Mapping

XML, Annotations

Annotations, XML

Cache Propagation

Thread local

Transaction

Extended cache scoping

Open session in view

Extended persistence context


Equivalent Transaction Management Functionality in Both Spring and EJB 3.0.

Feature

Spring

EJB 3.0

Declarative Transactions

√

√

Programmatic Transactions

√

√

Demarcation

AOP

Session bean methods

Supported Transaction Types

JDBC, Hibernate, JTA

JTA

Support for Distributed Transactions

√ (With JTA)

√

Configuration

XML

Transactional by default, override with annotations or XML


Teknolojilerin Google Trend’ten elde edilen yıllara göre arama sonuçlarının karşılaştırma tabloları:

ejb

Frame2

1.00

pojo

Frame3

0.16



ejb

Frame4

1.00


hibernate

Frame5

1.84

jpa

Frame6

0.24



Sonuç olarak Java EE uygulamalarda EJB'nin tercih edilmesini gerektirecek tek durum dağıtık transaction yönetimi ihtiyacı. POJO (dolayısıyla Spring) bu ihtiyaca karşılık veremiyor. Bunun dışındaki senaryolarda değişen trendler de göz önüne alınarak POJO programlama modelini temel alan çözümlerin (Spring, Hibernate, vs.) (EJB 3.0 gibi kopyalarının yerine :) ) seçilmemesinde hiç bir neden yok.

Kaynaklar

11.07.2008

Spring 2.5.3 ve Apache CXF ile Anlaşma-Sonra(Contract-Last) Yaklaşımlı Web Service Geliştirme


Bir önceki girdide Spring Web Service kullanarak anlaşma-önce web service geliştirme yaklaşımından ve bu yaklaşımının artılarından bahsetmiştik. WSDL belgesinin değişmesinin istemci ve sunucu kodlarını etkileyeceği için önce WSDL belgesinin oluşturulması gerektiğine değinmiştik. Bunun yanında anlaşma-önce yaklaşımın kullanılması geliştiriciyi Web Service geliştiriminin ayrıntılarından uzak tutacağı için küçük çaplı projelerde avantaj sağlayabilir. Bu girdide de Apache CXF kullanarak anlaşma-önce yaklaşımla basit bir web service geliştireceğiz.

Apache CXF’nin kullanacağı kütüphaneleri indirdikten sonra projemiz için gerekli olanları .zip kütüğünün lib dizininde yer alan WHICH_JARS kütüğünde bulabilirsiniz. Temel kullanım için gerekli olan kütüphanelerin listesi şu şekildedir:

- cxf.jar

- commons-logging.jar

- geronimo-activation.jar (Or the Sun equivalent) *

- geronimo-annotation.jar (Or the Sun equivalent) *

- geronimo-javamail.jar (Or the Sun equivalent) *

- geronimo-stax-api.jar (Or the Sun equivalent) *

- neethi.jar

- jaxb-api.jar *

- jaxb-impl.jar

- stax-utils.jar

- XmlSchema.jar

- wstx-asl.jar *

- wsdl4j.jar

- xml-resolver.jar

* Bu kütüphaneler Java 6 Update 4’den sonra JDK içinde mevcuttur.

Ayrıca Java sınıflarımızda Annotation kullanacağımız için Aegis ve JAX-WS kütüphalerine de ihtiyacımız var:

- jaxen.jar

- jdom.jar

- stax-utils.jar

- geronimo-ws-metadata.jar [6]

- jaxws-api.jar [6]

- saaj-api.jar [6]

- saaj-impl.jar [6]

- asm.jar

Örnek servis olarak kişi listesi döndüren bir servis yazalım:

package com.blogspot.mdasgin.examples.model;

import org.apache.cxf.aegis.type.java5.IgnoreProperty;

public class Kisi {

private String isim;

private String soyisim;

private Integer kimlikNo;

public Kisi() {

}

public Kisi(String isim, String soyisim, Integer kimlikNo) {

this.isim = isim;

this.soyisim = soyisim;

this.kimlikNo = kimlikNo;

}

public String getIsim() {

return isim;

}

public void setIsim(String isim) {

this.isim = isim;

}

public String getSoyisim() {

return soyisim;

}

public void setSoyisim(String soyisim) {

this.soyisim = soyisim;

}

/*

* @IgnoreProperty tells Aegis that I don't want getTamIsim() to show up in the auto-generated WSDL.

* It's just a read-only convenience method.

*/

@IgnoreProperty

public String getTamIsim() {

return soyisim + ", " + isim;

}

public Integer getKimlikNo() {

return kimlikNo;

}

public void setTamIsim(Integer kimlikNo) {

this.kimlikNo = kimlikNo;

}

}

@IgnoreProperty annotation’ı sayesinde Aegis, otomatik üretilen WSDL belgesinde bu niteliği göz ardı edecek. Web service arayüzü ve geliştirimi de şu şekilde olacaktır:

package com.blogspot.mdasgin.examples.contractlast.services;

import java.util.List;

import javax.jws.WebParam;

import javax.jws.WebService;

import com.blogspot.mdasgin.examples.model.Kisi;

/*

* @WebService annotation bu arayuzun bir web service arayuzu oldugunu belirtir.

*/

@WebService

public interface KisiService {

List<Kisi> getKisiList();

/*

* @WebParam annotation allows us to use an HTTP parameter called "message" to reference the operation's argument

* instead of having to call it "arg0", which is the default.

*/

void addKisi(@WebParam(name = "kisi")Kisi kisi);

}

---

package com.blogspot.mdasgin.examples.contractlast.services.impl;

import java.util.ArrayList;

import java.util.List;

import javax.jws.WebService;

import com.blogspot.mdasgin.examples.contractlast.services.KisiService;

import com.blogspot.mdasgin.examples.model.Kisi;

/*

* @WebService annotation bu sinifi bir web service geliştirimi olarak isaretler. Ayrica kullandigi arayuzu de belirtir.

*/

@WebService(endpointInterface="com.blogspot.mdasgin.examples.contractlast.services.KisiService")

public class KisiServiceImpl implements KisiService {

public List<Kisi> getKisiList() {

List<Kisi> kisiList = new ArrayList<Kisi>();

kisiList.add(new Kisi("Mustafa", "Dasgin", "11111111111"));

kisiList.add(new Kisi("Huzur", "Oncu", "22222222222"));

return kisiList;

}

public void addKisi(Kisi kisi) {

System.out.println(kisi.getTamIsim());

}

}

Bu aşamadan sonra web.xml’de gelen web service istemlerinin yönlendirilebilmesi için gerekli tanımları eklemeliyiz:

<servlet>

<servlet-name>CXFServlet</servlet-name>

<servlet-class>

org.apache.cxf.transport.servlet.CXFServlet

</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>CXFServlet</servlet-name>

<url-pattern>/webservices/*</url-pattern>

</servlet-mapping>

Tanımdan da anlaşılacağı gibi sunucumuza “/webservices/*” örüntüsünde gelen istemler CXFServlet’e yönlendirilecektir. Spring bean tanımlarımızı da yapalım:

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:cxf="http://cxf.apache.org/core"

xmlns:jaxws="http://cxf.apache.org/jaxws"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://cxf.apache.org/core

http://cxf.apache.org/schemas/core.xsd

http://cxf.apache.org/jaxws

http://cxf.apache.org/schemas/jaxws.xsd">

<import resource="classpath:META-INF/cxf/cxf.xml" />

<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />

<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

<!-- CXF'nin loglama ozelligi kullanilabilir fakat performans soz konusu ise kullanilmamasi onerilir.

-->

<cxf:bus>

<cxf:features>

<cxf:logging />

</cxf:features>

</cxf:bus>

<!-- The service bean -->

<bean id="kisiService"

class="com.blogspot.mdasgin.examples.contractlast.services.impl.KisiServiceImpl" />

<!-- Aegis data binding -->

<bean id="aegisBean"

class="org.apache.cxf.aegis.databinding.AegisDatabinding"

scope="prototype" />

<bean id="jaxws-and-aegis-service-factory"

class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean"

scope="prototype">

<property name="dataBinding" ref="aegisBean" />

<property name="serviceConfigurations">

<list>

<bean

class="org.apache.cxf.jaxws.support.JaxWsServiceConfiguration" />

<bean

class="org.apache.cxf.aegis.databinding.AegisServiceConfiguration" />

<bean

class="org.apache.cxf.service.factory.DefaultServiceConfiguration" />

</list>

</property>

</bean>

<!-- Service endpoint -->

<!-- See http://incubator.apache.org/cxf/faq.html regarding CXF + Spring AOP -->

<jaxws:endpoint id="kisiServiceEndPoint"

implementorClass="com.blogspot.mdasgin.examples.contractlast.services.impl.KisiServiceImpl"

implementor="#kisiService" address="/kisiws">

<jaxws:serviceFactory>

<ref bean="jaxws-and-aegis-service-factory" />

</jaxws:serviceFactory>

</jaxws:endpoint>

</bean>

Sunucu tarafımız hazır. Aşağıdaki istemlerle deneme yapabilirsiniz:

  • http://localhost:8080/denemeWSProje/webservices (Hizmet veren web servis listesi)

  • http://localhost:8080/denemeWSProje /webservices/kisiws?wsdl (Üretilen wsdl belgesi)

  • http://localhost:8080/denemeWSProje /webservices/kisiws/getKisiList

  • http://localhost:8080/denemeWSProje /webservices/kisiws/addKisi?kisi=...

Sunucuya bağlanacak istemci tarafında tanımlanması gereken spring bean’leri de şu şekilde olmalıdır (Sunucu tarafında tanımlanan aegisBean ve jaxws-and-aegis-service-factory beanleri de istemci tarafında tanımlanmalıdır):

<bean id="client"

class="com.blospot.mdasgin.examples.contractlast.services.KisiService"

factory-bean="clientFactory" factory-method="create" />

<bean id="clientFactory"

class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">

<property name="serviceClass"

value=" com.blogspot.mdasgin.contractlast.services.KisiService" />

<property name="address"

value="http://localhost:8080/denemeWSProje/webservices/kisiws" />

<property name="serviceFactory"

ref="jaxws-and-aegis-service-factory" />

</bean>

Kaynaklar: