23 Mart 2009 Pazartesi

Url Rewrite Filter ile arama moturu dostu URL yapmak...

Öncelikle arama motoru dostu bağlantılar artık moda olduğundan eninde sonunda karşınıza çıkacaktır. Neden mi? Çünkü MODA!

Peki Java'da bunu nasıl yaparız? Php de bir çok örneği var. Mesela Apache Http sunucusunun mod_rewrite eklentisi ile bunu php , perl v.b. destekli sunucularda yapmak kolay. Hatta php de buna özel betikler var.

Java'da bu soruna merhem olan API ler mevcut. Ben http://urlrewritefilter.googlecode.com adresindeki api kullanarak bir örnek yapacağım. Diğer ulaşılabilir adres ise http://tuckey.org .

Mesela yapmak istediğimiz şunlar olsun :
  • index.jsp yerine /index
  • index.jsp?id=44&baslik=Teneke-adam yerine /index/44/Teneke-adam olsun
yukarıdaki şekilde sitemdeki bağlantıların erişim adresleri arama motoru dostu olmasını çok istemekteyim. Peki bunu nasıl yaparız.

Önce Eclipse'de bir web projesi oluşturun. Bunun /WEB-INF/lib dizini altına urlrewrite-3.2.0.jar'ı ekleyin. Sonrasında ise /WEB-INF/urlrewrite.xml dosyası oluşturun. Adı urlrewrite.xml olan dosya sizin arama motoru dostu bağlantılarınızın kaynağı olacaktır. Sebebi burada geçerli bağlantı dokularını - url pattern - belirteceksiniz. Belirtilen bağlantı dokularına uyan bağlantılar o kurallara göre işletilerek istediğimizi elde edeceğiz.

Bağlantı dokularında dikkat edilmesi gereken bazı noktalar mevcut:

  • from etiketlerinde yazılan bağlantı dokuları ya da regex patternlerde
    ? yerine \?, = yerine \= , & yerine amp; kullanın.
  • Bağlantılarınızı otomatik outboundrule ile oluşturmak için kesinlikle response.encodeURL() kullanın. Örn: response.encodeURL("/index.jsp?id=44&baslik=dayimin-oglu"); gibi. Siz normal yazın ancak response.encodeURL() ile arama motoru dostu url olsun! Ancak unutmayın eğer bağlantı dokusunda - regex pattern - (^/index.jsp\?id\=([0-9]+)amp;baslik\=([0-9][a-zA-Z]+)$) olduğunda siz response.encodeURL("/index.jsp ....") index.jsp'nin önünde "/" işereti olmaz ise aynı dokuya denk değildir! Bunu unutmayın!

Kural örneği resmi:



index.jsp:




Gerisi sizin hayal gücünüze kalmış...

Örnek bir Eclipse projesi : örnek proje

Projeyi indirip baktığınızda daha iyi anlayacaksınız.

22 Mart 2009 Pazar

Php ile değişen alt yapılara ayak uyduran üyelik sistemi yazmak

Php ile değişen alt yapılara ayak uyduracak bir üyelik sistemi yazmak isteyelim mesela.
Bunu nasıl yaparız?

Örneğin sisteme girişlerin denetlemesini bir veritabanından okuyarak yapıyor olalım. Üyeler kullanıcı adlarını ve şifrelerini yazıp sisteme giriyor olsunlar. Her şey buraya kadar normal.

Bir gün patron gelsin ve artık biz o şirketle birleştik ve onların API'lerini kullarak üyelerin girişlerini denetleyeceklerini söyledi. Bu sırada siz kafayı sıyırabilirsiniz gönül rahatlığıyla...

Peki böyle değişken durumlara ayak uyduracak bir sistem yazabilsek ve üye girişlerinin genel yapısı değişmesede, ufacık bir değişiklikle tüm sistem alt yapısı bir anda değişse...

İşte burada sizin üyelik sistemini nasıl tasarladığınıza göre işiniz ya zor ya da kolay olacaktır.

$giris = new UyelikGiris(new BenimGirisAdaptorum("assd", "123"));

if($giris->girisOnaylandiMi()){
echo "Onaylandı\n";
}


