Kas 20

Bu yazıda google’ın open source olarak piyasaya sürdüğü ve giderek telefonlarda görmeye başladığımız Android işletim sistemine application(uygulama) yazmak için ilk adımları atacağız.

  • 1.       Android hakkında kısa bilgi
  • 2.       Android Application yazma hakkında bilgi
  • 3.       Android SDK kurulumu
  • 4.       Eclipse ve ADT(Android Development Kit) plugin kurulumu
  • 5.       Creating  “Hello Android” app
  • 6.       Virtual Device’da applicationı test etme


2005 yılında Google'ın Android adlı küçük şirketi aldı. Kasım 2007'de Android'in ilk SDK'sı sunuldu. Mart 2009 da 1.1 sürümü, Mayıs 2009'da 1.5, Eylül 2009'da 1.6 ve son olarakta geçen ay yani Ekim 2009'da da SDK 2.0 sürümünü yayınladı.

Android linux çekirdeğini kullanan mobil cihazlar için open source işletim sistemidir. Android'in SDK'sı Java ile program geliştirme araçlarını ve API'lerini sağlamaktadır. Sağladığı genel özellikler :
 debugger, libraries, a handset emulator , documentation, örnek kodlar, and yardımcı tutorialler.
Android uygulama geliştirebilmek için Androdin sitesinin developer bölümünden Androidin SDK'sını indiriyoruz.



Ben windows altında çalışma ortamımı oluşturacağım. İndirdiğimiz dosyayı çalışma ortamımıza çıkartıyoruz. Daha sonra klasörün içindeki "SDK Setup" ı çalıştırıyoruz. Ufak bi ayar yapmamız gerekmekte.



https ile genelde çalışmıyor. Bu yüzden böyle bir ayar yapıyoruz. Devamında :



Intalled package'a gelip update all diyoruz.



Burada önceki Sdk'ları yüklememize gerek olmadığı için ben screenshot'daki 4ünü seçtim. Install Accepted diyerek devam edelim.





Ve SDK kurulumda Son:



Şimdi Eclipse ortamını hazırlayabiliriz. Eclipse'in yeni sürümleri kullanmamız gerekiyor. (3.4 ve sonrası) Eclipse'i açıyoruz.
ADT Pluginini kuralım. bunun için:



Help > Install New Softare daha sonra gelen ekrandan Add e tıklayalım.




Sonra ekrandaki name alanına Android App yazabilirsiniz. Location alanına da
"http://dl-ssl.google.com/android/eclipse/" giriyoruz. Daha sonrası Next Next olayı.


Eclipse kapatılıp açılacaktır, açıldıktan sonra ADT araçları göreceksiniz. ARTIK ÇALIŞMA ORTAMIMIZ HAZIR. Şimdi ilk uygulamamızı yazalım.

------------İlk Örneğimiz HeLLO Android ----------
Bunun için eclipse de File > New > Project diyoruz.



Android Project'i seçiyoruz.



Gelen ekrandan gerekli alanları dolduruyoruz. Burada;
Project Name
     Eclipse de oluşturduğumuz projenin adı.
Application Name
     Android uygulamasının üzerinde görülecek olan isim
Package Name
    Javadaki package yapısı ile aynı
Create Activity
   İlk başta package altında açılacak olan class'ın adı. (Opsiyonel)

Şimdi com.jtpd.helloAndroid altındaki HelloAndroid.java class'ını açalım.


 
Şimdi de Uygulamamıza ekleme yapalım.


Tüm olay bu kadar basit. Şimdi de çalıştırıp Virtual Device da test edelim. Bunun için Run as -> Android Applicaton seçiyoruz.









Umarım basit bir olayı karmaşıklaştırmamışımdır. Yazıyı oluştururken yararlandığım kaynak http://developer.android.com .

Oca 26


Taner Diler
taner.diler[et]gmail.com


Bileşen bazı web çatısı (Component Based Web Framework) olan Apache Wicket ile kendimize ait bileşenler oluşturmak çok kolay. Web uygulamalarımızda çok kullandığımız kullanıcı yönlendirici mesajları göstermek için bir Wicket Bileşeni nasıl oluştururuz gelin hep birlikte görelim.
[--split--]

Apache Wicket ile Bileşen Tabanlı (Component Based) Web uygulaması gerçekleştirmek kolay ve zevkli bir iş haline geliyor. Bir iki klavye hamlesi ile AJAX uygulaması yazabilirsiniz.

Uygulamalarda kullanıcı bilgilendirme mesajları kimi zaman ilgili formun üzerinde, form girişlerinin yanında ve ya ayrı sayfalarda gösterilmektedir. Bu mesajların gösterimindeki görsel uyumluluk kullanıcının mesajı okumadan içeriği hakkında bilgi sahibi olmasını sağlar. Yönlendirme düğmeleri (button) kullanılarak hangi işleme devam etmesi seçenek olarak sunulur.

Aşağıdaki gibi bir mesaj kutusu tasarladım.




1. SUCCESS, INFO, WARNING, ERROR ve UNAUTHORIZED şeklinde 5 tip mesaj gösterebiliriz.
2. Her mesaj tipinin kendisine ait logosu olacak.
3. Bazı genel mesajlarda title ve footer alanı olmayacak.
4. İstediğim kadar yönlendirme düğmesi ekleyebilmeliyim.

Çizmiş olduğumuz arayüz tasarımını, tasarımcıya verip HTML ve CSS kodlamalarını gerçekleştirelim.

HTML kodları içerisinde Apache Wicket bileşenlerine wicket:id eklemesini yapalım.



Wicket bileşenleri:
 
         1. Mesaj Logosu
         2. Mesaj Başlık Panel’i
         3. Mesaj Başlığı (Title)
         4. Mesaj Gövdesi (Body)
         5. Mesaj Sonu (Footer)
         6. Yönlendirme Düğmeleri (Buttons)

<wicket:panel>
<div class="msg_container">
<div class="msg_body">
<table border="0" cellpadding="0" cellspacing="0">
      <tr>
            <td width="160"><img wicket:id="logo"/></td>
            <td><div wicket:id="titlePanel"></div>
            <br /><span wicket:id="body">[body]</span><br />
            <br /><span wicket:id="footer">[footer]</span><br />
            <br />
            <br />
                  <div style=" margin-right: 30px;">
                     <div wicket:id="buttons" style="float:right; margin-right:15px;" >
                       <input type="button" wicket:id="button"/>
                   </div>
                </div>
                  <div style="clean: both"/>
            </td>
      </tr>
</table>
</div>
</div>
</wicket:panel>

Neden mesaj başlığını bir panel içerisine koyuyoruz? Cevabı basit, başlığı olmayan bir mesaj göstermek istediğimde gövdenin yukarısında göze batacak kadar boşluk olmasını istemiyorum. Bu yüzden burada bulunan div’i gizlemem gerek. Bunun için de başlığın bulunduğu div’e bir wicket panel’i olarak işlem yapacağım.

<wicket:panel>
<strong style="color: #007087;">
<span wicket:id="title">[title]</span>
</strong><br />
</wicket:panel>


UML Sınıf Diyagramım aşağıdaki gibi olacaktır:




Gösterilecek olan başlık anahtarını, içerik anahtarını (ResourceBundle Key), düğmeleri taşıyacak Message sınıfı oluşturdum.


public class Message implements Serializable {
      private MessageType type;
      private String bodyKey;
      private String footerKey;
      private List buttons = new ArrayList();
      
      public Message(MessageType type, String titleKey, String bodyKey,
                  String footerKey) {
            this.type = type;
            this.titleKey = titleKey;
            this.bodyKey = bodyKey;
            this.footerKey = footerKey;
      }
      
      public void addButton(MessageButton button){
           this.buttons.add(button);
      }
      ...
}

Gösterilecek olan mesajın tipine göre logo değişimi olacaktır. Bu yüzden resim tanımlarını mesaj tipi ile ilişkilendirdim. Bunun için Enum yapısını kullanabiliriz. Eğer renk farklılığı da olması istenirse CSS tanımlarını da burada kullanabiliriz.

public enum MessageType {
      ERROR(ConfirmMessagePanel.ERROR_IMAGE),
      INFO(ConfirmMessagePanel.INFO_IMAGE),
      SUCCESS(ConfirmMessagePanel.SUCCESS_IMAGE),
      WARNING(ConfirmMessagePanel.WARNING_IMAGE),
      DENIED(ConfirmMessagePanel.DENIED_IMAGE);
      
      private ResourceReference image;
      
      private MessageType(ResourceReference image){
            this.image = image;     
      }
      
