Sunday, October 31, 2004

Otomatik Seçim Kutusu Üretmek, Seçmek ve İşlemek


JSP/Struts bazlı projelerde bazı sayfalarda dinamik olarak seçim kutusu (checkbox) üretmek gerekiyor. Veri tabanında kayıtlı olan müşterileri bir ekranda gösterip, seçim kutusu ile seçilen isimleri veri tabanından silmek gibi bir özellik için bu lazım olabilir. Bu seçim kutularına programatik olarak isim1, isim2, vs... gibi tekil no'lar da atanması gerekecektir. Kullanıcı tarafından seçim yapılıp sayfa form olarak servis'e gönderildiğinde, arka planda id'leri tanımak için, şöyle bir kod kullanmak gerekir.


  public void doGet(HttpServletRequest request,
                HttpServletResponse response)
...
...
for (Enumeration e = request.getParameterNames(); e.hasMoreElements() ;) {
  String key = (String)e.nextElement();
  if (key.indexOf("isim") != -1) {
    if (key.length() > 4) {
      String id = key.substring(4, key.length());
      // elde edilen id ile bir islem yap
    }
  }
}
...

Hepsini Seç Özelliği

Bazen müşterileriniz, eğer ekranda çok fazla seçim kutusu olması muhtemel ise, "hepsini seç" gibi tek bir seçim kutusu ile bütün seçim kutularını seçmeyi isteyebilirler. Bunu yapmak için Javascript kullanmamamız gerekiyor. Aşağıdaki Javascript işlevi, parametre olarak gönderdiğiniz herhangi bir isim "ile başlayan" bütün seçim kutularını otomatik olarak seçebiliyor. Bu kodu, lâzım olan JSP sayfalarının başına koyarak, sayfanın istediğiniz yerinden rahatça çağırabilirsiniz.


<script type="text/javascript" language="javascript">
function check_uncheck_all(grpStr, button) {
var form, el, e, f = 0;
var unbuttoned = (button.value.substring(0,2).toLowerCase() == 'un');
while (form = document.forms[f++]) {
e = 0;
while (el = form.elements[e++])
if (el.type == 'checkbox' && el.name.indexOf(grpStr) != -1)
  el.checked = !unbuttoned;
}
button.value = unbuttoned ? button.value.substring(2) : 'un' + button.value;
}
</script>

Çağırmak için...


       <INPUT type=checkbox name=list value="Tumunu Sec"
   onClick="check_uncheck_all('isim',this)">Tumunu Sec

Kaynaklar






Isim 1

Isim 2

Isim 3

Isim 4




onClick="check_uncheck_all('isim',this)">Tumunu Sec

Saturday, October 30, 2004

Message Driven Beans

J2EE standartının parçası olan JMS hakkında, daha önceki MDB yazımızda MQSeries çerçevesinde örnekler ile bahsetmiştik. Not olarak düşmek gerekir ki, piyasada olan diğer birçok mesaj kuyruğundan sadece bir tanesidir. Ayrıca Java piyasasındaki tüm ürünler artık JMS standartını destemektedir, bu yüzden biri için yazılan kod diğerine taşınabilir hâlde olmaktadır. Diğer ürünler arasında JBossMQ ve FioranoMQ gibi paketleri sayabiliriz.

Bu yazımızda, bir ileti kuyruğundan mesaj almanın "pür JMS" dışındaki alternatif yolları göstereceğiz. Bu alternatif yol Mesaj Tetikli Bean'dir, yâni Message Driven Beans (MDB). (Tabii ki MDB'ler alt süreçlerinde JMS kullanmaktadırlar, ama JMS arayüzlerini büyük miktarda programcıdan saklarlar).

MDB'ler Nedir?

MDB'ler aslında J2EE şemsiyesinin altıdaki diğer akrabaları EJB'ler gibi bir EJB sayılıyorlar. Hakikaten de MDB kodları yazarken ve paketleyip sonuç ortamına gönderirken (deploy), bu benzerliği daha rahat göreceksiniz. Fakat kodlama ve anlambilimsel olarak MDB kavramı Session Bean'lerden biraz değişiktir.

Bu değişikliklerden en önemlisi, bir MDB'nin ne zaman tetiklendiği yâni kullanılma anıdır. Bu an, MDB'nin gözlediği kuyruğa bir mesaj konduğu andır.

Bir MDB, her zaman bir kuyruk üzerinde bekçilik yapar. Ayar bağlamında, yazdığınız her MDB class tipi için bir ayartanım dosyasında o MDB için bir queue ismi tanımlamanız gerekir. Bunu yaptıktan sonra ve uygulama servisiniz MDB'niz ile koşmaya başladığında, artık o kuytuğa atılan her JMS mesajı, MDB'nin onMessage metotunu tetikleyecektir.


public void onMessage(javax.jms.Message message) {
...
}

Gördüğünüz gibi onMessage metotuna bir JMS message nesnesi parametre olarak geçilmiş. Ne kadar rahat! Programcının bu noktada tek yapması gereken bu mesajın içeriğine bakarak bazı kararlar alması ve diğer sistem birimlerine erişerek kodunu tamamlamasıdir.

Eğer aynı işi pür JMS kullanan şekilde yazsaydık, bir döngü içinde filan kuyruktan mesaj bekleyen kodlar yazmamız gerekecekti. karşılaştırırsanız, MDB yolunun ne kadar rahat olduğu belli olmaktadır.

Bir diğer fark ise, MDB'lerin, diğer EJB'lerin aksine HomeInterface ve RemoteInterface gibi garabetlere gerek bırakmamasıdır. Zaten bu tür kullanım EJB 3.0'da da standarttan atılmıştır. Hepimize kutlu olsun!

Şimdi MDB'lere dönelim.

Koşturma Anı

Koşturma sırasında her tek JMS mesajı, tek bir MDB tarafından servislenecektir. Bu mesaj muamele edildikten sonra, yâni MDB'nin onMessage metotu bittikten sonra, MDB'nin de işi bitmiş demektir. İşte bu her mesaj için gereken MDB'yi, ölçekleme açısından bir havuzda tutabilirsiniz. MDB'lerinizin başlaması (new metotu) zaman alan bir işlem ise, her mesaj için bu zamanı ziyan etmek yerine önceden başlatılmış MDB'lerin bir mesajı servislemesi daha hızlı olacaktır. Tüm modern uygulama servisleri bu tür bir ayarı desteklemektedir. Bu durumda bir mesajı servisleyen ve işi biten MDB'ler, geldikleri havuza dönerler.

JBossMQ

Şimdi gelelim örneğimize. Ekteki kodlarda JBoss üzerinde çalışan bir MDB örneği göreceksiniz. Bu örneğin gerçek dünya uygulamasına daha yakın olması için, paketin içine MDB'den Hibernate kullanarak veri tabanına erişen kodlar ve tanımlar da eklenmiştir.

Zip dosyasını açtıktan sonra yapmanız gereken, önce lib dizinini gerekli jarlar ile doldurmak (bunun için gereken jarları sitemizden bulabilirsiniz), ve sonra build.properties içindeki jboss.home adlı değişkeni JBOSS paketini kurduğunuz dizini gösterecek şekilde değiştirmektir.

Bunu yaptıktan sonra, önce "ant lokal-jboss-hazirla" ve sonra sadece "ant" ile MDB kodlarını derleyip, JBOSS altındaki JBOSS/server/default/deploy/ dizinine göndermeniz mümkün olacaktır.