Yukarıdaki kodda üyelik sistemi genel yapısı hiç değişmeden sadece Adaptör nesneyi değiştirerek bu işlemi gerçekleyebiliriz. Tüm denetleme yapıları aynı kalır. Sadece "BenimGirisAdaptorum" sınıfı yerine aynı interface'dan türemiş başka bir adaptör nesnesi kullanmamız yeterli olacaktır. Bu sayede üyelik mekanizması şeklen aynı kalacak ancak kullandığı alt yapı esasen değişmiş olacaktır.

Örnek kodlar aşağıda indirilebilir.

Örnek kod: örnek dosya

Örnek kodu incelerseniz herşey kafanızda daha da netleşecektir.

20 Mart 2009 Cuma

Ah filtre vah filtre, amanında web.xml

Evet filtre javada bir nimet olsa gerek. Hele request ve response nesnelerini değiştirme olanığınıyla tanıştıktan sonra acayip bir sevgidir aldı başını gitti içimde...

Neyse yine bir sorunla başlayalım. Sorunlar olmasa hayat çekilmez olurdu herhalde.

Sorun: Daha önce her şeyi ile doğru dürüst çalışan yönetim paneliniz vardır. Daha önce diyorum, çünkü, artık düzgün çalışmıyordur. Eskiden, yönetim paneliniz aracılığıyla girdiğiniz içeriklerde hiçbir sıkıntı olmadığını varsayıyoruz.

Örneğin: Türkçe içerik girdiğinizde hiç bir sorun yaşamıyordunuz. Fakat bir başka işlemi gerçeklemesi için "IkinciFiltre" adında bir filtre yazıyorsunuz. Her şey çok iyi görünürken bir de karşınıza daha önce çözdüğünüz ; Türkçe karekter sorununu ile yine burunburuna kaldınız.

Bu canınızı sıkmıştır. Muhtemelen "IkinciFiltre" her şeyi bozuyordur. Doğrudur. Ancak nasıl? Ve neden?

Burada basitçe filtreler ile alakalı bir kaç şey bilmek lazım herhalde. Filtrelerin ayaklanması ile alakalı işlem adımları aşağıda sırasıya verilmiş

  1. Web.xml'de önce filtreler ayaklanır - initialize -
  2. Ayaklanan filtrelerin önce init() fonksiyonları daha sonra ise bağlantı örüntüsü - url pattern - kimin sorumluluk alanına giriyorsa o filrelerin doFilter() fonksiyonları çalışır.
  3. Web.xml'de girilen sırada, yukarıdan aşağıya çağrılırlar. Eğer bir bağlantı örüntüsü birden fazla filtrenin sorumluluğunda ise web.xml'de hangisi ön sırada tanımlanmışsa onun doFilter() fonksiyonu çağrılır.
  4. Aynı bağlantı örüntüsü sorumluluk alanına giren birden fazla filtre var ise önce ilk tanımlanın doFilter() fonksiyonu çağrılır. Ardından ikinci filtreye birinci filtrenin doFilter() fonksiyonu içinde çağrılan chain.doFilter() fonksiyonuyla geçilir. Sonra n adet filte sırasıyla bu işlemi yapar. Ve zincirin - chain - en altındaki filtre işlemini tamamlarsa yani doFilter() son satırına kadar çalıştırılırsa bu sefer adımların tersinden, n. filtreden ikinciye oradan da birinci filtreye geri dönülür ve en son ilk çalışan filtrenin doFilter() fonksiyonu tamamlanır.
  5. Eğer zincirin en sonunda servlet var ise servlet çalışmasını bitirsikten sonra zincirin en son halkasında olan filtreye görev geri teslim edilir. doFilter() fonksiyonuna tamamlayan en son filtre görevi bir üste ve ... En son ilk çalışan filtre çalışmasını bitirir.
Bu arada servlet bağlantı adresi ile çağrıldığında önce servletin öntanımlı kurucu fonksiyonu çalıştırılır. Ardından servlet ayaklanır - initialize - . Ve ardından filtreler devreye girer. Sonrasında filtre zinciri işlemlerine başlar. Yani yukarıdaki maddeler işleme konulur sırasıyla...

Yukarıda anlatınları daha iyi anlamanıza yardımcı olabilecek bir adet resim aşağıda verilmiştir.