      public ResourceReference getImage(){
            return this.image;
      }
}

MessageButton soyut sınıfından oluşturacağımız her nesnenin kendine özel davranışı olacaktır. Bu yüzden soyut clickButton yordamı tanımladık. AjaxLink Wicket yapısını kullanarak butonların HTML Button’u olarak işlem görmesini Form Submit Button’u olarak tanımlanmamasını sağlarız. Parametre olarak aldığımız AjaxRequestTarget nesnesinin addCompenent() yordamını kullanarak bize Ajax Call’u sonunda hangi bileşenlerin yeniden yorumlanacağını (rendering) ve yeni HTML kodu üretileceğini belirleriz.

public abstract class MessageButton extends AjaxLink {
      public MessageButton(String labelKey) {
            super("button", new Model(labelKey));
            this.add(new SimpleAttributeModifier("value",
                            new ResourceModel(labelKey).getObject()));
      }
 
      public abstract void clickButton(AjaxRequestTarget target);
 
      @Override
      public void onClick(AjaxRequestTarget target) {
            this.clickButton(target);
      }
}

Gelelim mesajlarımızı ve diğer görsel bileşenleri Wicket Panel ile göstermeye. Bunun için Panel Wicket yapısından türemiş MessagePanel sınıfını oluşturmalıyız.

public class MessagePanel extends Panel implements IHeaderContributor {

    private static final long serialVersionUID = -3432489401302616102L;

    private ConfirmMessageModal modal;

    /** reference to the confirmbox's css resource */
    private static final ResourceReference CSS = new ResourceReference(
            MessagePanel.class, "confirmbox.css");

    /** reference to WARNING image */
    static final ResourceReference WARNING_IMAGE = new ResourceReference(
            MessagePanel.class, "WARNING.gif");

    /** reference to INFO image */
    static final ResourceReference INFO_IMAGE = new ResourceReference(
            MessagePanel.class, "INFO.gif");

    /** reference to ERROR image */
    static final ResourceReference ERROR_IMAGE = new ResourceReference(
            MessagePanel.class, "ERROR.gif");

    /** reference to SUCCESS image */
    static final ResourceReference SUCCESS_IMAGE = new ResourceReference(
            MessagePanel.class, "SUCCESS.gif");

    /** reference to DENIED image */
    static final ResourceReference DENIED_IMAGE = new ResourceReference(
            MessagePanel.class, "DENIED.gif");

    /*
     * (non-Javadoc)
     *
     * @see
     * org.apache.wicket.markup.html.IHeaderContributor#renderHead(org.apache
     * .wicket.markup.html.IHeaderResponse)
     */
    public void renderHead(IHeaderResponse response) {
        response.renderCSSReference(CSS);

    }

    public MessagePanel(String id, Message message) {
        this(id, message, false);
    }

    public MessagePanel(String id, Message message, boolean hideTitle) {
        super(id);

        TitlePanel titlePanel = new TitlePanel("titlePanel", new ResourceModel(
                message.getTitleKey(), message.getBodyKey()));

        add(new Image("logo", message.getMessageType().getImage()));
        add(titlePanel);

        add(new Label("body", new ResourceModel(message.getBodyKey(), message
                .getBodyKey())));

        add(new Label("footer", new ResourceModel(message.getFooterKey(), "")));
        add(new ListView("buttons", message.getButtonList()) {

            private static final long serialVersionUID = 3339539327149648078L;

            @Override
            protected void populateItem(ListItem item) {
                final MessageButton button = item.getModelObject();
                item.add(button);
            }
        });

        if (hideTitle) {
            titlePanel.setVisible(false);
        }
    }

    void setModal(ConfirmMessageModal modal) {
        this.modal = modal;
    }

    ConfirmMessageModal getModal() {
        return this.modal;
    }

    private class TitlePanel extends Panel {
        private static final long serialVersionUID = -1766112576379965369L;

        public TitlePanel(String id, IModel model) {
            super(id, model);
            add(new Label("title", model));
        }
    }

}


Yukarıda gördüğümüz gibi MessagePanel sınıfı IHeaderContributor arayüzünü gerçekleştirmiş. Eğer bir Wicket Bileşen’inin Header’da değişiklik yapmasını istiyorsak bu arayüzün renderHead() yordamını gerçekleştirmesini sağlamalıyız. CSS ve resim dosyalarının MessagePanel ile paketlemek istediğimiz için aynı dizinde bulunmalıdırlar. Wicket tarafından kullanılabilir olmaları için herbirine ait ResourceReference nesnesi oluşturuyoruz.

Mesaj kutusunun inşaası yapılandırıcı içerisinde gerçekleşmekte. Yapılandırıcı dışında onBeforeRender() yordamı içerisinde de bunu gerçekleştirebiliriz.

Yapılandırıcı içerisinde liste içerisindeki MessageButton’ları göstermek için ListView Wicket yapısını kullanıyoruz. Bu yapı da bir wicket html tanımına ihtiyaç duymaktadır.

<div wicket:id="buttons" style="float:right; margin-right:15px;" >
      <input type="button" wicket:id="button"/>
</div>

Önceki paragraflarda title’in isteğimize göre görünmesini/görünmemesini bunu ayrı bir Wicket Panel gibi düşünerek sağlayabiliriz demiştik. Yapılandırı içerisindeki son satırlarda göndermiş olduğumuz hideTitle parametresine göre panelin setVisible(false) yordamını çağırıyoruz. Başlığı içerecek kısmı panel olarak tanımladığımız için buna ait Wicket Panel sınıfı ve html dosyası oluşturmamız gerekmektedir. Encapsulation prensiplerine uyarak bu panel sınıf tanımını private erişim belirtecine sahip Inner Class olarak yapalım.

public class MessagePanel extends Panel implements IHeaderContributor {

    ...

    private class TitlePanel extends Panel {
        ...
        public TitlePanel(String id, IModel model) {
            super(id, model);
            add(new Label("title", model));
        }
    }

}

Wicket Html tanımı ise ConfirmMessagePanel$TitlePanel.html dosyası içerisinde bulunmalı. Dikkat edildiği gibi derleme sonrasında oluşacak inner class dosya ismi ile aynı.

<wicket:panel>
<strong style="color: #007087;"><span   wicket:id="title">[title]</span></strong>
<br />
</wicket:panel>


Oluşak olan uygulama dizin yapısı aşağıdaki gibidir:



Uygulama içerisinde MessagePanel’imizi nasıl kullanacağız? İşte burada bir örnek mevcut:


...
Message message = new Message(MessageType.INFO,
                "message.panel.title",
                "message.panel.body",
                "message.panel.footer");
message.addButton(new MessageButton("message.button.no"){
      ...
    @Override
    public void clickButton(AjaxRequestTarget target) {
        // DO NOTHING
    }
});
message.addButton(new MessageButton("message.button.yes"){
    ...
    @Override
    public void clickButton(AjaxRequestTarget target) {
        // DO NOTHING
    }
});
MessagePanel messagePanel = new MessagePanel("content", message);
add(messagePanel);
...

Sonuç :



Mesajlarımızın ModalBox içerisinde görünmesini istiyorsak

Apache Wicket ile modal pencereleri yapmak çok kolay. ModalWindow Wicket yapısından yeni yapılar türeterek bunu gerçekleştirebiliriz.

MessagePanel nesnesini Modal özelliği katmak için sarmalayıcı bir sınıf oluşturalım. MessageModal, ModalWindow’dan türeyen bir yapı.

public class MessageModal extends ModalWindow {

    public MessageModal(String id, Message message) {
        super(id);
        this.setMinimalHeight(176);
        this.setInitialHeight(176);
        MessagePanel panel = new MessagePanel(this.getContentId(), message, true);
        panel.setModal(this);
        this.setTitle(new ResourceModel(message.getTitleKey()));
        setContent(panel);
    }


    public void showMessage(AjaxRequestTarget target) {
        this.show(target);
    }

}


MessageModal ile gösterilen mesajlarda başlıklar pencerenin başlığı olarak görünmesini istedim. Bunun için MessagePanel’in yapılandırıcısına hideTitle parametresi için TRUE değeri gönderdim, ModalWindow’dan miras aldığım setTitle() ile ModalWindow’a başlık ataması yaptım.

ModalWindow’u göstermek için show() yordamını kullanıyoruz. Bunun için Ajax desteği olan bir bileşenin oluşturduğu istek ile AjaxRequestTarget nesnesi gelmesi gerekmektedir.

MessageModal’ın bir de HTML dosyası olmalı :

