Java SE 7 Update 4, JavaFX 2.1 Çıktı

Bugün itibari ile Oracle JDK 1.7 u4 ve Java FX 2.1 versiyonlarını çıkarttı. Yeni JDK ile çöp toplama mekanizmasının (Garbage Collector) algoritmasını değiştiren Oracle, Java FX’in yeni sürümünü de hem Windows hem de Mac işletim sistemleri için çıkarttı.

JDK’nın son update versiyonu Oracle Fusion Middleware ürünlerinin tamamına destek veriyor.

Tasarım Örüntüleri (Design Patterns)

Bir uygulama geliştirirken sistemin tasarımıyla ilgili sorunlarla birden çok defa karşılaşabiliriz. Karşılaştığımız problemi çözmek fazlaca zamanımızı alabilir. Burada kodu yazan programcının daha önceki tecrübelerinden yararlanması gerekir. Bahsettiğim problemler algoritmik bir düşünceden değil, tamamen kodun genel tasarımından kaynaklanan problemlerdir.

Tasarım örüntüleri, nesneye yönelik dizayn problemlerinin çözülmesi için tasarlanmış ve programlama dilinden bağımsız stratejilerdir. Bu stratejilerden her biri bir tasarım problemini çözmek için geliştirilmiştir. Türkçesi tasarım örüntüleri olan “Design Patterns”, 4 tane tecrübeli programcı tarafından kitap haline getirilmiş ve 1994 yılında piyasaya sürülmüştür. Sun tarafından Gang of Four (GoF) örüntüleri olarak adlandırılan bu dörtlünün kitabında 23 tane tasarım şablonundan bahsedilmektedir. Aslında yüzlerce tasarım örüntüsü vardır. Hatta bu güne kadar isimlerini bilmeseniz bile yazdığınız uygulamalarda mutlaka en az birini kullanmışsınızdır.

Tek bir problemi çözmek için tek bir örüntü kullanılır. Ancak çoğu zaman programcı bir sistemde birden fazla sorunla karşılaşır. Bu yüzden tüm sistemde birden fazla tasarım örüntüsü kullanılabilir. Çok fazla örüntü kullanmanın ilk bakışta sistemi çok karmaşıklaştırdığı düşünülse de, iyi belirlenerek kullanılmış tasarımları olan bir sistem, hiç tasarım örüntüsü kullanılmamış karmaşık bir sisteme tercih edilir.

Tasarım örüntüleri tekrar tekrar kullanılabildikleri için vaktimizi daha iyi değerlendirmemizi sağlar. Ayrıca tüm dünya tarafından kabul görerek çoğu programcı tarafından kullanıldıklarından dolayı başka programcıların tasarımı anlaması çok daha kolay olur.

Programcılığa yeni başlayan bir yazılımcıysanız size tavsiyem GoF’un 23 örüntüsünden en az birkaç tanesini bilmeniz. Yıllardır yazılımla uğraşan, nesneye yönelik kavramlarla ilgili tecrübeli olduğunu söyleyen fakat tasarım örüntülerinden haberi olmayan birçok programcı var. Sonuçta tasarım örüntüleri ile ilgili internette yüzlerce kaynak bulabilirsiniz. Ben de zamanım oldukça tek tek anlatmaya çalışacağım. Bu yazım sadece giriş niteliğinde olacak.

Tasarım örüntülerini üç ana başlıkta toplayabiliriz.

–          Yaratımsal Örüntüler (Creational Patterns) : Yaratımsal örüntüler nesneleri direk bizim yaratmamızdansa bizim için yaratan yapılardır. Bu sayede programlarımız daha esnek bir hal alarak belli bir durumda nesne yaratılmasına karar verebilir.

  • Abstract Factory
  • Builder
  • Factory Method
  • Prototype
  • Singleton

–          Yapısal Örüntüler (Structural Patterns) : Yapısal örüntüler sınıf-nesne arasındaki bağlantıdan sorumludurlar. Bu örüntülerde kalıtım kullanılarak arabirimler tasarlanır. Nesne yaratırken yeni fonksiyonaliteler eklenir.

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy

–          Davranışsal Örüntüler (Behavioral Patterns) : Bu örüntülerin neredeyse tamamı nesneler arası iletişim ile ilgilenir.

  • Chain of Responsibility
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template Method
  • Visitor

PrimeFaces ile autoComplete Örnek

JSF’te web sayfaları dizayn ederken sıklıkla 3. parti kütüphaneler kullanılır. Bu kütüphanelerden bazıları ;

–          PrimeFaces

–          IceFaces

