26 Eylül 2012 Çarşamba

Wicket Deployment Mode

 Wicket Deployment Mode ve ExceptionSettings

Wicket atanan deployment moduna göre yakalanmamış runtime exception'ları işlemektedir.
Eğer deploment mode RuntimeConfigurationType.DEVELOPMENT ise yakalanmamış exceptionlar stack trace bilgisi ile gösteriliyor.

Ancak Eğer deploment mode RuntimeConfigurationType.DEPLOYMENT ise yakalanmamış exceptionların stack trace bilgisi gösterilmiyor.

How can I see stack traces for my Wicket app? başlıklı soruda da cevaplandığı gibi DEPLOYMENT mod ile exceptionları göstermek için uygulamanın ExceptionSettings ayarları değiştirilebilir.

Eğer Wicket filter olarak kullanılıyorsa buradan aldığım şekildeki gibi web.xml dosyasından deployment mod da atanabilir.

Aşağıda bu sınıfın diğer sınıflar ile ilişkisi ve uygulama açılırken nereden okundğunu gösteren bir şekil bulabilirsiniz.


19 Eylül 2012 Çarşamba

Spring ve Factory Bean

Spring içindeki bazı FactoryBean sınıflarına örnekler. Collections başlıklı yazıya bakmakta da fayda var.

ListFactoryBean
ListFactoryBean sınıfı ile ilgili gördüğüm güzel bir cevap how does the <list> tag work in spring başlıklı soruda var.

Buradan aldığım örnekte List yaratan bir ListFactoryBean örneği var.


13 Eylül 2012 Perşembe

Hibernate hbm2ddl

Hibernate ile hbm2ddl isminde bir araç geliyor. Bu araç ile ilgili bulabildiğim en iyi yazılardan birisi Eyal Lupu tarafından yazılmış olan Hibernate's hbm2ddl tool başlıklı yazı.

Bu aracı kullanmak için konfigürasyon dosyasına

hibernate.hbm2ddl.auto = validate | update | create | create-drop seçeneklerinden birisini yazmak gerekiyor.

Aşağıdaki örnekte tablolar otomatik olarak yaratılıyor.

<hibernate-configuration>
    <session-factory>
        <property name="hbm2ddl.auto">create</property>
    </session-factory>
</hibernate-configuration>

Index Yaratma
Creating Indexes on DB with Hibernate @Index Annotation başlıklı soruda güzel bir cevap var.

Constraint Yaratma
@UniqueConstraint JPA anotasyon açıklaması ise burada.

12 Eylül 2012 Çarşamba

Apache Wicket ve Spring


Yazıya başlamadan önce hem Apache Wicket hem de Spring'in  bir servlet container içinde çalıştığını unutmamak lazım. Dolayısıyla ilk yapılması gereken iş, Servlet container ile bu iki yazılımı birleştirmek olmalı.

Spring ve Servlet Container


Spring ile Servlet Container'ı birleştirmeyi buradan aldığım şekil güzel açıklamış. Servlet Container bir spring sınıfı olan org.springframework.web.context.ContextLoaderListener sınıfını kullanarak Spring'i ayağa kaldırır. org.springframework.web.context.ContextLoaderListener sınıfının hiyerarşisi aşağıda.




ContextLoaderListener web.xml dosyasına aşağıdaki gibi tanımlanır.

ContextLoaderListene sınıfının okuması gereken dosyalar ise aşağıdaki gibi tanımlanır.

Burada okunacak dosyanın WEB-INF dizini altında olduğuna dikkat etmek lazım. Çünkü war dosyasının yapısı aşağıdaki gibi.

ContextLoader okuması söylenen dosyaları aşağıdaki şekildeki gibi okur ve Spring framework çalışmaya başlar.

Spring ayağa kalkınca herşeyin kalbi olan "ApplicationContext" nesnesini bir yerde saklaması gerekir. Bu iş için de ServletContext arayüzünü kullanır. Bu durumu gösteren şekli buradan aldım.