<wicket:panel>
    <div wicket:id="content"/>
</wicket:panel>


Modal kullanımları için ilgili modal kodlarını içerecek bir Wicket Bileşeni tanımlamamız gerekmektedir.

<div wicket:id="modal"></div>

MessagePanel oluşturur gibi MessageModal oluşturabiliriz:

Message message = new Message(MessageType.SUCCESS,
        "message.modal.title",
        "message.modal.body",
        "message.modal.footer");
message.addButton(new MessageButton("message.button.no"){
    @Override
    public void clickButton(AjaxRequestTarget target) {
        // DO NOTHING
    }
});
message.addButton(new MessageButton("message.button.yes"){
    @Override
    public void clickButton(AjaxRequestTarget target) {
        // DO NOTHING
    }
});
MessageModal messageModal = new MessageModal("modal", message);

Göstermek için ise bir Ajax olayına ihtiyacımız var. Bunun için bir önceki bölümde oluşturduğumuz MessagePanel nesnesine “Show” isimli yeni bir buton ekliyorum.

message.addButton(new MessageButton("message.button.show"){
    @Override
    public void clickButton(AjaxRequestTarget target) {
        modal.showMessage(target);
    }
});

Uygulamayı çalıştırıp sonucunu görelim:




Proje kodlarına buradan ulaşabilirsiniz.

Taner Diler
taner.diler[et]gmail.com
Şub 04

CETURK olarak Çankaya Üniversitesi Uygulamalı Matematik Bilgisayar Bilimleri Topluluğu ile birlikte  “JAVA ve Kariyer Günü” etkinliği düzenliyoruz. Etkinlik konusu dahilinde JAVA dünyasındaki kariyer olanaklarından bahsedilecek ve etkinlik sonundaki panelimiz ile bilgi alışverişi gerçekleştirilecektir.

Etkinliğe katılım her zamanki gibi ücretsizdir.Bu etkinliği sitesinde duyuran 2 kişiye kitap hediye edilecektir.



Konuşmacılar  ve Seminer Konuları:

Kadir Teke – Mehmet Gursul : İş İlanlarında Java

Kenan Sevindik : Java, Kariyer ve Gelecek

Mert Çalışkan : Fikrim Açık, Kodum Açık

Ümit Vardar : JavaFX


Adres:

Çankaya Üniversitesi – Mavi Salon

Tarih: 19 Şubat 2010

Saat: 10:30 – 17:00


Kayıt işlemi için tıklayın.


Dünya değişiyor, teknolojiler değişiyor ve yeni takım oyuncuları oyuna dahil oluyor. Google guice çok da yeni sayılmaz fakat benim için farklı ve yeni bir teknoloji. Bu yüzden bu teknolojiyi sizlerle paylaşmak istedim.

Bu yazının sonuna kadar aşağıdaki kavramları üzerinde dönüp duracağım, örnekler vereceğim. Bu kavramların ne olduğunu özetlersem:

  • Dependency Injection  : Bağımlılıktan kurtulmak için bağımlılığı şırınga etmece
  • Google guice : Dependecy Injection yapmanıza olanak veren sağlam bir  araç
  • Warp - persist : google guice ile veritabanı işlemlerini (transaction gibi) gerçekleştirmek için gerekli olan kütüphane
  • Wicket : Kral 

Şimdi bu yazıyı okumaya başlamadan evvel sizden örneği kurup-çalıştırmanızı rica ediyorum, işte gerekli adımlar.

  1. maven biliyor olmanız şart (fazla birşey değil, gözünüz korkmasın lütfen). Eğer bilmiyorsanız bu adresden okuyunuz. 
  2. Bir konsol açın. windows kullananlar cmd ile
  3. Örnek uygulamayı kendi bilgisayarınıza indiriniz, şöyle ki : svn checkout http://jtpd.googlecode.com/svn/trunk/googleguice_warp_wicket_proje  
  4. 8080 portunun boş olduğundan emin olun - Bu en sık yaptığım hatadır aman siz aynı hataya düşmeyin
  5. Sonra :  mvn jetty:run , deyiniz.
  6. Az kaldı; şimdi tarayıcıyınızı açarak : http://localhost:8080/google_guice_warp_wicket/  dediğinizde uygulamanın çalışıyor olmazı lazım ! 
  7. Eğer com.wideplay warp-persist bulunamadı şeklinde bir hata alırsanız. O zaman http://www.wideplay.com/guicewebextensions2 adresine gidip, buradaki jar dosyasını bilgisayarınıza indiriniz ve aşağıdaki komut ile local repository alanınıza bu wideplay-warp kütüphanesini ekleyeniz.

    > mvn install:install-file  -Dfile="C:\ASF\warp-persist\warp-persist-2.0-SNAPSHOT.jar" -DgroupId=com.wideplay 
    -DartifactId=warp-persist -Dversion=2.0 -Dpackaging=jar

    C:\ASF\warp-persist\warp-persist-2.0-SNAPSHOT.jar yerine siz jar dosyasını hangi dizine koymuşsanız onu belirtiniz.


Uygulamayı görüp motive olunması için bu yöntemi bence harika. "ohh uygulama çalıştı şimdi derinlere huzurla inebilirim" yaklaşımının daha cazip olacağını düşündüm. Bazıları beğenmeyebilir ama bu psikoloji bende commodore 64 den kalma. 





Uygulama çalıştı mı ? Evet ise yola devam, hayır ise GOTO 1 ;

Öncelikle Dependecy Injection kavramından bahsetmek istiyorum. 

Dependency Injection kavramı


Türkçeye çevirirsek, bağımlılık şırangası diyebiliriz. Yani bağımlılıktan kurtulmak için bir şırınga kullanımı. Bu kavramın altınta yatan tasarım prensibi şudur : "Sen bizi arama, biz seni ararız" - "Don't call us, we call you" Kısaca Hollywood prensibi olarak geçer. Bunu biraz daha açarsak; 


Yukarıdaki resim Head First Design Patterns kitabının 296. sayfaından alınmıştır ve benim tarafımdan Türkçe ibareler yerleştirilmiştir. 


Hımm, yanlız buradaki en önemli neyin alt neyin üst seviye bileşen olduğunu anlamaktan geçer. Template tasarım kalıbının içerisinde Hollywood prensibi uygulanır, çok da zor değildir. Şimdi olayı kısa bir kod parçası ile anlatmaya çalışalım.



Kod içerisinde sadece ve sadece 29. satıra odaklanmanızı istiyorum. Bu satır Dependency Injection prensibine aykırıdır, neden ?

  • EventDaoHibernateImp() sınıfı ile doğrudan iletişim kurmuş oldunuz ve EventPage sınıfı ile EventDaoHibernateImp() sınıfı ile arasında çok sıcak ve sıkı bağlar/ bağımlılıklar oluştu. Öyle ki, ileride EventPage sınıfındaki herhangi bir hata veya yenilik EventDaoHibernateImp() sınıfını aynı şekilde EventDaoHibernateImp() sınıfındaki her hata ve yenilik EventPage sınıfını doğruda yani birinci elden ilgilendirir oldu. Tatsız değil mi ?

  • EventDaoHibernateImp() sınıfı daha üst seviye bir sınıfdır çünkü veritabanı işlemleri ile ilgilenir ve hayatta ki ne amacı budur. Böyle bir sınıfı gidip de Apache Wicket sayfasının içerisinden direk çağırmak, işlerin hepsini görüntüleme katmanında - view layer - yaptığınız anlamına gelir. Kısaca tüm iş mantığı ön yüz sınıflarında yönetilmeye başlar -ki bu ileride anlamsız derecede acı verici olabilir.

  • Kontrol üst seviye bir bileşenden (sınıfdan) - alt seviye bir bileşene (sınıfa) verilmiştir. Bu da tatsız.

  • Kısacası üst seviye bir bileşeni (sınıfı), alt seviye bir bileşen içerisinden doğrudan ama doğrudan (new anahtar kelimesi ile) çağırmanız Dependency Injection prensibine aykırıdır.

new anahtar kelimesi Java'nın özünde olan birşey değil mi, neresi hata bunun ? Evet öyle new anahtar kelimesi hala çok değerli fakat bağımlılık oluşturmadan uygulama geliştirmenin önemi, işin esas sanatsal noktasıdır.

Peki nasıl bağımlılığı şırınga ederek, bağımlılığı ortadan kaldıracağız ? Cevap aşağıda : 