–          ADF Faces

–          RichFaces kütüphaneleridir.

Bu yazımda PrimeFaces kütüphanesinin autocomplete özelliğinden bahsedeceğim.

Öncelikle PrimeFaces kullanabilmek için kendi web sitesinden primefaces-version.jar dosyasını indirmelisiniz. Bu dosyayı indirdikten sonra yapmamız gereken tek şey WEB-INF/lib klasörü altına bu JAR dosyasını kopyalamak. Daha sonra hazır bileşenleri kullanabilmek için sayfa başında namespace tanımı yapmamız yeterli olacaktır.

Şimdi bir web sayfasında giriş kutusundan harfler girildiği anda Java sınıfında tanımlanmış listeden bilgileri otomatik olarak tamamlayan bir örnek kod yazalım. Örnek kodumuzda Java sınıfı içerisinde şehir isimleri tanımlayacağız. Web sayfasındaki giriş kutusuna harf girildiğinde o harfle başlayan tüm şehirler listelenecek. Aynı google’ın bize arama sonuçlarını önermesi gibi.

Eclipse’de yeni bir web projesi yaratıyorum ve primefaces-3.2.jar dosyasını lib dizinine kopyalıyorum. Projemin ilk görüntüsü aşağıdaki gibi olacaktır.

NOT : Web projesini yaratırken (Dynamic Web Project) Configuration kısmında JSF kullanacağımızı söylemeyi unutmayın.

Öncelikle Java sınıfımızı yazalım.

 [codesyntax lang=”java” lines=”no”]

package beans;

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class SehirTamamla {

	private static final String sehirler = "Adana,Adıyaman,Afyonkarahisar,Ağrı,Amasya,Ankara,Antalya,Artvin,Aydın,Aksaray";
	private static final String[] sehirDizisi = sehirler.split(",");
	private String sehir;

	public String getSehir() {
		return sehir;
	}

	public void setSehir(String sehir) {
		this.sehir = sehir;
	}

	public List<String> tamamla(String prefix) {
		List<String> eslesenler = new ArrayList<String>();
		for (String muhtemelSehir : sehirDizisi) {
			if (muhtemelSehir.toUpperCase().startsWith(prefix.toUpperCase())) {
				eslesenler.add(muhtemelSehir);
			}
		}
		return (eslesenler);
	}

	public String sehirGoster() {
		return "sonuc";
	}
}

[/codesyntax]

Burada biz otomatik olarak doldurulacak metinleri bir listeden aldık. İsterseniz veri tabanından okuyabilirsiniz.

Şimdi sayfalarımızı tasarlayalım.

[codesyntax lang=”html4strict” lines=”no”]

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:p="http://primefaces.org/ui">
<h:head>
	<title>Autocomplete</title>
</h:head>
<h:body>
	<div align="left">
		<table class="title">
			<tr>
				<th>Şehir Tamamla</th>
			</tr>
		</table>
		<p />
		<fieldset>
			<legend>A ile başlayan şehirleri getir</legend>
			<h:form>
				<p:autoComplete value="#{sehirTamamla.sehir}"
					completeMethod="#{sehirTamamla.tamamla}" forceSelection="true"
					required="true" requiredMessage="Bir şehir seçmelisiniz !" />
				<h:commandButton action="#{sehirTamamla.sehirGoster}" value="KAYDET" />
				<p />
			</h:form>
		</fieldset>
	</div>
</h:body>
</html>

[/codesyntax]

[codesyntax lang=”html4strict” lines=”no”]

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html">
<h:head>
	<title>Seyahat Onay</title>
</h:head>
<h:body>
	<div align="left">
		<table class="title">
			<tr>
				<th>Seyahat Onay</th>
			</tr>
		</table>
		<p />
		<h2>#{sehirTamamla.sehir} şehrine yolculuğunuz onaylanmıştır.</h2>
	</div>
</h:body>
</html>

[/codesyntax]

Programı çalıştırdığımızda ekran görüntüleri aşağıdaki gibi olacaktır.

Şehri seçip KAYDET düğmesine tıkladığımızda sonuc.xhtml sayfası açılacaktır.

JSF 2.0 Bean Scopes

Web uygulamalarında scope kavramını anlatırken bazı geçerlilik bölgelerinden bahsetmiştim. Bu bölgelerde nesneler saklanıp istenildiği zaman erişilebiliyordu.

JSF uygulamalarında da bean sınıflarının geçerlilik bölgeleri vardır. JSF 1.x versiyonlarında sadece request, session, application scope’lar varken, JSF 2.0 versiyonunda bu alanların sayısı 6’ya çıkmıştır.