JBOSS, deploy dizinleri altındaki her yeni EAR'i bir J2EE uygulaması olarak addettiği için, bu dosyayı açıp kendi içinde onu koşturmaya başlayacaktır.

Ant betiğinin bir diğer hissettirmeden yaptığı işlem, "ant lokal-jboss-hazirla" sırasında JBossMQ'da bir queue tanımlamasıdır. JBoss'ta queue tanımlamak için sonu "-servis.xml" ile biten bir dosya içinde şu bir tür tanım koymaktan ibarettir.



<?xml version="1.0" encoding="UTF-8"?>

<server>

<mbean code="org.jboss.mq.server.jmx.Queue"
name="jboss.mq.destination:service=Queue,name=OrnekQueue">
<depends optional-attribute-name="DestinationManager">
jboss.mq:service=DestinationManager</depends>
</mbean>

</server>





Bu -servis.xml dosyası, deploy dizini altına konduğu zaman JBoss koşturma anında -servis.xml ile biten tüm dosyaları başlatmaya çalışacağı için, burada tanımlı olan queue'muzda başlamış olacaktır.

Bu tanım dosyası içinde de gördüğümüz gibi OrnekQueue adında bir queue tanımlanmıştır. "Hangi queue'yu hangi MDB'nin beklediği" ise, dd/ dizini altıdaki jboss.xml içinde tanımlıdır. Bunun örneği de aşağıdaki gibidir.



<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE jboss PUBLIC
"-//JBoss//DTD JBOSS 3.2//EN"
"http://www.jboss.org/j2ee/dtd/jboss_3_2.dtd">

<jboss>
<enterprise-beans>
<message-driven>
<ejb-name>OrnekMDB</ejb-name>
<destination-jndi-name>queue/OrnekQueue</destination-jndi-name>
</message-driven>
</enterprise-beans>
</jboss>





jboss.xml dosyası, servis dosyaları aksine EAR paketi içine konulması gereken bir dosyadır. J2EE standartına göre bu böyledir. Ant betiği bunları da otomatik olarak yapacaktır.

Kod derlenip EAR olarak gönderildikten sonra, geriye kalan JBOSS'u başlatmaktan ibarettir. Test etmek için, herşey başladıktan sonra "ant test-integ-single -Dtest=MdbTestUnit.class" komutu ile queue'ya bir mesaj göndermeyi test edebilirsiniz. OrnekQueue üzerine gidecek mesaj, OrnekMDB tarafından okunacak, ve bu MDB içinde Hibernate üzerinden veri tabanındaki bir tablo okunmaya çalışılacaktır.

Diğer Konular

Sıralama

Ölçekleme bağlamında bir mevzudan daha bahis etmek gerekiyor. Eğer elimizde bir MDB havuzu var ise, ve queue'ya çok hızlı bir şekilde bir sürü mesaj geliyor ise, aynı mesajı birden fazla MDB alamaz mı?

Hayır, bu imkansızdır. MDB'lerin queue'dan mesaj okuması, aslında bir mesaj kapma ruhunda ilerleyen bir işlemdir. Bir MDB'ye verilen mesaj, sadece o MDB'ye verilir, ve o anda queue'dan çıkartılır. Yâni MDB o mesaji kapmış olur.

Bu ufak detayı da, aslında, MDB bazlı sisteminizi ölçeklemek için bir mihenk taşı olarak kullanabilirsiniz. Öyle ki, üzerine mesaj konan queue, mesela ayrı bir JBOSS JVM'i içinde olabilir, ve okuyan MDB'ler birden fazla ve yine ayrı JBOSS JVM'leri üzerinden, uzaktaki bu queue'ya erişiyor olurlar, ve mesajları kaparlar. En hafif yüklü olan JBOSS process'inin MDB'leri muhtemelen bir sonraki mesaji kapacağı için, kendiliğinden bir yük dengeleme işlemi (load balancing) yapılmış olur. Bu yazıdaki örneğimizde uzak (remote) bir queue'ya bağlanmayı göstermiyoruz, fakat İnternet kaynaklarından bu tekniği uygulamaya geçirebilirsiniz.

JBossMQ Nerede?

JBossMQ, JBOSS uygulama servisinin bir parçasıdır. Yâni başka hiçbir ek program kurmanız gerekmiyor. JBossMQ, belli bir port üzerinden servis yapan diğer JBoss altbirimleri gibi JBOSS'un bir parçasıdır, ve eğer servisi tanımlı ise (ki JBOSS/server/default tanımı bunu yapmaktadır), run.sh ile JBOSS'u başlattığınızda işleme konacaktır. Yâni, MQSeries ya da FioranoMQ gibi "startQueue.sh" gibi bir betiği aramanıza gerek yok! JBoss'un olağan ayarları size bir Queue idare sistemi bedavadan verecektir.

İyi calışmalar,

Kaynaklar


* JBOSS Sitesi
* Uzak Bir Queue'ye Erişmek
* Örnek Kodlar #1: Gösterilen teknikler, JBOSS'ta MDB tanımı, bu MDB'ye erişilmesi, ve MDB içinden Hibernate kullanarak DB'den veri alınması.
* Örnek Kodlar #2: Üstteki test, artı bir Servlet.

Log4j İle Log Etmek

Java Programlarımızın hatalarını tamir için, ne yaptığını görmemiz gerekir. Görsel, kullanıcı bazlı, tamamı tek servis içinde işleyen kodları hata ayıklayıcı (debugger) gözetiminde işletmek kolaydır, fakat servis bazlı, dağıtık, birden fazla thread ile çalışan programları ayıklayıcı içinde başlatmak ve hatasını bulmak zordur.

Çözüm olarak koda System.out.println ekleyerek program hakkındaki bilgi üretiriz. Bu çıktıyı bir "dosyaya" yönelterek kalıcı günlük tutabiliriz. Fakat bu basit bir çözümdür, komut satırı seviyesinde dosyaya yöneltemeyi ayrı yazmak gerekmektedir, ve hangi mesajın yazılıp yazılamayacaği hakkında elimize kontrol vermez.

Log4j ile bunların hepsini elde edebiliriz.

Log4J

Log4J, hata ve bilgilendirme mesajlarımızı yaratmamızı sağlayan API'lar içeriyor. Bu arayüzleri mesaj gereken her yerden çâğırebiliriz. Önemli hatalar için error(), bilgilendirme için debug(), ve uyarı mesajları için warn() kullanabiliriz.

Bu çağırımlar kodumuzun içinde kalır. Hangi tür mesajların yazılıp yazılmayacağını log4.properties dosyasından kontrol ediyoruz. Daha da ilginci, bu kontrol sınıf seviyesinde bile yapılabiliyor, yani, istersek "sadece A sınıfından gelen mesajları yaz, B sınıfından gelenleri yazma" gibi bir log4j.properties ayarı bile yapmak mümkün.

Sınif seviyesinde tanım yapmak istemezsek, en üst paket seviyesinde yapılan tanım, onun altındaki sınıflar için de kullanılacaktır. com.test adlı paketin debug() ve daha üst (yani error()) seviyesindeki mesajlarını görebilmek için,

log4j.logger.com.test=debug

tanımı gerekiyor, com.test paket ismi, log4j.logger öneki günlükleme fonksiyonu için kullanılmış.