Dependency Injection kavramının bir çok uygulayıcısı vardır. Benim aklıma gelen ilk ve en meşhuru Spring Framework 'dür. İkincisi ise Google Guice. Yukarıdaki kod örneği Google guice kullanılarak hazırlanmış projeden ufak bir kesittir - ki bu projeyi siz zaten bilgisayarınıza az önce indirdiniz, değil mi ?


Google guice (juice diye okuyunuz) : Dependecy Injection yapmanıza olanak veren sağlam bir araç


Google Guice teknolojisi bence Spring Framework'a nazaran basit ve anlaşılır.  Spring Framework ve Google Guice birbirlerine birebir rakip ürünler değillerdir. Spring Framework devasal alt projeleri ile bir çok probleme derman olurken, Google Guice sadece Dependency Injection ve AOP yani Aspect Oriented Programming kısmında hizmet sunar. Google Guice, Google'ın Adwords ve Wave projelerinde kullanılan sağlam bir yapı olduğunu hatırlatmak isterim. 


Özellikle Spring Security Framework kullanan bir kişi Google Guice da bu tür alt ürünlerin karşılığını bulamaz. Bu arada güvenlik işlemleri için Apache Shiro yu öneririm. Google Guice bir çok web sistemi ile entegre olarak çalışmaktadır, Örneğin Wicket, JSF, Struts. Hatta Struts için özel örnekler bile hazırlanmıştır.



Warp :: Persist

Warp - Persist projesine erişmek için buraya tıklayınız. Google Guice ile yazılan uygulamalara veritabanı desteği veren proje.   Google Guice çekirdek ve bu çekirdeğin etrafında ihtiyaca göre değişik yardımcı projeler mevcut. Warp - persist projesi de bu bunlardan biri. Peki bu proje nasıl kullanılır ?


Bu basit kod örneği çok şeyi anlatıyor. @Transactional annotation sayesinde - bir nesneyi veritabanı kaydederken güvenli bir şekilde veritabanına kaydetmeye olanak verir. Eğer kaydetme anında bir hata olursa geri alma (rollback) otomatik olarak gerçekleşir. Benim en sevdiğim kısmı ise try-catch-finally bloklarından kurtulunuyor olunması ve session.close() yapmaya gerek olunmaması. Artık herşey üst katmanın sorumluluğunda böylece bağlantı kaçakları da kolayca engellenmiş olur.


Sadece veritabanından veri çeken bir yordamı readonly transcational yapmak gayet basit.


Wicket

Bu örneğimizde Apache Wicket ile web uygulamasını gerçekleştirdik. Apache Wicket benim hayatımda gördüğüm en basit (kolay değil) , etkili ve doğal web geliştirme sistemi. İncelemenizi tavsiye ederim. Dediğim gibi Google Guice diğer java web sistemleri ile  - örneğin JSF veya Struts - rahatça çalışabilmektedir.

Uygulamanın detayları


Uygulamanın detaylarından bahsetmeye şimdi başlıyoruz. Öncelikle web.xml


web.xml de iki şeyin tanımını yaptık.
  1. warp-persist : Web oturumuna göre veritabanı bağlantılarını yönetebilmesi için. Bu büyük performans artışlarına sebebiyet veren güzel bir davranıştır.
  2. Wicket : Apache Wicket, tüm isteklere (request) bakması için vekil tayin ettik.

Sıra uygulamanın ayar işlemlerinin yapıldığı WicketApplication sınıfı

WicketApplication.java



Wicket ile Google Guice teknolojilerinin birbirlerine karıştırmak için  getGuiceInjector yordamına ve 24. satırdaki addComponentInstantiationListener(getGuiceInjector) komutuna dikkat çekmek isterim.


Bence uygulamadaki diğer dikkate değer nokta ise veritabanı işlemlerinin yapıldığı sınıfın içerisinde gerçekleşmektedir.


AbstractDaoHibernateImp.java

Hibernate session sınıfına ait nesne oluşturmak için direk new anahtar kelimesi ile değil, bağımlılığı şıranga ederek bağımlılıktan kurtulunmuş oldu. 

Kaynakça

Size göstermiş olduğum örnek http://www.jweekend.com/dev/LegUp  adresinden alınmadır. Burada değişik kombinasyonlardaki teknolojilere ait örnek projeleri alıp, üzerinlerinde rahatça oynayabilirsiniz. Göz atmanızı tavsiye ederim.

Altuğ Bilgin Altıntaş.
altug -at- kodcu.com


Şub 10
"In the end, the project was a big success and a breakthrough not in the country but at the global level. So I think developing enterprise application doesn’t mean you gotta go JavaEE. Putting together your own OSGI stack is much better. Plus while developing, you will get the joy of restarting the application in a matter of seconds rather then in minutes in comparison to application servers..."

