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

--Potter Stewart

14.11.2008

En Basit Tasarım Örüntüsü Singleton (mu?)

Singleton örüntüsü bir sınıfın sadece tek bir nesnesi olması gerektiği durumlarda kullanılır ve sınıfın ihtiyaç duyulduğu zaman yaratıldığı en bilindik kullanım şekli şu şekildedir:

public class DateUtils {


private static DateUtils instance = null;


private DateUtils() {}


public static DateUtils getInstance() {


if(instance == null)


instance = new DateUtils();


return instance;


}

...

}


Böyle bir kullanım çoklu işletim dizilerinde (multithreads) sorunlara neden olabilmektedir. Aynı anda iki farklı işletim dizisinin instance niteliğini kontrol etmesi ve null görmesi sonucu iki farklı olgunun yaratılma olasılığı vardır. Bunun önüne iki şekilde geçilebilir. İlki sınıfın static niteliğinin uygulama ayağa kalkarken yaratılması:


public class DateUtils {


private static DateUtils instance = new DateUtils();


private DateUtils() {}


public static DateUtils getInstance() {

return instance;

}

...

}

İkincisi ise getInstance() yönteminin synchronize hale getirilmesi. Tüm yöntemin senkron hale getirilmesi, sadece nesnenin null durumunda kontrol edilmesi gereken, nesne yaratıldıktan sonra da performansa olumsuz etki yapan bir durum olduğu için kullanımından kaçınılmaktadır. Bunun yerine instance niteliği null ise senkronu başlatan bir yöntem tercih edilmiştir:


public class DateUtils {


private static DateUtils instance;


private
DateUtils() {}

public static DateUtils getInstance () {


if(instance == null) {


synchronized(DateUtils.class)
{


if(instance == null)


instance = new DateUtils();


}


}


return instance;


}

}

Ne var ki “Double-Checked Locking” olarak bilinen bu yöntem JDK 5’ten önce çalışmıyor. Ayrıntılı bilgiye “The Double-Checked Locking is Broken Declaration” bağlantısından ulaşabilirsiniz. JDK 5 ile gelen volatile bu
sıkıntıya derman oluyor:


public class DateUtils {


private volatile static DateUtils instance;


private DateUtils() {}


public static DateUtils getInstance () {


if (instance == null) {


synchronized(DateUtils.class)
{


if (instance == null)


instance = new DateUtils();


}


}


return instance;


}

}

Singleton örüntüsünde dikkat edilmesi gereken bir başka husus ise sınıf Clonable arayüzünü gerçekleştiren bir başka sınıftan türetilmişse ortaya çıkıyor. Singleton sınıfımızın clone() yöntemi ile çoğaltılmasının önüne geçmek istiyorsak bu metodun üstüne yazmamız gerekiyor:

public Object clone() throws CloneNotSupportedException {


throw new CloneNotSupportedException();

}

13.11.2008

Hibernate Data Filtering (Süzme)

Verilerin tamamını değil de belirli kriterlerle süzülüp işimize yarayacakları veritabanından sorgulamak günlük hayatta çokça karşılaştığımız bir senaryo. Örneğin “Abone” nesnesinin belirli tarihten önceki ödenmemiş faturalarına erişmek istediğimiz zaman abone.getFaturalar()
şeklinde bir erişim, eğer bir süzme uygulanmazsa abonenin tüm faturalarını getireceği için Java kodlarıyla süzme işlemini yapmamızı gerektirecektir. Buna benzer ya da veri güvenliği (kullanıcıya sadece görmesi gereken verilerin gösterilmesi) gibi senaryolarda Hibernate Data Filtering, Java kodlarında gerçekleştirmemiz gereken süzme maliyetinden kurtulmamıza olanak sağlıyor.


Öncelikle süzme işleminde kullanacağımız süzgeci, biricik ismiyle tanımlamamız gerekiyor:

@org.hibernate.annotations.FilterDef(name="faturaOdemeFilter",


parameters={
@ParamDef(name="donem",type="integer"),
@ParamDef(name="kalanTutar",type="double"),
@ParamDef(name="durumConditions",type="long")

})


Tanımladığımız süzgecin ismi faturaOdemeFilter ve dinamik süzme işlemi yapabilmemiz için üç tane parametre alıyor. Parametrelerin kurulma işlemine birazdan değineceğiz. Bu tanım global nitelikli olduğu için herhangi bir sınıfta ya da package-info.java içerisinde yazılabilir. Yazıldığı sınıfın davranışında bir etkisi yoktur fakat uygun olan tanımın ilgili sınıfta yazılmasıdır. Süzgeç tanımımız olgusunu da süzme işleminin yapılacağı sınıfta ya da ilişkide yazılması gerekmektedir:

@Entity
@Table(name="FATURA")

@Filter(name="faturaOdemeFilter", condition="ODEME_DONEMI <= :donem and FATURA_DURUM in (:durumConditions) and KALAN_TUTAR >:kalanTutar")

public class Fatura {...}


Birden fazla süzgeç @org.hibernate.annotations.Filters ile gruplanabilir. Yukarıdaki gibi sınıf üzerine yazılmış süzgeç olgusu


List<Fatura> filteredItems = session.createQuery("from Fatura").list();


List<Fatura> filteredItems = session.createCriteria(Fatura.class).list();


Deyimlerinde çalışacaktır. Id ile sorgulamalarda (id'yi biliyorsak süzmeye de gerek yok) ve nesne niteliklerinin sorgulanmasında sınıf üzerine yapılan tanım çalışmayacaktır. abone.getFaturalar()deyimi gibi abonenin ilişkili olduğu faturaların süzülmesi için süzgeç olgusunun ilişki üzerinde tanımlanması gerekmektedir:


@Entity
@Table(name = "ABONE")


public class Abone {


@OneToMany(mappedBy="abone")
@Filter(name="faturaOdemeFilter", condition="ODEME_DONEMI <= :donem and FATURA_DURUM in (:durumConditions) and KALAN_TUTAR > :kalanTutar")


private Set<Fatura> faturalar = new HashSet<Fatura>();


...

}


Süzgeç tanımının kullanılması için Hibernate Session’ında süzgeç aktif hale getirilerek varsa aldığı parametreler kurulmalıdır. Veriler çekildikten sonra da süzgeç tekrar pasif hale getirilebilinir. (JPA API’sinde EntityManager filtrelemeye destek sağlamadığı için Hibernate arayüzü kullanılmalıdır.)


List<Long> durumConditions = new ArrayList<Long>();

durumConditions.add(FaturaDurumEnum.ODENMEMIS.getValue());
durumConditions.add(FaturaDurumEnum.
PARCALI_ODENIYOR.getValue());


Filter filter = session.enableFilter("faturaNormalOdemeFilter");


filter.setParameter("donem",donem).setParameter("kalanTutar",new Double(0)).setParameterList("durumConditions", durumConditions);


Set<Fatura> faturalar = abone.getFaturalar();


session.disableFilter(("faturaNormalOdemeFilter");