30 Mayıs 2011 Pazartesi

Apache Commons Lang Kütüphanesi-3: lang.time.* Paketi

Lang kütüphanesini incelemeye org.apache.commons.lang.time paketi ile devam ediyoruz.

Bu pakette bulunan sınıflar, zaman değerleriyle ilgili işlemler yapmak için daha pratik yöntemler sunar:

import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang.time.StopWatch;

import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;

public class TimeTrial {
    public static void main(String[] args) {
        //Tarihi dd-MM-yyyy biçiminde göster
        System.out.println("1) dd-MM-yyyy >>>" +
            DateFormatUtils.format(new Date(), "dd-MM-yyyy"));

        //Tarihi SMTP_DATETIME_FORMAT biçiminde göster 
        System.out.println("2) SMTP_DATETIME_FORMAT >>>" +
            DateFormatUtils.SMTP_DATETIME_FORMAT.format(new Date()));

        //Tarihi ISO_DATE_FORMAT biçiminde göster 
        System.out.println("3) ISO_DATE_FORMAT >>>" +
            DateFormatUtils.ISO_DATE_FORMAT.format(new Date()));

        //Girilen milisaniye değerini tarih olarak göster
        System.out.println("4) MMM dd yy HH:mm >>>" +
            DateFormatUtils.format(System.currentTimeMillis(), "MMM dd yy HH:mm"));

        //Girilen milisaniye değerini UTC biçiminde tarih olarak göster
        System.out.println("5) MM/dd/yy HH:mm >>>" +
            DateFormatUtils.formatUTC(System.currentTimeMillis(),
                "MM/dd/yy HH:mm"));

        StopWatch stWatch = new StopWatch();

        //StopWatch'ı başlat
        stWatch.start();

        //Pazartesi'den başlamak üzere haftanın tüm günleri için iterator nesnesi al.
        Iterator itr = DateUtils.iterator(new Date(),
                DateUtils.RANGE_WEEK_MONDAY);

        while (itr.hasNext()) {
            Calendar gCal = (Calendar) itr.next();
            System.out.println(gCal.getTime());
        }

        //StopWatch'ı sonlandır
        stWatch.stop();
        System.out.println("Time Taken >>" + stWatch.getTime());
    }
}

Çıktısı:
1) dd-MM-yyyy >>>09-12-2003
2) SMTP_DATETIME_FORMAT >>>Tue, 09 Dec 2003 00:34:47 +0530
3) ISO_DATE_FORMAT >>>2003-12-09
4) MMM dd yy HH:mm >>>Dec 09 03 00:34
5) MM/dd/yy HH:mm >>>12/08/03 19:04
Mon Dec 08 00:00:00 GMT+05:30 2003
Tue Dec 09 00:00:00 GMT+05:30 2003
Wed Dec 10 00:00:00 GMT+05:30 2003
Thu Dec 11 00:00:00 GMT+05:30 2003
Fri Dec 12 00:00:00 GMT+05:30 2003
Sat Dec 13 00:00:00 GMT+05:30 2003
Sun Dec 14 00:00:00 GMT+05:30 2003
Time Taken >>31

Bu örneklerde tarih bilgisini biçimlendirmeye örnek vermek için SMTP_DATE_FORMAT ve ISO_DATE_FORMAT biçimleri kullanılmıştır. Bu ikisi dışında DateFormatUtils sınıfında 7 ayrı biçim daha vardır. Hiçbiri işinize yaramazsa kendi biçimlendirmenizi de tanımlayabilirsiniz.

StopWatch sınıfı da bir çeşit kronometre uygulamasıdır.

Kolay Gelsin.

Apache Commons Lang Kütüphanesi-3: lang.math.* Paketi

Lang kütüphanesini incelemeye org.apache.commons.lang.math paketi ile devam ediyoruz.

Bu pakette bulunan sınıflar java.math paketindekilere ek özellikler katar. İncelemeye değer en önemli sınıf NumberUtils'dir. Diğer sınıflar bu sınıfın kullandığı bazı tanımlamaları içerir.

import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.math.RandomUtils;

import java.math.BigDecimal;

public class MathUtilsTrial {
    public static void main(String[] args) {
        //İki double değeri karşılaştır
        System.out.println("(FIRST > SECOND) >>> " +
            NumberUtils.compare(2.11, 1.11));
        System.out.println("(FIRST < SECOND) >>> " +
            NumberUtils.compare(1.11, 2.11));
        System.out.println("(FIRST == SECOND) >>> " +
            NumberUtils.compare(1.11, 1.11));

        //Karakter katarından bir BigDecimal oluştur
        BigDecimal bDecimal = NumberUtils.createBigDecimal("123456789");

        //Bir karakter katarının sadece sayılardan oluştuğunu doğrular
        System.out.println("Is Digits >>> " + NumberUtils.isDigits("123.123"));

        //Bir karakter katarının geçerli bir sayı ifade ettiğini doğrular
        System.out.println("Is Number >>> " + NumberUtils.isNumber("123.123"));

        //Dizinin en büyük elemanını döner
        System.out.println("MAX >>> " +
            NumberUtils.max(new double[] { 3.33, 8.88, 1.11 }));

        //Karakter katarını int değere çevirir. Çeviremezse öntanımlı değeri döner: 77
        System.out.println("String to Int >>> " +
            NumberUtils.toInt("ABCD", 77));

        //Rastgele sayıla üretir
        System.out.println("Random double >>> " + RandomUtils.nextDouble());
        System.out.println("Random float >>> " + RandomUtils.nextFloat());
        System.out.println("Random int >>> " + RandomUtils.nextInt());
    }
}

Çıktısı:
(FIRST > SECOND) >>> 1
(FIRST < SECOND) >>> -1
(FIRST == SECOND) >>> 0
Is Digits >>> false
Is Number >>> true
MAX >>> 8.88
String to Int >>> 77
Random double >>> 0.2720979622981403
Random float >>> 0.8221457
Random int >>> 738187848

compare() metodu, iki değer eşitse 0, ilk değer daha büyükse 1, ikinci değer daha büyükse -1 döner.

Dikkate değer bir diğer metod da createNumber()'dır. Bu metod bir karakter katarını  java.lang.Number 'ın alt tiplerinden uygun olan bir tanesine dönüştürür. Daha detaylı açıklarsak, bildiğiniz gibi Java'da bütün sayısal sarıcı sınıflar (Integer, Float, Double...) java.lang.Number'ın alt sınıfıdır.  createNumber() neredeyse bütün sayısal gösterimlerden anlar (int, float, double, hex, binary, octal, ...) ve bulduğu sayıyı uygun tipte döner.

Bu pakette ayrıca xxxRange kalıbında birkaç sınıf daha vardır. Bu sınıfları kullanarak double, float, int ve long tipleri için sayı aralıkları tanımlayabilir ve herhangi bir değerin bu aralıkta olup olmadığını kontrol edebilirsiniz.

Kolay Gelsin.

Apache Commons Lang Kütüphanesi-2: lang.builder.* Paketi

Lang kütüphanesini incelemeye org.apache.commons.lang.builder paketi ile devam ediyoruz.

Bu pakette kendi sınıflarınız için benzersiz olarak oluşturmanız gereken equals, toString, hashCode, ve compareTo metotlarını daha kolay üretebilmeniz için yardımcı birkaç sınıf bulunur. Şimdi bütün kayda değer metotların kullanıldığı bir örnek görelim ve hepsini teker teker açıklayalım:

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class BuilderTrial {
    private String name;
    private int age;

    public BuilderTrial(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
        //Birkaç nesne oluşturalım.
        BuilderTrial one = new BuilderTrial("Becker", 35);
        BuilderTrial two = new BuilderTrial("Becker", 35);
        BuilderTrial three = new BuilderTrial("Agassi", 33);

        //one ve two farklı nesnelerde aynı verileri tutuyor.
        //three nesnesi ise farklı veri barındırıyor.
        System.out.println("One>>>" + one);
        System.out.println("Two>>>" + two);
        System.out.println("Three>>>" + three);

        System.out.println("one equals two? " + one.equals(two));
        System.out.println("one equals three? " + one.equals(three));

        //one ve two aynı verileri barındırdığı için, aynı hashcode dönülür.
        System.out.println("One HashCode>>> " + one.hashCode());
        System.out.println("Two HashCode>>> " + two.hashCode());
        System.out.println("Three HashCode>>> " + three.hashCode());
    }

    public boolean equals(Object objCompared) {
        if (!(objCompared instanceof BuilderTrial)) {
            return false;
        }

        BuilderTrial rhs = (BuilderTrial) objCompared;

        return new EqualsBuilder().append(name, rhs.name).append(age, rhs.age)
                                  .isEquals();
    }

    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("Name",
            name).append("Age", age).toString();
    }

     public int compareTo(Object o) {
     BuilderTrial builderTrial = (BuilderTrial ) o;
     return new CompareToBuilder()
       .appendSuper(super.compareTo(o)
       .append(this.name, builderTrial.name)
       .append(this.age,  builderTrial.age)
       .toComparison();
    }

    public int hashCode() {
        return new HashCodeBuilder(15, 19).append(name).append(age).toHashCode();
    }
}


Çıktısı:
One>>>BuilderTrial@5[
  Name=Becker
  Age=35
]
Two>>>BuilderTrial@6[
  Name=Becker
  Age=35
]
Three>>>BuilderTrial@7[
  Name=Agassi
  Age=33
]
one equals two? true
one equals three? false
One HashCode>>> -923455822
Two HashCode>>> -923455822
Three HashCode>>> -1433293806


Bir sınıf için equals metodu yazmak, eğer çok fazla üyesi varsa, sayısız if ile boğuşmanızı gerektirebilir. EqualsBuilder sınıfı bu iş için size daha kolay bir yol sunar. Örneğini yukarıda da gördüğünüz gibi, tek yapmanız gereken EqualsBuilder'ın bir örneğinin oluşturup, bu nesne üzerinde, eşitlik kontrolü yapacağınız her alan için append() metodunu çağırmaktır. Tabi en son olarak da isEquals() metounu çağırmayı unutmayın.


ToStringBuilder sınfı toString() metodunun daha anlamlı ve okunabilir çıktılar üretmesini sağlamak için kullanılır. EqualsBuilder sınıfına benzer şekilde, ToStringBuilder'ın bir örneğini oluşturup, üretilecek çıktının biçimini belirtip sonra toString() metodunda olmasını istediğiniz detayları append() ile eklemeniz kafidir. Yine en son toString() metodunu çağırmayı unutmayın tabi.

ToStringBuilder'ı kullanırken çıktı biçimini belirtmek zorunlu değildir. Belirtilmezse DEFAULT_STYLE kullanılır. Diğer biçimler de şunlardır: MULTI_LINE_STYLE, NO_FIELD_NAMES_STYLE, SHORT_PREFIX_STYLE, SIMPLE_STYLE.

Eğer kendi çıktı biçiminizi tanımlamak isterseniz StandartToStringStyle sınıfını genişletebilirsiniz(extend).


HashCodeBuilder sınıfı hashCode() metodunu daha pratik yoldan üretmek için tasarlanmıştır. Diğer xxxBuilder sınıflarından farklı olarak, HashCodeBuilde'ın örneğini oluştururken, iki tane rastgele seçilmiş tek ve sıfırdan farklı sayı belirtirsiniz. Asal sayı kullanmanız tavsiye edilir! Sonra öncekiler gibi append() ile hashcode'da olmasını istediğiniz alanları ekler, toHashCode() ile hashcode'u oluşturursunuz.

HashCodeBuilde, EqualsBuilder ile ortak çalışır. Yani "equals() metodu true dönen iki nesne için hashcode'lar eşit olmalıdır" kuralına uyar.


CompareToBuilder da neredeyse aynıdır. Argüman olan Object referansını uygun tipe dönüştürdükten(cast) sonra CompareToBuilder'ın bir örneğini oluşturup, karşılaştırmak istediğiniz alanları append() ile ekleyip, sonra toComparison() metodunu çağırarak karşılaştırma işlemini gerçekleştirebilirsiniz. append() için sadece çalıştığınız sınıfın alanları ile sınırlı olmadığınıza dikkat edin. Örneğin biz burada appendSuper() ile bir üst sınıfın compareTo() metodunu da hesaplamamıza kattık.