Hasan Ceylan (http://tr.linkedin.com/in/hasanceylan) tarafından yazılan yazının devamı için buraya gidebilirsiniz.




Oca 24
Java 1.5 ile gelen yenilikler içerisinde bulunan Genel Tipler ile bazı kod yazma pratiklerimizi değiştirmek ve kendimizi geliştirmek zorunda kaldık. Data Access Object ve Service gibi Üst Seviye Tasarım Kalıplarında (Enterprise Design Patterns), Java Torbalarında (Collections & Map) çok sık kullanır olduk. Tasarımsal olarak getirdiği faydalar olduğu gibi kötü kullanımda da kod okunabilirliliğini azaltmaktadır. Gelin Genel Tipler'in nasıl kullanıldığını bir bakalım...  Yazının diğer bölümleri : Bölüm-2
[--split--]
Nedir bu genel tipler (Generic Types)? Beynimizi çok yormaya gerek yok. Java 1.5 öncesinde bir liste oluşturduğumuzda ve bu listeden bir nesne almak istediğimizde zahmetli bir işe kalkışırdık :
    1:   List liste = new ArrayList();
    2:   liste.add(new Integer(0));
    3:   liste.add(new Integer(1));
    4:   for(int i=0; i<liste.size(); i++){
    5:        Integer sayi = (Integer) liste.get(i);
    6:   }

6. satırda olduğu gibi istediğimiz tipe dönüşüm yaparak (upcasting / downcasting) istediğimiz nesneyi kullanabilirdik.
     1:    List liste = new ArrayList();
    2:   liste.add(new Integer(0));
    3:   liste.add(new Integer(1));
    4:   liste.add(new String("test"));
    5:   for(int i=0; i<liste.size(); i++){
    6:        Integer sayi = (Integer) liste.get(i);
    7:        System.out.println("["+i+"] = "+ sayi);
    8:   }

Sonuç:
[0] = 0
[1] = 1
Exception in thread "main" java.lang.ClassCastException: java.lang.String
    at com.articles.generics.objectcaching.ObjectPoolManager.main(ObjectPoolManager.java:67)

Oluşturduğumuz liste nin sadece Integer tipindeki nesneleri içereceğini düşünürken takım arkadaşımız başka bir yordam içerisinde öyle bir kod yazmışki bu liste içerisine String tipinde bir nesne atmış ( 4. satır ). Çalışma zamanında (Runtime) bu liste içerisindeki nesneleri Integer tipine dönüştürerek alırken String tipinde bir nesnenin gelmesi hata fırlamasına ve uygulamamızın durmasına neden olmaktadır.


Java 1.5 ile gelen genel tipler ( Generics ) bize tam burada yardımımıza koşmaktadır : çok sık kullandığımız Collection ve Map hiyerarşisindeki torbaların (containers) kullanımında yukarıdaki sorunların ortadan kalkması...
     1:    List<Integer> intList = new ArrayList<Integer>();
     2:    intList.add(new Integer(1));
     3:    intList.add(new Integer(2));
     4:    intList.add(new String("3"));

Satırları javac ile derlemeye çalıştığımızda :

şeklinde derleme uyarısı alırız. Çünkü 1. satırda <Integer> ifadesi (tip parametresi) ile oluşturacağımız listeye Integer tipi üzerinde işlem gerçekleştireceğimizi söyleriz. String tipinde bir nesneyi listeye koymak istediğimizde ise derleme hatası alırız. Böylece çalışma zamanında (Runtime) beklenmedik tip dönüşümlerinden meydana gelen hatalardan kurtulmuş oluruz.
Nesne Havuzu ( Object Pool )

Jenerik yapıları anlamak için gelin bir uygulama geliştirelim. Bu uygulama veritabanı bağlantı havuzu (DB Connection Pool) yada iş parçacıkları havuzu (Thread Pooling) gibi asıl amacı sürekli tekrarlayan işlemlerde belli bir tipteki nesnelerin her seferde oluşturulması ve silinmesini engellemektir. Böylece uygulamada gereksiz yavaşlamaları engelleyebilir ve nesne takibini iyileştirebiliriz.


Gelin öncelikle uygulamamızı süper yapıları tanımlayarak başlayalım. Bu süper yapılar : arayüzler (interface), süper sınıflar (super class) ve soyut sınıflar (abstract class) olabilir.
Süper yapılara üzerinden uygulamamızı geliştirdiğimiz zaman ileriye yönelik geliştirme ve sistemler arası iletişim daha kolay yapılmış olacaktır.


Oluşturacağımız süper yapılar:

1.      Yedeklenebilir Arayüzü (Interface) : Sistem tarafından havuzda tutalacak olan nesnelerin sınıf tanımlamaları bu arayüzü gerçekleştirmelidir.
2.      Havuz Arayüzü (Interface) : doldur(), cek()/koy(), bos() soyut yordamlarını içeren arayüzdür. Bu arayüzü gerçekleştiren sınıflar <<Yedeklenebilir>> arayüzünü gerçekleştirmiş yapılar için sınırlandırılmalıdır.
3.      HavuzYöneticisi Arayüzü (Interface) : nesneCek(), nesneKoy() ve havuzuKontrolEt() yordamlarını içermektedir.
    a.      nesneCek() yordamı istenen nesnenin tipine göre ilgili havuzdan nesne çekecek
    b.      nesneKoy() yordami gönderilen nesneyi, nesnenin tipine göre ilgili havuza geri koyar.
    c.       havuzuKontrolEt() yordami nesneCek() yordami çağrıldığında ilgili nesne için havuz nesnesinin yaratılıp içerisinin doldurulmasını kontrol eder.


          
 
Havuz Arayüzü


/**
*{@link Yedeklenebilir}arayüzünügerçekleştirmiş
*nesneleriçinhavuzgörevinigörür.
*
*@param<T extends YedeklenebilirNesne>
*/
public interface Havuz <T extends Yedeklenebilir> {
    
     /**
      *Havuzdannesneçeker.
      *@returnT
      */
     T cek();
    
     /**
      *Nesneyigerikoyar.
      *@paramobject
      */
     void koy(T nesne);
    
     /**
      *clazztipindenesneleriyaratipkendisinidoldurur.
      *@paramclazz
      *@throwsNesneYaratmaHatasi
      */
     void doldur(Class<T> clazz) throws NesneYaratmaHatasi;
    
     /**
      *clazztipindenesnelerdenbelirtilenadetkadar
* yaratipkendisinidoldurur.
      *@paramclazz
      *@paramadet
      *@throwsNesneYaratmaHatasi
      */
     void doldur(Class<T> clazz, int adet) throws NesneYaratmaHatasi;
    
     /**
      *Havuzunbosolupolmadigikontroledilir
      *@returnboolean
      */
     boolean bos();
}


Havuz arayüzüne ait yukarıdaki tanımlamada dikkatimizi <T extends Yedeklenebilir> tip parametresi çekmektedir. Böylece Havuz arayüzünü sadece Yedeklenebilir arayüzüne erişmiş yapılar için genelleştirmiş / sınırlandırmış (bounding) olduk.

Taner Diler
taner.diler[et]gmail.com
Oca 25
Java 1.5 ile gelen yenilikler içerisinde bulunan Genel Tipler ile bazı kod yazma pratiklerimizi değiştirmek ve kendimizi geliştirmek zorunda kaldık. Data Access Object ve Service gibi Üst Seviye Tasarım Kalıplarında (Enterprise Design Patterns), Java Torbalarında (Collections & Map) çok sık kullanır olduk. Tasarımsal olarak getirdiği faydalar olduğu gibi kötü kullanımda da kod okunabilirliliğini azaltmaktadır. Gelin Genel Tipler'in nasıl kullanıldığını bir bakalım...  Yazının diğer bölümleri : Bölüm-1
[--split--]

NesneHavuzu Sınıfı


public class NesneHavuzu<T extends Yedeklenebilir>
     implements Havuz<T> {
    
     private Vector<T> havuz = new Vector<T>();


     /* (non-Javadoc)
      * @see com.articles.generics.objectcaching.Havuz#doldur(java.lang.Class)
      */
     public void doldur(Class<T> clazz) throws NesneYaratmaHatasi {
           this.doldur(clazz, 5);      
     }
    
     /* (non-Javadoc)
      * @see com.articles.generics.objectcaching.Havuz#doldur(java.lang.Class, int)
      */
     public void doldur(Class<T> clazz, int adet)
throws NesneYaratmaHatasi {


           try {
                 for(int sayac=0; sayac<adet; sayac++){
                       this.havuz.add(clazz.newInstance());
                 }
           } catch (InstantiationException e) {
                 NesneYaratmaHatasi ex =
new NesneYaratmaHatasi(clazz, e.getStackTrace());
                 throw ex;
           } catch (IllegalAccessException e) {
                 NesneYaratmaHatasi ex =
new NesneYaratmaHatasi(clazz, e.getStackTrace());
                 throw ex;
           }
     }
    
     /*
      * (non-Javadoc)
      *
      * @see com.articles.generics.objectcaching.Pool#pull()
      */
     public T cek() {
           T object = havuz.remove(0);
           return object;
     }


     /*
      * (non-Javadoc)
      *
      * @see com.articles.generics.objectcaching.Pool#push(com.articles.generics.objectcaching.CachableObject)
      */
     public void koy(T object) {
           havuz.add(object);
     }


     /* (non-Javadoc)
      * @see com.articles.generics.objectcaching.Havuz#bos()
      */
     public boolean bos() {
           return this.havuz.isEmpty();
     }}


NesneHavuzu sınıfına dikkat edersek :  Havuz arayüzündeki tip parametresi
<T extends Yedeklenebilir>  burada da mevcut. Neden böyle?  Bakalım:


NesneHavuzu sınıfında <T extends Object> tanımını kullanıp derlemek istediğimizde :
şeklinde bir uyarı ile karşılaşırdık. Bu uyarıda NesneHavuzu sınıfı tanımlamasındaki tip parametresi, Havuz arayüzünün beklediği tip parametresinin sınırları dışında oluduğu belirtilmektedir.

NesneHavuzu sınıfında <T extends X_Nesne> tanımını kullanıp derlemek istediğimizde herhangi sorun ile karşılaşmayız çünkü T tip parametresi Havuz arayüzünün beklediği sınırlar yani Yedeklenebilir arayüzünün alt hiyerarşisi içerisindedir.


Peki Havuz arayüzünün tanılamasını public interface Havuz <T> şeklinde değiştirdiğimiz de ne olur? Birşey olmaz çünkü böyle yaparak Havuz arayüzü üzerindeki kısıtlamayı kaldırıp bu arayüzü her tipten yapı için çalışır duruma getirmiş oluruz, standart Java paketi içerisindeki torba (Hash, List ...) yapılarında olduğu gibi.


Şimdi de şöyle bişey deneyelim. Havuz arayüzünü eski haline getirelim ama bu sefer NesneHavuzu sınıfı tanımını NesneHavuzu<T> implements Havuz<T> şeklinde değiştirelim. Derlemek istediğimiz de


<T extends Object> örneğimizde olduğu gibi yine aynı nedenden dolayı derleme zamanında uyarı  alırız.

Peki alt hiyerarşi sınırlandırması için bir tanımlama mevcutken üst hiyerarşi sınırlandırması için bir tanımlama mevcut mu?  <T super Yedeklenebilir> Yedeklenebilir arayüzünün üst hiyerarşisi için sınırlama yapılır.

Şimdiye kadar yazmış olduğumuz yapıların testini gerçekleştirelim.


public class HavuzTest extends TestCase {
     private X_Nesne x_n1 = new X_Nesne();
     private X_Nesne x_n2 = new X_Nesne();
     private Y_Nesne y_n1 = new Y_Nesne();
     private Y_Nesne y_n2 = new Y_Nesne();
    
     Object obje_1 = new Object();
    
     private NesneHavuzu<X_Nesne> x_havuz = new NesneHavuzu<X_Nesne>();
     private NesneHavuzu<Y_Nesne> y_havuz = new NesneHavuzu<Y_Nesne>();
     private NesneHavuzu<Yedeklenebilir> genel_havuz = new NesneHavuzu<Yedeklenebilir>();
    
     public void testCek() {
           X_Nesne x_nesne_1 = x_havuz.cek();
//          Y_Nesne x_nesne_2 = x_havuz.cek(); Derleme hatasi verir
           Y_Nesne y_nesne_1 = y_havuz.cek();
          
          
//          Cek yordami Yedeklenebilir tipinde değer dönerken
//          biz X_Nesne tipinde bekliyoruz.
//          X_Nesne x_nesne_3 = genel_havuz.cek();
          
           X_Nesne x_nesne_3 = (X_Nesne) genel_havuz.cek();
          
     }


     public void testKoy() {
           x_havuz.koy(x_n1);
           x_havuz.koy(x_n2);
//          x_havuz.koy(y_n1); Derleme hatasi verir
          
           y_havuz.koy(y_n1);
           y_havuz.koy(y_n2);
          
           genel_havuz.koy(x_n1);
           genel_havuz.koy(y_n1);
    
//          x_havuz.koy(obje_1);         DERLEME HATASI
//          y_havuz.koy(obje_1);         DERLEME HATASI
//          genel_havuz.koy(obje_1);     DERLEME HATASI
     }
}


HavuzYoneticisi Arayüzü

public interface HavuzYoneticisi {
    
<T extends Yedeklenebilir> void nesneKoy(T nesne) throws NesneYaratmaHatasi;
    
<T extends Yedeklenebilir> T nesneCek(Class<T> clazz) throws NesneYaratmaHatasi;
    
<T extends Yedeklenebilir> void havuzuKontrolEt(Class<T> clazz) throws NesneYaratmaHatasi;
}

Burada dikkat etmemiz gereken, arayüzü değil arayüz içerisindeki yordamları genelleştiriyor olmamız. <T extends Yedeklenebilir> tip parametresi korunarak yine hiyerarşi sınırlandırması yapmış oluyoruz. Eğer HavuzYoneticisi arayüzünü de <T extends Yedeklenebilir> tip parametresi ile genelleştirmiş olsaydık sadece tek tip bir yapı için çalışıyor hale gelirdi. Tıpkı Havuz arayüzü gibi :

           NesneHavuzu<X_Nesne> x_havuz = new NesneHavuzu<X_Nesne>();


NesneHavuzuYoneticisi Sınıfı

public class NesneHavuzuYoneticisi implements HavuzYoneticisi {


     private Map<Class<? extends Yedeklenebilir>,
Havuz<? extends Yedeklenebilir>>
havuzMap = new HashMap<
Class<? extends
15 Ekim 2009 Perşembe günü Java Teknolojileri ve Programcıları Derneği olarak altıncı JTS (Java Teknolojileri Saati) 'yi gerçekleştirdik. 

Bu ay ki konuklarımız :

  • Natali Yeşilbahar  (http://www.xing.com/ Türkiye İş Geliştirme ve Satış Müdürü)
  • Emre Sokullu (grou.ps kurucusu)

Öncelikle çok eğlenceli ve eğitici saatler geçirdiğimizi ifade etmek isterim. gelmeyen kişiler için üzgünüz :) 

Natali Yeşilbahar 'ın sunumunu sunmadan önceki oyunu (-ki detaylarını burada vermeyeceğim) inanılmaz etkiliyici ve etkileşimliydi. Bu oyunu JTPD olarak her etkinliğimizde oynakmak için elimizden geleni yapacağız. 


Uygulama gelişticiler genel olarak kendi reklamlarını ve çevre oluşturma konusunda başarısız sayılabilecek kadar ilgisiz olduklarınız düşünüyordum - kendimden de pay çıkartarak. Natali hanımın bu sunumu tabiri yerindeyse aklımızı başımıza getirdi. 



Evet; çevremiz hepimiz için önemlidir; iletişim kanallarını geliştirmek ve bunu kariyer için kullanmak bizler için ne kadar önemli olduğunu Natali hanım çok iyi vurguladı. 



Natali Yeşilbahar'ın etkiliyici ve eğlenceli sunumundan sonra bir klasik çay - kahve ve sohbet molasından bir görüntü : 



Sıra ikinci semineri özetlemeye; büyük sistemler nasıl kurulur ve nasıl ayakta tutulur sorularının cevaplarını sevgili Emre çok iyi ve samimi bir şekilde anlattı. Bu seminerin tam videosunu yayınlayacağız ama tam bir tarih veremem. 


JTPD, Grou.ps sisteminin alt yapısını kullanmakta olduğunu, bilmeyenlere tekrardan söyleyelim. Bu sistem sayesinde gerçekten odaklamamız gereken noktalara daha fazla zaman ayırabiliyoruz. 
Bu seminer de Grou.ps sisteminin alt yapısının detayları ve bu alt yapının bu kadar yoğun trafiğe nasıl kaldırdığını sevgili Emre tarafından anlatıldı.   Grou.ps tamamen açık kaynak kod yazılımlar kullanarak geliştirilmiş bir sistem olduğunu da hatırlatmakta fayda var.



Grou.ps sayesinde bir çok topluluk kendi sayfalarını kolayca kurabilmekte ve en etkin bir şekilde kullanabilmektedirler.


Bu ay ki seminerlerimizden bilgi ve fotograf aktarımının sonu. Tekrardan katılımcılarımıza çok teşekkür etmek istiyorum.

Not : Bu ay EKÜ gerçekleştiremedik. Bu ay programda olmasına rağmen, EKÜ salonunda yer karışıklığından dolayı olmadı ama bu ay ki EKÜ programını bir sonraki ay (kasım 2009) gerçekleştirmeyi hedeflemekteyiz.

"Scalability @ Grou.ps"  sunumuna buradan ulaşabilirsiniz.

JTPD adına Altuğ Bilgin ALTINTAŞ

Saygılar.

29 Nisan 2010 Perşembe günü Java Teknolojileri ve Programcıları Derneği olarak sekizinci JTS (Java Teknolojileri Saati) 'yi gerçekleştirdik. 

Bahadır Ödevci'nin SOE or SOA or SOI or EAI, Which migration path to chose ? konusunu bizlere sundu. Özellikle bankacılık sektöründe yoğun olarak kullanılan bu teknolojilerin artı ve eksi yanlarını ve hangi durumda hangi teknolojiyi seçmeliyiz sorularını cevaplandıran Bahadır Ödevci'ye bir kez daha teşekkür ederiz.







Pizza arasından görüntüler : 





Pizza arasından sonra sunulan tek tip içeriğin farklı Mobil cihazlarda gösterimini sağlayan(device specific rendering) Mobile-Wap çözümleri olan Volantis-MCS ve Ericsson-Drutt ürünleri sevgili Furkan Horasan tarafından sunuldu. Furkan bey'in aktardığı bilgiler çok değerliydi, kendisine tekrardan teşekkür ediyoruz.





Bir sonraki Java Teknoloji Saatlerinde (JTS) görüşmek üzere.

Sevgiler.

JTPD ekibi.


Yeni başlayanlar veya kendi işini kurmak için plan yapanlara birazdan bahsedeceğim üçgeni paylaşmak istiyorum.

İşte sizlerle paylaşmak istediğim üçgen - B-I Üçgeni:




Bu üçgen bir işletmedeki olması gereken parçaları gösteriyor. Bu konunun Java ile bir ilgisi yok (aaaaa!) ama durun ! Kendi işinizi kurarken bu bilgiler hayati önemi var (bence). Şöyle ki, her yazılımcının kafasında kendi fikri ve hayali vardır diye tahmin ediyorum. Bir site yapsam ve tutsa ahh be ! şeklinde söylemler heryerde, herkesin kafasında. İşleyen bir site ve kurumsal bir yapı kurmak için B-I üçgenini ve parçalarını teker teker açıklamaya çalışayım.

B-I üçgeninin açılımı : kaynak : Robert Koyosaki

Misyon - Ülkü (mission) : Bu şirketin var oluş amacını belirler. Şirket sadece para kazanmak için var olmuş ise bu şirket büyük ihtimalle çökecektir. örnek misyonlar :

  • Her eve bilgisayar girecek - Microsoft
  • Araba herkesin alabileceği kadar ucuz olmalı ve biz herkese araba satacağız- Henry Ford - Ford

Takım (team): İyi bir ekip ve ekip çalışması olmaz ise, şirketin devamı söz konusu olamaz. Takım oyunu başarı için şarttır. Şirket için görev tanımları kesin ve net olmalıdır. Kim genel müdür, kim kodcu, kim pazarlamacı, kim devlet vergi işlerinden sorumlu ?


Leadership (liderlik): Bu ekibin başında bir lider olması gerekir. Lidersiz bir işletme, yönünü her an kaybedebilir. Bu da şirketin devamını tehlikeye atabilir.


Bu üç ana maddeye özetle değindik sonra üçgenin iç kısımlarını sırayla incelersek.


CashFlow (NakitAkışı == finansal planlama ve muhasebe) : Yeni başlayan şirketler bir çoğu bu kısmı iyi bir şekilde yönetememektedirler. Bunun sonucu olarak şirket maddi olarak zora girmekte ve çöküş gerçekleşmektedir. Bu noktada finansal planlama da işin büyükçe bir kısmını oluşturmadır. Bu üçgenin en temel kısmını oluşturduğundan eğer bu kısımda bir aksaklık oluşursa, şirketin geri kalan kısmının ayakta kalabilmesi çok güçtür.


İletişim ve pazarlama (comminication) : Firmanın iyi bir iletişim alt yapısı ve pazarlama kollarının olması gerekir. Satış yapabildiğiniz sürece varsınız (sanırım mühendislerin uyuz olduğu bir cümle ya da en azından bana öyle geliyor ama ne yazik ki doğru ...)


Sistemler (Systems) : "Şirketin işleyişinin sistemlere bağlanması, kişilere değil" prensibini esas almamız gereken katman, işlerin büyümesi esnasında son derece önemlidir. Bu nokta işlerin büyümesi için önemli zira McDonalds hep bu katmanda örnek gösterilen şirkettir. En vasıfsız kişilerle bile işleri yürüten bir sistem !!! . Kısacası şirketin başarılı ve büyümesi için birçok sisteme ihtiyaç var. Aklıma gelenler :

  • Muhasebe kontrol ve takibi için bir düzen / sistem
  • Proje geliştirme sistemleri : Agile süreçler veya bir başkası
  • Hudson sistemim var mı (https://hudson.dev.java.net/) ?
  • Kod versiyonlama sistemi var mı ?
  • Hata yakalama ve ayıklama sistemi
  • Her hafta uygulama geliştiriciler arasında sistemli toplantılar.
  • JSF yerine Apache Wicket kullanılması (Bu kısım tamamen şahsi fikrimdir, JSF kullananlar lütfen alınmasın :P )
  • ...


Resmi hususlar (Legal) : Anlaşmalar, patent ve telif hakları konuları dikkatli bir şekilde takip edilmelidir yoksa oyun başlamadan biter

.

Ürün (Product) : Elbette şirketin sunacağı muhteşem bir ürün olmalıdır.



Dikkat ediniz! Ürün bu üçgenin en ufak kısmını oluşturuyor. Ben bu üçgeni görmeden evvel hep ürene odaklanmıştım. Ürüne şu özelliği de koysak muhteşem olurdu veya şu özelliği çıkartsak mı ? Bu tür sorularda bir tuhaflık yok, sorulmalı da fakat bunun yanında bir çok soru daha sorulmalı ve cevapları olmalı. İşte o sorulardan aklıma gelenler  : Yasal vergi oranları ne kadar ? Stopaj nedir ? Muhasebe bilgim nasıl ? Nakit akış planım var mı ? Pazarlama ve satış konusunda ne yapmalım ? Takımım iyi mi ? Ben iyi bir lider miyim ? Misyonumuz nedir ? iyi bir avukatım var mı ? Ben bu şirketi neden açtım deli mıyım ? :) ... .....


İşe başlarken ve yürütüken sadece ürüne (bu kısım için yazılım da diyebiliriz) odaklanırsa, sonuçları felaket olabilir, aman dikkat.


Altuğ Bilgin ALTINTAŞ

altug - at - kodcu.com







Eyl 24
Maven – Spring – Hibernate – Wicket Entegrasyonu

Taner Diler
taner.diler@gmail.com



Maven, Spring, Hibernate, Wicket ile uygulama geliştirmek için atacağınız ilk adımlar...

İzleyeceğimiz adımlar: 

1. Maven kurulumu
2. Pom.xml'in oluşturulması, Spring Container'i için gerekli paket bağımlılık ayarlarının yapılması
3. Spring application-context.xml'in oluşturulması ve basit bir uygulama ile injection yönetiminin test edilmesi
4. Hibernate paket bağımlılık ayarlarının yapılması ve Hibernate konfigurasyonunun gerçekleştirilmesi
5. Wicket için pom.xml üzerinde paket bağımlılık ayarlarının yapılması
6. Spring application-context.xml ve web.xml de Spring ve Wicket ayarlarının yapılması 

Maven kurulumu için maven.apache.org sitesinden maven paketini indirip açtıktan sonra içerisindeki bin klasörününü de sistemin “Ortam Değişkenleri”ne tanımlayabilirsiniz.

mvn archetype:create -DgroupId=org.jtpd
                          -DartifactId=maven_spring_hibernate_wicket
                          -DpackageName=org.jtpd


komutunu kullanarak maven projemizi oluşturalım. Pom.xml içerisindeki packaging tanımını war yapalım.

Oluşan pom.xml :

<'project ...>
      <'modelVersion>4.0.0<'/modelVersion>
      <'groupId>org.jtpd<'/groupId>
      <'artifactId>maven_spring_hibernate_wicket<'/artifactId>
      <'packaging>war<'/packaging>
      <'version>1.0-SNAPSHOT<'/version>
      <'name>maven_spring_hibernate_wicket<'/name>
      <'url>http://maven.apache.org<'/url>
      <'dependencies>
            <'dependency>
                  <'groupId>junit<'/groupId>
                  <'artifactId>junit<'/artifactId>
                  <'version>3.8.1<'/version>
                  <'scope>test<'/scope>
            <'/dependency>
            <'dependency>
                  <'groupId>org.slf4j<'/groupId>
                  <'artifactId>slf4j-jdk14<'/artifactId>
                  <'version>1.4.2<'/version>
            <'/dependency>
       <'/dependencies>
<'/project>

Oluşan dizin yapısı:

 maven_spring_hibernate_wicket/

 maven_spring_hibernate_wicket/pom.xml

      /src/

      /src/main/

          /main/java

      /src/test/

          /test/java


Log4j, Spring gibi konfigurasyon dosyalarını koymak için /src/main/resources dizinini ve web dosyalarını koymak için /src/main/webapp oluşturalım. Ve sonrasında pom.xml'i açıp aşağıdaki ayarlamaları yapalım.

  <'build>
    <'resources>
      <'resource>
        <'directory>src/main/resources<'/directory>
        <'filtering>true<'/filtering>
      <'/resource>
    <'/resources>
   <'plugins>
       <'plugin>
         <'groupId>org.apache.maven.plugins<'/groupId>
         <'artifactId>maven-compiler-plugin<'/artifactId>
         <'version>2.0.2<'/version>
         <'configuration>
             <'source>1.5<'/source>
             <'target>1.5<'/target>
         <'/configuration>
       <'/plugin>
   <'/plugins>
 <'/build>

Gelin şimdi Spring & Hibernate paket bağımlılıklarını ayarlayalım:

<'dependencies>
...
      <'!--  SPRING DEPENDENCIES  -->
      <'dependency>
          <'groupId>org.springframework<'/groupId>
          <'artifactId>spring<'/artifactId>
          <'version>${spring.version}<'/version>
      <'/dependency>
      <'dependency>
          <'groupId>org.springframework<'/groupId>
          <'artifactId>spring-web<'/artifactId>
          <'version>${spring.version}<'/version>
      <'/dependency>
      <'dependency>
            <'groupId>org.springframework<'/groupId>
            <'artifactId>spring-aspects<'/artifactId>
            <'version>${spring.version}<'/version>
      <'/dependency>
      <'!--  HIBERNATE DEPENDENCIES  -->
      <'dependency>
            <'groupId>mysql<'/groupId>
            <'artifactId>mysql-connector-java<'/artifactId>
            <'version>5.1.6<'/version>
      <'/dependency>
      <'dependency>
            <'groupId>javax.persistence<'/groupId>
            <'artifactId>persistence-api<'/artifactId>
            <'version>1.0<'/version>
            <'scope>provided<'/scope>
      <'/dependency>
      <'dependency>
            <'groupId>org.hibernate<'/groupId>
            <'artifactId>hibernate-annotations<'/artifactId>
            <'version>3.4.0.GA<'/version>
      <'/dependency>
      <'dependency>
            <'groupId>org.hibernate<'/groupId>
            <'artifactId>hibernate-entitymanager<'/artifactId>
            <'version>3.4.0.GA<'/version>
      <'/dependency>
...
<'/dependencies>
 
<'properties>
<'spring.version>2.5.6<'/spring.version>
<'/properties>

Spring konfigurasyonunu gerçekleştirelim. Bunun için src/main/resources altında application-context.xml dosyasını oluşturalım.

<'?xml version="1.0" encoding="UTF-8"?>
<'beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util-2.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-2.1.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
       >
 
     
    <'context:annotation-config />
    <'context:component-scan base-package="org.jtpd" />
    <'aop:aspectj-autoproxy />
    <'tx:annotation-driven />
 
    <'bean  id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <'property name="dataSource" ref="dataSource" />
       
        <'property name="annotatedClasses">
            <'list>
                <'value>org.jtpd.core.User<'/value>
    <'value>...<'/value>
            <'/list>
        <'/property>
 
        <'property name="hibernateProperties">
            <'props>
                <'prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect<'/prop>
                <'prop key="hibernate.show_sql">true<'/prop>
            <'/props>
        <'/property>
    <'/bean>
 
    <'bean id="dataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource" destroy-method="close">
        <'property name="url" value="jdbc:mysql://db.jtpd.org:3306/jtpd" />
        <'property name="user" value="root" />
        <'property name="password" value="****" />
    <'/bean>
 
    <'bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <'property name="sessionFactory" ref="sessionFactory"/>
        <'property name="dataSource" ref="dataSource"/>
    <'/bean>
<'/beans>

Yukarıdaki konfigurasyonda, spring injectionlarının ve transaction tanımlarının annotationlar üzerinden yapılacağı belirtilir.
Uygulama içerisindeki kullanımı :

@Entity
@Table(name=”User”)
public class User {
      @Id
      @GeneratedValue(strategy=GenerationType.IDENTITY)
      private Integer id;
  ...
}
 
@Repository  //Spring Annotation
@Transactional
public abstract GenericDAO<'T> {
 
   @Autowired   //Spring Annotation
   private SessionFactory sessionFactory;
 
   public Session getSession(){
       return sessionFactory.openSession();
   }
 
   public void save(T entity){
       getSession().save(entity);
   }
}
 
@Repository  //Spring Annotation
@Transactional
public class UserDAO extends GenericDAO<'User> {
   ...
}
 