ServletContext içinde bir nesne saklanmasını göstern örnek kodu buradan aldım.

// following method is invoked one time, when you web application starts (is deployed)
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    // ...
    final int numberOfThreads = ...;
    final ExecutorService threadPool = Executors.newFixedThreadPool(numberOfThreads); // starts thread pool
    final ServletContext servletContext = servletContextEvent.getServletContext();
    servletContext.setAttribute("threadPoolAlias", threadPool);
    // ...
}

// following method is invoked one time when your web application stops (is undeployed)
public void contextDestroyed(ServletContextEvent servletContextEvent) {
    // following code is just to free resources occupied by thread pool when web application is undeployed
    final ExecutorService threadPool = (ExecutorService) servletContextEvent.getServletContext().getAttribute("threadPoolAlias");
    threadPool.shutdown();
}

Apachet Wicket ve ServletContainer

 Apache Wicket ile ServletContainer'ın nasıl birleştiğini aşağıdaki şekil gösteriyor.
Daha sonra javax.servlet.ServletContext nesnesine erişmek için Wicket Notes yazısındaki kod parçası kullanılabilir.


Eğer bir war dosyası içindeki relative path kullanmak istiyorsak Wicket - Relative Image Path without Mounting Page sorusundaki gibi UrlUtils.rewriteToContextRelative metodu kullanılabilir. context.getRealPath() metodu /MyApp gibi bir dizin döndürdüğü için rewriteToContextRelative  metodu /MyApp/images/img1.png gibi bir path döndürür. Aşağıda war dosyasının dizin yapısı görülebilir.


Benzer bir işi How do i link to my Image-Folder inside my Apache Wicket Application? sorusunda cevaplandığı gibi ContextRelativeResource sınıfını kullanarak ta yapabiliriz.
  Apachet Wicket içinden Spring ApplicationContext'e erişmek


Spring ile entegre olmak için wicket-spring.jar dosyasının projeye dahil edilmesi gerekiyor.


Apache Wicket ve Spring'i birbirine entegre etmek çok kolay. Nasıl yapılacağı burada anlatılıyor.

Not : Spring ve Bean Yaratılması başlıklı yazıda Spring Container'ın çalışması ile ilgili biraz daha detaylı bilgi bulabilirsiniz.

1. Annotation Yöntemi

En kolay yöntem de Annotation Based Approach paragrafında anlatıldığı gibi yapmak. Aşağıda buradan aldığım @SpringBean anotasyonu kullanılan örnek bir kod parçası var.


Spring-Wicket: optional but named bean still required sorusunda da anlatıldığı gibi @SpringBean ile required=false kullanarak enjeksiyonu engellemek te mümkün.

2. Kod İle Elle Enjeksiyon Yöntemi
 
Yalnız bu dokümanda dikkat edilmesi gereken bir nokta var. Örnekte de verildiği gibi SpringComponentInjector sınıfı sadece Wicket Component'ları yaratıldığı zaman çağırılan bir listener.Aşağıdaki şekilde bir Component yaratılınca nasıl listener'ın çağırıldığını görmek mümkün.



Halbuki Wicket içindeki her sınıf Component sınıfından türemiyor. Örneğin Model sınıfı gibi. Aşağıdaki şekli buradan aldım ve Component hiyerarşisini kabaca gösteriyor.



Bu durumda model sınıfında @SpringBean anotasyonu kullanılsa bile işe yaramaz.Bunun yerine


InjectorHolder.getInjector().inject(this)

kodunu kullanmak lazım.

Bu da Wicket'ın bir azizliği işte. Bir çok yazılım çatısında da çatıdaki her sınıfın ortak bir atadan türemediğini gördüm. Burada da aynı durum var ve nadiren de olsa bazen normal kullanımdan sapmayı gerektirebiliyor.

3. Kod İle ApplicationContext Nesnesine Erişim Yöntemi