Bu yazımda JSF 2.0’da bean sınıflarının saklandığı scope’lardan bahsedeceğim. Öncelikle bean’lerin hangi scope’ta saklandığı bilgisinin bir şekilde container’a söylenmesi gerekir. Bunu faces-config.xml dosyasında yapabildiğimiz gibi sınıfların başında annotation’larla da belirtebiliriz.

Bean sınıflarının başında kullanabildiğimiz annotation’lar ve geçerlilik bölgeleri aşağıdaki gibidir.

  1. @RequestScoped : Varsayılan geçerlilik bölgesidir. Bean sınıfının başında @RequestScoped yazılmasa da bu alan kullanılır. Her gelen HTTP isteğinde bean instance’ı tekrar yaratılır. Örneğin bir sayfada göstermek istediğimiz ilk değerler varsa bean iki defa yaratılır. Bunlardan ilki sayfadaki bileşenlerin değerleri gösterilirken diğeri ise form submit’lendiğinde gerçekleşir.
  2. @SessionScoped : Bu alanda saklanan bean sınıflarına aynı kullanıcıdan gelen bütün isteklerden erişilebilir. Bean sınıfının Serializable olması gerekir. İsteklerin aynı tarayıcı oturumunda yapılması gerekir. Alış veriş sitelerindeki sepet mantığında ya da kullanıcı bilgilerine her sayfadan erişme gibi bir ihtiyaçta kullanılabilir. Ayrıca sayfa yönlendirmelerinde dönüş değerinin sonuna faces-redirect=true yazılabilir. Bu sayede forward işlemi yerine yalnız redirect işlemi yapılacağı JSF’e söylenmiş olur.
  3. @ApplicationScoped : Bu geçerlilik bölgesinde tutulan bir bean sınıfına uygulamayı kullanan herkes erişebilir. Yani tüm kullanıcılar tarafından ortak kullanılan bir sınıftır. Bu sebeple aynı anda erişimde karşılaşılacak sıkıntılar için gerekli önlem alınmalıdır. Bir web sayfasında kullanılan çoklu seçme kutusunun birden fazla sayfada aynı şekilde kullanıldığını düşünebilirsiniz. Combobox içindeki veriler, tüm sayfalar ve tüm kullanıcılar tarafından erişilebilir. Bean instance’ı ilk erişildiğinde yaratılır ve tüm kullanıcılar aynı nesneyi kullanır.[codesyntax lang=”java” lines=”no”]
    @ManagedBean
    @ApplicationScoped
    public class KartalBean() { ... }

    [/codesyntax]

    Eğer sınıf içerisinde zaman alacak bir işlem yapılıyorsa uygulama hafızaya yüklenirken bean instance’ı yaratmak mantıklı olabilir. Bu durumda ;

    [codesyntax lang=”java” lines=”no”]

    @ManagedBean(eager=true)
    @ApplicationScoped
    public class KartalBean() { ... }

    [/codesyntax]

    yazılır.

  4. @ViewScoped : Aynı bean instance’ı aynı sayfadaki aynı kullanıcı tarafından kullanılır. Örneğin bir Ajax isteği ya da bir düğmeye tıklanıldığında yapılacak işlemler için kullanılabilir. Bu geçerlilik bölgesi JSF 2.0 ile birlikte eklenmiştir. Bean sınıflarının Serializable olması gerekir.
  5. @CustomScoped(value=”#{ someMap}”) : Bean bir Map’te saklanır ve yaşam döngüsü kullanıcı tarafından kontrol edilir. JSF 2.0 ile birlikte gelmiştir.
  6. @NoneScoped : Bean herhangi bir geçerlilik bölgesinde saklanmaz. Başka scope’larda bulunan ve bu bean’ler tarafından referans gösterilen bean sınıfları için kullanışlıdır. View Scope ve Custom Scope gibi JSF 2.0 ile birlikte eklenmiştir.

JSF 2 vs. Struts

Çok katmanlı mimari kullanarak web uygulamaları geliştirmek için birden fazla teknoloji vardır. Bunlardan en çok kullanılanları,

–          Spring MVC

–          Sturts

–          Sturts 2

–          JSF

–          JSP, Servlets

teknolojileridir.

Her biri diğerinin ikamesi teknolojiler gibi görünse de her birinin kendine göre avantajları vardır. Bu yazımda JSF 2 ve Struts  framework’lerini karşılaştıracağım.

Öncelikle JSF’in Struts’a göre avantajlarından bahsedelim.

  1. JSF’te custom bileşenler sayesinde çok karmaşık web sayfaları bile kolay bir şekilde dizayn edilebilir. Struts buna izin vermez. PrimeFaces, RichFaces, ADF, IceFaces gibi 3. parti kütüphaneler sayesinde hazır bileşenler kullanılır.
  2. JSF, HTTP ve HTML’e bağlı değildir. Başka protokolleri de destekler. Struts ise sadece HTTP destekler.
  3. JSF’te bean sınıflarına erişmek için web sayfasında isimlerini yazmak yeterlidir. Struts’ta sınıf erişimi ve yönlendirme için karmaşık işlemler yapılmalıdır. (xml mapping)
  4. JSF 2.0 Java EE 6’nın bir parçasıdır ve Java EE 6 destekleyen tüm sunucularda çalışır.
  5. JSF’te kullanılan EL (Expression Language) çok daha kolay ve güçlüdür. Struts’ta bean:write etiketleri kullanılır.
  6. JSF’te bean sınıfları herhangi başka bir sınıftan türemez. İçerlerinde de sabit isimli aynı parametreleri alan metotlar bulunmaz. Struts’ta tüm sınıflar Action’dan türer ve execute() metodu kullanılır. (Struts 2 ‘de bu durum JSF’tekiyle aynıdır)
  7. JSF’te kullanılan konfigurasyon dosyası faces-config.xml, Struts’ta kullanılan struts-config.xml’e göre çok daha kolay ve anlaşılır bir yapıdadır. 
  8. JSF, Eclipse ve NetBeans gibi en fazla kullanılan IDE’ler tarafından direk desteklenir.

Gelelim Struts’ın avantajlarına.

  1. Günümüzde yapılan araştırmalarda iş verenler Struts bilenleri JSF bilenlerden daha çok arıyor. bkz. indeed.com
  2. JSF sayfalarının uzantıları .xhtml olarak biter ama adres satırından .jsf ya da programcının web.xml’de belirlediği başka bir uzantı ile çağrılır. Bu sebeple JSF sayfaları olan bir uygulamada dizinler arasında gezinme problem olabilir. JSF olmayan statik sayfalara erişim ve bağlantıları tanımlamak zor olabilir. (faces-config.xml)
  3. Struts’ta web sayfası ve web sayfasını ele alan sınıfın URL’leri birbirinden farklıdır. JSF’te her ikisine de .jsf diyerek erişilir.
  4. Struts’ın validasyon işlemlerini daha başarılı bir şekilde ele aldığı düşünülebilir. Ne var ki PrimeFaces gibi 3. parti kütüphaneler sayesinde JSF’de de validasyon kolay ve güçlü bir şekilde yapılabiliyor. Ancak sanki Struts hala bir adım önde gibi.
  5. Struts ile istemci tarafında JavaScript ile bileşen – girdi kontrolü yapılabilir. JSF’de Ajax kullanılabilir.

Bir web uygulaması geliştirmeye başlamadan önce mutlaka ihtiyaçların tam anlamıyla belirlenmesi gerekir. Daha sonra bu ihtiyaçları en iyi karşılayacak teknoloji seçilmelidir.

“Destination Path Too Long” dizin silinemiyor hatası

Benim gibi Eclipse kullanan programcıların başına gelmesi muhtemel bir bug’dan bahsedeceğim.

Eclipse’de var olan bir projeyi başka bir workspace altına kopyalayarak çalıştırmak için import seçeneğini sıkça kullanıyoruz.

Daha önceden yazmış olduğum bir projeyi C diskinden D diski altındaki başka bir klasöre taşıyordum. Eclipse IDE’sinde Import -> General -> Existing Projects Into Workspace seçeneğini kullanarak projeyi kopyalamaya başladım. Belli bir süre geçtikten sonra hedef dizinin ismi dikkatimi çekti. Projemin ismi InfoExam’di ve hedef dizin InfoExam/InfoExam/InfoExam/InfoExam/InfoExam/InfoExam şeklinde gidiyordu. Hemen işlemi iptal ettim ve açmış olduğum workspace içerisinde oldukça uzun, içe içe aynı isimde birçok klasör oluşturulduğunu gördüm.

Internetteki araştırmalarım sonucu, komut satırından rmdir, deltree gibi komutlar kullanmayı denedim. Başarılı olamayınca checkdisk yaparak robocopy kullandım ama o da fayda etmedi.

Windows işletim sisteminin fazla uzunluktaki klasör isimlerine ve adres satırının fazlaca uzun olmasına destek vermediğini biliyordum. Fakat sorun o kadar klasörün iç içe kopyalanmasına nasıl izin verdiğiydi. Madem ki okunamayacak, silinemeyecek o zaman yaratılmasına da izin verme 🙂

Bende Java kodu ile bu problemi çözmeye karar verdim. Neyse ki Windows’un sıkıntısını yine Java çözdü. Aşağıda yazdığım kodu paylaşıyorum. Siz de aynı sıkıntıyla karşılaştıysanız fazla zaman kaybetmeyin.

[codesyntax lang=”java” lines=”no”]

import java.io.File;

public class Sil {
	static int dizinSayisi = 0;
	public static void main(String[] args) {
		dizinSil(new File(silinecekDizinIsmi));
	}

	static void dizinSil(File dizin) {
		System.out.println(dizinSayisi++);
		for (File dosya : dizin.listFiles()) {
			if (dosya.isDirectory()) {
				dizinSil(dosya);
			}
			dosya.delete();
		}
	}
}

[/codesyntax]

Benim yukarıdaki kodu birkaç defa çalıştırmam gerekti. Kodu çalıştırıp sileceğiniz dizini kontrol edin. Gerekirse tekrar çalıştırın.

ThreadLocal Sınıfı

Thread Local konusu ilginç, ilginç olduğu kadar da kullanışlı bir yapıdır. Birçok Java programcısının adını bile duymadığı bu güzel yapıyı basitçe anlatmaya çalışacağım.

Thread Local, veri saklamak için kullandığımız geçerlilik bölgelerine benzer bir yapı olarak düşünülebilir. Web uygulamalarında scope kavramı adındaki makalemde bu konuya değinmiştim.

Aynı request scope, session scope gibi herhangi bir nesneyi, bir thread içerisine set etmemizi sağlar. Thread Local içerisine set edilen nesnelere, aynı thread’e erişilen her yerden ulaşılabilir. Bunun yanında her bir thread’in kendi özel Thread Local değişkeni vardır. Bir thread başka bir thread’in Thread Local değişkenlerine erişemez.

Normalde kod yazarken yarattığımız nesneler birden fazla thread tarafından erişilerek paylaşılabilir. Bunu istemiyorsak ve her bir thread’in kendi yerel değişkenlerini kullanmak istiyorsak ThreadLocal kullanılabilir.

Başka bir deyişle thread-safe olmayan bir nesnemiz varsa ve synchronization işlemlerinden kaçınmak istiyorsak nesnelerimizi thread’e özel tanımlarız.

Pek çok frameworkte ThreadLocal kullanımıyla karşılaşırız. Örneğin varolan bir transaction ThreadLocal’de saklandığında, bu transaction’ı her bir metoda parametre göndermeye gerek kalmaz. Bu sayede rahatça istendiği zaman istendiği yerden erişilebilir.

Örneğin bir projede veri tabanına bağlanmak için kullandığımız Connection, PreparedStatement ve ResultSet arabirimlerini ThreadLocal değişkeni olarak yaratmak mantıklı olabilir.

[codesyntax lang=”java” lines=”no”]

private static ThreadLocal<Connection> connection = new ThreadLocal<Connection>();

private static ThreadLocal<List<PreparedStatement>> stmtList = new ThreadLocal<List<PreparedStatement>>();

private static ThreadLocal<List<ResultSet>> rsList = new ThreadLocal<List<ResultSet>>();

[/codesyntax]

Bağlantıları yöneten sınıfta Connection, PreparedStatement listesi ve ResultSet listesi saklayan ThreadLocal değişkenler tanımladığımızı düşünelim. Bağlantıyı connection pool’dan alırken ThreadLocal tanımlanan bu değişken değerleri set’lenerek daha sonra get metodu ile değerleri okunabilir.

Bu sayede katmanlar arasındaki ilişki bağımsız olarak kalmış olur ve nesneler parametre olarak gönderilmeden ilgili sınıflardan çağrılarak kullanılabilir.

ThreadLocal sınıfı Java 2’den beri var olan bir sınıftır. İçerisinde get, set, initialValue ve remove metotları bulunur.

get() : ThreadLocal değişkeninin değerini döndürür.

set(T value) : ThreadLocal değişkeninin değerini günceller.

initialValue() : ThreadLocal değişkeninin ilk değerini döndürür.

remove() : ThreadLocal değişkeninin değerini siler. (Java 5 ile eklendi)

Bu 4 metodun yanında bir de parametre almayan default constructor’ı bulunan ThreadLocal sınıfını daha da detaylı olarak incelemek için lütfen tıklayın.