@Service  //Spring Annotation
@Transactional
public UserService {
 
   @Autowired   //Spring Annotation
   private IuserDAO userDAO;
 
   //Ornek
   public void save(User user){
       // Transaction Yönetimi spring tarafindan yapilmakta
       userDAO.save(user);
   }
}

Şu ana kadar yazmış olduğumuz kod örneğini ve konfigurasyonu test etmek için standalone çalışabilecek bir kod çalışması yapalım. Öncelikle pom.xml içerisinde aşağıdaki konfigurasyonu yapalım.

      <'build>
         <'plugins>
         ...           
                 <'plugin>
                        <'groupId>org.codehaus.mojo<'/groupId>
                        <'artifactId>exec-maven-plugin<'/artifactId>
                        <'executions>
                             <'execution>
                                   <'phase>package<'/phase>
                                   <'goals>
                                         <'goal>java<'/goal>
                                   <'/goals>
                             <'/execution>
                        <'/executions>
 
                        <'configuration>
                             <'mainClass>org.jtpd.App<'/mainClass>
                        <'/configuration>
                  <'/plugin>
          ...
          <'/plugins>
       <'/build>

org.jtpd.App java dosyasını oluşturalım:

package org.jtpd;
 
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class App {
 
      public static void main(String[] args) {
            try {
                  ApplicationContext factory = new FileSystemXmlApplicationContext(
                             "targetclassesapplication-context.xml");
                  IUserService userService = (IUserService) factory
                             .getBean("userService");
                  userService.save(new User());
            } catch (Exception e) {
                  e.printStackTrace();
            }
      }
}