Root logger, çıkış ortamının ne olduğunu belirliyor. Eğer ekrana basmak istiyorsak,

### günlük mesajlarını ekrana (stdout) yönlendir ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

log4j.rootLogger=warn, stdout

Eğer dosyaya yazman istiyorsak,

### günlük mesajlarını dosyaya (bizimgunluk.log) yönlendir ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=bizimgunluk.log # buraya herhangi bir isim olabilir
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

log4j.rootLogger=warn, file

Eğer tek bir dosya gereğinden fazla büyüyorsa, birden fazla dosyaya yazmak için, aşağıdaki tanımları kullanın. Hattâ sonuç ortamında dönüşümlü (rotating) günlük dosyaları en tercih edilir durumdur.

log4j.appender.R.File=gunluk.log

log4j.rootLogger=debug, stdout, R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=[%d{dd MMM yyyy HH:mm:ss}] SMSGW%8p (%F:%L) - %m%n
#log4j.appender.stdout.layout.ConversionPattern=[%d{dd MMM yyyy HH:mm:ss}] %5p (%F:%L) - %m%n

log4j.appender.R=org.apache.log4j.RollingFileAppender

log4j.appender.R.MaxFileSize=5000KB
log4j.appender.R.MaxBackupIndex=25

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[%d{dd MMM yyyy HH:mm:ss}] %5p - %m%n

Apache Commons

Demo'dan da görebileceğiniz gibi, Log4J ile beraber, bu örnek için Apache Commons Logging adlı bir yardımcı paketi de Log4J ile beraber kullandık. Günlükleme fonksiyonlarını basitleştiren bu yardımcı paketi kullanmanızı tavsiye ediyoruz. Gerekli olan kütüphaneler commons-logging.jar, junit.jar, log4j.jar yerlerine konduktan sonra, günlüğe yazmak isteyen her sınıf önce iki Apache Commons sınıfıni import eder.

...
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class HerhangiBirSinif {
...
}

Bu sınıflar alındıktan sonra, debug mesajları için

    if ( log.isDebugEnabled()) log.debug("Bu bir debug mesajidir");

Uyarılar için

    log.warn ("sadece bir uyari");

Exception atıldıktan ve catch() içinde tutulduktan sonra önemli hata bildirmek için

    ...
} catch (Exception e) {
log.error("Burada ciddi hata cikti", e);
}
..

şeklinde kullanılabilir.


Kaynaklar

* Log4J Sitesi
* Apache Commons Logging
* Demo

Friday, October 29, 2004

Aynı Makina, Birden Fazla JBOSS

Eğer aynı makina üzerinde birden fazla JBoss'un işletmek istiyorsanız, bunun en kolay yolu, JBOSS'un kurulmuş olduğu dizinde server dizinine gidip, default dizininin bir kopyasını çıkartmaktır. Server altındaki dizinler, servis tanımları için kullanılır. Her servisin kullandığı port'ların ne olacağı da bu dizin altında yapılır. Yeni kopya servisinizi başlatmak için

$ run.bat -c yeniservistanim

Fakat bir noktayı unutmayın; Kopyayı çıkarttıktan sonra, kopya dizindeki port değerlerini değiştirmeniz gerekiyor, yoksa eski servis tanımı ile beraber çalıştırdığınızda port çakışmaları yaşacayacaksınız. Yâni, yeni servis tanımı için, yeni port numaraları kullanmanız gerekiyor.

Bir projemiz için yeni servis tanımı port'ları tanımlarken, en basit olarak eski 8080 gibi port numaralarının başına bir '1' ekleyerek yeni bir port numarası yarattık. Önemli not: JBoss içinde birçok servis değişik portlar kullanmaktadır, ve bütün gereken port'ları değiştirmek epey zamanınızı alır. Bu port'lar envai yerdeki farklı dosyalar üzerine dağılmış olduğu için, işiniz zor olabilir.

Bu değişimi rahatlatmak için, JBOSS/server/yeniservistanimi altında port değişimi için gereken tüm dosyaları belli port sayıları için biz değiştirip bir zip içinde paketledik.

Ekteki dosyayı indirip açtığımız zaman, şöyle dizinleri göreceksiniz.

  1-port
2-port
...
6-port

Eğer 18080 port'u ile çalışmak istiyorsanız, 1-port altındaki tüm dosyaları JBOSS/server/yeniservistanim altına atmakla değişimi gerçekleştirmiş olacaksınız. Aynı şekilde 28080 için 2-port, 38080 için 3-port, vs..vs..

Artık yeni JBoss'u başlattıktan sonra http://localhost:yeniport adresinden web sitenize erişebilirsiniz.

Dosyalar


* Yeni Port'lar İçin JBoss 4.0.1 Yaması
* JBoss Sitesi

EJB ve JBOSS

JBoss uygulama servisi (application server), J2EE standartını gerçekleştiren, bedava, son zamanlarda oldukça ilgi toplamış olan bir yazılımdır. Serbest yazılım dünyasında önemli bir boşluğu doldurmuştur; İnternet servisi olarak Apaçe, JSP/Servlet için Tomcat, işletim sistemi seviyesinde Linux'tan sonra, EJB tarifnâmesini serbest yazılım dünyasında hayata geçirmek JBoss gurubuna nasip olmuştur.


İlk EJB'leri desteklemek için ortaya çıkan JBoss, artık J2EE katmanlarının (arayüzlerinin) hepsini kodlamış/gerçekleştirmiş, ve bu tam hali ile piyasadaki rakiplerinin karşısına çıkmıştır.

Bu yazımızda JBoss'un kurulması, bir Servlet ve bir oturum EJB'sinin nasıl kodlanıp işletileceğini göreceğiz.

EJB'lerin Mimaride Yerleri

Örnek bir mimari sunduğumuz yazımızda EJB'leri üst arakat katmanında olabileceğini görmüştük. Ayrıca, proje büyüklüğüne göre bu katmanın koyulmasına gerek olmayabileceğinden bahsettik.

Ayrıca bir başka yazıda, sırf Servlet (ve JDO) bazında kodlanmış olan bir J2EE uygulamasının bile ölçeklenmesinin Tomcat ile mümkün olabileceğini gördük.

Peki o zaman, bu es geçilebilen EJB katmanı ne zaman kullanılır olur?

Ölçeklemeyi Servlet seviyesinde değil, EJB'ler üzerinden yapmak için EJB katmanının (üst arakat) eklenmesi mümkündür. Bunun çeşitli sebepleri olabilir; EJB kabının (JBoss gibi) ölçeklenme teknolojisine Tomcat seviyesindekinden daha çok güveniyor olabilirsiniz, ya da JBoss ölçeklenmesi hakkında şirketinizde daha çok bilgi mevcut olabilir, vs. Ya da, servisinize bağlantı kuran teknolojiler sırf tarayıcı değil, görsel olmayan bazı diğer teknolojiler olabilir: Bu durumda oturum takibi için Servlet katmanı kullanılmadığı için, oturum takibi, oturum bilgilerinin kaybedilmeden tutulması, oturuma verilen servisin ölçeklenmesi işleminin görsel ortamdan bağımsız başka bir katmanda yapılması gerekecektir. İşte bu gibi durumlar için JBOSS üzerinde EJB'ler yararlı olur.