Yukarıda kod ile enjeksiyon yönteminde enjekte edilecek nesnelerin sınıfın bir üyesi (member attribute) olması gerekiyor. Eğer bunu da istemiyorsak ve metod içinde kullanmak üzere ApplicationContext nesnesine erişmek istersek Spring bize kolaylık olması için WebApplicationContextUtils isimli sınıfı kullanılabilir.

Aşağıdaki örnekte olduğu gibi Wicket'ın Application sınıfından ApplicationContext nesnesine erişim mümkün.

public ApplicationContext getContext() {
        return WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
 }


Wicket Stateful ise Spring ile Nasıl Entegre Oluyor ?

Wicket statefull bir yazılım. Bu durumu anlatan güzel bir örneği burada bulabilirsiniz. Bu basit örnekte aynı safya defalarca tazelendiği halde Wicket'ın nasıl stateful çalıştığı anlatılmış. Aslında Wicket bir oturum içinde gösterilen tüm sayfalar için state tutuyor. Bu durumu gösteren güzel bir şekli buradan aldım.


Bu çalışma modeli bir sayfa'nın içindeki herşeyin Serializable olmasını gerektiriyor. Peki bu durumda sayfaya enjekte edilen Spring Bean'lerin de Serializable olması gerekmiyor mu ? Hal böyle ise bir bean ve onun bağımlı olduğu tüm beanlerin de yazılması gerekir.

Eğer böyle olsaydı Wicket Spring ile hayatta entegre olamazdı. @SpringBean ile enjekte edilen sınıf aslında bir proxy. Dolayısıyla @SpringBean ile Spring Framework'teki kullanımın aksine sadece interface kullanılabilir. Sayfa da session'a yazılınca üretilen proxy yazılıyor, atıfta bulunduğu Spring Bean sınıfı değil. Bu durumu açıklayan güzel bir soruyu burada buldum. Yine aynı konuya değinen güzel bir cevabı da burada buldum.. Bir diğer açıklama ise Double-click seems to disrupt Wicket-Spring injection sorusunda açıklanmış.

5 Eylül 2012 Çarşamba

Paralel İşlemler

Paralel işlemler konusundaki kafa karışıklığım devam ediyor. Bir çok dil farklı farklı yapılar sunuyorlar. Ben de notlarımı aşağıya ekliyorum.

Parallel işlemlerle ilgili Data Parallelism sunumu çok faydalı. Sunumun temel konusu donanı mümkün olduğunca çok kullanıp, sinekten yağ çıkarmak. Bu amaç için de izlenebilecek yöntemler aşağıdaki gibi sıralanmış.
En çok kullanılan yöntemleri kırmızı çerçeve içine aldım. "Work Queue" ile "Divide and Conquer" arasında çok ince bir ayrım var. İlki işleri kabaca sadece paralel olarak yürütmeye çalışırken, ikincisi işleri çok daha küçük parçalara ayırarak paralel olarak yürütmeye çalışıyor. Burada ne kadar küçük parçalara ayırmalıyız sorusuna verilen cevap aşağıda.

Yani sequential olarak yürütmenin paralel yürütmekten daha hızlı olduğu noktaya kadar bölmek lazım. Dolayısıyla Fork-Join çatısı I/O işlemleri için kullanılamaz.

Java fork/join framework logic yazısı da konuyu irdelemek açısından faydalı.
 

24 Ağustos 2012 Cuma

Hibernate ve Foreign Key

Foreign Key Nedir
Foreign key kısaca Parent ve Child tabloların birbirlerine bağlanması amacını taşır.

Aşağıdaki şekilde grouptable bir Parent, story ise Child olarak kullanılmış. Her iki tabloyu birbirine bağlayan bir de foreign key var.




Bir başka benzer örneği de burada buldum.



Hibernate ve One-to-Many Kullanımı