Hepsinin Kısayolu
Bütün bu anlattığımız örneklerin Java Reflection API kullanan bariz bir şekilde daha kısa bir yolu var.

public boolean equals(Object obj) {
    return EqualsBuilder.reflectionEquals(this, obj);
}
public String toString() {
    return ToStringBuilder.reflectionToString(this
           , ToStringStyle.MULTI_LINE_STYLE);
}

public int hashCode() {
    return HashCodeBuilder.reflectionHashCode(this);
}

public int compareTo(Object o) {
   return CompareToBuilder.reflectionCompare(this, o);
}

Bu örneklerdeki kodda neredeyse herşey otomatikleştirilmiştir. Metodların içindeki tek satırlık kodlar, Java'nın Reflection özelliklerini kullanarak, ilgili sınıfın bütün alanlarına erişir ve karşılaştırma ve hesaplama işlemlerini bizim müdahalemize gerek kalmadan gerçekleştirir. Ancak bu yaklaşımın bir eksi yanı vardır. Diğer yönteme göre bariz şekilde yavaştır ve oluşturulan kod üzerinde çok daha az kontrolümüz vardır.

Kolay Gelsin.

27 Mayıs 2011 Cuma

Apache Commons Lang Kütüphanesi-1: lang.* Paketi

Apache Commons projesini incelemeye Lang kütüphanesi ile devam ediyoruz.

Lang kütüphanesi JDK'nın java.lang paketine bazı genel, çok sık kullanılan, her programcının işine yarayabilecek bileşenler ekler. Şimdi bunlardan en çok göze çarpanları inceleyelim. Açıklamaları yazarken zaman kaybetmemek için kodun içinde yapacağım.

CharsetUtils sınıfı karakterlerle alakalı işlemler için birkaç yardımcı statik metod barındırır. Not: Her ne kadar aşağıdaki kod örneklerinde aranacak karakterleri (ikinci parametre) String olarak belirtsek de, içindeki karakterlerin hepsi için tek tek kontrol yapılır.

import org.apache.commons.lang.CharSet;
import org.apache.commons.lang.CharSetUtils;
public class CharSetUtilsDeneme {
    public static void main(String[] args) {
        //Birinci parametredeki String'in içinde,
        //İkinci parametredeki karakterleri sayar.
        System.out.println("B and o count = " +
            CharSetUtils.count("BorisBecker", "Bo")); //3
        System.out.println("B,o,k,e and r count = " +
            CharSetUtils.count("BorisBecker", new String[] { "Bo", "ker" })); //8

        //Birinci parametredeki String'in içinden,
        //İkinci parametredeki karakterleri siler.
        System.out.println("Delete B and o = " +
            CharSetUtils.delete("BorisBecker", "Bo")); //risecker
        System.out.println("Delete B,o,k,e and r = " +
            CharSetUtils.delete("BorisBecker", new String[] { "Bo", "ker" })); //isc

        //Birinci parametredeki String'in içinde,
        //sadece ikinci parametredeki karakterleri tutar. Diğerlerini siler.
        System.out.println("Keep B and o = " +
            CharSetUtils.keep("BorisBecker", "Bo")); //BoB

        //Birinci parametredeki String'in içinden,
        //İkinci parametredeki karakterlerin tekrarlarını siler.
        System.out.println("Squeeze B and o = " +
            CharSetUtils.squeeze("BBoooorisbbbecker", "Bo")); //Borisbbbecker
    }
}

Çıktısı:
B and o count = 3
B,o,k,e and r count = 8
Delete B and o = risecker
Delete B,o,k,e and r = isc
Keep B and o = BoB
Squeeze B and o = Borisbbbecker

ObjectUtils sınıfı equals, toString gibi bütün sınıflar için ortak olan bazı metodların NullPointerException fırlatılmasına karşı daha güvenilir olan biçimlerini içerir. Bu metodları kullanarak örneğin null referanslı bir nesne için toString metodu çağırıldığında "null" yerine "" veya "Boş referans" gibi istediğiniz bir karakter katarının dönülmesini sağlayabilirsiniz.

import org.apache.commons.lang.ObjectUtils;

/**
 * Bu sınıfta kullanılan metodların hepsi NullPointerException'a
 * karşı güvenlidir. null veri girilse bile hata fırlatmaz
 */
public class ObjectUtilsTrial {
    public static void main(String[] args) {
        //ObjectUtilsTrial nesnelerini oluşturalım
        ObjectUtilsTrial one = new ObjectUtilsTrial();
        ObjectUtilsTrial two = one; //Aynı referans
        ObjectUtilsTrial three = new ObjectUtilsTrial(); //Yeni nesne
        ObjectUtilsTrial four = null;

        //birinci referans null ise ikinci nesneyi dön
        System.out.print("1) If null return DEFAULT >>>");
        System.out.println(ObjectUtils.defaultIfNull(four, three));

        //equals kontrolü
  //ikisi de aynı nesneyi refere ediyor.
        System.out.print("2) References to the same object >>>");
        System.out.println(ObjectUtils.equals(one, two));

  //equals kontrolü
        //farklı nesneleri refere ediyorlar.
        System.out.print("3) Check object references and not values >>>");
        System.out.println(ObjectUtils.equals(one, three));

        //toString methodu çağırılır
        System.out.print("4) toSring gets invoked >>>");
        System.out.println(one);

        //nesnenin detaylarını gösterir. toString metodu çağırılmaz
        System.out.print("5) Display object details >>>");
        System.out.println(ObjectUtils.identityToString(one));

        //toString'e null geçilse bile boş karakter katarı dönülür: ""
  //çıktı **** olacaktır
        System.out.print("6) Pass null and get back an Empty string >>>");
        System.out.println("**" + ObjectUtils.toString(null) + "**");
  
  //null verinin hashCode'u 0 olarak dönülür
  //çıktı **0** olacaktır
        System.out.print("6) Pass null and get back an Empty string >>>");
        System.out.println("**" + ObjectUtils.hashCode(null) + "**");
    }

    public String toString() {
        return "toString Output";
    }
}


Bu paketteki bir başka yardımcı sınıf da SerializationUtils'dir. Java'da en basit dosyaya okuma işlemi için bile bir ton sınıfla uğraşmanız gerekir. Bu sınıf serileştirme işlemini tek bir metod çağrısına kadar indirger. Tek yapmanız gereken serileştirmek istediğiniz veriyi ve çıktıyı vereceğiniz akışı belirmektir. Örneğin;

//File to serialize object to
String fileName = "testSerialization.ser";

//New file output stream for the file
FileOutputStream fos = new FileOutputStream(fileName);

//Serialize String
SerializationUtils.serialize("SERIALIZE THIS", fos);
fos.close();

//Open FileInputStream to the file
FileInputStream fis = new FileInputStream(fileName);

//Deserialize and cast into String
String ser = (String) SerializationUtils.deserialize(fis);
System.out.println(ser);
fis.close();

StringUtils sınıfı belki de bu pakette en çok kullanacağız sınıf olacak. İçinde 100'den fazla statik metod bulunur. Bu metodlar java.lan.String sınıfınının karakter katarı işlemede yetersiz kaldığı durumlardaki boşluğu doldurur. Ayrıca hepsi NullPointerException'a karşı güvenilirdir. Şimdi bu metodlardan bazıları iş başında görelim:

import org.apache.commons.lang.StringUtils;

public class StringUtilsTrial {
    public static void main(String[] args) {
        //12 karakter kısalt
        System.out.println("1) Abbreviate Once upon a time >>>" +
            StringUtils.abbreviate("Once upon a time ", 12));

        //İki karakter katarının benzerliklerinin bittiği yerin indexini döner.
        System.out.println(
            "2) Index Of Difference between ABCXYZ and ABCPQR >>>" +
            StringUtils.indexOfDifference("ABCXYZ", "ABCPQR"));

        //Karakter katarının sonundan, ikinci argümandaki katarı çıkar.
        System.out.println("3) Chomp END >>>" +
            StringUtils.chomp("A test String END", "END"));

        //İlk argümanın sadece ikinci argümandaki karakterleri içerdiğini doğrular
        System.out.println("4) Check if 643287460 contains only 0123456789 >>>" +
            StringUtils.containsOnly("643287460", "0123456789"));

        //İki argümanı karşılaştırır, farklı oldukları kısmı döner.
        System.out.println("5) Compare ABCDEFG and ABCdefg >>>" +
            StringUtils.difference("ABCDEFG", "ABCdefg"));

        //Girilen nesne referansı null ise, "" dönülür.
        //ObjectUtils.toString() ile aynıdır.
        System.out.println("6) Return default string >>>" + "**" +
            StringUtils.defaultString(null) + "**");

        //Dizideki bütün karakter katarlarını araya "$#$" koyarak bir katara yerleştirir
        System.out.println("7) Join Strings using separator >>>" +
            StringUtils.join(new String[] { "AB", "CD", "EF" }, "$#$"));

        //SubString
        System.out.println("8) Substring >>>" +
            StringUtils.substring("SUBSTRING", 1, 5));

        //Katarı ters çevirir.
        System.out.println("9) Reverse >>>" + StringUtils.reverse("REVERSE"));

        //Katardaki boşlukları budar. null ise "" döner.
        System.out.println("10) Trim String. No NullPointerException >>>" +
            StringUtils.trim(null));

        //Katardaki boşlukları budar. null ise "" döner.
        System.out.println("11) Empty String >>>" +
            StringUtils.trimToEmpty(null) + "<<<");

        //Equals kontrolu yapar. NullPointerException fırlatmaz!
        System.out.println("12) Comapre null and null >>>" +
            StringUtils.equals(null, null));

        //Baştaki ve sondaki boşlukları budar
        //null ise "" döner.
        System.out.println("13) Strip whitespace >>>" +
            StringUtils.stripToEmpty("     ABCD      "));

        //İlk argümandaki katarın "!@#$%^&*" karakterlerini içermediğini doğrular
        System.out.println("14) Check that ABCD contains none of !@#$%^&* >>>" +
            StringUtils.containsNone("ABCD", "!@#$%^&*"));
    }
}

SystemUtils sistem değişkenlerini okur ve uygun değerleri döner. Örneğin programınızın çalışacağı sistemin Java'nın en az 1.3 sürümünü desteklemesinin istiyorsanız: SystemUtils.isJavaVersionAtLeast(1.3f)); metodunu kullanabilirsiniz. Örnek kullanım:

import org.apache.commons.lang.SystemUtils;

public class SystemUtilsTrial {
    public static void main(String[] args) {
        System.out.println("1) FILE_SEPARATOR =" + SystemUtils.FILE_SEPARATOR);
        System.out.println("2) JAVA_EXT_DIRS =" + SystemUtils.JAVA_EXT_DIRS);
        System.out.println("3) JAVA_HOME =" + SystemUtils.JAVA_HOME);
        System.out.println("4) Is 1.3 + =" +
            SystemUtils.isJavaVersionAtLeast(1.3f));
        System.out.println("5) JAVA_EXT_DIRS =" + SystemUtils.JAVA_EXT_DIRS);
        System.out.println("6) JAVA_VENDOR =" + SystemUtils.JAVA_VENDOR);
        System.out.println("7) OS_NAME =" + SystemUtils.OS_NAME);
    }
}

Çıktısı:
1) FILE_SEPARATOR =\
2) JAVA_EXT_DIRS =C:\JDeveloper\jdk\jre\lib\ext
3) JAVA_HOME =C:\JDeveloper\jdk\jre
4) Is 1.3 + =true
5) JAVA_EXT_DIRS =C:\JDeveloper\jdk\jre\lib\ext
6) JAVA_VENDOR =Sun Microsystems Inc.
7) OS_NAME =Windows 2000