Oturum yönetimine gelelim: Eğer EJB'leri bir Servlet tarafından çağırıyorsak, eskiden Servlet oturumu üzerinde sakladiğımız bütün bilgileri artık bir EJB oturum bileşeni üzerinde saklamamız gerekir. Çünkü, artık bütün hafıza/zaman gerektirecek işlemleri yapacak olan, ve bunun sebebiyle tarafımızdan ölçeklenecek servis, EJB servisidir.

Servlet<-->EJB eşlemesini gerçekleştirmek basit olacak. Eğer Servlet'in HttpSession'ı üzerinde EJB oturum bileşenine ait olan göstergeçi saklarsak, Servlet'in ihtiyacı olan bütün oturum bilgilerini artık bu oturum bileşeninden alabiliriz. Ağır işlemleri de EJB'lere geçirirsek, böylece bütün ağır yük, Servlet'ten EJB üzerinde geçmiş olur.

Yazımızın devamında, çok basit bir örnek olaran tek bir Servlet ile tek bir EJB oturum bileşeni kullanımını göreceğiz. Bu örnek sadece ekrana bir mesaj yazacak.

JBOSS kurmak

JBoss sitesinden downloads bağlantısını takip ederek en son JBoss sürümünü indirin. Elinize geçen ZIP dosyasını bir dizinde açın, ve içeriğine gözatın.

Kontrol etmek için, JBOSSDIZINI/bin/run.sh ya da JBOSSDIZINI/bin/run.bat betiğini kullanarak hemen JBoss'u başlatabilirsiniz.

Şimdi, örnek uygulamamızı indirip, istediğiniz dizin altına açın.


Yapmanız gereken tek değişiklik, JBoss'un sonuç dizinini build.xml içinde değiştirmek. Bunun için build.xml içindeki {jboss.dizin} değişkenine JBOSSDIZIN/server/default/deploy değerini girmeniz yeterlidir. (JBOSSDIZIN sizin sabit diskinizde JBoss en üst dizininin nerede olduğuna bağlıdır).

Deploy, gönderim/sonuç dizini anlamına gelir, yani yazdığımız kodların JBoss tarafından işletilebilmesi için paketimizi koymamız gereken yerdir. Paket, J2EE standartına göre JSP/Servlet/Java/EJB kodlarının hepsini içeren .ear dosyasıdır. Ant build.xml betiği bu dosyayı otomatik olarak kodlarımıza göre yaratacak, ve JBoss'a sunacak.

Şimdi örnek dizine komut satırından geçerek, ant komutunu işletin. Kodlar derlenip sonuca gönderilecektir.

Evet! Ufak sitemizi işletmeye hazırız. JBoss, aynen Tomcat gibi 8080 portu üzerinden işlem yapmaktadır. Tarayıcınızı

http://localhost:8080/jboss-ejb-ornek/index.jsp

adresine işaret ederseniz, ilk Servlet/EJB uygulamanızın sonucu görebilirsiniz.


Sıcak Servis (Hot Deployment)

Bu ufak uygulamayı kullanarak, JBoss'u daha yakından tanımanız mümkün. Mesela, sıcak servis (hot deployment) özelliğini kullanarak, JBoss'u indirip kaldırmaya gerek kalmadan, EJB, Servlet kodlarında yapılan değişiklikleri servisin anında işlem sokması mümkün olmaktadır. Buna şahit olmak için, örnek kod üzerinde herhangi bir değişiklik yapıp, JBoss çalışırken ant komutunu işletirseniz, derleme/gönderimden sonra JBoss'un yeni kodları otomatik olarak farkedip (JBoss penceresinden bunu görebilirsiniz) hemen işleme soktuğunu göreceksiniz.

Dosyalar


* Servlet/EJB Örnek Kodları
* JBoss Sitesi

Dağılımlar Hakkında

Baglanti

Thursday, October 28, 2004

JDBC ve Birim Testler - HSQLDB

JDBC'yi direk kullanan ya da perde arkasında JDBC aracılığı ile bir şekilde veri tabanına bağlanan kodların birim testten geçirilmesi, bilgi işlemde dünyasında önemli hususlardan biridir.

Fakat, bu kodları test için hangi yöntemi takip edeceğiz? JDBC kodlarıyla işlettiğimiz SQL, ve bu SQL'dan ile gelen veri, çoğu bilgi işlem uygulamasının kalbini oluşturmaktadır. Eğer birim testleri için sadece JDBC arayüzlerinin taklidini koyarsak (ve bu taklitlerden betonlanmış boş veri geri döndürürsek), o zaman Java kodunun içindeki SQL komutlarının doğruluğunu test etmemiş olacağız. Hâlbuki bu kodların doğruluğu da işlem mantığının doğruluğu için çok önemlidir.

Zorlukları şöyle sıralayabiliriz:


* İşlem mantığı kodu, JDBC ile her noktada temas halindedir. Bu yüzden taklit etmek zordur.
* Birim test, eğer Oracle gibi okkalı, dısarıda çalışan bir veri tabanı kullanıyorsa, bu tabanın her zaman çalışıp çalışmayacağı garanti değildir, ya da programcının her zaman Oracle'ın olduğu yerde olması herhangi bir Oracle'a erişimi mümkün değildir.

Bu yüzden, daha önceki yazıda bahsettiğimiz taklit nesne kalıbını JDBC testleri için takip etmeyeceğiz. JDBC kodları için arayüzlerin konuştuğu nesneleri değil, veri tabanını tamamen değiştireceğiz.

Veri Tabanını Değiştirmek

Uygulamamız eğer Oracle kullanıyorsa, Oracle'in yerine "testler için" sadece hafızada çalışan pür Java bir veri tabanı koyabiliriz. Bu bellek veri tabanını çalıştırmak için tek lâzım olan tek bir JAR içinde olacaktır, ve ayrı bir süreç içinde çalışmasına gerek olmamalıdır, yâni admin gerekliliği sıfır olmalıdır. Bu test veri tabanı üzerinde tüm CREATE TABLE, INSERT komutlarını "testler" tarafından her lâzım olduğunda işletiriz.

Öte yandan, işlem mantığındaki JDBC kodlarının Connection nesnesini dışarıdan alması gerekecektir, böylece test sırasında işlem mantığı Oracle Connection'i ile değil, bu yeni "test veri tabanı" Connection'ı üzerinde işlem yapacaktır. Yâni test edilen işlem mantığı metotunu ateşlediğimiz zaman, çağrılan işlem mantığı dışarıda ne olduğundan habersiz, hep işlettiği kodları aynen çalıştırmaya devam edecektir.

Fakat arka planda, SQL komutları bizim sırf bu test için hazırlamış olduğumuz bellek veri tabanı üzerinde işletilecektir. Eğer kullandığımız SQL, ANSI standartına uygun ise, her taban üzerinde aynen işlemesi gerekir.

HSQLDB

Böyle bir veri tabanı Java için mevcuttur. HSQLDB veri tabanı, pür Java içinden kontrol edilebilen ve hafızada çalışan ANSI uyumlu bir veri tabanıdır. Kurmak için tek yapmanız gereken hsqldb.jar dosyasına CLASSPATH'e koymaktır!

Örnek olarak bir veri tabanı oluşturmak, tablo yaratmak ve veri koymak, şu şekilde yapılabilir.