Burada S1, S2, S3 servlettir. F1, F2, F3 filtredir. Okların akış yönü tarayıcının isteğinden - request - sunucuya ve ilgili web bileşenlere doğrudur.

Kaynaklar:
  1. http://java.sun.com/products/servlet/Filters.html
  2. http://www.javaworld.com/javaworld/jw-06-2001/jw-0622-filters.html?page=1

18 Mart 2009 Çarşamba

Bir problemim var "String" ile...

Geçen gün bir hata ayıklama - debug - işlemi sırasında bir String tipinde nesneyi split fonksiyonu ile parçalara ayırdığınızda, bu parçalardan her birinin asıl nesnenin değerinin bir kopyasını da taşıdığını gördüm.

Aslında bunun böyle olduğunu ilk başta anlamadım. :)

İlk aklıma gelen soru şu idi: Alla alla nasıl olurda parçaladığım nesnenin değeri her bir parçanın içinde bulunur ve parçaların değerleri ile value özelliği - attribute - aynı değeri taşımaz?

Yani nesne değeri başka , nesne.value -> String.value <- değeri başka mı ? Nasıl olurda String tipinde bir nesne split fonksiyonuyla n adet parçaya ayrılır ve bu parçalardan her biri olan String tipindeki nesnecikler asıl nesnenin - parçaladığımız nesne - değerini taşır?



Yukarıda bu hata ayıklama işlemini görebilirsiniz.

Sonra şu aklıma geldi: Bir parçadan asıl nesnenin değerine ulaşabilir miyim?
Evet bu fikir takıldı kafama ve uyuyamayacaktım ben de araştırmaya başladım internette...

Bu değeri nasıl alabilirdim? Ve bu değer neden nesnenin parçalarında bulunuyordu?
Sonra Allah'a şükür etmek istiyorum ki; java iyi ki açık kaynak kod - open source -.
OpenJDK'dan java.lang.String nesnesinin kaynak kodunu buldum.

Evet anahtar özellik "private final char value[];". Bu özellik eğer String tipinde bir nesne oluşturulunca değerinin bir kopyası value de tutuluyor olması. :) İşte sorumun cevabına yaklaşma anı! Ancak bu value private :) yani ben nasıl ulaşabilirim bu özelliğin değerine?

Evet onun cevabı da Reflection ...

Aşağıdaki kod parçasıyla bu değeri almayı başardım:


String msg = "*141#3#123455666656564645#";
StringTokenizer st = new StringTokenizer(msg, "*");
String ilk = st.nextToken();
StringTokenizer st2 = new StringTokenizer(ilk, "#");
String ikinci = st2.nextToken();
String ucuncu = st2.nextToken();
String aman = "tamam";

Class t = String.class;
Field f = t.getDeclaredField("value");
f.setAccessible(true);
System.out.println(f.get(ucuncu));
System.out.println(f.get(ikinci));
System.out.println(f.get(ilk));
System.out.println(f.get(msg));
System.out.println(f.get(aman));


Peki bunu başardım ama bu String nesnesini parçaladım bir örüntüye göre - pattern - ancak hepsinde asıl nesnenin değerinin olması biraz pahalı bir işlem değil miydi?

Yani value private final idi...
Her parça aynı nesnenin value özelliğine bir adres ile işaret etmiyorsa - pointer - bu kadar hafızayı boş yere heba etmenin ne anlamı vardı? GC'ye o kadar güveniyorlardı yani?

Yukarıda verdiğim java kodunu çalıştırırsanız enterasan bir sonuç çıkıyor:


System.out çıktıları:

[C@addbf1
[C@addbf1
[C@addbf1
[C@addbf1
[C@42e816

burada farklı olan [C42e816 yani yeni bir String tipinde nesnedir. Diğerleri ise split ile parçlanmış nesnenin parçacık nesneleri ...

Ve aynı özelliği -
value - paylaşıyorlar!

Hem private final bir özellik ve hem de parçalara ayrılmış nesnenin tüm parçacık nesnelerinde aynı tip dolayısıyla aynı değer !

Neyse sonunda bazı şeyleri çözmüş ve rahatlamış olarak uyudum.
Anlamış olmasamda...