Hibernate ile iki tablo arasındaki foreign key kullanılarak one-to-many ilişkisi kurulmak isteniyorsa önümüzde iki tane seçenek var.

  1. Çift yönlü (bidirectional) One-to-Many. 
  2. Tek yönlü (unidirectional) One-to-Many kullanımı.


One-To-Many İlişkisinin Çift Yönlü (Bidirectional) olması ve Foreign Key kullanması

Çift Yönlü Olması durumunu aşağıda açıklamaya çalıştım.


@Entity
public class Child{

private Long id;
private String childName;
private Parent parent;

     @ManyToOne
     public Parent getParent() {
         return parent;
     }
}
@Entity
public class Parent{

 private Long id;
 private String name;
 private String description;
 private List<Children> children;

 @Id @GeneratedValue
 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 @OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
 public List<Children> getChildren() {
  return children;
 } 
}
One-To-Many ve Foreign Key Sütun İsmi
Bu kodda mappedBy kullanımı şu anlama geliyor. Parent ve Child sınıfları ilişkililer ve ilişki için Child sınıfındaki parent alanı için için üretilen foreign key kullanılacak.

Benim verdiğimden farklı örnek bir kodu burada bulabilirsiniz.

Yukarıda verilen örnek kodda @JoinColumn kullanılmamış. Bu gösterimin kullanılmadığı durumda üretilen foreign key sütununun isminin nasıl üretildiği şöyle açıklanmış.
If no @JoinColumn is declared on the owner side, the defaults apply. A join column(s) will be created in the owner table and its name will be the concatenation of the name of the relationship in the owner side, _ (underscore), and the name of the primary key column(s) in the owned side.
Bu açıklamada dikkat edilmesi gereken bir nokta şu. Object Oriented dünyada "owning side" Parent iken, SQL dünyasında foreign key'i içeren taraf "owning side" oluyor (yani Child) . Bu durum burada daha iyi açıklanmış.

Yukarıdaki açıklamaya göre Child nesnesi "owning side" olduğu için @JoinColumn kullanılmazsa bizim üretilecek foreign key sütununun ismi parent_id olacaktı.

Böyle bir konfigürasyon ilk defa yaratılıp save() metodu çağrılırsa üretilen SQL şuna benzer bir şey oluyor.

Hibernate: insert into PARENT (x, y, z) values (?)
Hibernate: insert into CHILD (x, y, z, parent_id) values (?, ?, ?, ?, ?)
Hibernate: insert into CHILD (x, y, z, parent_id) values (?, ?, ?, ?, ?)

Bu şekilde oluşturulan ilşkilerde N+1 select problemi de çok rastlanılan bir durum. Bu konuyla ilgili Hibernate ve N+1 Select problemi başlıklı yazıyı da okuyabilirsiniz.

One-To-Many ve CascadeType (Ard arda İşlemler Seçenekleri)

One-To-Many ilişkilerde yeni parent ve child nesneleri kaydederken foreign key kısıtından dolayı hata almamak için asgari CascadeType.PERSIST seçeneğinin tanımlı olması lazım. Böylece yukarıdaki üretilen SQL örneklerinde de görülebileceği gibi önce parent nesnesi kaydedilir ve onun birincil anahtarı child nesnelerde foreign key olarak kullanılır.

One-To-Many İlişkisinin Tek Yönlü (Unidirectional) olması ve Foreign Key kullanması

Bu durumu açıklayan güzel bir örneği burada buldum. Bir başka örnek ise burada.

Parent sınıfa normalde eklenmesi gereken
mappedBy özelliği yerine bu sefer sadece @JoinColumn gösterimi ekleniyor.

@Entity
public class Child{

private Long id;
private String childName;
}
 
@Entity
public class Parent{

 private Long id;
 private String name;
 private String description;
 private List<Children> children;

 @Id @GeneratedValue
 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 @OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="parent_id", referencedColumnName="id")
 public List<Children> getChildren() {
  return children;
 } 
  