public class BizimTest {

static String tabloSql =
"CREATE TABLE HESAP" +
"(" +
" kolon1 VARCHAR (12) NOT NULL" +
" , kolon2 decimal (10)" +
")" ;

static String testSatir1[] = {
"insert into hesap values ('111111111111',1)",
"insert into hesap values ('211111111111',1)",
"insert into hesap values ('311111111111',1)"
};

public void testVeriSatirlariniEkle(String arg[], Connection c) throws Exception{
for (int i=0;i<arg.length;i++){
PreparedStatement ps = c.prepareStatement(arg[i]);
ps.execute();
}
}

public void testTabaniOlustur(Connection c) throws Exception {
c.createStatement().execute("DROP TABLE HESAP IF EXISTS");
c.createStatement().execute(tabloSql);
c.commit();
}

Connection baglantiAl() throws Exception {
Class.forName("org.hsqldb.jdbcDriver");
return DriverManager.getConnection("jdbc:hsqldb:.", "sa", "");
}

...
...



Örnek veri koymak için gerekli olan işlevi testVeriSatirlariniEkle içinde görüyoruz.

Tabloları CREATE TABLE ile yaratmak için tablo yapısını gerçek (Oracle için yazılmış olan) CREATE TABLE komutlarından hareketle yazmamız gerekiyor. Kolon tiplerinin bazılarının değişmesi gerekebilir, meselâ Oracle NUMERIC tipini kullanırken, HSQLDB DECIMAL ya da DOUBLE tipini kullanmaktadır. Bu değişimi otomatik olarak yapacak bir Perl betiği aşağıda verilmiştir.

open IN, $ARGV[0];
undef $/;
open OUT, ">hsqldb_tablo_yarat.sql";
$_ = <IN>;

s/BLOB/VARCHAR/sg;
s/CREATE TABLE (.*?)\n\(/DROP TABLE $1 IF EXISTS\;\nCREATE TABLE $1\n\(/sg;
s/(.*?)(\s*?)NUMBER(\s*?)\((.*?)\)/$1$2DECIMAL$3\($4\)/sg;
s/(\s*?)NUMBER(\s*?)/$1DECIMAL$2/sg;
s/(\s*?)RAW(\s*?)/$1VARCHAR$2/sg;
s/(.*?)(\s*?)VARCHAR2(\s*?)\((.*?)\)/$1$2VARCHAR$3\($4\)/sg;

print OUT;
close IN;
close OUT;


Şimdi bir test yazalım:

        ...
public void testKacHesapVar() throws Exception {

testTabaniOlustur(c);
Connection c = baglantiAl();
testVeriSatirlariniEkle(testSatir1, c);

IslemMantigi mantik = new IslemMantigi(c)

ResultSet rs ;

rs = mantik.kacKisiVar();

int kisiSayisi = 0;
while (rs.next()) kisiSayisi++;
assertTrue(kisiSayisi == 2);
}

} // BizimTest sonu


Şimdi, IslemMantigi nesnesi içinde test edilen kacKisiVar() metodunun gerçekleştirimini görelim.

public class IslemMantigi {

protected Connection baglanti = null;

public IslemMantigi() {
try {
Class.forName("jdbc:oracle:oci:@TEST");
baglanti = DriverManager.getConnection("oracle.jdbc.driver.OracleDriver".
"kullanici", "sifre")
} catch (Exception ex) {
log.error("",ex);
}
}

public IslemMantigi(Connection c) {
baglanti = c;
}


public int kacKisiVar() {

int kac = 0;

try {
PreparedStatement ps2 =
queryConnection.prepareStatement("SELECT COUNT(*) FROM HESAP");
ps2.setInt(1, 1);
ResultSet rs = ps2.executeQuery();
while (rs.next()) {
kac = rs.getInt(1);
}
rs.close();
} catch (SQLException ex) {
System.err.println("" + ex);
}

return kac;
}
...
}

Dikkat edelim: IslemMantigi nesnesinde bir değil, iki tane kurucu metot (constructor) var. Bunun sebebi, daha önce bahsettiğimiz veri tabanı bağlantısını testler için dışarıdan verme ihtiyacından ileri gelmektedir. Boş kurucu metodun bağlantıyı Oracle'a giderek kendi kendine aldığını görüyoruz, testlerin de IslemMantigi nesnesini HSQLDB'ye işaret eden bir Connection ile yaratabileceğini görüyoruz. Nesnesinin geri kalan kısmının tüm bu taklalardan hiçbir haber olmamaktadır. Bu bölümler için zaten bir Connection vardır, ve PreparedStatement, ResultSet ile gereken işlemler yapılır.

Kaynaklar


* HSQLDB, jMock, ve diğer bazı test etme tekniklerini anlatan bir sunum
* HSQLDB
* JDBC Kodlarının Tasarımı ve Testi (Design and Test JDBC Code)

Projemiz Niye Başarılı Oldu?

Alttaki liste, Hibernate'in ürününün çok popüler olmasında etken olan geliştirme süreci ve yöntemleri açısından doğru yaptığımız şeylerin (fikrimce) bir listesidir.

Hızlı Sürüm Yapmak

Sıkça yaptığımız sürümler (hattâ bazen bir iki gün içinde) projemizi hatasız ve kullanıcarımızı 'ilgili" tutmanın en çabuk yoluydu diyebilirim. Sık sürüm gören kullanıcılar projemizin aktif ve ivmeli olduğuna kanaat getirdiler, ve projeye ilgili kaldılar. Ayrıca bir yazılımda hangi özelliğin (functionality) kullanılan, ihtiyaç duyulan bir özellik olduğunu anlamanın en iyi yolu, işleyen bir yazılımı şöyle bir dışa açmaktır.

Regresyon Testleri

Herhalde artık tüm Java cemaati, otomize edilmiş birim testlerinin önemini biliyor. Çok sayıda ve detaylı bir test havuzu, bizim projemizin kaynak kodlarının idare edilir ve stabil hâlde kalmasında en büyük faktördür, çünkü projemiz inanılmaz büyüklükte dizayn ve özellik listesi değişiklikleri yaşadı. Mentalite öyle olmalıdır ki, eğer bir özellik (feature) için bir test yoksa, o özelliğin çalışır mı çalışmaz mı olduğu hakkında hiçbir fikrimiz olamaz.

'Tek' Bir Şeyi 'İyi' Yapın

Bir şey konusunda en iyi olun. En iyi olamayacağınız şeylerde bırakın öteki projeler iyi olsun.

'Aşırı Dizayn' Hastalığına Kapılmayın

Çok fazla soyutluk ve ürününüze çok fazla esnekliği projenin çok başında tanıştırmak istemek, büyük bir zaman kaybı olacaktır. Bu zamanı çok daha verimli bir şekilde kullanıcıların ihtiyacı olan gerçek problemleri çözmek için kullanmalısınız. İşleyen en basit çözümü kodlayın. Kullanıcıları alakâdar etmeyen problemleri çözmek için uğraşmayın. Kod açısından gerçekleştirimin zarif olup olmadığı HİÇ ÖNEMLİ DEĞİLDİR, en azından projenin en başında bu böyledir. Önemli olan, "kullanışlı özellikleri" "zamanında" kullanıcıya verebilmektir.

Merkezi Vizyon

Bir komite ile karar veriyor olmanız için, devasa bir projede olmanız lazım. Diğer çoğu projelerde, bir iki tane açık fikirli insanın projenin vizyonunu ve yönünü idare etmesi, geliştirmesi yeterlidir. Bu sayede proje tek bir şeyi iyi yapmaya odaklanabilir. Kanımca açık yazılım projelerini çökerten en yaygın sebeplerden biri özellik enflasyonudur (scope creep).

Belgeleme

Belgelenmemiş özellik sözü, telâfuzu imkansız bir şey, anlambilimsel bir imkansızlıktır. Eğer kullanıcılarınız bir özelliğin olduğunu bilmiyorsa, o özellik, yok demektir. Ya belgeleyin, ya da kaynak koddan özelliği atın. Kaynak kodunuzda yer işgal etmekten başka bir şey yapmıyor.

Standartizm Hastalığından Korunun

Doğru hazırlanmış standartlar (meselâ JMS, JDBC) sistemlerarası çalışabilen programlar ve taşınabilir kodlar için fevkalâde yardımcıdır, kötü hazırlanmış standartlar yaratıcılığın ve teknoloji mucitleri için fevkalade bir engeldirler. "XXX standartını destekliyor" gibi bir etiket, hiçbir ürün için bir kullanıcıdan gelen istek/gereksinimin cevabı olamaz, hele ve hele XXXX standartı bir "uzman" komitesi tarafından hazırlanmış ve bu uzmanlardan hiçbiri kendi pişirdiği tatsız yemeği yemek zorunda olmamamış insanlardan oluşuyor ise. En iyi yazılım, deneme, yanılma ve deneyler ile yazılmaktadır. Çoğunluğun standartı olarak bilinen de facto standartlar, kullanıcılar için tepeden indirilmiş, apriori standartlardan daha elverişli ve sağlıklıdır.

10 Dakikada Hazır..İşliyor...Çalışıyor

Müstakbel bir kullanıcının, bir yazılımı indirir indirmez kurmak, ayarlamak ve bazı kuruluş hatalarıyla uğraşmak için harcayacağı zaman, yarım saatten az olmalıdır, bundan fazlası kullanıcıya fazla gelir. Bizim amacımız, yeni kullanıcılarımızın demo'yu "5 dakikada" çalıştırabilmesidir (JDBC bilgilerinin olduğunu farzederek), ve "yarım saatte" kendi Merhaba Dünya programlarını yazabiliyor hâlde olabilmeleridir.

Programcılardan Cevapların Çabuk Gelmesi (Responsiveness)

Kullanıcılar bir problemle karşılaştıkları zaman, ki muhakkak karşılaşacaklardır, ürünü yazmış olan programcıların cevap vermekte hazır ve nazır olmaları gerekir. Kullanıcılar size belgelerinizdeki boşlukları bulmakta yardımcı da olacaklardır (çünkü anlamadıkları bir özelliği kullanamazlar). Kullanıcılar test havuzunuzun kaçırabileceği kendini iyi saklamış hataları bulmanıza da yardımcı olurlar. Sonuçta kullanıcısız bir proje çarçur edilmiş zamandan başka bir şey değildir.

Hatalar hakkındaki komik durum şudur: Aslında hata bulmak kullanıcıları rahatsız etmiyor eğer bu hatalar çabuk tamir edilirse. Çabuk hata onarmak (responsiveness), bir hatanın, bir haftadan önce tamir edilebilmesi demektir. Genel onarma zamanı da (rapor edilmesi ile tamirin CVS'e koyulması arasındaki geçen zaman) 24 saat olursa en idealidir.

Çabuk Güncellenebilen Wiki Sayfaları

..

Gavin King

Projelerde Hata Takip Düzeni

Bilgi işlem projelerinde hata takip için bir sistem kurmanız gereken vakit, stabil bir uygulamanın ortaya çıkmaya başladığı ve sistemi müşterilere göstermeye başladığınız zamana yakın bir arada olmalıdır.

Hatalar, herhangi bir programcının herhangi bir JSP sayfasında/özelliğinde çıkan hatayı tamir etmesi gibi bir istek olabilir; Bu gibi istekler zamanla biriktikçe, hangisinin tamir edilmiş olduğu, test etmeye hazır olduğu gibi konular idare açısından saç yolduracak seviyeye gelebilirler. 20-30 tane bu şekilde hata bile bir hata takip sistemi kurmamızı gerektir.

Bu sistemin ana özellikleri şunlar olmalıdır. Sistem;


* Programcılara ait hataları sadece onlara gösterebilmeli
* Hataların tamir durumunu kaydedebilmeli
* Test edilecek/bitmiş hataların hangileri olduğunu testçilere gösterebilmeli
* Hataların testçiden programcıya, ve tamir edildikten sonra programcıdan testçiye geri olan iş akışını destekleyebilmeli.
* Hataların değişim tarihçesini, herkezin düştüğü notları kayıtlı tutabilmeli ve gösterebilmelidir

Bu ana hatları destekleyecek en iyi uygulama türü, portal şeklinde olan bir hata takip sistemidir. Buna karşılık, Excel tablolarında hata takip yapmak çok külfetli olacaktır, çünkü bu şekilde tablolarda iş akışı, tarihçe tutmak imkansızdır. Tek bir Excel tablosunda birkaç programcının hatalarının en son durumunu kaydedilip birleştirilmesi çok zordur.

Portal bazlı hata takip programı, her programcıya ve testçiye (genelde bir tane olur) bir giriş ismi verecek, testçilerin yarattığı hataları programcılara göndermesini sağlayacaktır.

İş Akışı

İş akışının genel hatları şöyle olur. Testçi, hata portal'ına kendi kullanıcı ismini kullanarak girer projenin uygulamasında gördüğü bir hatayı sisteme ekler. Bu hatayı, bir programcıya atar. Bu programcı, o hatanın çıktığı kodu yazan, ya da o kodu iyi bilen bir başka programcı olabilir.

Bu programcı, günün herhangi bir saatinde portal'e girip hataları listesini kontrol edecektir (ya da hata portal'inden otomatik e-posta almıştır, portal hata atanır atanmaz programcıya e-posta atmak için ayarlanmış olabilir), ve listesindeki kendine atanmış hatayı görür. Herkesin benimPortal listesi, kendine atanan hataları göstermesi için ayarlanmıştır (buna testçi de dahil, çünkü ona da hatalar atanabilir)

Programcı hatanın detayına tıklar, ve tanımı okur. Kendi geliştirme ortamında hatayı tekrar ettirerek (duplicate) kendi de görür, ve tamir etmek için kolları sıvar.

Programcı hatayı tamir edince, yeni kodu kaynak kontrol sistemine ekler. Projenin teknik lideri her gün başında test makinasına zaten sürüm yapıyordur, ya da acil bir sürüm yapılarak (o hata çok önemli ise) test makinasına en son kodlar atılır.

Programcı, portal'den tamir edilmiş hatanın detayına tekrar inerek, bu sefer bir değişiklik yapar. Hatanın statüsünü "Çözüldü" olarak değiştirir, ve hatanın yeni sahibi olarak "testçi" arkadaşını seçer. Hatayı kaydeder. Şimdi programcı kendi benimHataPortal ekranına döndüğünde, tamir etmiş olduğu hatanın kaybolduğunu görecektir. Ne güzel! Yapacak iş azaldı!

Bu hata tabii kaybolmadı. Testçi kimse, benimHataPortal'ına girdiğinde (ya da aynı şekilde e-posta aldığında) portal'a girecek, ve listesindeki hatayı görecektir. Testçilerin hata alması garip olmamalı, testçinin görevi sadece test etmek olduğu için bu hatanın onun listesinde olmasının tek bir anlamı vardır: Hata tamir edilmiştir, ve tekrar test edilmeye hazırdır.

Test makinasında da en son kodlar olduğuna göre, testçi arkadaş bu makinaya bağlanarak hatanın olduğu kısma/bölüme giderek kontrolünü yapar.

Eğer hata gerçekten tamir olduysa, testçi portal'a dönerek o hatanın detayına gelecek, ve "Kapandı" statüsüne getirecektir. Başka yapması gereken bir şey yoktur. Ama eğer hata hâlâ orada ise, o zaman hatanın statüsünü "açık" olarak değiştirmeli, ve sahibi olarak (tamir ettiğini zanneden) programcıyı atamalı, yani, hatayı programcıya geri göndermelidir! Ve bu şekilde iş akışı tekrar başlamış olur.

Eğer hata tamir olmuş ise, kapandı statüsünü alan hata herkezin listesinden kaybolacak, yani tamir edilen hataların arasına karışmış olacaktır.

Ekler


* Dikkat edilmesi gereken bir nokta, bir hatanın tamir olmuş ama, o hatadan bağımsız başka bir hata aynı ekranda/bölümde bulunmasında ortaya çıkar. Bu yeni hatanın eski hata üzerine not düşülmemesi gerekir. Çünkü yeni hata değişik bir hatadır. Ayrı şekilde takip edilmesi gerekecektir.
* Üstte tarif edilen düzende bir nüans farkı şöyle olabilir: Testçi hatayı atar (programcıyı seçerek). Ama programcı, tamirden sonra tesçiye geri atama yapmaz. Sadece hata statüsünü "çözüldü" ye getirir. Bu durumda testçinin görevi, periyodik bir şekilde portal üzerinde statüsü "çözüldü" durumunda olan hataları kontrol etmektir çünkü hatayı geri kendi benimPortal listesinde görmeyecektir.

ITracker

Evet, genel hatları ile tarif ettiğimiz bu iş akışını ITracker programı ile gerçekleştirmeye çalışacağız. ITracker'in nasıl kurulacağını başka bir yazıda işlemiştik.

Programa admin olarak ilk girdiğinizde bu ekranı göreceksiniz. (Eğer bu ekran İngilizce geldiyse, My Preferences altından Turkish seçerek Türkçe ekrana gelebiliriz)


Yukarıdaki ekranda bekleneceği gibi hiçbir proje yok. İlk yapmamız gereken, bir proje yaratmak. İlk önce Sistem Bakımı seçeneğine tıklayın.


Proje Bakımı | Bakım Yap seçeneğinden Proje Listesi ekranına gelin.


Şimdi üst sağda bulunan sayfa ikonuna basarak yeni proje yaratma sayfasına gelebilirsiniz.


Üstteki örnek bilgileri girerek hemen bir proje yaratmamız mümkün. Proje ismi "deneme" olarak seçildi.


Kullanıcılar

Şimdi de kullanıcılar yaratmamız gerekiyor. Bu kullanıcılar, projede görev yapan programcılar, proje müdürü gibi kimseler olacaklar. ITracker'ı kullanan herkese ayrı bir kullanıcı ismi gerekecek, çünkü herkes kendine ait olan sorunlari (hataları) kendi kullanıcısı üzerinden görecek.

Aşağıda ilk kullanıcıyı yaratıyoruz. Kullanıcının ismi ali, ve bu kimse projede sorumlu kişilerden biri. Ali, testçi görevini yürütecek. Ali, uygulamayı test edip çıkan hataları programcılara atamak ile görevli.

Ali'yi eklediğimiz ekrana dikkat ederseniz, Ali'ye birçok hak verdiğimizi görüyoruz. Bunlardan en önemlisi Proje Bakım ve Sorunu Kapat haklarıdır. Proje müdürü (ya da testçisi) olarak Ali, sorunları tamir edildikten sonra tekrar test edip, sorunun çözülüp çözülmeyeceğine karar verebilecek tek kişi olmalıdır. Programcılar sorunları kapatmamalı, Ali'ye test edilmesi için yollamalıdır.


Aynen Ali'yi yarattığımız gibi, Veli'yi de benzer şekilde ekleyebiliriz. Tabii Veli'de testçilere özel haklar olmayacak.

Hata Eklemek

Bu noktada, Ali ve Veli sistemi kullanmaya hazırlar. Ali testçi, Veli programcı. Şimdi, Ali'nin sisteme nasıl sorun eklediğini görelim.

Ali, ilk giriş yaptığında benimITracker ekranını görecek. Buradan, üst kısımdaki Proje Listesi seçeneğinden "deneme" projesini görebilir. Ali, en solda bulunan üçlü ikon gurubundan ortadakini seçerek, yeni bir sorun ekleyecek ve Veli'ye atayacak. Görelim.


Atanma yapıldıktan sonra, görmek için Veli olarak sisteme girebilirsiniz.


İşte listede gördüğünüz gibi bir sorun Veli'ye atanmış.

Not: Eğer Veli, benimITracker'ında çıkan listesini, sadece ona atanmış sorunlara indirmek istiyorsa, bunun ayarını rahatlıkla yapabilir. En üstteki "Tercihlerim" seçeneğinden,


.. "benimITracker Bölümlerimi Sakla" kısmına gidip, orada Atanmış Sorunlar hariç bütün diğer listeleri kapatabilir.

Şimdi gelelim iş akışımızda önemli bir bölüme: Veli, uygulama kodlarını hatasını tamir etmek üzere değiştirdi, kendi geliştirme makinasında test etti ve tamir edildiğine karar kıldı. Şimdi, bu hatanın "tekrar test için Ali'ye geri gönderilmesi gerekiyor.

Hata listesinden bu hatayı değiştirmeyi seçip, aşağıdaki gibi bir giriş yaparsa, hatayı Ali'ye geri göndermiş olacaktır (kırmızı ile işaretli alanlardan)


Bu sayede Ali, kendi benimITracker sayfasından, tamirini istediği hatanın geri gelmiş olduğunu görecek, bu hatayı test ederek eğer tamir olmuşsa Kapat seçeneği ile hatayı kapatacaktır. Kapanmış statüsündeki hatalar kimsenin benimITracker listesinde gözükmezler. Onlar tamir edilmiştir!

Hata Takip Aracı - ITracker

Java projemiz için hata takip programı gerektiğinde, İnternet'te ufak bir arama yaptık. XP projelerini idarede kullandığımız XPlanners tecrübesi, bizi tekrar aynı şekilde Struts ve J2EE tabanlı bir uygulama aramaya itti. J2EE bazlı programların kurulumu oldukça kolay oluyor, ve envai türden işletim sistemi ve veri tabanı ile çalışabiliyorlar.

Bu yüzden ITracker adlı programı denemeye karar verdik.

ITracker


ITracker'ı kurmak için, itracker_xxx.noaxis.bin.zip şeklinde olan dosyayı indirin. Bu zip içinde web tabanlı çalışabilen işlerkodları bulabilirsiniz. Öteki listelenen dosyalar başlangıçta lazım olmayacaktır. Mesela içinde axis kelimesi geçen zip, ITracker'ı bir Web Servisi olarak işletiyor ve öteki programlar ile XML üzerinden iletişim kurmasını sağlıyor! Başlangıçta çok fazla. (İleride kurcalamak isterseniz aklınızda olsun).

Bu yazımızda ITracker'ı, JBoss ve PostgreSQL üzerinde kurmayı tarif edeceğiz.

Kurmak

JBoss ve PostgreSql kurulduktan sonra, aynı makinada birden fazla JBoss servisi işletip işletmeyeceğinize karar verin. Makina kıtlığı çeken projeler genelde hata takip programlarını, proje idare araçlarını ve uygulamalarının test edildiği servisi hep aynı makina üzerine koyabiliyorlar. Eğer projeniz JBoss üzerinde geliştirilen/test edilen bir uygulama ise, ve aynı makinada ITracker ve sizin uygulamanız aynı anda çalışacaksa, iki JBoss arasında port çakışması yaşanacaktır! Evet, aynı JBoss içine birden fazla EAR atabilirsiniz, ama bir uygulamayı iptal ettiğiniz anda, öteki uygulamada duracaktır. En iyisi, iki uygulamayı tamamiyle birbirinden izole edin. Ayrı JBoss'lar.

Aynı makinadaki PostGreSql veri tabanı, herhalde başka uygulamalar tarafından da kullanılıyordur. ITracker için yeni bir veri tabanı yaratırsak, idaresi daha rahat olur. Bu veri tabanının ismi itracker olsun.

createdb itracker

Diğer yazımızda tarif edilen admin kullanıcısı, bu veri tabanı için de geçerli olacak.

Şimdi, ITRACKERDIZINI\sql\postgres\install\create_itracker_core.sql adlı dosyayı,
psql itracker
ile komut satırına girdikten sonra
\i create_itracker_core.sql
kullanarak işletin.

Güzel. Şimdi JBoss dizininize girin, ve ITracker için gerekli olan veri kaynak dosyasını yaratın. itracker-ds.xml adını verebileceğiniz bu dosyayı JBOSSDIZINI/server/default/deploy altına bırakın. İçeriği şöyle olabilir (jndi-name mutlaka ITrackerDS olmalı)





ITrackerDS
jdbc:postgresql://localhost:5432/itracker
org.postgresql.Driver
admin





Şimdi, JBOSSDIZINI/server/default/conf/standardjbosscmp-jdbc.xml dosyasını açın. Default datasource'u değiştirmeniz gerekecek. DefaultDB kelimesi yerine şöyle olsun:

   ...

java:/ITrackerDS
...


En son olarak ITRACKER/docs/itrackerApplication.properties dosyasını JBOSSDIZINI/server/default/conf altına koyarsanız, herşey tamamlanacak. JBoss'u başlattıktan sonra,

http://makinaismi:port/itracker

... adresinden programı kullanmaya başlayabilirsiniz. Program otomatik olarak ilk kullanıcıyı yaratıyor, kullanıcı: admin, şifre: admin ile programa girip projeniz için gerekli bilgileri girmeye başlayabilirsiniz.

ITracker resmi sürümü, blogumuz yardımlarıyla Türkçeleştirilmiştir durumdadır. Kullanıcı olarak sisteme girdikten sonra, "Tercihlerim" (My Preferences) seçeneği altından Türkçe'yi seçerek uygulamanın dilini tamamen değiştirmeniz mümkün.

Kaynaklar


* ITracker
* JBoss
* Mantis Bugtracker adlı Apache/PHP/MySQL bazlı çalışan alternatif bir program.

Java İle Excel Nasıl Okunur?

Bir Excel dosyasını herhangi bir veri tabanına yüklemeniz gerekebilir. Müşteriniz, belki de bazı verileri Excel üzerinden girmekte, ya da Excel dosyaları başka bir veri ortamından sizin ortamınıza aktarma yapmak için bir aracı format olarak kullanılmaktadır. Her iki durum için de, Java dili ile Excel .xls dosyasında istediğiniz hücreye erişmeniz gerekecektir.

Excel çalışma kitapları (workbook) birçok çalışma sayfasından (worksheet) oluşmaktadır. Her sayfa iki boyutlu bir tabloyu içerir. Bu tablolar, hücrelerden oluşmaktadır.

Java Excel API

Yukarıda anlatılan türden bir erişimi sağlamak için Java Excel API biçilmiş kafandır.

Isletmek icin jxl.jar lazim. 

Örnek Kullanım

İlk önce, tek satır kod yazmadan, bir .xls dosyasının içeriğini ekranda göstermeyi örnekleyelim.


java -jar jxl.jar -csv benimexceltablom.xls

İşte bu kadar! Tabii isteğimize uygun değişik bir program yazmak biraz daha uğraş gerektiriyor. Sitemizden indirebileceğiniz dosyada, ExcelTablo.java adlı bir dosya bulacaksınız. Bu dosya, basit bir kullanım kalıbını örneklemektedir. Mesela, çalışma kitabını açmak için gereken kod aşağıdadır.


 String kodlama = "ISO-8859-9";
WorkbookSettings settings = new WorkbookSettings();
settings.setEncoding(kodlama);
Workbook workbook = Workbook.getWorkbook(new File("Book8.xls"));

Daha sonra, bu çalışma kitabından, birinci çalışma sayfasını çıkartalım, ve 1. satır, 1. kolondaki hücreye erişelim.


 Sheet sheet = workbook.getSheet(0);
Cell a1 = sheet.getCell(1,1);
String stringa1 = a1.getContents();
byte tampon[] = stringa1.getBytes(kodlama);

Bu kadar!

Kodlama (encoding)

Özellikle setEncoding komutu ile gösterdiğimiz kodlamanın ne işe yaradığını anlatmamız gerekiyor.

Java Excel API'ın kendi örneklerinde kodlama (encoding) hakkında bir tavsiye bulamayacaksınız. Biz, projemiz dahilinde Türkçe karakterler olan bir Excel tablosunu okumamız gerekince, bu ekleri yapmamız gerektiğini farkettik.

Bulgularımıza göre, doğru karakterleri görebilmek için bir hücreden gelen String nesnesini getBytes(kodlama) ile kullanacağımızı, ya da daha önceden, çalışma kitabı seviyesinde kullandığımız kodlamayı (encoding) JVM'e (Java'ya) bildirmemiz gerekmektedir.

import java.io.*;
import java.util.Date;
import jxl.*;

public class ExcelTablo
{
    public String hucre(int i, int j) throws Exception{
String encoding = "ISO-8859-9";

WorkbookSettings settings = new WorkbookSettings();
settings.setEncoding(encoding);

Workbook workbook = Workbook.getWorkbook(new File("Book8.xls"));
Sheet sheet = workbook.getSheet(0);
Cell a1 = sheet.getCell(i,j);
String stringa1 = a1.getContents();

byte tampon[] = stringa1.getBytes(encoding);

return new String(tampon);
    }
    
    public static void main (String args[] ) throws Exception {
String encoding = "ISO-8859-9";

WorkbookSettings settings = new WorkbookSettings();
settings.setEncoding(encoding);

Workbook workbook = Workbook.getWorkbook(new File("Book8.xls"));
Sheet sheet = workbook.getSheet(0);
Cell a1 = sheet.getCell(0,0);
String stringa1 = a1.getContents();

File f = new File ("out.txt");
FileOutputStream out = new FileOutputStream(f);

byte tampon[] = stringa1.getBytes(encoding);

out.write(tampon);
out.close();
    }
}