Thursday 28 October 2010

Heavyweight AWT bilesenleri ile Lightweight Swing Bilesenlerinin Beraber Kullanimi

Çoğu zaman kullandığımız Swing bileşenlerinin transparency(non-opaque) özelliğini kullanırız. Mesela kullandığımız JPanel veya JInternalFrame’e köşeleri oval olan bir border verip window manager’ın bize verdiği title barı kullanmak isteyemeyebiliriz, veya kendimize özgü uygulamada şeffaf olarak kullanılmasını istediğimiz bilgi panelleri olabilir. Uygulamamızda sadece Lightweight olan Swing bileşenlerini kullandığımızda bu durum sorun olmaz fakat yaptığımız uygulamayı heavyweight AWT bileşenleri üzerinde kullanmak istediğimiz zaman transparency sorun olacaktır. Çünkü heavyweight AWT bileşenleri transparent olamazlar. Bizim başımıza 3D GIS API’si WorldWind (http://worldwind.arc.nasa.gov/java/) kullanırken geldi. Uygulamamızı önce 2D GIS apilerini kullanarak geliştirdik. Sonrada uygulamaya 3D eklemeye karar verdik. Özelliği ekledimizde ana panel olarak GLCanvas sınıfından türeyen WorldWindowGLCanvas sınıfını kullanmıştık. Tabi alt tarafta AWT bir bileşen olunca uygulamadaki tüm transparancey özellik gitti, birde menülerde gezerken flickr problemi başladı. Aslında bunun çözümü çok basit GLCanvas yerine GLJPanel’den türeyen WorldWindowGLJPanel kullandığınız takdirde probleminiz çözülecektir.(WorldWind bizim yerimize düşünmüş).

Ama biz ilk başta bu sınıfı fark etmediğimizden dolayı başka bir takım çözümlere başvurmuştuk. Şimdi onları aktarayım. Öncelikle flickr probleminin çözümünü aktarayım. Uygulamanıza JVM paramatresi olarak -Dsun.awt.noerasebackground=true eklediğinizde bu kaybolacaktır. Gelelim ikinci sorunumuza Transparent panel. Bunun için Javanın sitesinde gerekli bilgiyi bulabilirsiniz ama yinede ben burada yaptığımız değişiklikleri aktarayım. Bu işi yaparken reflection kullanacağız ve AWTUtilitiesClass.setMixingCutoutShape() ile yapacağız. Bunun için aşağıdaki gibi bir sınıf oluşturuyoruz.



package X;
import java.awt.Component;
import java.awt.Shape;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AWTUtilitiesClass {
private static final Logger LOGGER = LoggerFactory.getLogger(AWTUtilitiesClass.class);
private static Method mSetComponentMixing;

static {
Class awtUtilitiesClass;
try {
awtUtilitiesClass = Class.forName("com.sun.awt.AWTUtilities");
mSetComponentMixing =
awtUtilitiesClass.getMethod("setComponentMixingCutoutShape", Component.class, Shape.class);
}
catch (Exception exc) {
LOGGER.error(exc.toString(), exc);
}
}

public static void setMixingCutoutShape(Component c, Shape s) {
if (mSetComponentMixing != null) {
try {
mSetComponentMixing.invoke(null, c, s);
}
catch (Exception exc) {
LOGGER.error(exc.toString(), exc);
}
}
}
}


Sonrada istediğimiz sınıfta setOpaque(false) dedikten sonra AWTUtilitiesClass.setMixingCutoutShape(this, new Rectangle());

çağırıyoruz. Burada bizim ekranlarımızın standart dışı (oval) olduğundan dolayı Rectangle yerinine kendimize özgü Polygon tanımlayarak verdik. Sizde istediğiniz gibi java.awt.Shape nesnesi kullanabilirsiniz.

http://java.sun.com/developer/technicalArticles/GUI/mixing_components/index.html

http://today.java.net/article/2009/11/02/transparent-panel-mixing-heavyweight-and-lightweight-components

Tuesday 30 March 2010

SLF4J

SLF4J, java.util.logging, log4j ve logback gibi loglama altyapılarının abstract edilmesi için kullanılan bir kütüphanedir. Uygulamaların hangi loglama altyapısını kullanacaklarına kurulum sırasında karar verilmesine imkan tanır.

Logger Nesnesi
--------------------------------------------------------------------------------
Geliştirilen Java sınıfında loglama yapmak için kullanılacak olan logger nesnesi, SLF4J tarafından sağlanan LoggerFactory sınıfı yardımıyla tanımlanır. Logger nesnesinin ismi tanımlama esnasında belirlenir:
Logger logger = LoggerFactory.getLogger("Test");

Loglama Seviyeleri
--------------------------------------------------------------------------------
SLF4J kullanılarak loglanacak olaylar, kritiklik derecelerine göre 5 ayrı kategoride değerlendirilir:
ERROR Uygulamanın sonlanmasına yol açacak olanlar dahil, çalışma sırasında alınan hataların loglanması için kullanılan seviyedir.
WARN Hata olmamakla birlikte, beklenmeyen ya da istenmeyen olarak nitelendirilebilecek durumlarda kullanılır.
INFO Çalışmanın başlangıcı veya bitişi gibi olayların, bilgi amaçlı loglanmasına yardımcı olan seviyedir.
DEBUG Detaylı bilgi edinme amaçlı kullanılan seviyedir.
TRACE Çok detaylı bilgi edinme amaçlı kullanılan seviyedir.


Loglama
--------------------------------------------------------------------------------
Loglama işlemi, kullanılabilecek loglama seviyelerine karşılık gelen ve parametre de içerebilen metodlar yardımıyla yapılır. Parametre desteği için "{}" dizisi ile birlikte bir nesne koleksiyonu kullanılır. "{}" dizilerinin sırası, parametrenin ilgili nesne koleksiyonundaki indeksine karşılık gelir:
logger.warn("Güncelleme işlemi sırasında {} ID'li olay için {} tane uyarı alınmıştır.", new Object[] {eventID, new Integer(warningCount)});

Yukarıdaki örnekte, WARN seviyesinin etkin olduğu durumda, ilk "{}" dizisi yerine eventID, ikinci "{}" dizisi yerine ise warningCount parametresi getirilecek ve elde edilen yeni dizi loglanacaktır. Loglanacak dizinin elde edilmesi için parametrelerin yerleştirilmesi işlemi, sadece WARN seviyesinin etkin olduğu durumda gerçekleştirileceğinden, bu seviyenin kapalı olduğu zamanlarda ekstra bir yük getirmeyecek ve uygulamanın performansına olumsuz bir etki yapmayacaktır.

MDC (Mapped Diagnostic Context)
--------------------------------------------------------------------------------
MDC, loglama işlemleri sırasında thread özelinde değişken tanımlamak ve tanımlanan değişkenleri yöneterek loglamaya katkıda bulunmak amacıyla geliştirilmiş bir mekanizmadır. MDC sınıfının statik metodları olan put ve get yardımıyla yönetilen değişkenler, kullanılacak loglama altyapısının konfigürasyonda kullanılan "%X{[değişken adı]}" dizisi ile birlikte, thread özelinde loglama yapmaya imkan tanır:
Loglama İşlemi Loglama Altyapısı Konfigürasyonu (Log4j) Log Çıktısı

MDC.put("userName", "admin");
logger.info("Olay tanımı yapıldı");

admin -- Olay tanımı yapıldı

Yukarıdaki örnekte, MDC ile tanımlanmış "userName" değişkeni, Log4j konfigürasyonunda belirtilen "%X{userName}" dizisi yardımıyla, loglanan bütün olayların içeriğine otomatik olarak dahil edilmiştir.


Konfigürasyon
--------------------------------------------------------------------------------
SLF4J mevcut loglama altyapılarının abstract edilmesi için kullanıldığından özel bir konfigürasyon dosyasına ihtiyaç duymamaktadır. Bunun yanında, SLF4J desteğinin kullanılabilmesi için uygulamanın classpath içeriğinde, SLF4J API tanımlarını barındıran jar dosyasının yanında, ilgili loglama altyapısı için özelleştirilmiş SLF4J jar dosyasının da bulunması gerekmektedir. Örneğin, SLF4J'in log4j altyapısı ile birlikte kullanıldığı durumda classpath içeriğinde slf4j-api.jar, slf4j-log4j.jar ve log4j.jar dosyaları yer almalıdır.

Tuesday 8 September 2009

Agile ve Klasik Metodolojiler

Bütün projeler tek amaç doğrultusunda geliştirilirler. Bu yegane hedef bütün gereksinimleri karşılayabilen, kaliteli, belirlenen bütçe ve zaman gibi kısıtlara uygun yazılım ürününü müşteriye teslim edebilmektir. Oysa http://www.standishgroup.com sitesinde yapılan bir araştırmaya göre projelerin %31 tamamlanmadan sonlandırılıyor. %53’ü ilk tahminlemeden %189 u daha maliyetli. Tamamlanamayan projeler için 81 milyar dolar gidiyor. Yazılım projelerinin %16’sı zamanında ve bütçesinde tamamlanıyor. Bu amaçlar doğrultusunda yazılımcılar çeşitli yöntemler uygulayarak projenin verimliliğini artırma eğilimine girmişlerdir.

Halihazırda çoğu firma tarafından kullanılan şelale(waterfall) gibi klasik yöntemlerde proje planı ve gereksinim analizi projenin başında detaylı olarak belirlenmeye çalışılır ki buda henüz proje başlamadan uzun süreli bir planlama analiz çalışması gerektirir. Tabi projenin devamında da bu yapılan detaylı analizler kapsamında devam edilmeye çalışılır. Herşey proje başından belirlendiği düşüncesinden dolayı proje devam ederken olabilecek değişiklikler kontrol altında tutulmaya, mümkünse önüne geçilmeye çalışılır. Bu sebeplerden dolayı bu eski klasik yöntem değişiklik ihtimalinin olmadığı projelerde ancak verimli olabilir.

Klasik metodlarda başta yapılan detaylı analiz sürecinden sonra yazılım yaparken yapılan değişiklikler büyük maliyetler oluşturur. Çevik yazılım geliştirmede ise, süreçlerin katı kurallarla yönetilmesi yerine amaca yönelik verimli ve etkin pratiklerin yapılmasını esas alır, yani hem yazılım geliştirenlerin hem de müşterilerin ana hedeflerini karşılar. Değişimin maliyeti olabildiğince düşüren pratikler içerir.

Çevik süreçler iterative yazılım geliştirme metodunu esas almışlardır. Buna göre parçalara ayrılan yazılım sık aralıklarla teslim edilir. Agile parça olarak yazılım telimatını,değişimi, takım içindeki iletişimin artırılmasını, test odaklı yazılım yazılım geliştirmeyi teşvik eder. Farklı ihtiyaçlara göre formüle edilmiş XP, Scrum, Feature Driven Development, DSDM , Lean, Crystal methodoloji gibi süreçler mevcuttur.