App sınıfını komut satırından

mvn exec:java

komutu ile çalıştırabiliriz.
 
Herşey istediğimiz gibi ise şimdi geliştirdiğimiz yapıyı web uygulaması haline getirelim. Bunun için pom.xml'de :

       <'dependencies>
            ...
            <'dependency>
                  <'groupId>org.apache.wicket<'/groupId>
                  <'artifactId>wicket-spring<'/artifactId>
                  <'version>${wicket.version}<'/version>
            <'/dependency>          
            <'dependency>
                  <'groupId>org.apache.wicket<'/groupId>
                  <'artifactId>wicket<'/artifactId>
                  <'version>${wicket.version}<'/version>
            <'/dependency>
            <'dependency>
                  <'groupId>org.apache.wicket<'/groupId>
                  <'artifactId>wicket-extensions<'/artifactId>
                  <'version>${wicket.version}<'/version>
            <'/dependency>
            <'/dependencies>
   
       ...
 
       <'properties>
            <'wicket.version>1.4.0<'/wicket.version>
            <'spring.version>2.5.6<'/spring.version>
       <'/properties>

src/main/webapp altında WEB-INF/web.xml dosyasını oluşturalım ve aşağıdaki konfigurasyonları tanımlayalım

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">
 
    <display-name>JTPD</display-name>
 
    <filter>
        <filter-name>wicket-spring-hibernate</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationFactoryClassName</param-name>
            <param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
        </init-param>
    </filter>
 
    <filter-mapping>
        <filter-name>wicket-spring-hibernate</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
   
    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application-context.xml</param-value>
      </context-param>
     
      <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
 