Bu kullanım şeklinde dikkat edilmesi gereken nokta mappedBy kullanılmadığı için Parent sınfı "owning side"
haline geliyor ve kendi id sütununu Child tablosuna foreign key olarak yazıyor.

Bir diğer nokta ise bu kullanım şekli sadece JPA 2.0 ile destekleniyor.

Bir dikkat edilmesi gereken nokta ise bu kullanım şekil tavsiye edilmiyor.

Kullanılan Collection Sınıfları

Hibernate ile "one-to-many" ilişkisinı kullanırken dikkatimi çeken bir şey oldu.

Kod içinde List, Set, Map gibi collection interface'leri kullanılırken Hibernate bu interfacelerden türeyen kendi sınıflarını kullanıyor. Örneğin org.hibernate.collection.PersistentSet gibi.

8 Ağustos 2012 Çarşamba

JExcel ve Apache POI

JExcel ve RowsExceededException
JExcel API'si eski olduğu için büyük excel dosyaları üretirken 65536 satırdan fazla satır yaratılmaya çalışılırsa RowsExceededException exception'ı atıyor. WritableSheetImpl.java dosyasındaki bu satır hatanın sebebi.

Büyük dosyalar üretmek için http://poi.apache.org/spreadsheet/how-to.html adresinde örnek verildiği gibi SXSSFWorkbook sınıfını kullanmak lazım. Zaten bu sınıfın açıklamasında da "Streaming version of XSSFWorkbook implementing the "BigGridDemo" strategy. " yazıyor.


JExcel ve Yuvarlama Hatası
JExcel kullanırken Number tipi alanların değerlerini getContents() metodu ile String olarak alırken dikkatli olmak lazım. Çünkü jxl.read.biff.NumberRecord sınıfı kendi içinde aşağıdaki gibi bir DecimalFormat nesnesi tutuyor. Ancak bu nesne sadece 3 hane hassasiyete kadar doğru değerleri döndürüyor. Eğer girilen değer daha fazla hassasiyete sahipse sonuç yuvarlanarak veriliyor ki bu da farkında olmadan hatalara sebep olabilir.

Aşağıda Jexcel'in kismi sınıf hiyerarşisi var.

Understanding the Excel .xls Binary File Format başlıklı yazıda da Excel'in veriyi nasıl sakladığı anlatılıyor.

XLSX Formatı
XLSX formatı aslında zip dosya formatı ile aynı.Eğer xlsx dosyasını bir zip programı ile açarsak karşımıza aşağıdaki görüntü çıkar.
XSSFSheetXMLHandler sınıfı ile  xml dosyasını parse etmek imkanı var. Bu sınıfın en önemli özelliği her hücreyi String olarak okuyabilmemizi sağlaması.

Excel Hücre Tipleri
Bir hücre aşağıdaki gibi Number olarak görünüyor olsak bile
hücrenin tipi SST_STRING olabiliyor. Bu durumda da string olarak okunabiliyor.

Eğer hücreye format verilmişse
hücrenin tipi NUMBER oluyor. XML içindeki veri 0.22556399999999999 olsa bile


double'a parse edilirken 0.225564 şekline dönüyor. Daha sonra formatlama stringi #,##0.000000 olduğu için java.text.DecimalFormat sınıfı sayesinde Türkçe 0,225564 haline geliyor.


POI ve Number hücrenin sağa/sola dayalı olması
Excel üzerinde 16,466166 görüyoruz ancak xml'de 16.466166000000001 de yazılı.
Eğer hücre sağa dayalı ise xml aşağıdaki gibi
<c r="A1"><v>16.466166000000001</v></c> --> çıktı 16.466166000000001





Eğer hücre sola dayalı ise xml aşağıdaki gibi
<c r="A2" s="1"><v>16.466166000000001</v></c> --> çıktı :  16,466166 çünkü s=1 ile style olarak "general format" kullanıyor