ClassUtils sınıfı Java Reflection API'yi kullanmadan sınıflarınız hakkında daha detaylı bilgiye sahip olmanızı sağlar. Ancak bu metodları kullanırken iki kere düşünün. Çünkü çoğu durumda böyle bir özelliği kullanmanız yazılımınızın tasarımının kötü olduğu anlamına gelir.

import org.apache.commons.lang.ClassUtils;

public class ClassUtilsTrial {
    public static void main(String[] args) {
        System.out.println("1) Interfaces implemented by java.lang.String >>> " +
            ClassUtils.getAllInterfaces(String.class));
        System.out.println("2) SuperClasses of java.lang.String >>> " +
            ClassUtils.getAllSuperclasses(String.class));
        System.out.println("3) PackageName of a string >>> " +
            ClassUtils.getPackageName("A String", "IfNull"));
        System.out.println("4) Every String is an Object = " +
            ClassUtils.isAssignable(String.class, Object.class));
        System.out.println("5) Every Object is an String = " +
            ClassUtils.isAssignable(Object.class, String.class));
    }
}

Çıktısı:
1) Interfaces implemented by java.lang.String >>> [interface java.io.Serializable
, interface java.lang.Comparable, interface java.lang.CharSequence]
2) SuperClasses of java.lang.String >>> [class java.lang.Object]
3) PackageName of a string >>> java.lang
4) Every String is an Object = true
5) Every Object is an String = false

StringEscapeUtils sınıfı da yeri geldiğinde çok işinize yarayacak bir sınıftır. Program yazarken bazen Java sözdizimi ile  HTML, JavaScript, SQL gibi dillerin söz dizimleri karışabilir. Örneğin; bir servlet'in <p>MyName<p> metnini ekrana basmasını isteyip doğrudan sayfaya yazdırırsanız, web sunucusu bunu HTML olarak olarak yorumlayıp <p><p> etiketlerini kaldıracaktır: MyName. Bu hatadan kurtulmak için StringEscapeUtils'in sağladığı metodları kullanabilirsiniz. StringEscapeUtils HTML'den başka birçok dili daha desteklemekte:

import org.apache.commons.lang.StringEscapeUtils;

public class StringEscapeUtilsTrial {
    public static void main(String[] args) {
        String strHTMLInput = "<p>MyName<p>";
        String strEscapeHTML = StringEscapeUtils.escapeHtml(strHTMLInput);
        String strUnEscapeHTML = StringEscapeUtils.unescapeHtml(strEscapeHTML);
        System.out.println("Escaped HTML >>> " + strEscapeHTML);
        System.out.println("UnEscaped HTML >>> " + strUnEscapeHTML);
    }
}


ArrayUtils sınıfı da onlarca metod ve bunların bütün ilkel tipler ve java.lang.Object için aşırı yüklenmiş hallerini içerir. Ayrıca yine aşağıdaki xxx kısaltması bütün ilkel tipler ve Object sınıfı için kullanılmıştır. Sizin de tahmin edebileceğiz gibi bu metodlar dizi tipindeki değişkenler üzerinde yapılan çeşitli işleri kolaylaştırır.
  • add(xxx[], xxx) bir diziye yeni bir eleman ekler. Dizinin boyutunu büyüterek tabii ki
  • clone(xxx[]) dizinin kopyasını döner.
  • contains(xxx[], xxx)dizide bir eleman arar.
  • getLength(Object) dizinin eleman sayısını döner. Geçirilen referans dizi değilse, IllegalArgumentException fırlatılır.
  • hashCode(Object), equals(Object, Object), toString(Object)
  • daha önce tanıttığım metodların diziler üstünde çalışanı.
  • indexOf(xxx[], xxx) and indexOf(xxx[], xxx, int) String sınıfındaki metodlarla aynı işeve sahiptirler. Ancak diziler üzerinde çalışırlar. Ayrıca a lastIndexOf metodu da vardır.
  • isEmpty(xxx[]) dizinin boş veya null kontrolünü yapar.
  • isSameLength(xxx[], xxx[]) argümanlarındaki dizilerin aynı uzunluğa sahip olup olmadığını kontrol eder.
  • add() metodunun yanında iki tip remove metodu da vardır. İlki verilen indexteki elemanı, remove(xxx[], int), belirtilen elemanı siler, remove(xxx[], xxx).
  • reverse(xxx[]) diziyi ters çevirir.
  • subarray(xxx[], int, int) dizinin belirtilen aralıklardan bir alt dizisini oluşturup döner.
  • toObject(xxx[]) ve toPrimitive(Xxx[]) metodları ilkel tipler ile bunların sarıcıları arasında dönüşüm yapar 