</web-app> 

Web.xml de  Spring ve Wicket çatılarına ait tanımlamaları yaptık.application-context.xml içerisinde de Wicket uygulamasını tanımlamamız gerekiyor. Web.xml içerisinde  WicketFilter konfigurasyonunda Wicket çatısına aşağıdaki WebApplication sınıfını hangi factory üzerinden alacağımızı belirtiyoruz. Burada Wicket ile Spring entegrasyonunu gerçekleştirmiş oluyoruz.

...
<bean id="wicketApplication" class="org.jtpd.web.JTPDWicketApplication" />
...

Şu ana kadar Maven, Spring, Hibernate ve Wicket entegrasyonunu bir şekilde gerçekleştirmiş bulunmaktayız. Fakat Wicket bileşenlerinden Spring bean'lerine injection yöntemiyle erişmek için JTPDWicketApplication sınıfının yapılandırıcı yordamlarında

addComponentInstantiationListener(new SpringComponentInjector(this));
 
çağırımlarını yapmamız gerekmektedir.
 
JTPDWicketApplication sınıfı :

package org.jtpd.web.JTPDWicketApplication;
 
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
 
/**
 * Application object for your web application.
 * <'p/>
 * If you want to run this application without deploying, run the Start class.
 */
public class JTPDWicketApplication extends WebApplication {
 
      /* (non-Javadoc)
       * @see org.apache.wicket.protocol.http.WebApplication#init()
       */
      @Override
      protected void init() {
            // TODO Auto-generated method stub
            super.init();
            addComponentInstantiationListener(new SpringComponentInjector(this));
      }
 
      @Override
      public Class<'Index> getHomePage() {
            return Index.class;
      }
 
}

WebApplication, WebPage gibi Wicket bileşenleri içerisinden Spring bean'lerini kullanabilmek için @SpringBean annotation'ını kullanmamız gerekmektedir. JTPDWebApplication içerisinden çağırılan Index.class yani WebPage'den türeyen Index sınıfını oluşturalım ve buradan userService Spring Bean'ini nasıl çağırdığımızı görelim.

package  org.jtpd.web;
 
/**
 * @author tdiler
 *
 */
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.jtpd.core.IUserService;
import org.jtpd.core.User;
 
/**
 * Homepage
 */
public class Index extends WebPage {
 
      private static final long serialVersionUID = 1L;
 
      @SpringBean
      IUserService userService;
 
      public Index(final PageParameters parameters) {
            User user = new User();
            userService.save(user);
            add(new Label("label", "Kullanıcı kaydedildi."));
      }
}

Wicket çatısında yazılan WebPage, Panel gibi bileşenler için markup tanımlarını içeren  sınıf ile aynı isimde *.html uzantılı dosyalar bulunmalıdır. Maven ile derleme ve paket oluşturma sonucunda bu html dosyalarınında değerlendirilmesi için pom.xml’de şu eklemeyi yapacağız:

<resources>
...
      <resource>
            <filtering>false</filtering>
            <directory>src/main/java</directory>
            <includes>
                  <'include>**</include>
            </includes>
            <excludes>
                  <exclude>**/*.java</exclude>
            </excludes>
      </resource>
...
</resources>

İlgili çalışmaya ait kodlara buradan ulaşabilirsiniz.


Eyl 14






Taner Diler
Tasarım Kalıpları & AntiPatterns & Tasarım Prensipleri

taner.diler@gmail.com


View more presentations from jtaz.