ArrayUtils.toMap(Object[]) iki boyutlu dizilerden Map nesnesi oluşturur. Örneğin;

    Map colorMap = MapUtils.toMap(new String[][] {{
               {"RED", "#FF0000"},
               {"GREEN", "#00FF00"},
               {"BLUE", "#0000FF"}
    });
    

    Kolay Gelsin

    24 Mayıs 2011 Salı

    Takip Ettiğiniz Kişi Facebook Chat'te Çevrimiçi Olunca Haber Veren Program

    O kadar lazım çok olur mu bilmem ama bana lazım oldu ve çözümü şöyle buldum. Daha farklı da yapılabilir tabi.

    Ön Bilgi: Facebook Chat servisi XMPP/Jabber protokolü üzerinde çalışıyor. Bu protokolün belirtimlerine(specification) göre, ne zaman bir arkadaşınız FB Chat'te durumunu değiştirirse (Çevrimiçi, Dışarıda, Çevrimdışı) protokol istemcilerini bilgilendirir. MSN gibi yani.

    Benim yöntemim bu protokolü kullanarak FB'a bağlanıp gelen uyarılar içinden istediğiniz kişiyi süzmekten oluşuyor.

    Bunun için öncelikle bir FB Chat istemcisine ihtiyacımız var. Açık Kaynak Yazılım felsefesi sağolsun burada imdadımıza yetişiyor. SourceForge'da JFBChat adında işimizi görecek küçük bir program var. Kaynak kodlarını SVN'den indirebilirsiniz.



    İşin zor kısmı programın FB'den gelen uyarıları dinleyen kısmı bulmakta. Kodu biraz deştiğinizde jfbchat.listeners.MyRosterListener sınıfının bu işi yaptığını fark edebilirsiniz. Gerisi artık sadece bir if kontrolüne kalıyor. Aşağıdaki ilk satır bir kullanıcı durumunu değiştirdiğinde konsola bir debug mesajı basıyor.

    new DMessage(contact.getUser() + " has changed status and he is now " + contact.getPresence().toString() + ".").println();
    

    contact.getUser()

    Çağrısı ile kullanıcının FB'taki tam adına erişebilirsiniz.
    Debug mesajından sonra şöyle basit bir if ile istediğiniz kullanıcıyı süzebilir, çevrimiçi olduğunda, sınırları hayalleriniz ve programcılık yeteneklerinizle belirlenmek üzere istediğiniz uyarıyı verdirebilirsiniz.

    if (contact.getUser().indexOf("KULLANICI-ADI")!=-1)
    {
    System.out.println("Kahvenin Hatırı'nın debug çağrısı");
    new MP3("C:\\PolisFilmTheme.mp3").play();
    }
    

    Netbeans projesi de burada.
    Kolay gelsin.

    22 Mayıs 2011 Pazar

    Apache Commons IO Kütüphanesi

    Apache Yazılım Derneği'nin Java'da sık karşılaşılan, JDK tarafından sağlanan sınıflarla yaparsanız "bin dereden su getirmeye" benzeyen görevleri, daha kolay biçimde gerçekleştirmenizi sağlayan araçları bir araya getirdiği Commons adında bir projesi var.

    Bu yazıda bu projenin giriş çıkış işlemleri üzerine yoğunlaşan IO kütüphanesini inceliyoruz.Kütüphaneyi buradan indirebilirsiniz. commons-io-2.0.1.jar dosyasını projenizin classpath'ına eklemeniz yeterli.

    Bu jar'ın içindeki bazı önemli sınıfları inceleyelim.

    IOUtils sınıfı okuma, yazma ve kopyalama işlemleri için bazı yardımcı metodlar barındırır. Bu metodlar InputStream, OutputStream, Reader ve Writer nesneleri üzerinde çalışır.

    Örneğin çok sık karşılaşılan bir işlem olan "herhangi bir InputStream'dan gelen verilere String formatında erişme" yi JDK sınıflarıyla şu şekilde gerçeklersiniz:

    InputStream in = new URL( "URL-HERE" ).openStream();
     try {
       InputStreamReader inR = new InputStreamReader( in );
       BufferedReader buf = new BufferedReader( inR );
       String line;
       while ( ( line = buf.readLine() ) != null ) {
         System.out.println( line );
       }
     } finally {
       in.close();
     }
    

    Ancak IOUtils sınıfını kullanarak, bu işlemi çok daha basit bir şekilde halledebilirsiniz:

    InputStream in = new URL( "URL-HERE" ).openStream();
     try {
       System.out.println( IOUtils.toString( in ) );
     } finally {
       IOUtils.closeQuietly(in);
     }
    


    Buradaki
    IOUtils.toString( in );

    metodu herhangi bir InputStream'i String olarak döner. Biz burada URL'den gelen bir akış(stream) kullandık. Ama sadece bununla sınırlı değilsiniz. InputStream dönen herhangi bir kaynak kullanabilirsiniz. Örneğin; File nesneleri, BufferedReader'lar...

    FileUtils sınıfı File nesneleriyle birlikte kullanabileceğiniz çeşitli metodlar içerir. Bu metodları kullanarak dosyalarla okuma, yazma, kopyalama ve karşılaştırma işlemlerini çok daha kolay yapabilirsiniz. Örneğin; bir dosyayı satır satır okumak için şu kod parçasını kullanabilirsiniz.

    File file = new File("/commons/io/project.properties");
    List lines = FileUtils.readLines(file, "UTF-8");
    

    FilenameUtils sınıfı da File nesneleri kullanma zorunluluğunu ortadan kaldırarak, dosya adlarıyla uğraşmanın daha basit yollarını sunar. Bu sınıf genelde Linux/Windows sistemler arası uyumluluğu sağlamak için kullanılır. Örneğin bir dosya adındaki çift noktaları kaldırmak için şu kodu kullanabilirsiniz.

    String filename = "C:/commons/io/../lang/project.xml";
    String normalized = FilenameUtils.normalize(filename);
    // çıktı: "C:/commons/lang/project.xml"
    

    FileSystemUtils sınıfı işletim sistemindeki dosya sistemi yapısı ilgili işlemler yapmak için JDK'da bulunmayan bazı yardımcı metodlar içerir. Örneğin: C diskindeki boş alan miktarını öğrenmek için;

    long freeSpace = FileSystemUtils.freeSpace("C:/");
    

    LineIterator sınıfıyla metin tabanlı bir dosyanın satırlarına kolayca tek tek ulaşabilirsiniz. LineIterator kurucu ile oluşturulabileceği gibi IOUtils ve FileUtils sınıfları üzerinden fabrika meodlarıyla da oluşturulabilir. Örnek kullanımı:

    LineIterator it = FileUtils.lineIterator(file, "UTF-8");
     try {
       while (it.hasNext()) {
         String line = it.nextLine();
         /// do something with line
       }
     } finally {
       LineIterator.closeQuietly(iterator);
     }
    

    Hazır Dosya Filtreleri
    org.apache.commons.io.filefilter paketinde JDK'nın java.io.FileFilter ve java.io.FilenameFilter. interface'lerini birleştirip, bunlara daha gelişmiş ek özellikler katan IOFileFilter interface'i bulunur. Pakette ayrıca bu interface'in hazır örnekleri de mevcuttur. Bu filtreleri örneğin bir FileDialog nesnesinde sadece belli tür dosyaları göstermek için kullanabilirsiniz. Hazır filtrelerden bazıları şunlardır. Not: Sınıf isimleri yeterince açıklayıcı olduğu için, ayrıca açıklamalarını yazmadım.


    DirectoryFilter, PrefixFileFilter, SuffixFileFilter, NameFileFilter, WildcardFileFilter, AgeFileFilter, SizeFileFilter, TrueFileFilter, FalseFileFilter, NotFileFilter, AndFileFilter, OrFileFilter

    Örneğin, geçerli dizindeki, dizin olmayan, "A" ile başlayıp,  ".java" veya ".class" ile biten dosyaları listelemek için:

    File dir = new File(".");
      String[] files = dir.list( 
        new AndFileFilter(
          new AndFileFilter(
            new PrefixFileFilter("A"),
            new OrFileFilter(
              new SuffixFileFilter(".class"),
              new SuffixFileFilter(".java")
            )
          ),
          new NotFileFilter(
            new DirectoryFileFilter()
          )
        )
      );
      for ( int i=0; i<files.length; i++ ) {
        System.out.println(files[i]);
      }
    


    Bu pakette ayrıca FileFilterUtils sınıfı da mevcuttur. Bu sınıf az önce saydığın filtre sınıflarını import etmeden statik alanlar üzerinden çok daha kolay çağırmayı sağlar. Az önceki örnek bu sınıf yardımıyla tekrar yazılırsa şu hale dönüşür:

    File dir = new File(".");
      String[] files = dir.list( 
        FileFilterUtils.andFileFilter(
          FileFilterUtils.andFileFilter(
            FileFilterUtils.prefixFileFilter("A"),
            FileFilterUtils.orFileFilter(
              FileFilterUtils.suffixFileFilter(".class"),
              FileFilterUtils.suffixFileFilter(".java")
            )
          ),
          FileFilterUtils.notFileFilter(
            FileFilterUtils.directoryFileFilter()
          )
        )
      );
      for ( int i=0; i<files.length; i++ ) {
        System.out.println(files[i]);
      }
    

    Dosya Karşılaştırıcıları
    org.apache.commons.io.comparator paketi java.io.File sınıfı için java.util.Comparator interface'inin birkaç hazır örneğini içerir. Bu karşılaştırıcılar dosya listelerini veya dizilerini sıralamak için kullanılabilir.

    Bütün karşılaştırıcılar kendi özelliklerine göre uygun sort(File...) ve sort(List) metodlarını içerir. Örneğin, bir dizindeki dosyaları dosya adına göre sıralamak için;

    File[] files = dir.listFiles();
    NameFileComparator.NAME_COMPARATOR.sort(files);
    

    Aynı işlemi tek satırda da yapabilirsiniz:

    File[] files = NameFileComparator.NAME_COMPARATOR.sort(dir.listFiles());
      

    CompositeFileComparator sınıfı karşılaştırma ve sıralama işlemini birkaç karşılaştırıcıyı birleştirerek yapabilir. Örneğin dosyaları önce türüne sonra da adına göre sıralamak için;

    CompositeFileComparator comparator =new CompositeFileComparator(
    DirectoryFileComparator.DIRECTORY_COMPARATOR,NameFileComparator.NAME_COMPARATOR);
    File[] files = dir.listFiles();
    comparator.sort(files); 


    Akışlar(Stream)
    org.apache.commons.io.input ve org.apache.commons.io.output paketleri akışların kullanışlı birkaç örneğini içerir. Bazıları;

    • Null output stream - Kendisine gönderilen bütün veriyi emer (yok eder).
    • Tee output stream - Çıktıyı tek akış yerine iki akışa yönlendirir.
    • Byte array output stream - JDK'daki abisinin daha hızlısı
    • Counting streams - Aldığı veriyi byte olarak sayan akış
    • Proxy streams - Proxy tasarım desenini uygular ve akışı uygun metoda yönlendirir.
    • Lockable writer
    Bu yazıda Apache Commons'un IO kütüphanesini tanıtmaya çalıştım. Sınıflar ve kullanımları hakkında daha detaylı bilgiyi kütüphanenin Javadoc'unda bulabilirsiniz.

    14 Mayıs 2011 Cumartesi

    Basit Bir Anlık Mesajlaşma Yazılımı

    Şimdi farkettim 2 sene olmuş İşletim Sistemleri dersinden ödev olarak basit bir MSN Messenger yapalı.

    Proje hakkında bilgiyi aşağıdaki sunumda bulabilirsiniz:



    İndirme bağlantısı da burada.

    Pulp Fiction Duvar Kağıdı

    Türkçesi: "İntikamımı aldığımda..."



    Polis Filmi Duvar Kağıdı

    Polis en sevdiğim filmdir. Bir zamanlar en önemli sahnelerinden biri için bir duvar kağıdı yapmıştım. Buyrun:

    13 Mayıs 2011 Cuma

    SCJP Sticker'ı

    SCJP sınavını geçince şöyle bir sticker hazırlamıştım.





















    Beğenip de kullanmak isteyen olursa buyursun.
    Tasarımı Paint.Net 'te yapmıştım. Bu da kaynak dosyası.

    12 Mayıs 2011 Perşembe

    Dosya Paylaşımı İçin Box.net'e Geçtim

    Blog'umdan dosya paylaşımı daha rahat yapabilmek için box.net kullanmaya karar verdim. Daha önce paylaştığım Maven Rehberi'ne buradan ulaşabilirsiniz.

    MAVEN-REHBER.pdf


    25 Nisan 2011 Pazartesi

    Maven3 (Proje yönetim aracı)-6: Örnek Çok Modüllü Proje

    Bu yazıda daha önce Maven3 (Proje yönetim aracı)-4: Örnek Proje(simple-weather) ve Maven3 (Proje yönetim aracı)-5: Örnek Web Projesi(simple-webapp) nde anlattığım örnek projeleri bir araya getirip çok modüllü bir proje oluşturacağız. Proje kodlarını buradan indirebilirsiniz.

    Çok modüllü bir proje, içinden sahip olduğu alt modüllere referans veren bir ebeveyn POM ile oluşturulur. Yani ebeveyn projemizi simple-parent/ dizinine koyar ve içine de şu POM'u koyarsak, simple-weather ve simple-webapp adında iki alt modülü olan bir çok modüllü proje elde etmiş oluruz:

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                          http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>org.sonatype.mavenbook.multi</groupId>
      <artifactId>simple-parent</artifactId>
      <packaging>pom</packaging>
      <version>1.0</version>
      <name>Multi Chapter Simple Parent Project</name>
     
      <modules>
        <module>simple-weather</module>
        <module>simple-webapp</module>
      </modules>
    
      <build>
        <pluginManagement>
          <plugins>
            <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <configuration>
                <source>1.5</source>
                <target>1.5</target>
              </configuration>
            </plugin>
          </plugins>
       </pluginManagement> 
      </build>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    

    Dikkat ederseniz ebeveyn projemizin paketleme tipi olarak JAR veya WAR gibi herhangi bir arşiv çesidi vermedik. Paketleme çeşidimiz sadece diğer projelere referansla içeren basit bir POM dosyası. Ayrıca bu POM'da modules adında daha önce karşılaşmadığınız bir öğe var: modules Bu öğe altındaki her module öğesi ebeveyn projenin dizini altındaki alt modüllerin dizinlerine işaret eder. Yani bizim örneğimize göre simple-weather ve simple-webapp adında iki alt dizine (modüle) sahibiz.
    Bu ebeveny POM tarafından tanımlanmış bütün ayarlar, bağımlılıklar v.s. alt modüller tarafından kalıtım alınır.

    simple-weather Alt Modülü
    Modülümüzün POM'unu şu şekilde oluşturuyoruz:

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                          http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>org.sonatype.mavenbook.multi</groupId>
        <artifactId>simple-parent</artifactId>
        <version>1.0</version>
      </parent>
      <artifactId>simple-weather</artifactId>
      <packaging>jar</packaging>
    
      <name>Multi Chapter Simple Weather API</name>
    
      <build>
        <pluginManagement>
          <plugins>
            <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-surefire-plugin</artifactId>
              <configuration>
                <testFailureIgnore>true</testFailureIgnore>
              </configuration>
            </plugin>
          </plugins>
        </pluginManagement> 
      </build>
    
      <dependencies>
        <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.14</version>
        </dependency>
        <dependency>
          <groupId>dom4j</groupId>
          <artifactId>dom4j</artifactId>
          <version>1.6.1</version>
        </dependency>
        <dependency>
          <groupId>jaxen</groupId>
          <artifactId>jaxen</artifactId>
          <version>1.1.1</version>
        </dependency>
        <dependency>
          <groupId>velocity</groupId>
          <artifactId>velocity</artifactId>
          <version>1.5</version>
        </dependency>
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-io</artifactId>
          <version>1.3.2</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    

    Modülün detaylarına inmeden önce burada birşey dikkatinizi çekmeli: parent öğesi. Bu öğe ile modülümüzün ebeveyn projesinin koordinatlarını belirtiyoruz.

    Bu modülde şöyle bir yol izleyeceğiz: Tekrar kullanılabilirliği sağlamak için bir tane servis sınıfı yazacağız. Bu sınıf aynen komut satırından çalışan simple-weather projesi gibi girilen bölge koduna ait şehrin hava durumu bilgilerini geri dönecek. Servis sınıfımız işlemlerini gerçekleştirmek için simple-weather projesinin sınıflarını kullanacak.

    package org.sonatype.mavenbook.weather;
    
    import java.io.InputStream;
    
    public class WeatherService {
    
        public WeatherService() {}
    
        public String retrieveForecast( String zip ) throws Exception {
            // Retrieve Data
            InputStream dataIn = new YahooRetriever().retrieve( zip );
    
            // Parse Data
            Weather weather = new YahooParser().parse( dataIn );
    
            // Format (Print) Data
            return new WeatherFormatter().format( weather );
        }
    }
    

    simple-webapp Alt Modülü
    Bu modülümüz ise az önce simple-weather'da oluşturduğumuz servis sınıfını kullanıp, ondan aldığı verileri yayınlamak üzere birkaç servlet tanımlayacak. Şimdi öncelikle simple-weather modülünü kullanacağımız için POM'umuzda bu projeyi bağımlılık olarak belirtmeliyiz. POM'un geri kalanı zaten simple-webapp projesininkiyle aynı olacak.

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                          http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>org.sonatype.mavenbook.multi</groupId>
        <artifactId>simple-parent</artifactId>
        <version>1.0</version>
      </parent>
    
      <artifactId>simple-webapp</artifactId>
      <packaging>war</packaging>
      <name>simple-webapp Maven Webapp</name>
      <dependencies>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
          <version>2.4</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>org.sonatype.mavenbook.multi</groupId>
          <artifactId>simple-weather</artifactId>
          <version>1.0</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>simple-webapp</finalName>
        <plugins>
          <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    </project>

    Servletimizde ise HTTP isteğinden bölge kodunu okuyoruz ve bir önceki modülde oluşturduğumuz WeatherService sınıfının retreiveForecast() metodunu çağırıyoruz. Dönen cevabı da out.println() ile istemciye yolluyoruz:
    package org.sonatype.mavenbook.web;
    
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class SimpleServlet extends HttpServlet {
        public void doGet(HttpServletRequest request,
                          HttpServletResponse response)
            throws ServletException, IOException {
     PrintWriter out = response.getWriter();
     out.println( "SimpleServlet Executed" );
            out.flush();
            out.close();
        }
    }
    

    Son olarak web.xml'imizde /weather adresine yapılan istekleri karşılamak üzere WeatherServlet'i kaydediyoruz:
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <servlet>
        <servlet-name>simple</servlet-name>
        <servlet-class>org.sonatype.mavenbook.web.SimpleServlet</servlet-class>
      </servlet>
      <servlet>
        <servlet-name>weather</servlet-name>
        <servlet-class>org.sonatype.mavenbook.web.WeatherServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>simple</servlet-name>
        <url-pattern>/simple</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>weather</servlet-name>
        <url-pattern>/weather</url-pattern>
      </servlet-mapping>
    </web-app>
    

    Çok Modüllü Projeyi Derlemek
    Sıra projelerimizi derlemeye geldi. simple-webapp, simple-weather'a bağımlı olduğu için, daha önce derlenmesi gerekli. Ancak bunu dert etmenize gerek yok, çünkü Maven (Reactor eklentisi) hangisinin daha önce derlenmesi gerektiğini bilecek kadar akıllı. Tek yapmanız gereken ebeveyn projenin olduğu dizinden mvn clean install komudunu çalıştırmak:
    ~/examples/ch-multi/simple-parent$ mvn clean install
    [INFO] Scanning for projects...
    [INFO] Reactor build order: 
    [INFO]   Simple Parent Project
    [INFO]   simple-weather
    [INFO]   simple-webapp Maven Webapp
    [INFO] ----------------------------------------------------------------------
    [INFO] Building simple-weather
    [INFO]    task-segment: [clean, install]
    [INFO] ----------------------------------------------------------------------
    [...]
    [INFO] [install:install]
    [INFO] Installing simple-weather-1.0.jar to simple-weather-1.0.jar
    [INFO] ----------------------------------------------------------------------
    [INFO] Building simple-webapp Maven Webapp
    [INFO]    task-segment: [clean, install]
    [INFO] ----------------------------------------------------------------------
    [...]
    [INFO] [install:install]
    [INFO] Installing simple-webapp.war to simple-webapp-1.0.war
    [INFO] 
    [INFO] ----------------------------------------------------------------------
    [INFO] Reactor Summary:
    [INFO] ----------------------------------------------------------------------
    [INFO] Simple Parent Project ............................... SUCCESS [3.041s]
    [INFO] simple-weather ...................................... SUCCESS [4.802s]
    [INFO] simple-webapp Maven Webapp .......................... SUCCESS [3.065s]
    [INFO] ----------------------------------------------------------------------
    

    Tavsiye: Aslında yapmak zorunda olmasanız da mvn komudunu her çalıştırdığınızda clean evresini de ekleyin. Böylece Maven, daha önce oluşturulmuş bütün çıktıları silecek ve "temiz" bir inşa işlemine başlayacaktır.

    Uygulamayı Çalıştırmak
    Artık bildiğiniz üzere:
    ~/examples/ch-multi/simple-parent/simple-webapp $ mvn jetty:run
    [INFO] ----------------------------------------------------------------------
    [INFO] Building simple-webapp Maven Webapp
    [INFO]    task-segment: [jetty:run]
    [INFO] ----------------------------------------------------------------------
    [...]
    [INFO] [jetty:run]
    [INFO] Configuring Jetty for project: simple-webapp Maven Webapp
    [...]
    [INFO] Webapp directory = ~/examples/ch-multi/simple-parent/\
                              simple-webapp/src/main/webapp
    [INFO] Starting jetty 6.1.6rc1 ...
    2007-11-18 1:58:26.980::INFO:  jetty-6.1.6rc1
    2007-11-18 1:58:26.125::INFO:  No Transaction manager found
    2007-11-18 1:58:27.633::INFO:  Started SelectChannelConnector@0.0.0.0:8080
    [INFO] Started Jetty Server
    

    Jetty başladıktan sonra http://localhost:8080/simple-webapp/weather?zip=01201 adresine gidip servisi test edebilirsiniz. Sondaki 5 haneli numarayı değiştirip istediğiniz bölgenin hava durumunu öğrenebilirsiniz.
    Aslında Türkiye'nin kodlarını da bulup İstanbul'un hava durumunu da öğrenmek lazım ya. Bu da size ödev olsun :)

    Kolay Gelsin.

    Maven3 (Proje yönetim aracı)-5: Örnek Web Projesi

    Merhabalar. Bu yazıda basit bir web uygulamasını Maven kullanarak nasıl yapılacağını anlatacağım. Oluşturacağımız proje bir önceki yazıda anlattığım projeye büyük oranda benzeyecek. Bu yüzden hafizanızı tazelemenize ihtiyacınız olabilir. Hadi başlayalım.

    Önce yine şu komut ile proje oluşturulmasını tetikleyin:
    mvn archetype:generate -DgroupId=org.sonatype.mavenbook.simpleweb -DartifactId=simple-webapp -Dpackage=org.sonatype.mavenbook
    
    Sorulduğunda proje iskeleti olarak maven-archetype-webapp'ı seçin. İşlem tamamlandığında şuna benzer bir POM oluşacak.

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
             http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.sonatype.mavenbook.simpleweb</groupId>
      <artifactId>simple-webapp</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>simple-webapp Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
      <build>
        <finalName>simple-webapp</finalName>
      </build>
    </project>
    

    Bu POM'da bir önceki projeninkinden farklı olarak dikkatinizi çekebilecek 2 şey var. Birincisi projenin paketleme biçimi WAR olarak belirlenmiş. İkincisi ise build öğesi altına finalName öğesini eklenmiş. Bu öğe paketleme evresinde WAR'a son adını vermekte kullanılır. Bu örneğe göre, projemiz target/ dizini altına simple-webapp.war olarak yayınlanacak.

    Projeyi Çalıştırmak
    Bir önceki projenin aksine bu proje bir web uygulaması olduğu için çalıştırmak için Exec eklentisini kullanamayız. Normal şartlar altında(NŞA) bu iş için Tomcat ya da Jetty gibi bir Servlet Kabı(Container)'nı internetten indirip, ayarlarını yapıp, simple-webapp.war dosyasını webapps/ altına koyup sonra da kabı başlatmanız gerekir. Ancak bunun daha kolay bir yolu var. Maven Jetty eklentisini bu iş için kullanabilirsiniz. Şu POM parçasını projenize eklemeniz yeterli:

    <project>
      [...]
      <build>
        <finalName>simple-webapp</finalName>
        <plugins>
          <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
      [...]
    </project>
    

    Sonrasında Jetty eklentisinin Run hedefini kullanarak uygulamayı çalıştırabilirsiniz.

    ~/examples/ch-simple-web/simple-webapp $ mvn jetty:run
    ...
    [INFO] [jetty:run]
    [INFO] Configuring Jetty for project: simple-webapp Maven Webapp
    [INFO] Webapp source directory = \
           ~/svnw/sonatype/examples/ch-simple-web/simple-webapp/src/main/webapp
    [INFO] web.xml file = \
     ~/svnw/sonatype/examples/ch-simple-web/\
    simple-webapp/src/main/webapp/WEB-INF/web.xml
    [INFO] Classes = ~/svnw/sonatype/examples/ch-simple-web/\
    simple-webapp/target/classes
    2007-11-17 22:11:50.532::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
    [INFO] Context path = /simple-webapp
    [INFO] Tmp directory =  determined at runtime
    [INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml
    [INFO] Web overrides =  none
    [INFO] Webapp directory = \
           ~/svnw/sonatype/examples/ch-simple-web/simple-webapp/src/main/webapp
    [INFO] Starting jetty 6.1.6rc1 ...
    48
    2007-11-17 22:11:50.673::INFO:  jetty-6.1.6rc1
    2007-11-17 22:11:50.846::INFO:  No Transaction manager found 
    2007-11-17 22:11:51.057::INFO:  Started SelectChannelConnector@0.0.0.0:8080
    [INFO] Started Jetty Server
    

    DİKKAT: Maven Jetty eklentisini Windows altında çalıştırıyorsanız, yerel deponuzu adında boşluk içermeyen bir dizine almanız gerekebilir. Çünkü böyle durumlarda (örneğin yerel deponun "C:\Documents and Settings\" altında olması durumunda) bazen Jetty'nin başlatılamaması hatası ile karşılabilirsiniz. Çözüm deponuzu adında boşluk içermeyen bir yere alıp, bu yeri de ~/.m2/settings.xml dosyasında tekrar belirtmektir.
    Jetty başlatıldıktan sonra, tarayıcınızdan http://localhost:8080/simple-webapp/ adresine gidin. Eğer herşey yolundaysa bir "Merhaba Dünya" görmelisiniz. Karşınıza gelen sayfa maven-archetype-webapp iskeletinin oluşturduğu index.jsp sayfasıdır. Maven ön tanımlı olarak herhangi bir web uygulamasının ana dizinini src/main/webapp/ olarak kabul eder. İşte az önce gördüğümüz index.jsp de bu dizindedir. İçeriğini merak ettiyseniz:


    <html>
      <body>
        <h2>Hello World!</h2>
      </body>
    </html>
    

    src/main/webapp/WEB-INF altında ise yine çok basit bir web.xml dosyası vardır:

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    </web-app>
    

    Servlet Eklemek
    Şimdi projemize biraz Java kodu ekleyelim. Öncelikle eğer halihazırda yoksa src/main/java/org/sonatype/mavenbook/web dizinini sonra da içinde SimpleServlet.java sınıfını oluşturun. İçine de şunları yazın:

    package org.sonatype.mavenbook.web;
    
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class SimpleServlet extends HttpServlet {
        public void doGet(HttpServletRequest request,
                          HttpServletResponse response)
            throws ServletException, IOException {
     PrintWriter out = response.getWriter();
     out.println( "SimpleServlet Executed" );
            out.flush();
            out.close();
        }
    }
    

    Servlet'imiz aslında bir çeşit "Merhaba Dünya" servlet'inden başka birşey değil. Bu servlet'i uygulamamız altında çağrılan bir yola bağlamak için web.xml'i kullanacağız. Aşağıdaki web.xml ile servlet'imizi simple/ yoluna bağlıyoruz. Yani ne zaman http://localhost:8080/simple-webapp/simple adresine bir istek yapılsa bu servlet çağırılacak.

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <servlet>
        <servlet-name>simple</servlet-name>
        <servlet-class>org.sonatype.mavenbook.web.SimpleServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>simple</servlet-name>
        <url-pattern>/simple</url-pattern>
      </servlet-mapping>
    </web-app>
    

    Şimdi de projemize Servlet API'nin bağımlılığını ekleyelim:

    <project>
      [...]
      <dependencies>
        [...]
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
          <version>2.4</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
      [...]
    </project>
    

    Burada bağımlılığın kapsamının provided olduğuna dikkat edin. Bu Maven'a bağımlılığı WAR dosyasının içine koymamasını çünkü servlet kabı tarafından sağlanacağını söyler. Eğer projede JSP etiketleri kullanırsanız JSP belirtim kütüphanesini de classpath'a eklemeniz gerekir.

    <project>
      [...]
      <dependencies>
        [...]
        <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.0</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
      [...]
    </project>
    

    Şimdi uygulamamamızı çalıştırabiliriz. Uygulama kodları değiştiği için, Jetty'i tekrar çalıştırmamız gerekecek. Eğer Jetty hala çalışıyorsa CTRL+C tuşlarıyla durdurun. mvn clean install komutu ile tekrar inşa edin ve mvn jetty:run ile Jetty'i tekrar çalıştırın.

    Tarayıcınızdan http://localhost:8080/simple-webapp/simple adresine gittiğinizde "Simple Executed" çıktısını görmeniz lazım.

    Bu yazıda basit bir Java Web uygulaması geliştirdik, uygulmamıza bir servlet ekledik ve servlet kabı içinden çalıştırdık. Şimdi bu temel uzerine kendiniz geliştirmeler yapabilirsiniz. Örneğin POM'a PrimeFaces kütüphanesini ekleyip biraz JSF alıştırması yapın.
    Kolay Gelsin.

    24 Nisan 2011 Pazar

    Maven3 (Proje yönetim aracı)-4: Örnek Proje

    Bu yazıda sıfırdan Maven kullanarak bir proje geliştireceğiz. Proje kodlarını buradan indirebilirsiniz.
    Projemiz Yahoo Weather RSS servisine bağlanıp girilen koda karşılık gelen bölgenin hava durumu bilgilerini getiren bir konsol uygulaması olacak.
    Önce bir önceki yazıda anlattığım maven-quickstart-archive'ı kullanarak bir proje oluşturalım:

    mvn archetype:generate -DgroupId=org.sonatype.mavenbook.custom -DartifactId=simple-weather -Dpackage=org.sonatype.mavenbook -Dversion=1.0
    

    Komut satırında sorulduğunda proje iskeleti olarak maven-quickstart-archive'ı seçin. Maven komutu işlemeyi bitirdiğinde simple-weather dizinini oluşturacak ve içine projenin pom.xml dosyasını koyacaktır. Bu dosya:

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                          http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.sonatype.mavenbook.custom</groupId>
      <artifactId>simple-weather</artifactId>
      <packaging>jar</packaging>
      <version>1.0</version>
      <name>simple-weather</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    

    Projenin hedef Java sürümünü Derleme eklentisi aracılığyla Java 5'e ayarlayın:
    <project xmlns="http://maven.apache.org/POM/4.0.0" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                          http://maven.apache.org/maven-v4_0_0.xsd">
      .................
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>1.5</source>
              <target>1.5</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
      .............
    </project>
    

    Kod yazmaya başlamadan önce pom'a proje hakkında biraz bilgi girelim:
    <project xmlns="http://maven.apache.org/POM/4.0.0" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                          http://maven.apache.org/maven-v4_0_0.xsd">
    ...
    
      <name>simple-weather</name>
      <url>http://www.sonatype.com</url>
    
      <licenses>
        <license>
          <name>Apache 2</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <comments>A business-friendly OSS license</comments>
        </license>
      </licenses>
    
      <organization>
        <name>Sonatype</name>
        <url>http://kahveninhatiri.blogspot.com/</url>
      </organization>
    
      <developers>
        <developer>
          <id>kh</id>
          <name>Kahvenin Hatiri</name>
          <email>kahveninhatiri@gmail.com</email>
          <url>http://kahveninhatiri.blogspot.com/</url>
          <organization>Kahvenin Hatiri</organization>
          <organizationUrl>http://kahveninhatiri.blogspot.com/</organizationUrl>
          <roles>
            <role>developer</role>
          </roles>
          <timezone>+1</timezone>
        </developer>
      </developers>
    ...
    </project>
    

    Sıra geldi projeye birkaç bağımlılık eklemeye. Projemizin XML verileri çözümleme işleri için Dom4J ve Jaxen kütüphanelerini, komut satırına vereceğimiz çıktıyı formatlamak için Velocity kütüphanesini ve günlük kaydı için de Log4J kütüphanesini kullanacağız. Bu bağımlılıkları şu şekilde ekliyoruz:

    <project>
      [...]
      <dependencies>
        <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.14</version>
        </dependency>
        <dependency>
          <groupId>dom4j</groupId>
          <artifactId>dom4j</artifactId>
          <version>1.6.1</version>
        </dependency>
        <dependency>
          <groupId>jaxen</groupId>
          <artifactId>jaxen</artifactId>
          <version>1.1.1</version>
        </dependency>
        <dependency>
          <groupId>velocity</groupId>
          <artifactId>velocity</artifactId>
          <version>1.5</version>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
      [...]
    </project>
    

    Peki ben bu bağımlılıkların koordinatlarını nasıl buldum? Bu iş için jarvana.com adresini kullanabilirsiniz.
    Şimdi projemizin kaynak kodlarını ekleyelim. Öncelikle proje iskeleti ile gelen App ve AppTest sınıflarını silelim. Projemiz 5 tane sınıftan oluşacak:

    • org.sonatype.mavenbook.weather.Main: Çalıştırılabilir main() metodunu barındıran sınıf.
    • org.sonatype.mavenbook.weather.Weather: Hava durumu nesnesi. Yer, sıcaklık, nem v.b. bilgileri tutan basit bir JavaBean.
    • org.sonatype.mavenbook.weather.YahooRetriever: Yahoo servisine bağlanıp, RSS kaynağından bir InputStream döner.
    • org.sonatype.mavenbook.weather.YahooParser: Yahoo'dan dönen XML i çözümleyip, bilgileri bir Weather nesnesi olarak döner.
    • org.sonatype.mavenbook.weather.WeatherFormatter: Weather nesnelerini alıp, tanımladığımız Velocity temasına göre formatlar.

    package org.sonatype.mavenbook.weather;
    
    public class Weather {
     private String city;
     private String region;
     private String country;
        private String condition;
        private String temp;
        private String chill;
        private String humidity;
        
        public Weather() {}
    
     public String getCity() { return city; }
     public void setCity(String city) { this.city = city; }
    
     public String getRegion() { return region; }
     public void setRegion(String region) { this.region = region; }
    
     public String getCountry() { return country; }
     public void setCountry(String country) { this.country = country; }
    
     public String getCondition() { return condition; }
     public void setCondition(String condition) { this.condition = condition; }
    
     public String getTemp() { return temp; }
     public void setTemp(String temp) { this.temp = temp; }
            
     public String getChill() { return chill; }
     public void setChill(String chill) { this.chill = chill; }
    
     public String getHumidity() { return humidity; }
     public void setHumidity(String humidity) { this.humidity = humidity; }
    }
    

    package org.sonatype.mavenbook.weather;
    
    import java.io.InputStream;
    import org.apache.log4j.PropertyConfigurator;
    
    public class Main {
    
     public static void main(String[] args) throws Exception {
      // Configure Log4J
      PropertyConfigurator.configure(Main.class.getClassLoader().getResource("log4j.properties"));
    
      // Read the Zip Code from the Command-line (if none supplied, use 60202)
      String zipcode = "02101";
            try {
        zipcode = args[0];
            } catch( Exception e ) {}
    
      // Start the program
      new Main(zipcode).start();
     }
    
     private String zip;
    
     public Main(String zip) {
      this.zip = zip;
     }
     
     public void start() throws Exception {
      // Retrieve Data
      InputStream dataIn = new YahooRetriever().retrieve( zip );
    
      // Parse Data
      Weather weather = new YahooParser().parse( dataIn );
    
      // Format (Print) Data
      System.out.print( new WeatherFormatter().format( weather ) );
     }
    }
    

    package org.sonatype.mavenbook.weather;
    
    import java.io.InputStream;
    import java.net.URL;
    import java.net.URLConnection;
    import org.apache.log4j.Logger;
    
    public class YahooRetriever {
    
     private static Logger log = Logger.getLogger(YahooRetriever.class);
    
     public InputStream retrieve(String zipcode) throws Exception {
      log.info( "Retrieving Weather Data" );
      String url = "http://weather.yahooapis.com/forecastrss?p=" + zipcode;
      URLConnection conn = new URL(url).openConnection();
      return conn.getInputStream();
     }
    }
    

    package org.sonatype.mavenbook.weather;
    
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.log4j.Logger;
    import org.dom4j.Document;
    import org.dom4j.DocumentFactory;
    import org.dom4j.io.SAXReader;
    
    public class YahooParser {
    
     private static Logger log = Logger.getLogger(YahooParser.class);
    
     public Weather parse(InputStream inputStream) throws Exception {
      Weather weather = new Weather();
      
      log.info( "Creating XML Reader" );
      SAXReader xmlReader = createXmlReader();
      Document doc = xmlReader.read( inputStream );
    
      log.info( "Parsing XML Response" );
      weather.setCity( doc.valueOf("/rss/channel/y:location/@city") );
      weather.setRegion( doc.valueOf("/rss/channel/y:location/@region") );
      weather.setCountry( doc.valueOf("/rss/channel/y:location/@country") );
      weather.setCondition( doc.valueOf("/rss/channel/item/y:condition/@text") );
      weather.setTemp( doc.valueOf("/rss/channel/item/y:condition/@temp") );
      weather.setChill( doc.valueOf("/rss/channel/y:wind/@chill") );
      weather.setHumidity( doc.valueOf("/rss/channel/y:atmosphere/@humidity") );
      
      return weather;
     }
    
     private SAXReader createXmlReader() {
      Map uris = new HashMap();
            uris.put( "y", "http://xml.weather.yahoo.com/ns/rss/1.0" );
            
            DocumentFactory factory = new DocumentFactory();
            factory.setXPathNamespaceURIs( uris );
            
      SAXReader xmlReader = new SAXReader();
      xmlReader.setDocumentFactory( factory );
      return xmlReader;
     }
    }
    

    package org.sonatype.mavenbook.weather;
    
    import java.io.InputStreamReader;
    import java.io.Reader;
    import java.io.StringWriter;
    
    import org.apache.log4j.Logger;
    import org.apache.velocity.VelocityContext;
    import org.apache.velocity.app.Velocity;
    
    public class WeatherFormatter {
    
     private static Logger log = Logger.getLogger(WeatherFormatter.class);
    
     public String format( Weather weather ) throws Exception {
      log.info( "Formatting Weather Data" );
      Reader reader = new InputStreamReader( getClass().getClassLoader().getResourceAsStream("output.vm"));
      VelocityContext context = new VelocityContext();
      context.put("weather", weather );
      StringWriter writer = new StringWriter();
      Velocity.evaluate(context, writer, "", reader);
      return writer.toString();  
     }
    }
    


    Bu sınıfları simple-weather\src\main\java\org\sonatype\mavenbook dizini altında oluşturun.
    Şimdi Log4J ve Velocity için ayar dosyalarını ekleyelim. Önce eğer yoksa src/main/ altında resources/ klasörü oluşturun. Bu klasörün içinde log4j.properties dosyası oluşturup içine şunları yazın:

    # Set root category priority to INFO and its only appender to CONSOLE.
    log4j.rootCategory=INFO, CONSOLE
    
    # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.Threshold=INFO
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern=%-4r %-5p %c{1} %x - %m%n
    

    Bu ayarlar Log4J'nin günlük çıktılarını ekrana hangi formatta basacağı ile ilgilidir.

    Sıra velocity'nin ayar dosyasında. Yine aynı klasörde output.vm dosyasını oluşturun ve içine şunları yazın.

    *********************************
    Current Weather Conditions for:
    ${weather.city}, ${weather.region}, ${weather.country}
    
    Temperature: ${weather.temp}
    Condition: ${weather.condition}
    Humidity: ${weather.humidity}
    Wind Chill: ${weather.chill}
    *********************************
    

    Sizin de tahmin edebileceğiz gibi bu ayar dosyası bir Weather nesnesinin alanlarına erişip (${weather.temp}) verilecek çıktı için bir düzen tanımlar.

    Projemizin çalışması için gerekli herşey bu kadar. Şimdi mvn install komutuyla projeyi yerel depoda yayınlayalım.
    3. parti bir eklenti olan Exec eklentisi ile projeyi çalıştıralım:
    mvn exec:java -Dexec.mainClass=org.sonatype.mavenbook.weather.Main
    
    Bu komut ön tanımlı olan 60202 bölge kodlu Evanston'ın hava durumu bilgilerini ekrana getirecektir. Eğer komut satırından başka bir bölge kodu girmek isterseniz, şöyle yapabilirsiniz.

    mvn exec:java -Dexec.mainClass=org.sonatype.mavenbook.weather.Main -Dexec.args="70112"
    

    Maven en başta bizim eklediğimiz 4 bağımlılığın dışında,geçişli bağımlılıkları da classpath'e ekler. Hangi kütüphanelerin classpath'ta olduğunu öğrenmek için, bağımlılıkları çözümleyebilrisiniz. Bunun için gerekli komut:

    mvn dependency:resolve
    ...
    [INFO] [dependency:resolve]
    [INFO] 
    [INFO] The following files have been resolved: 
    [INFO]    com.ibm.icu:icu4j:jar:2.6.1 (scope = compile)
    [INFO]    commons-collections:commons-collections:jar:3.1 (scope = compile)
    [INFO]    commons-lang:commons-lang:jar:2.1 (scope = compile)
    [INFO]    dom4j:dom4j:jar:1.6.1 (scope = compile)
    [INFO]    jaxen:jaxen:jar:1.1.1 (scope = compile)
    [INFO]    jdom:jdom:jar:1.0 (scope = compile)
    [INFO]    junit:junit:jar:3.8.1 (scope = test)
    [INFO]    log4j:log4j:jar:1.2.14 (scope = compile)
    [INFO]    oro:oro:jar:2.0.8 (scope = compile)
    [INFO]    velocity:velocity:jar:1.5 (scope = compile)
    [INFO]    xalan:xalan:jar:2.6.0 (scope = compile)
    [INFO]    xerces:xercesImpl:jar:2.6.2 (scope = compile)
    [INFO]    xerces:xmlParserAPIs:jar:2.6.2 (scope = compile)
    [INFO]    xml-apis:xml-apis:jar:1.0.b2 (scope = compile)
    [INFO]    xom:xom:jar:1.0 (scope = compile)
    

    mvn dependency:tree komutu bağımlılıkları ağaç yapısında gösterir.

    mvn dependency:tree
    ...
    [INFO] [dependency:tree]
    [INFO] org.sonatype.mavenbook.custom:simple-weather:jar:1.0
    [INFO] +- log4j:log4j:jar:1.2.14:compile
    [INFO] +- dom4j:dom4j:jar:1.6.1:compile
    [INFO] |  \- xml-apis:xml-apis:jar:1.0.b2:compile
    [INFO] +- jaxen:jaxen:jar:1.1.1:compile
    [INFO] |  +- jdom:jdom:jar:1.0:compile
    [INFO] |  +- xerces:xercesImpl:jar:2.6.2:compile
    [INFO] |  \- xom:xom:jar:1.0:compile
    [INFO] |     +- xerces:xmlParserAPIs:jar:2.6.2:compile
    [INFO] |     +- xalan:xalan:jar:2.6.0:compile
    [INFO] |     \- com.ibm.icu:icu4j:jar:2.6.1:compile
    [INFO] +- velocity:velocity:jar:1.5:compile
    [INFO] |  +- commons-collections:commons-collections:jar:3.1:compile
    [INFO] |  +- commons-lang:commons-lang:jar:2.1:compile
    [INFO] |  \- oro:oro:jar:2.0.8:compile
    [INFO] +- org.apache.commons:commons-io:jar:1.3.2:test
    [INFO] \- junit:junit:jar:3.8.1:test
    ...
    

    Eğer proje için düşünülmüş ama sürüm uyuşmazlığı veya diğer nedenlerle seçilmeyen bağımlılıkları da görmek isterseniz, komutu hata ayıklama kipinde çalıştırın:

    mvn install -X
    ...
    [DEBUG] org.sonatype.mavenbook.custom:simple-weather:jar:1.0 (selected for null)
    [DEBUG]   log4j:log4j:jar:1.2.14:compile (selected for compile)
    [DEBUG]   dom4j:dom4j:jar:1.6.1:compile (selected for compile)
    [DEBUG]     xml-apis:xml-apis:jar:1.0.b2:compile (selected for compile)
    [DEBUG]   jaxen:jaxen:jar:1.1.1:compile (selected for compile)
    [DEBUG]     jaxen:jaxen:jar:1.1-beta-6:compile (removed - )
    [DEBUG]     jaxen:jaxen:jar:1.0-FCS:compile (removed - )
    [DEBUG]     jdom:jdom:jar:1.0:compile (selected for compile)
    [DEBUG]     xml-apis:xml-apis:jar:1.3.02:compile (removed - nearer: 1.0.b2)
    [DEBUG]     xerces:xercesImpl:jar:2.6.2:compile (selected for compile)
    [DEBUG]     xom:xom:jar:1.0:compile (selected for compile)
    [DEBUG]       xerces:xmlParserAPIs:jar:2.6.2:compile (selected for compile)
    [DEBUG]       xalan:xalan:jar:2.6.0:compile (selected for compile)
    [DEBUG]       xml-apis:xml-apis:1.0.b2.
    [DEBUG]       com.ibm.icu:icu4j:jar:2.6.1:compile (selected for compile)
    [DEBUG]   velocity:velocity:jar:1.5:compile (selected for compile)
    [DEBUG]     commons-collections:commons-collections:jar:3.1:compile 
    [DEBUG]     commons-lang:commons-lang:jar:2.1:compile (selected for compile)
    [DEBUG]     oro:oro:jar:2.0.8:compile (selected for compile)
    [DEBUG]   junit:junit:jar:3.8.1:test (selected for test)
    

    Aslında proje oluşturma aşaması burada bitti. Ancak Maven'ın yeteneklerini göstermek için devam edelim ve projemize Birim Testleri ekleyelim.
    Öncelikle eğer yoksa src\test\java\org\sonatype\mavenbook sizini oluşturun. Biz burada iki sınıfı test edeceğiz, birincisi YahooParser. Bunun için YahooParserTest sınıfını oluşturun ve içine şunları yazın.

    package org.sonatype.mavenbook.weather;
    
    import java.io.InputStream;
    
    import junit.framework.TestCase;
    
    import org.sonatype.mavenbook.weather.Weather;
    import org.sonatype.mavenbook.weather.YahooParser;
    
    public class YahooParserTest extends TestCase {
    
     public YahooParserTest(String name) {
      super(name);
     }
     
     public void testParser() throws Exception {
      InputStream nyData = 
       getClass().getClassLoader().getResourceAsStream("ny-weather.xml");
      Weather weather = new YahooParser().parse( nyData );
      assertEquals( "New York", weather.getCity() );
      assertEquals( "NY", weather.getRegion() );
      assertEquals( "US", weather.getCountry() );
      assertEquals( "39", weather.getTemp() );
      assertEquals( "Fair", weather.getCondition() );
      assertEquals( "39", weather.getChill() );
      assertEquals( "67", weather.getHumidity() );
     }
    }
    

    Bu sınıftaki JUnit detaylarına girmeyeceğim, bu kısmı JUnit'i anlattığım bir yazıda açıklarım belki. Burada YahooParser sınıfının gelen XML bilgisini doğru çözümleyip çözümlemediği kontrol ediyoruz. Bunun önce sınayacağımız bir veriye ihtiyacımız var. Bu veriyi classpath'taki ny-weather.xml dosyasından alıyoruz. (birazdan bu dosyayı classpath'e koyacağız.) ve bu dosyadaki değerlerle karşılaştırıyoruz. Hepsi doğruysa test hata vermeden tamamlanacaktır.

    İkinci testimiz WeatherFormatter sınıfı için. Bunun için WeatherFormatterTest sınıfını aynı dizinde oluşturun.

    package org.sonatype.mavenbook.weather;
    
    import java.io.InputStream;
    
    import org.apache.commons.io.IOUtils;
    
    import org.sonatype.mavenbook.weather.Weather;
    import org.sonatype.mavenbook.weather.WeatherFormatter;
    import org.sonatype.mavenbook.weather.YahooParser;
    
    import junit.framework.TestCase;
    
    public class WeatherFormatterTest extends TestCase {
    
     public WeatherFormatterTest(String name) {
      super(name);
     }
     
     public void testFormat() throws Exception {
      InputStream nyData = 
       getClass().getClassLoader().getResourceAsStream("ny-weather.xml");
      Weather weather = new YahooParser().parse( nyData );
      String formattedResult = new WeatherFormatter().format( weather );
      InputStream expected = 
       getClass().getClassLoader().getResourceAsStream("format-expected.dat");
      assertEquals( IOUtils.toString( expected ), formattedResult );
     }
    }
    

    Bu sınıfta WeatherFormatter ın Weather nesnelerini doğru biçemlendirip biçimlendirmediği sınıyoruz. Bunun için karşılaştıracağımız bir kaynağa ihtiyacımız var. Bu kaynağı format-expected.dat dosyasından alıyoruz (bu dosyayı da birazdan oluşturacağız.).
    Burada açıklamam gereken bir ayrıntı daha var. G/Ç işleriyle uğraşmamak için bir InputStream i String olarak dönen Apache Commons un commons-io kütüphanesini kullanıyoruz. Aslında bunu elle de yapabilirdik ancak test kapsamlı bağımlıkları göstermek için bu kütüphaneyi kullanıyoruz. Şimdi bu bağımlılığı pom'a ekleyelim.

    
      ...
      
        ...
        
          org.apache.commons
          commons-io
          1.3.2
          test
        
        ...
      
    
    

    Şimdi daha önce söz verdiğimiz dosyaları ekleyelim. Önce eğer yoksa src/test/resources dizinini oluşturun.
    format-expected.dat dosyasını oluşturup içine şunları yazın.

    *********************************
    Current Weather Conditions for:
    New York, NY, US
    
    Temperature: 39
    Condition: Fair
    Humidity: 67
    Wind Chill: 39
    *********************************
    

    ny-weather.xml dosyasını oluşturup içine şunları yazın.

    <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
    <rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
     <channel>
     <title>Yahoo! Weather - New York, NY</title>
     <link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/10002_f.html</link>
     <description>Yahoo! Weather for New York, NY</description>
     <language>en-us</language>
     <lastBuildDate>Sat, 10 Nov 2007 8:51 pm EDT</lastBuildDate>
    
     <ttl>60</ttl>
     <yweather:location city="New York" region="NY" country="US" />
     <yweather:units temperature="F" distance="mi" pressure="in" speed="mph" />
     <yweather:wind chill="39" direction="0" speed="0" />
     <yweather:atmosphere humidity="67" visibility="1609" pressure="30.18" rising="1" />
      <yweather:astronomy sunrise="6:36 am" sunset="4:43 pm" />
      <image>
     <title>Yahoo! Weather</title>
    
     <width>142</width>
     <height>18</height>
     <link>http://weather.yahoo.com/</link>
     <url>http://l.yimg.com/us.yimg.com/i/us/nws/th/main_142b.gif</url>
     </image>
     <item>
     <title>Conditions for New York, NY at 8:51 pm EDT</title>
    
      <geo:lat>40.67</geo:lat>
     <geo:long>-73.94</geo:long>
      <link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/10002_f.html</link>
     <pubDate>Sat, 10 Nov 2007 8:51 pm EDT</pubDate>
     <yweather:condition text="Fair" code="33" temp="39" date="Sat, 10 Nov 2007 8:51 pm EDT" />
     <description><![CDATA[
    <img src="http://l.yimg.com/us.yimg.com/i/us/we/52/33.gif" /><br />
     <b>Current Conditions:</b><br />
     Fair, 39 F<BR /><BR />
     <b>Forecast:</b><BR />
      Sat - Partly Cloudy. High: 45 Low: 32<br />
      Sun - Sunny. High: 50 Low: 38<br />
     <br />
    <a href="http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/10002_f.html">Full Forecast at Yahoo! Weather</a><BR/>
     (provided by The Weather Channel)<br/>
     ]]></description>
     <yweather:forecast day="Sat" date="10 Nov 2007" low="32" high="45" text="Partly Cloudy" code="29" />
    
    <yweather:forecast day="Sun" date="11 Nov 2007" low="38" high="50" text="Sunny" code="32" />
      <guid isPermaLink="false">10002_2007_11_10_20_51_EDT</guid>
     </item>
    </channel>
    </rss><!-- p7.weather.re3.yahoo.com compressed/chunked Sat Nov 10 17:57:31 PST 2007 -->
    

    Şimdi testlerimizi çalıştırabiliriz. Aslında mvn package veya mvn install komutlarını çalıştırınca bu evrelerden önce olan test evresi de çalıştırılır. Ancak sadece test evresini çalıştırmak isterseniz mvn test komutunu da kullanabilirsiniz. Bu komutu çalıştırınca Maven Surfire eklentisi testlerinizi çalıştıracaktır ve testler hakkında detaylı bilgileri ${basedir}/target/surefire-reports altına koyacaktır. Eğer bir şeyler ters giderse buraya bakın :)

    Eğer hatalı testlerin inşa işlemini bölmesini istemiyorsanız Bunu iki şekilde belirtebilirsiniz. İlki pom'a şu parçayı ekleyerek:

    <project>
      [...]
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
              <testFailureIgnore>true</testFailureIgnore>
            </configuration>
          </plugin>
        </plugins>
      </build>
      [...]
    </project>
    

    İkincisi komut satırından:
    mvn test -Dmaven.test.failure.ignore=true
    

    Eğer bir inşada testleri atlamak isterseniz bunu da yine iki şekilde yapabilirsiniz. İlki pom'a şu parçayı ekleyerek:

    <project>
      [...]
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
              <skip>true</skip>
            </configuration>
          </plugin>
        </plugins>
      </build>
      [...]
    </project>
    

    İkincisi yine komut satırından:
    mvn install -Dmaven.test.skip=true
    ...
    [INFO] [compiler:testCompile]
    [INFO] Not compiling test sources
    [INFO] [surefire:test]
    [INFO] Tests are skipped.
    ...
    

    Kolay Gelsin.

    23 Nisan 2011 Cumartesi

    Maven3 (Proje yönetim aracı)-3: maven-archetype-quickstart İskeleti

    Technorati Etiketleri: ,,,,,
    Bu bölümde örnek bir Maven projesi oluşturup detaylarıyla inceleyeceğiz. Anlatacaklarım daha önce yayınladığım Maven Rehberi belgesindeki bilgilerin üzerine kurulacak. Eğer okumadıysanız şimdi okumanın tam zamanı.

    Komut satırından mvn archetype:generate komutunu girerek, etkileşimli kipte proje oluşturmaya başlayın. Listelenen proje iskeletleri arasından maven-archetype-quickstart'ı seçin ve istenilen bilgileri girin. Projenizin artifacId'sini simple olarak adlandırırsak, Maven komutu çalıştırdığınız dizinde simple/ adında bir dizin oluşturacaktır. Bu dizinin yapısı:

    simple/[1]
    simple/pom.xml[2]
          /src/
          /src/main/[3]
              /main/java
          /src/test/[4]
              /test/java
    

    Bu yapıyı incelersek oluşturulan her proje için şunların yapıldığı sonucuna varabiliriz:
    • Projenin artifactId'si ile aynı adda bir dizin: simple/.[1]
    • İçinde POM.xml.[2]
    • Projenin kaynak kodlarının koyulacağı src/main dizini.[3]
    • İçinde groupId ile aynı paket yapısının içinde App adlı basit bir Java programı.
    • Test kodlarının koyulacağı src/test dizini ve içinde App programının testi olan AppTest.[4]
    Bu projeyi inşa etmek için komut satırından POM un bulunduğu dizine geçin ve mvn install komutunu çalıştırın. Bu komut projeyi derler, testlerini çalıştırır, paketler ve yerel deponuza kaydeder. Ayrıca target/ dizini altına simple-1.0-SNAPSHOT.jar dosyasını koyar.

    maven-archetype-quickstart proje iskeleti Maven'ın tanımladığı en basit proje yapısını oluşturur. Bu projede sade bir POM, App adında bir Merhaba Dünya uygulaması ve bunun AppTest adında bir testi bulunur.

    mvn install komutu simple projesi üzerinde İnşa Yaşam Döngüsünün install evresini çalıştırır. İnşa Yaşam Döngüsü bir projeyi inşa etmek için teker teker çalıştırılan(geçilen) bir dizi evredir(phase). Maven'ın işletebileceği birçok yaşam döngüsü vardır. Ancak en önemlisi projenin kontrolü, derlenmesi, paketlenmesi, yayınlamasını da içeren İnşa'dır. Eklenti hedefleri yaşam döngüsü hedeflerine bağlanabilir. Maven döngüde ilerlerken her evreye bağlanmış hedefleri sırayla çalıştırır. Her evrenin sıfır veya daha fazla hedefi olabilir. Örneğin bizim projemiz JAR çıktısı verdiği için package evresine jar:jar hedefi bağlanmıştır. Eğer WAR çıktısı verseydi war:war hedefi çalıştırılacaktı.



    Maven'da bir evreyi çalıştırmak, belirtilen evre ve öncesindeki bütün evrelerin çalıştırılmasına neden olur. Örneğin mvn package komutu çalıştırıldığında Maven package ve öncesindeki her evre için resimde görülen hedefleri çalıştırır. Çalıştırılacak hedeflerin seçimi projenin ayarlarının belirtildiği POM dosyasındaki girdilere göre değişir.

    maven-archetype-quickstart iskeleti projenin testlerini çalıştırmak için kullanılmak üzere JUnit-3.8.1 için bir bağımlılık tanımlar. mvn install komutunu çalıştırdığınızda Maven, bu bağımlılığı internetten indirip yerel deponuza JUnit'in koordinatlarını da göz önünde bulundurarak koyar. Junit-3.8.1 in koordinatları şöyledir: junit:junit:3.8.1. Eğer ~/.m2/repository/ altına bakarsanız, bu şekilde bir dizin yapısı oluşturulduğunu ve içine de junit-3.8.1.jar ın yerleştirildiğini görürsünüz: /junit/junit/3.8.1/junit-3.8.1.jar

    Maven bağımlılıklar için jar'ın dışında bağımlılığın pom.xml dosyasını ve indirmenin doğru yapılıp yapılmadığını kontrol için SHA-1 dosyalarını da indirir. Bağımlılığın pom'u geçişli bağımlılıkları bulabilmek için indirilir.

    18 Nisan 2011 Pazartesi

    Maven3 (Proje yönetim aracı)-2: Türkçe Maven Rehberi

    Sonatype'ın birkaç tane CC lisanslı Maven kitabı var. Maven konusundaki Türkçe kaynak sıkıntısını gidermek adına Maven: The Complete Reference kitabının giriş ve orta seviye için önemli gördüğüm yerlerini Türkçeye çevirerek bir rehber hazırladım.
    Maven Rehberi
    Faydalı olması dileğiyle...

    3 Nisan 2011 Pazar

    Maven3 (Proje yönetim aracı)-1: Giriş ve Kurulum

    Merhabalar. Bu yazımızda piyasada çok kullanılan bir proje yönetim aracı olan Maven’ı işliyoruz.

    Maven bir proje yönetim aracıdır. “Ben projelerimi zaten kendim (ya da IDE’m vasıtasıyla) yönetebiliyorum. Bunun için bir araca ne gerek var?”, demeyin. Bu yazı dizisi çaylak Javacılara hitap ettiği için muhtemelen projeleriniz Maven kullanmanızı gerektirecek büyüklükte değildir. Kurumsal projeler ise bazen o kadar büyük olabiliyor ki, Maven gibi araçlara ihtiyaç duyulabiliyor.

    Maven ne yapar?

    Maven en başta projeleriniz (tipine göre) için bir standart dizin yapısı tanımlar. Bu sayede, örneğin siz Netbeans’te çalışıyorken Netbeans’in oluşturduğu dizin yapısı ile arkadaşınız Eclipse’de çalışıyorken Eclipse’in oluşturduğu dizin yapısı veya bunların kullandığı özel ayarlar yüzünden projelerin taşınabilirliğinin olmamasının önüne geçer.

    Kurumsal Java projeleri o kadar büyük olabilir ki, bazen 100’lerce 3. Parti kütüphane jar’ı kullanmanız gerekebilir. Bu jarları internetten birbirleriyle uygun sürümlerine göre indirip IDE’nizde kütüphaneleri koyduğu yere koymanız, sonra ayrı ayrı javadoc ve kaynak kodlarını ayarlamanız ve bunları proje üzerinde geliştirme yapan herkesin standart bir şekilde uygulaması angarya olur. Öyle ki projeyi geliştirmekten çok yönetimine kafa patlatırsınız. Maven buna da çözüm getirir. Maven’ın yaklaşık 200 GB büyüklüğünde çevrimiçi bir deposu vardır. Siz Maven’a projenizde hangi kütüphaneyi kullanmak istediğinizi söylersiniz, o da bu depodan jarları indirip sizin yerel deponuza kaydeder ve projenin classpath’ını bu jarları da dâhil edecek şekilde değiştirir.

    Maven projenin yönetimi için standart bir yaşam döngüsü tanımlar: Temizle-Derle-Test Et-Çalıştır-Yayınla… gibi. Siz çeşitli eklentilerle (plugin) bu döngüye müdahale edebilir, projenizin gerekliliklerine göre değiştirebilirsiniz. Maven’ın çekirdeği aslında çok basittir. Çekirdek sadece gerekli jarları internetten nasıl indireceğini ve XML dosyalarıyla yapılan ayarların nasıl uygulanacağını bilir. Bu yüzden çok hafiftir (lightweight). Eklentilerle Maven’ı ayarlamak size kalır.

    Maven projeler için kendi modelini tanımlar. Projenin ayar dosyasına girdiğiniz verileri (tanım, geliştiriciler, lisans, bağımlı olduğu diğer projeler v.s.) çok çeşitli işlerde kullanabilir. Bu açıklamaları kullanarak tek bir komutla projeye özel bir web sitesi bile oluşturabilir.

    Kurulum

    Maven 3’ü http://maven.apache.org/download.html adresinden indirebilirsiniz. Kurulumunu sadece Windows’a göre anlatacağım. Çünkü zaten diğer işletim sistemlerini kullananlar biraz sonra anlatacağım ayarları kendi sitemlerinde nasıl yapacakları biliyorlardır.

    İndirdiğiniz sıkıştırılmış dosyayı C:\ dizinine açın. Bu dizinde şuna benzer bir klasör oluşmalı: C:\apache-maven-3.0.3

    Bilgisayarıma sağ tıklayıp Özellikler’e tıklayın (ya da Denetim Masası’ndan Sistem’i açın). Gelişmiş sekmesinde Çevre değişkenlerine (environment variables) tıklayın. Sistem değişkenleri (system variables) altında Yeni’ye tıklayın. Değişken adına: M2_HOME , değerine de C:\apache-maven-3.0.3 girin, Tamam’a tıklayın.

    Aynı pencerede tekrar Yeni’ye basın. Bu sefer değişken adına M2 değerine de %M2_HOME%\bin girin.

    Yine aynı pencerede Path değişkenine tıklayıp, düzenle’yi seçin. Değer kısmının en sonunda ; yoksa ekleyin, sonra da %M2% ‘ yi ekleyin.

    Yine ayrı pencerede JAVA_HOME değişkeni yoksa ekleyin ve değerine JDK’nın bulunduğu dizinin yolunu verin. Örneğin C:\Program Files\Java\jdk1.6.0_24

    Sonra Path değişkenine üstteki gibi %JAVA_HOME% ‘yi ekleyin.

    Windows+R tuşlarına basıp cmd ‘yi çalıştırın. Komut satırından mvn –v ‘yi çalıştırarak kurulumunuzu sınayın.

    Kurulum Ayrıntıları

    Maven’ın yalın 3.0.3 sürümü yaklaşık 2.9 MB boyutunda. Bu kadar küçük olmasının nedeni, gerektiğinde ihtiyacı olduğu eklentileri kendi deposundan indirebiliyor olmasıdır.

    Maven kurulum dizini şu dosya ve klasörleri içerir:

    LICENSE.txt 
    NOTICE.txt 
    README.txt 
    bin/ 
    boot/ 
    conf/ 
    lib/ 
    

    Bunlardan, bin/ içinde Maven’ı çalıştıran mvn komut kümesi (batch)’i barındırır. boot/ içinde Maven’ın çalıştırıldığı bir Sınıf Yükleyici (Class Loader)’yi oluşturan plexus-classworlds-2.4.jar dosyası vardır. conf/ klasöründe Maven’ın global ayarlarını bulunduran settings.xml’i barındırır. lib/ içinde de Maven çekirdeğini oluşturan maven-core-3.0.3.jar dosyası bulunur.

    Yerel Maven Deposu ve Ayarları

    Maven’ı projelerinizde ilk kullanmaya başladığınızda, işletim sisteminizin kullanıcı dizininde (Win XP: C:\Documents and Settings\Foobar\.m2 ya da Linux: /home/foobar ya da genel adıyla ~/) .m2 adında bir klasör oluşturur. Bu klasör sizin yerel ayarlarınızın ve kütüphane (jar) deponuzun (repository) bulunduğu dizindir. Bu dizinde iki tane girdi olacaktır:

    ~/.m2/settings.xml : Kullanıcıya özel Maven ayarlarının bulunduğu dosya.

    ~/.m2/repository: Yerel Maven deposu. İnternetten indirilen jarlar buraya konulur.

    Eğer Maven’ın ayarlarını değiştirmek isterseniz ~/.m2/settings.xml dosyasında değişiklik yapmanız daha doğru olacaktır.


    Devamı gelecek…