Bu Blogda Ara

java etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
java etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

24 Kasım 2012 Cumartesi

Yapay Sinir Ağları İleri Besleme & Geri Yayılım Algoritmaları - XOR Örneği




http://scitechdaily.com/ibm-supercomputer-simulates-530-billion-neurons-100-trillion-synapses/


IBM'in yapmış olduğu çalışmanın haberini okuduktan sonra yapay zeka meselesi hakkında küçük bir yazı yazmaya karar verdim. Tabiki haberdeki çalışmaya nazaran bizim yapacağımız örnek çok iptidai kalmaktadır. Lakin buradaki maksadım bir şekilde meseleye giriş yapmak bilahare daha gelişmiş örneklerle konuyu izah etmek şeklinde olacaktır.

Yapay zeka çok geniş bir kavram ve bir çok alt dalları bulunmaktadır (bkz: http://en.wikipedia.org/wiki/List_of_basic_artificial_intelligence_topics). Ben burada giriş mahiyetinde Yapay Sinir Ağları (bkz: http://en.wikipedia.org/wiki/Artificial_neural_network) hususunda ileri besleme (Feed forward bkz: http://en.wikipedia.org/wiki/Feedforward_neural_network) ve geri yayılım (bkz: http://en.wikipedia.org/wiki/Back-propagation) algoritmalarını kullanarak artık klasikleşmiş ve tabiri caizse bıktırmış olan XOR örneğini gerçekleyeceğim. 

Yukarıda verdiğim bağlantılara göz atarsanız algoritmanın nasıl çalıştığını kolayca anlayabilirsiniz. Bu noktada fazla bir teferruat icap etmiyor zira yapacağımız örnekteki XOR problemi 2 neron hidden layer için 1 neron da output layer için kafidir. Mühim bir not; biz bu örnekte BIAS değerini tüm neronlara ayrı ayrı vermek yerine bir kukla neron (dummy neuron, ağırlıkları ve çıktısı değişmeyen) kullanacağız.

Biraz gerçekleme (implementation) detaylarına göz atalım. 

Uygulamayı Java ile yapacağız. Aslınca C gibi bir dil ile çok daha basit ve hızlı bir şekilde gerçeklenebilirdi lakin müstakbel uygulamalarımızda yapacağımız muameleler daha karmaşık olacağından bu yapı ileride bize fayda sağlayacaktır, şu anda aksi gibi görünse dahi.


Temel olarak Object-Oriented yapı:

Neuron (Class)
NN (Class)
IActivation (Interface)
SigmoidActivation (Class) -> IActivation
DummyActivation (Class) -> IActivation


Başlamdan önce belirlenmesi gereken ilk husus neronların ilk ağırlık değerleridir, burada önceden çalıştığı bilinen bir küme de seçilebilir ya da sözde rastgele değerlerde seçilebilir, neticede kötü seçilen değerler sadece sonuca ulaşma süremizi uzatacaktır. Biz rastgele değerler üreteceğiz bu yüzden programı her çalıştırdığınızda farklı bekleme süreleri ile karşılacaksınız. Ayrıca eğitim sürecinde iterasyon sayısını bir hudut koyuyoruz çünkü bazı durumlarda gelen değerler deltaW değeri sıfıra çok yaklaştığı için istenilen değere (desired value) bir türlü yaklaşılamıyor ve çok bekleme yaşanıyor. Bu sebeple azami tekerrür 3.000.000 olarak seçiyoruz, beklenen hata nispetini ise 0.005 olarak seçtim. Bu değerler tamamen keyfi olup siz de istediğiniz gibi değiştirebilirisiniz.

Kaynak kodda herhangi bir dış kütüphane kullanmadım, doğrudan derleyip çalıştırabilisiniz.

Şimdi kaynak kodumuza bir göz atalım:




// Main.java

package ann.xor;

/**
 *
 * @author ramazan
 */
public class Main {

    public static String quantizeResult(float result) {
        return Integer.toString(Math.round(result)) + " (" + Float.toString(result) + ")";
    }
    
    public static void main(String[] args) {
        NN nn = new NN(5E-3f, 1.0f, 0.1f);
        SigmoidActivation sa = new SigmoidActivation();
        DummyActivation da = new DummyActivation();
        float BIAS = -1f;

        Neuron input1 = new Neuron(da, 0);
        Neuron input2 = new Neuron(da, 0);
        Neuron input3 = new Neuron(da, 0); // BIAS.
        Neuron hidden1 = new Neuron(sa, 3);
        Neuron hidden2 = new Neuron(sa, 3);
        Neuron hidden3 = new Neuron(da, 3); // Dummy neuron.
        Neuron output1 = new Neuron(sa, 3);

        nn.addInputNeuron(input1);
        nn.addInputNeuron(input2);
        nn.addInputNeuron(input3);

        nn.addHiddenNeuron(hidden1);
        nn.addHiddenNeuron(hidden2);
        nn.addHiddenNeuron(hidden3);

        nn.addOutNeuron(output1);

        hidden3.setDummy(true);
        input3.setOutput(BIAS);

        System.out.println("All inputs & weights has been set.");
        System.out.println("Training has been started.");
        
        int iteration = 0;
        do {
            iteration++;
            
            input1.setOutput(0);
            input2.setOutput(0);
 
            output1.desired = 0;

            nn.train();

            input1.setOutput(0);
            input2.setOutput(1);

            output1.desired = 1;

            nn.train();

            input1.setOutput(1);
            input2.setOutput(0);

            output1.desired = 1;

            nn.train();

            input1.setOutput(1);
            input2.setOutput(1);

            output1.desired = 0;

            nn.train();
            
            if (iteration % 50000 == 0) {
                System.out.println("-------------------------------");
                System.out.println("Current iteration:" + iteration);
                System.out.println("Current error:" + nn.getE());
                System.out.println("-------------------------------");
            }
        } while(!nn.learnt() && iteration < 3000000);
        
        System.out.println("Training has been completed.");
        System.out.println("Total iteration: " + iteration + ", accepted error: " + nn.getE());
        System.out.println("Test cases are in progress...");
        
        input1.setOutput(1);
        input2.setOutput(0);

        nn.test();

        System.out.println("1 XOR 0 = " + quantizeResult(nn.getOutput(0).getOutput()));

        input1.setOutput(1);
        input2.setOutput(1);

        nn.test();

        System.out.println("1 XOR 1 = " + quantizeResult(nn.getOutput(0).getOutput()));

        input1.setOutput(0);
        input2.setOutput(1);

        nn.test();

        System.out.println("0 XOR 1 = " + quantizeResult(nn.getOutput(0).getOutput()));

        input1.setOutput(0);
        input2.setOutput(0);

        nn.test();

        System.out.println("0 XOR 0 = " + quantizeResult(nn.getOutput(0).getOutput()));
    }
}



// NN.java

package ann.xor;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author ramazan
 */
public class NN {
   
    private List<neuron> inputLayer;
    private List<neuron> hiddenLayer;
    private List<neuron> outputLayer;
    private float E;
    private float e;
    private float lambda;
    private float nu;
    
    public NN(float E, float lambda, float nu) {
        inputLayer = new ArrayList<>();
        hiddenLayer = new ArrayList<>();
        outputLayer = new ArrayList<>();
        this.E = E;
        e = 0;
        this.lambda = lambda;
        this.nu = nu;
    }
    
    public void addInputNeuron(Neuron neuron) {
        inputLayer.add(neuron);
    }
    
    public void addHiddenNeuron(Neuron neuron) {
        hiddenLayer.add(neuron);
    }
    
    public void addOutNeuron(Neuron neuron) {
        outputLayer.add(neuron);
    }
    
    public Neuron getOutput(int index) {
        return outputLayer.get(index);
    } 
    
    public void train() {
        feedForward();
        calculateError();
        backPropagation();
        //System.out.println("Error value: " + e);
    }
    
    public void test() {
        feedForward();
    }
    
    protected void feedForward() {
        for (Neuron nH : hiddenLayer) {
            float inputs = 0;
            for (Neuron nI : inputLayer) {
                int i = inputLayer.indexOf(nI);
                inputs += nI.getOutput() * nH.getWeight(i);
            }
            nH.setInput(inputs);
            nH.activate(lambda);
        }
        
        for (Neuron nO : outputLayer) {
            float inputs = 0;
            for (Neuron nH : hiddenLayer) {
                int i = hiddenLayer.indexOf(nH);
                inputs += nH.getOutput() * nO.getWeight(i);
            }
            nO.setInput(inputs);
            nO.activate(lambda);
        }
    }
    
    protected void calculateError() {
        e = 0;
        for (Neuron nO : outputLayer) {
            nO.error = nO.desired - nO.getOutput();
            e += (float) Math.pow(nO.error, 2);
        }
        
        e = (float)Math.sqrt(e); 
    }
    
    protected void backPropagation() {
        for (Neuron nO : outputLayer) {
            nO.calculateDelta(lambda, nO.error);
            for (Neuron nH : hiddenLayer) {
                int i = hiddenLayer.indexOf(nH);
                nH.calculateDelta(lambda, nO.getDelta() * nO.getWeight(i));
                float diff = nu * nO.getDelta() * nH.getOutput();
                nO.setWeight(i, nO.getWeight(i) + diff);
            }
        }
        
        for (Neuron nH : hiddenLayer) {
            for (Neuron nI : inputLayer) {
                int i = inputLayer.indexOf(nI);
                float diff = nu * nH.getDelta() * nI.getOutput();
                nH.setWeight(i, nH.getWeight(i) + diff);
            }
        }
    }

    public float getE() {
        return e;
    }
    
    public boolean learnt() {
        return (e < E);
    }
}



// Neuron.java

package ann.xor;

import java.util.Random;

/**
 *
 * @author ramazan
 */
public class Neuron {

    private float[] weights;
    private float input;
    private float output;
    private IActivation activation;
    private float delta;
    public float desired;
    public float error;
    private boolean dummy;
    private static final Random random = new Random();

    public Neuron(IActivation activation, int weights) {
        this.weights = new float[weights];
        this.activation = activation;
        delta = 0;
        dummy = false;
        error = desired = 0;
        
        for (int i = 0; i < weights; i++) {
            this.weights[i] = getRandomWeight();
        }
    }
    
    protected final float getRandomWeight() {
        final float r = random.nextFloat();
        final float range = 2.4f / weights.length;

        return (r * 2 * range) - range;
    }

    public float getWeight(int index) {
        return weights[index];
    }

    public void setWeight(int index, float weight) {
        if (!dummy) {
            weights[index] = weight;
        }
    }

    public float getInput() {
        return input;
    }

    public void setInput(float input) {
        this.input = input;
    }

    public float getOutput() {
        return output;
    }

    public void setOutput(float output) {
        this.output = output;
    }

    public float getDelta() {
        return delta;
    }

    public boolean isDummy() {
        return dummy;
    }

    public void setDummy(boolean dummy) {
        this.dummy = dummy;
    }
    
    public void activate(float lambda) {
        float value = input;
        if (!dummy) {
            value *= -lambda;
        }
        output = activation.activate(value);
    }

    public void calculateDelta(float lambda, float error) {
        if (!dummy) {
            delta = error * lambda * activation.derivative(output);
        }
    }
}



// IActivation.java

package ann.xor;

/**
 *
 * @author ramazan
 */
public interface IActivation {
    public float activate(float input);
    public float derivative(float input);
}



// SigmoidActivation.java

package ann.xor;

/**
 *
 * @author ramazan
 */
public class SigmoidActivation implements IActivation {

    @Override
    public float activate(float input) {
        return (float) (1. / (1. + Math.exp(input)));
    }

    @Override
    public float derivative(float input) {
        return input * (1 - input);
    }
    
}



// DummyActivation.java

package ann.xor;

/**
 *
 * @author ramazan
 */
public class DummyActivation implements IActivation {

    @Override
    public float activate(float input) {
        return input;
    }

    @Override
    public float derivative(float input) {
        return input;
    }
}



Şimdi örnek bir çıktı üretelim:

run:
All inputs & weights has been set.
Training has been started.
-------------------------------
Current iteration:50000
Current error:0.02354227
-------------------------------
-------------------------------
Current iteration:100000
Current error:0.014160486
-------------------------------
-------------------------------
Current iteration:150000
Current error:0.011045283
-------------------------------
-------------------------------
Current iteration:200000
Current error:0.009226563
-------------------------------
-------------------------------
Current iteration:250000
Current error:0.008103463
-------------------------------
-------------------------------
Current iteration:300000
Current error:0.0073397583
-------------------------------
-------------------------------
Current iteration:350000
Current error:0.006666307
-------------------------------
-------------------------------
Current iteration:400000
Current error:0.00628476
-------------------------------
-------------------------------
Current iteration:450000
Current error:0.0058559924
-------------------------------
-------------------------------
Current iteration:500000
Current error:0.0055325483
-------------------------------
-------------------------------
Current iteration:550000
Current error:0.0051981094
-------------------------------
Training has been completed.
Total iteration: 586265, accepted error: 0.004999997
Test cases are in progress...
1 XOR 0 = 1 (0.9973595)
1 XOR 1 = 0 (0.004999945)
0 XOR 1 = 1 (0.9919734)
0 XOR 0 = 0 (0.0039330246)

BUILD SUCCESSFUL (total time: 4 seconds)


Bu basit örnek ile konuyu teorik olarak okuduktan sonra pratik olarak uygulamasını görerek daha iyi anlaşılacağı kanaatindeyim. Bir sonraki yazıda, yine klasikleşmiş olan tanıma (recognition) uygulamalarından bir örnek yapabilirim veyahut farklı bir anlada mesela Multi-agent systems simulation bir çalışma olabilir. Henüz karar vermedim. :)

Umarım faydalı olmuştur, böylelikle uzunca bir aradan sonra yazı yazabilmenin huzuruyla sizlere veda ediyorum, Allah'a emanet olunuz...

18 Eylül 2010 Cumartesi

Java ile Nesneleri Dosyaya Kaydetme ve Okuma (Serialization)

Nesne yönelimli programlamada bellekte yüklü nesnelerin dosyaya kaydedilmesi ve tekrar dosyadan okunarak belleğe yüklenmesi olayına Serialization (Serileştirme olarak tercüme edilebilir) denmektedir.


Örneğimize geçmeden önce bu yöntem ile neler yapabileceğimizi değerlendirelim. Geliştirdiğimiz programlarda tüm işlemleri nesneler üzerinden gerçekleştiririz. Bazı durumlarda uygulamamızda kullanacağımız bilgileri bir dosya üzerinde saklamak isteyebiliriz. Bu noktada aklımıza veritabanı sistemleri gelebilir, fakat burada bahsettiğimiz veriler programın mantıksal verileri olduğu için genelde büyük boyutta olmazlar. Aynı zamanda nesnelerimizi veritabanında da tutabiliriz. Unutmamız gereken nokta Serialization dediğimiz olay nesnelerin hafızadaki yapısını ikili (binary) olarak saklamaktır. Neler yapılabilir sorusuna çok çeşitli cevaplar veribilir benim aklıma gelen şu başlıklar:
- Uygulamanın ayarlarının kaydedilmesi
- Basit bir veritabanı olarak kullanılması
- Programın çökmesi durumunda en son tutarlı yerden devam etmesi için hafızanın kaydedilmesi...

Normalde düşündüğümüz zaman bir nesneyi diskte saklamak çok külfetli bir iştir. Nesnenin tüm bilgilerini tek tek toplayıp bir sıraya koyacaksınız, ardından bunları karıştırmadan ve atlamadan (null değişkenler olabilir, ya da String benzeri dinamik genişleyen generic yapılar olabilir) doğru bir şekilde yazmalısınız. Okuma olayına hiç girmiyorum zaten. Ayrıca her nesnenin iç yapısı farklı olacaktır!

Peki hafızadan direk BYTE dizisi olarak diske yazmak? Java dilinde hafızaya direk erişimimiz olmadığı (işaretçilerin olamaması) için normal şartlar altında mümkün olmaması lazım. Fakat Java bize bu işlemi çok kolay bir şekilde yapacak bir imkan sağlamaktadır.

Java'da yazılan tüm nesneler Serializable arayüzünden (interface) kalıtım aldığı sürece sorunsuz bir şekilde diske yazılabilmektedir. Aynı rahatlıkla diskten okunabilmektedir. Bunun için özel olarak hazırlanmış yazan ve okuyan sınıfları kullanmaktadır.

Lafı fazla dolandırmadan örneğimize geçelim. Yorum satırlarını yeterli gördüğüm için tekrardan açıklama gereği duymadım.



/*
* Öğrenci Sınıfı
* Ogrenci.java
*/

package rbellek.blogspot.com;

import java.io.Serializable;

/**
*
* @author Ramazan
*/
public class Ogrenci implements Serializable {

private String isim;

public String getIsim() {
return isim;
}

public void setIsim(String isim) {
this.isim = isim;
}
}


/*
* Serilazation Örnek
* Main.java
*/
package rbellek.blogspot.com;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author Ramazan
*/
public class Main {

public static void main(String[] args) {
Ogrenci o1 = new Ogrenci(); // Yeni bir öğrenci nesnesi oluşturalım.
o1.setIsim("Ahmet"); // İsmini verelim.
System.out.println(o1.getIsim()); // Test edelim.
try {
// Nesneyi dosyaya kaydedelim.
FileOutputStream yazmac = new FileOutputStream("Ogrenci1.nesne"); // Dosyaya veri aktarım akışı nesnesi oluşturalım.
ObjectOutputStream nesneYazmac = new ObjectOutputStream(yazmac); // Nesneleri veri akışlarına yazmaya yarayan nesneyi oluşturalım.
nesneYazmac.writeObject(o1); // Öğrenci nesnemizi dosyaya yazıyoruz.
nesneYazmac.close(); // akışı kapatalım.
} catch (FileNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}

o1.setIsim("Mehmet"); // Öğrenci nesnemizin adını değiştirelim.
System.out.println(o1.getIsim()); // Test edelim.

Ogrenci o2 = null; // Başka bir öğrenci nesnesi referansı. (Henüz bir nesne oluşturmadık!)

try {
FileInputStream okuyucu = new FileInputStream("Ogrenci1.nesne"); // Dosyadan veri alan akış nesnesi.
ObjectInputStream nesneOkuyucu = new ObjectInputStream(okuyucu); // Dosyada kayıtlı nesneleri okuyan nesne.
o2 = (Ogrenci) nesneOkuyucu.readObject(); // Öğrenci nesnemizi okuyalım.
nesneOkuyucu.close(); // akışı kapatalım.
} catch (FileNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}

System.out.println(o2.getIsim()); // Okunan nesne adı Ahmet olmalı...
}
}



İyi çalışmalar...

20 Mayıs 2010 Perşembe

Spring Framework - Web MVC / NetBeans 6.8 / Bölüm 2

Not: Bu yazı Spring Framework - Web MVC / NetBeans 6.8 adlı yazının devamı niteliğindedir.

Bir önceki yazımda kaldığım noktadan devame etmeye çalışacağım. Giriş yazımda bir Spring Web MVC projesini NetBeans 6.8 ile oluşturmuştuk. Şimdi yapıyı incelemeye devam edeceğiz. WEB-INF dizini altındaki ayar dosyalarını inceleyerek devam edelim.


İlk olarak Web.xml den biraz bahsetmek istiyorum. Bu dosya Java Web projelerinde genel ayarların yapıldığı standart bir dosyadır. Tıpkı Asp.NET projelerindeki Web.config dosyası gibi. Arzu ederseniz içeriğine bir gözatalım.


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>redirect.jsp</welcome-file>
</welcome-file-list>
</web-app>


İlk bakışta göze batan karmaşıklık sizi korkutmasın. Aslında anlaması gayet basit. Burada XML formatında ayarlar mevcut. Şimdilik bu dosya salt okunur gibi olmalı. Buradan herhangi bir ayarı değiştirmeyelim. Aksi takdirde uygulamamız doğru çalışmayabilir. Fakat anlamadan da geçemeyiz. Eğer bu detayları iyi kavramazsak, frameworke tam olarak hakim olamayız. context-param kısmında projemiz için içerik ayarlarının yapıldığı düğümdür. Buraya contextConfigLocation adında bir anahatar ve /WEB-INF/applicationContext.xml şeklinde bir değer girilmiştir. Bu dosya Spring projemizde yapacağımız bazı ayarların (veritabanı bağlantı cümleleri vb.) bulunacağı dosya. listener düğümünde dinleyici sınıfları belirtiyoruz. Değer olarak org.springframework.web.context.ContextLoaderListener sınıfı eklenmiş. Daha sonra bir servlet tanımlanmış. dispatcher adındaki bu servlet Spring'in temel çözümleme servlet sınıfıdır. Sınıfın yolu org.springframework.web.servlet.DispatcherServlet şeklinde eklenmiş. servlet-mapping düğümü ile hangi servlet hangi desenle (örüntü - pattern) eşleceği belirtiliyor. dispatcher servleti için *.htm şeklinde bir desen verilmiş. Daha önceki yazımda belirtiğim noktaya geldik. Kullanıcı web tarayıcısıyla web sunucumuza *.htm şeklinde bir sorgu yaptığı zaman web sunucumuz bunu anlayarak ilgili servleta (burada dispatcher oluyor) yönlendirecektir. Son olarak welcome-file-list düğümü ile sitemiz ilk açılışta hangi sayfayı direk gösterecek onu belirtiyoruz. Örneğin Apache web sunucusunda varsayılan karşılama dosyası index.html, index.htm ya da index.php, IIS sunucusunda default.html, default.htm, default.asp ya da default.aspx şeklinde olabilir. NetBeans otomatik olarak redirect.jsp dosyasını seçmiş. Bu kısmı dilediğiniz gibi (desene uygun bir URL ile) edeğiştirebilirsiniz.



NetBeans Web.xml için görsel ayar penceresi


Şimdi gelelim dispatcher-servlet.xml dosyamıza. Bu dosya Web.xml dosyasında belirtiğimiz dispathcer servlet sınıfı için ayar niteliğindedir. Vakit kaybetmeden içeriğine bir göz atalı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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

<!--
Most controllers will use the ControllerClassNameHandlerMapping above, but
for the index controller we are using ParameterizableViewController, so we must
define an explicit mapping for it.
-->
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="index.htm">indexController</prop>
</props>
</property>
</bean>

<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />

<!--
The index controller.
-->
<bean name="indexController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="index" />

</beans>


İlk baştaki uzun tanımlamaları direk atlıyorum. Şimdilik bu ayarlar konumuz değil. Olduğu gibi bırakıyoruz.

bean tagıyla başlayan satırda yeni Spring bean sınıfını (org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping) tanımlıyoruz. Alt satırdaki yorum bu satırları anlamamız için önemli. Yorum satırında bu eklediğimiz sınıfın (ControllerClassNameHandlerMapping) bir çok kontrollör sınıf tarafından kullanıldığından fakat indexController sınıfı için ParameterizableViewController sınıfının kullanıldığını bu yüzden harici bir rota belirlememiz gerektiğinden bahsetmektedir.
Bir alt satırda org.springframework.web.servlet.handler.SimpleUrlHandlerMapping sınıfının tanımlanmasıyla görebiliyoruz. Verdiği değerler önemli. index.htm şeklinde gelen bir isteğin indexController nesnesi tarafından yorumlanacağı bu satırda belirtilmektedir. Siz burayı dilediğiniz gibi değiştirebilirsiniz. Örneğin merhaba.htm yapabilirsiniz. Dikkat etmeniz gereken bir nokta olarak dosya uzantısı .htm olaması söylenebilir. Unutmayalım Web.xml dosyasında dispatcher servlet için *.htm şeklinde bir desen belirlemiştik. Buna uymak zorundayız.
Bir sonraki satırda viewResolver sınıfının tanımlandığını görüyoruz. Bu çok önemli özellikle yapıyı idrak etme hususunda. class="org.springframework.web.servlet.view.InternalResourceViewResolver" Spring'in dahili kaynak görüntü çözümleyici sınıfı. p:prefix="/WEB-INF/jsp/" ve p:suffix=".jsp" satırları dışardan gelen istekleri uygulamamızın iç yapısında nereye karşılık geldiğini gösterir. prefix (öntakı) değeri ile görüntülerin dizinini suffix(son ek) ile yerel dosyaların uzantısını belirtiyoruz. Yani dışarıdan gelen index.htm şeklindeki bir sorgu dispatcher servleta söylediğimiz *.htm şeklindeki desene uygun olarak parçalanır ve index kelimesi görüntü olarak elde edilir. Bir önceki satırda belirtilen rotaya uyun olarak (index.htm -> indexController), bir sonraki satırda inceleyeceğimiz görüntü<->kontrollör tanımlaması ile index görüntüsü olduğu karar kılınır. Sonra /WEB-INF/jsp/index.jsp dosyası (indexController denetiminde) görüntü olarak açılır.
Bir sonraki satırda (az önce de söylediğim gibi) görüntü<->kontrollör tanımlaması yapılmakta. name="indexController" ile kontrollör adını, class="org.springframework.web.servlet.mvc.ParameterizableViewController" ile kullanılacak sınıfı (burada hazır sınıf kullandık, kendi sınıfımızı oluşturup bu sınıftan kalıtım da alabilirdik), p:viewName="index" ile görüntü adını belirtiyoruz.

Ayarlarla ilgili kısmı burada noktalıyorum. Bir sonraki yazımda görüntü ve kontrollör oluşturma ve kullanma konularına değineceğim inşallah. Anlatımda kusurum varsa affınıza sığınıyorum.
Görüşmek üzere...

16 Mayıs 2010 Pazar

Yığın Veri Yapısı

Merhabalar,
Bu yazımda yığın veri yapısından bahsetmek istiyorum. Çalışması LIFO (Last In First Out - Son Giren İlk Çıkar) ilkesine dayanmaktadır. Fiziksel bir örnek vermek gerekirse yalnızca bir tek arabanın geçebileceği kadar genişlikte olan çıkmaz bir sokağa arabaların ard arda girmesi gibidir. Son giren araba ilk çıkmalıdır ki diğer arabalar çıkabilsin.

Peki Ne İşe Yarar?
Günümüzde bir çok sistem hafıza yönetiminde bu veri yapısını kullanmaktadır. Özellikle sıranın önemli olduğu durumlarda. Mesela, programlama dillerinde açtığımız parantezlerin kapatılıp kapatılmadığının kontrolü, işletim sistemi düzeyinde fonksiyonların çağrımı sırasında parametrelerin aktarımı, aritmetik işlemlerde işlem önceliğinin sağlanması ( çarpmanın toplamaya üstünlüğü), karakter katarlarının ters çevrilmesi vb. bir çok alanda kullanılmaktadır.

Teknik olarak açıklamak gerekirse...
Belirli bir hafıza bölgesini programcıdan soyutluyoruz. Direk erişimi engelliyoruz. Programcıya hafızaya erişmesi için fonksiyonlar veriyoruz. Bunlar push, pop ve isEmpty olabilir. Sırasıyla açıklayalım.
  • Push
Yığına bir eleman eklemek istediğimizde bu fonksiyonu çağırırız. Fonksiyona veridiğimiz değer yığının en sonuna eklenir.
  • Pop
Yığından bir eleman çekmek için kullanılır. Bu fonksiyon bize yığının en sonundaki yani son eklediğimiz elemanı yığından alır bize verir. Daha önceki elemanlara erişmek için Pop fonksiyonunu çağırmaya devam etmeliyiz. Bu fonksiyon herhangi bir parametre almaz.
  • isEmpty
Bu fonksiyon ile yığının boş olup olmadığını kontrol edebiliriz.
Siz fonksiyonlarınıza istediğiniz ismi verebilirsiniz. Korumanız gereken tek şey LIFO ilkesidir. Geri kalan kısmı değiştirmekte özgürsünüz.

Hemen Java ile bir örnekleme yapalım:

package test;

import java.util.ArrayList;

class Stack
{
private ArrayList<Object> objectList; // nesneleri tutacak generic yapımız.

public Stack()
{
objectList = new ArrayList<Object>(); // nesnemizi üretelim.
}

public boolean isEmpty()
{
return objectList.isEmpty(); // liste boş ise yığında boştur.
}

public void Push(Object obj)
{
objectList.add(obj); // yığına eleman ekleyelim.
}

public Object Pop()
{
if (objectList.isEmpty())
return null; // yığın boş ise eleman çekemeyiz. Sonuç null değeri.
Object o = objectList.get(objectList.size()-1); // sondan bir elemanı alalım.
objectList.remove(objectList.size()-1); // sonra bu elemanı yığından çıkartalım.
return o; // geriye döndürelim.
}
}


public class Main{

public static void main(String[] args) {

Stack s = new Stack();
if (s.isEmpty())
System.out.println("yığın boş.");
s.Push(5);
if (s.isEmpty())
System.out.println("bu satırı görmememiz gerekiyor.");
s.Push(45);
System.out.println(s.Pop());
System.out.println(s.Pop());
System.out.println(s.Pop());
System.out.println(s.Pop());
if (s.isEmpty())
System.out.println("yığında eleman yok.");
}

}




En basit haliyle böyle gerçeklenebilirdi sanırım. Veri yapılarını açıklamaya devam edeceğim.
Görüşmek üzere...

15 Mayıs 2010 Cumartesi

Spring Framework - Web MVC / NetBeans 6.8

Herkese merhaba,
Bu yazımda sizlerle Spring Framework ile mvc web uygulamalarına giriş yapacağız. Amacım framework altyapısını uzun uzun anlatmak, çıkış hikayesi vb. yazılarla aklınızı karıştırmak değil. Detaylı bilgi almak isteyenler http://www.springsource.com/ adresinden ya da arama motorlarını kullanarak bilgi alabilirler. Arama yaptığınızda siz de anlayacaksınız, tüm sitelerde bu konuya giriş yapılmış. Framework alt yapısı çalışma mantığı anlatılmış fakat elle tutulur bir proje yok. En büyük sorun çalışan uygulama eksikliği. Elimden geldiğince sizlere gerçek şartlarda çalışan uygulamalar göstermeye çalışacağım.

Hangi IDE?

Ben bu örnekte Netbeans 6.8 üzerinden anlatacağım. Bu geliştirme ortamını seçmemin sebebi kolay olması. İçeresinde bir çok gerekli kütüphane hazır olarak geliyor. Olayı kavradıktan sonra Eclipse ile projelerimizi geliştirmeye devam edeceğiz. Buradaki tek amacımız Spring, IDE kaynaklı sorunlarla kafamızı yoramayız.

Ortamın Hazırlanması

Netbeans 6.8 Web EE içeren bir paketini kurmanız yeterli. Ayrıca Java kodlarının derlenmesi için JDK gerekli konumuz Java olmadığı için bundan bahsetme gereği duymuyorum.
File | New
Netbeans geliştirme ortamını açtıktan sonra yeni bir Dynamic Web Application projesi oluşturuyoruz.



Daha sonra dikkat etmeniz gereken tek nokta projemize dahil edeceğimiz kütüphanelerdir. Burada Spring Web MVC 2.5 seçeneğini işaretliyoruz.



Finish diyerek projemizi oluşturuyoruz. Sonra karşınıza şu şekilde bir görüntü çıkmalı.



Şimdi projemizi Run menüsünden ya da F6 kısayol tuşu ile çalıştıralım. Karşınıza aşağıdaki gibi bir ekran çıktıysa merak etmeyin doğru yoldasınız :)



Dur bir dakika! Burada neler oluyor?
Hemen izah edeyim. Az önce bir Spring Web MVC projesi oluşturduk. Netbeans bizim yerimize varsayılan bazı ayarlamaları ve iskelet yapıyı oluşturdu. Bu Netbeans'in özelliği. Sol taraftaki klasör yapısına bakmamız yapıyı anlamada faydalı olacaktır. Web Pages klasörü altında WEB-INF, META-INF klasörleri ve redirect.jsp dosyası var. WEB-INF ve META-INF dışarıdan erişilemeyen (dışarıdan derken, projeyi siteye yüklediğimizde internetten sitemize giren kullanıcıları kastediyorum) özel ayar klasörleridir. Bu klasörlerden bahsetmeden önce ana dizinde bulunan tek dosya olan redirect.jsp ye bakalım. Bildiğimiz gibi Java Dynamic Web projelerinde bütün JSP dosyaları Web Pages altında olurdu ve biz buradaki dosyalara web tarayıcımız vasıtasıyla erişebiliyorduk. Fakat burada yalnız bir dosya var? Öyle ise hemen merakımızı redirect.jsp dosyasına bakarak giderelim.

Buyurun efendim:


Hiçbir şey anlamadım?
Kesinlikle çok saçma! index.htm nerede? Olmayan bir dosyaya yönlendirme mi yapılıyor? Burada bir gariplik var sanki. Evet durum biraz garip ama biraz incelediğimizde ve detaylara dikkat ettiğimizde aslında ne kadar güzel bir yapı olduğunu daha iyi anlayacağız. Burada index.htm dosyasına yönlendirerek aslında index.htm dosyasını açmıyoruz, index adındaki görüntüyü çağırıyoruz.
Görüntü mü? Nasıl yani?
MVC tasarım şablonunun (Model View Controller) ortasındaki View olayından bahsediyoruz. Bu tasarım desenini anlamak biraz sancılı olabilir ama anladıktan sonra hele bir de nimetlerinden faydalandıktan sonra ne kadar güzel bir şey olduğunu siz de anlayacaksınız. Görüntü dediğimiz kavram, önceden hazırlanmış tasarım dosyalarıdır. Herbiri bir controller nesnesine bağlıdır. Onun yetkisi olamadan ilgili görüntüye erişmek mümkün değildir.
İyice karıştı, Controller derken?
Controller sınıflar görüntüleri kullanıcıdan gelen talepler doğrultusunda göstermek ve şekillendirmek adına geliştirilmiştir. Daha detaylı bilgiyi ilerleyen kısımlarda vereceğim.

Tamam ama hâlâ olmayan bir index.htm dosyasını nasıl açtığımızı anlayamadım?

Sır perdesi WEB-INF klasörünü açmamızla aralanacaktır. Bildiğimiz gibi WEB-INF klasörü özel bir ayar klasörü.



xml uzuntılı dosyalar ayarlama için gerekli dosyalar. Sorumuzun cevabı ise jsp klasörü altında gizli. Evet haklısınız, index.jsp :D
Görüntü dosyalarımızı bu klasör altına atmamızın sebebi dış dünyadan soyutlamak. Yalnızca controller nesnesi tarafından erişilmesini sağlamak için yapılmış bir sarmalama mekanizması. Zekice!
Hmm.. Peki ya uzantı?
Sizden de hiçbir şey kaçmıyor :) ama yine de dikkatsizsiniz. Projemizi ilk oluşturduğumuz zamana geri dönelim. Orada Spring Web MVC 2.5 kütüphanesini seçerken Dispatcher Mapping: *.htm şeklinde bir desen girmiştik. İşte bu *.htm şeklinde gelen istekleri .jsp uzantılı görüntülere aktarılmasını sağlıyor. Bu desen çok farklı şekilde olabilir bunları daha sonra inceleyeceğiz. Tüm bu ayarlar WEB-INF altındaki xml uzantılı dosyalarda tanımlanıyor. Bu konuya da daha sonra değineceğim.
Kafam karıştı, böylece bırakıp gidemezsin!
Bu yazımı burada noktalayacağım. Amacım çalışan örneklerle bu konuya değinmekti. Tam olarak hedefime ulaştığım söylenemez, fakat parça parça anlatmak daha faydalı olacak gibi. Konu hakkında yazmaya kaldığım yerden devam edeceğim.
Görüşmek üzere...

27 Nisan 2010 Salı

Dynamic-Link Library (DLL) / Giriş

DLL dosyaları Microsoft'un Windows ve OS/2 işletim sistemleri için gerçeklediği kütüphane paylaşım konsepti olarak tanımlanabilir. Bu kütüphaneler genellikle DLL, OCX ya da DRV uzuntasındadır.

DLL dosyaları aynen EXE dosyaları gibi kod, veri ve kaynak bölümlerine (ve bunların herhangi bir kombinasyonunda) olabilir.

Windows işletim sisteminin ilk sürümlerinde tüm programlar tek bir bellek bölgesinde koşturuluyordu. İşletim sistemi düzeyindeki tüm işlemler MS-DOS tarafından gerçekleştirilirken yüksek seviyeli hizmetler Windows DLL leri tarafından sağlanıyordu. Çizim API'leri yani GDI.EXE, kullanıcı arayüzü işlemleri USER32.EXE adlı kütüphane dosyasında gerçeklenmiştir.


Günümüzde daha farklı bir yaklaşım kullanılmaktadır. Sistem tarafından sunulan kütüphaneler uygulamalara ayrı ayrı yüklenmektedir. Korumalı modda olduğu için bir program başka bir programın hafıza alanına doğrudan bir müdehalede bulunamıyor.

Assembly dilinde basit bir mesaj gösteren DLL uygulaması şu şekilde olabilir:


.386 ; intel x86 architecture
.model flat,stdcall ; use flat memory management
option casemap:none ; ignore letter case

include \masm32\include\windows.inc
include \masm32\include\user32.inc ; for MessageBox func.
include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
message db "Test message...",0 ; content of our simple message

.code
DllEntry proc hInstance:HINSTANCE, reason:WORD, reserved1:WORD ; DLL entry point function
mov eax,TRUE
ret
DllEntry Endp

SimpleMessage proc
invoke MessageBox,NULL,addr message,NULL,MB_OK ; win32 MessageBox func.
ret
SimpleMessage Endp

End DllEntry




Bu programı derlemek için birde def dosyası oluşturmalıyız. Bu dosyada 2 satır bilgi gerekiyor. Birinci satırda kütüphanenin ismini ikinci satırda ise kütüphaneden dışarı aktarılacak yani diğer programların hizmetine sunuculacak olan fonksiyonların isimleri.

örnek olarak

LIBRARY Simple
EXPORTS SimpleMessage


Projemizi derlemek için komut satırına bazı komutlar girmemiz gerekecek. Bu işlemin otomasyonu için şöyle bir batch dosya oluşturabiliriz.


c:\masm32\bin\ml.exe /c /coff /Cp "%CD%\Simple.asm"
c:\masm32\bin\link.exe /DLL /DEF:"%CD%\Simple.def" /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm32\lib "%CD%\Simple.obj"


Not: Bu uygulamayı derleyebilmeniz için sisteminizde Masm32 derleyicisi yüklü durumda olmalıdır. http://www.masm32.com/

Şimdi oluşturduğumuz bu DLL dosyasını başka bir programdan çağıralım. Bunun için çağırı yapacak programımızı derlerken DLL dosyamızın yapısını bildirmek üzere bir .lib dosyası vereceğiz. Bu dosya DLL projemizi derlerken derleyici tarafından otomatik olarak oluşturulmaktadır.

Kısa basit bir örnek:

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib Simple.lib ; lib file of Simple.dll to inform linker
includelib \masm32\lib\kernel32.lib

SimpleMessage PROTO ; name of the function in DLL

.code
start:
invoke SimpleMessage ; invoke the function in DLL
invoke ExitProcess,NULL ; terminate process
end start




Şimdi benzer bir çağırı programını C++ dilinde dinamik çağırma yöntemiyle yapalım.


#include <stdio.h>
#include <windows.h>

typedef void (WINAPI *SimpleMessage)(); // type defination to call dll function.

int main(int argc, char **argv)
{
HINSTANCE hDLL = LoadLibrary(L"simple.dll"); // loads our DLL into application memory section.
SimpleMessage sm = (SimpleMessage)GetProcAddress(hDLL,"SimpleMessage"); // gets address of our function in the dll.
if (!sm) // function address validation.
{
printf("Couldn't load library!\n");
}
else
{
sm(); // simple call.
}
return 0;
}



C# tarafında işler çok daha kolay:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace SimpleCall
{
class Program
{
[DllImport("simple.dll")]
static extern void SimpleMessage();

static void Main(string[] args)
{
SimpleMessage();
}
}
}


Java tarafında direk bir erişim şekli mevcut değil. Bunun yerine bazı 3. parti kütüphaneleri kullabiliriz. Bunlar JNI (Java Native Interface) tabanlı kütüphaneler. Biz bu örnekte JNA (Java Native Access) kullanacağız.

Bu kütüphanenin açıklamasını daha önceki bir yazımda (Bkz: http://rbellek.blogspot.com/2010/04/java-native-access-basit-ornek.html) bahsettiğim için burada yüzeysel geçiyorum.

Örnek uygulama:


//Main.java
package simple;

import com.sun.jna.Native;

public class Main {

public static void main(String[] args)
{
Simple simpleDLL = (Simple)Native.loadLibrary("e:\\Simple.dll", Simple.class);
simpleDLL.SimpleMessage();
}
}



//Simple.java
package simple;

import com.sun.jna.Library;

public interface Simple extends Library {
void SimpleMessage();
}



DLL dosyasının aynı EXE dosyaları gibi bir giriş noktları mevcuttur. Bu noktanın adı DllEntry adlı bir fonksiyondur. Ve giriş parametreleri olarak şu 4 değerden birini almaktadır.

DLL_PROCESS_ATTACH
DLL_PROCESS_DETACH
DLL_THREAD_ATTACH
DLL_THREAD_DETACH

Basit bir toplama kütüphanesi:


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
AppName db "Simple 2",0
HelloMsg db "Hello, you're calling a function in this DLL",0
LoadMsg db "The DLL is loaded",0
UnloadMsg db "The DLL is unloaded",0
ThreadCreated db "A thread is created in this process",0
ThreadDestroyed db "A thread is destroyed in this process",0

.code
DllEntry proc hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
.if reason==DLL_PROCESS_ATTACH
invoke MessageBox,NULL,addr LoadMsg,addr AppName,MB_OK
.elseif reason==DLL_PROCESS_DETACH
invoke MessageBox,NULL,addr UnloadMsg,addr AppName,MB_OK
.elseif reason==DLL_THREAD_ATTACH
invoke MessageBox,NULL,addr ThreadCreated,addr AppName,MB_OK
.else ; DLL_THREAD_DETACH
invoke MessageBox,NULL,addr ThreadDestroyed,addr AppName,MB_OK
.endif
mov eax,TRUE
ret
DllEntry Endp

Addition proc param1:DWORD, param2:DWORD
mov ebx,param1
mov eax,param2
add eax,ebx
ret
Addition endp
End DllEntry




Bu toplama fonksiyonunu (parametreli) çağıran C++ uygulaması:


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

typedef int (WINAPI* Addition)(int,int); // two DWORD (32-bit integer) in parameters
// WINAPI same as __stdcall
// __stdcall gives order of parameters in stack
int main(int argc, char **argv)
{
HINSTANCE hDLL = LoadLibrary(L"calculator.dll");
Addition addition = (Addition)GetProcAddress(hDLL,"Addition");
if (!addition)
{
printf("Couldn't load library!");
}
else
{
printf("5 + 9 = %i",addition(5,9)); // simple two parameter call
}
return EXIT_SUCCESS;
}



Şimdilik basit bir girişle yetiniyorum. Umarım devamında detaylandırabilirim...

4 Nisan 2010 Pazar

Java Native Access Basit Örnek

Java ile program geliştirmek çok rahat ve güvenilir olabilir. Fakat diğer tüm yorumlamaya dayalı diller gibi(C# vs.) Java'da doğrudan makine diline çevrilen programlama dilleri kadar hızlı değildir. Hız söz konusu değilse tabiki hiç bir sorun yok. Fakat bizim için hız önemli olduğunda ne yapacağız?
a)Java vb. dilleri bırak, C/C++ ya da Delphi gibi dilleri kullan.
b)Kullandığın dillerden vazgeçme gerekli bölgeyi soyutla.

Ben b şıkkını seçiyorum :) Peki b şıkkında anlatamak istediğim nedir?

Örneğin bir program geliştreceğiz. Bu programda çok ağır matematiksek işlemler var. Bunları Java ile yaptığımız zaman istediğimiz sürede istediğimiz verimlilikte sonuçlar alamıyoruz. Öyle ise bize sıkıntı çıkartan kısmı alıp, C/C++, Delphi ya da bir başka donanıma yakın olan bir dil ile yazıyoruz. Bu yazdığımız bölümü DLL olarak oluşturuyoruz. Artık tek yapmamız gereken Java projemizden bu DLL içerisindeki gerekli fonksiyonları zamanı geldiğinde çağırmak.

Bunu yapmamız için Sun Microsystems tarafından yazılmış bir kütüphane mevcut. JNA (Java Native Access). Bu kütüphane ile sabit disk üzerideki (başka bir dil ile yazılmış) DLL dosyalarındaki fonksiyınları çağırabiliyoruz.

Şimdi yamamız gereken temel adımlardan bahsedeyim.

1) Bir java projesi oluşturalım.
2) https://jna.dev.java.net/ adresinden JAR dosyasını sabit diskimize indirelim.
3) İndirdiğimiz kütüphaneyi projemize ekleyelim.
(NetBeans 6.8 için ekleme)
Libraries (sağ tık) -> Add JAR/Folder...


4) Projemizde bir interface oluşturarak kullanacağımız fonksiyonların tanımlamasını yapmalım.
5) İhtiyacımız olan fonksiyonu çağıralım. :)

Örnek bir kod parçası:

import com.sun.jna.*;

public class testMessage {

public interface Simple extends Library
{
public void TestMessage();
}

public static void main(String[] args)
{
Simple dll = (Simple)Native.loadLibrary("Simple.dll", Simple.class);
dll.TestMessage();
}

}


Bu kadar basit. JNA ile yalnızca Windows değil MacOS X, Linux ve Unix platformlarında da çalışabilirsiniz. Yanlız hata kontrolünü çok iyi tutmak gerekiyor. Lakin benim bir kaç denememde JVM (java.exe) çökmesi gibi durumlarla karşılaştım. Çünkü direk düşük seviye işlemleri yapılıyor. Java için son olarak birde JNI (Java Native Interface) var. Kendi yazdığımız C programlarına direk erişim için. Onu kısmet olursa başka bir zaman anlatmayı düşünüyorum.

C# tarafında da aynı olayın mümkün olduğunu söyleyebilirim. Orada işler biraz daha basit. Herhangi bir kütüphane kullanmanıza gerek yok. Yapı şu şekilde:

[DllImport("Simple.dll")]
static extern int TestMessage();

static void Main(string[] args)
{
TestMessage();
}


Sonuç olarak Java, C# vb. dillerin görsellik, güvenilirlik ve diğer mükemmel özelliklerini alıp, hantallık gibi diğer kötü özelliklerini bu sistemle değiştirmiş oluyoruz. Her sistemin güzel özelliğini bir araya getirerek çok kaliteli ürünler ortaya çıkarmak mümkün.

29 Kasım 2009 Pazar

Singleton Tasarım Şablonu / Java / JFrame

YouTube video: http://www.youtube.com/watch?v=QPr-J-c49W8







Singleton tasarım şablonu ile Java JFrame örneği.


//
// Ramazan Bellek
// Singleton Tasarım Şablonu
// rbellek.blogspot.com - 2009
// Pencere.java
//

package singleton;

import java.awt.Dimension;

import javax.swing.JFrame;

public class Pencere extends JFrame {

private static Pencere ornek;
private static Object kilit = new Object();

private Pencere()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension boyutlar=java.awt.Toolkit.getDefaultToolkit().getScreenSize();
setBounds(boyutlar.width/2-400,boyutlar.height/2-300,800,600);
}

public static Pencere instance()
{
if (ornek==null)
{
synchronized (kilit) {
if (ornek==null)
{
ornek=new Pencere();
}
}
}
return ornek;
}


public void setBaslik(String baslik)
{
setTitle(baslik);
}

public void goster()
{
setVisible(true);
}
public void gizle()
{
setVisible(false);
}


}



/*
* Ramazan Bellek
* Singleton Tasarım Şablonu
* rbellek.blogspot.com - 2009
* Main.java
*/

package singleton;

public class Main {

public static void main(String[] args)
{
Pencere.instance().setBaslik("Signleton deneme uygulaması");
Pencere.instance().goster();
}

}


15 Kasım 2009 Pazar

Kare Dalga Üretimi / Java

Fourier Açılımı (Detaylı bilgi...) ile kare dalga üretimi yapan java uygulaması. Veri iletişiminde kusursuza yakın kare dalgalar üretiminde kullanılmaktadır. Kare dalganın sinüs bileşenleri çıkartılır ve ardından bu dalgaların birbiriyle toplanmasıyla kare dalgaya yaklaşılabilir. Uygulamayı ilgili dersin ödevi için hazırlamıştım.

Ekran görüntüsü:



Uygulama Kodları:


/*
* Ramazan Bellek
*
* Sakarya University Computer Engineering Department
* Data Communication / Signal Generator Application
*
* File: Grafik.java
*
* 2009
*/

package dataComm;


import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;

import javax.swing.JPanel;

class Koordinat
{
public Koordinat(int x,int y,Color c)
{
this.x=x;
this.y=y;
this.c=c;
}
public int x,y;
public Color c;
}

class Yazi
{
public String yazi;
public Koordinat k;
public Yazi(String yazi, Koordinat k)
{
this.yazi=yazi;
this.k=k;
}
}

public class Grafik extends JPanel {

private ArrayList<Koordinat> koordinatlar;
private ArrayList<Yazi> yazilar;
private Color c;

public Grafik()
{
super();
koordinatlar = new ArrayList<Koordinat>();
yazilar = new ArrayList<Yazi>();
c=Color.BLUE;
}


@Override
public void paint(Graphics g)
{
g.setColor(Color.BLACK);
g.fill3DRect(0, 0, 800, 400, false);

for(Koordinat k : koordinatlar)
{
g.setColor(k.c);
g.fillOval(k.x, k.y, 1, 1); // Windows için g.fillOval(k.x, k.y, 2, 2);
// Mac OSX (Unix) için g.fillOval(k.x, k.y, 1, 1);
}
for(Yazi y : yazilar)
{
g.setColor(y.k.c);
g.drawString(y.yazi, y.k.x, y.k.y);
}

}

public void noktaCiz(int x, int y,Color c)
{
koordinatlar.add(new Koordinat(x,y,c));
}


public void yaziYaz(String yazi, int x, int y, Color c)
{
yazilar.add(new Yazi(yazi,new Koordinat(x,y,c)));
}
public void yenile()
{
repaint();
}

public void temizle()
{
koordinatlar.clear();
}

public void renkSec(Color c)
{
this.c=c;
}
}







/*
* Ramazan Bellek
*
* Sakarya University Computer Engineering Department
* Data Communication / Signal Generator Application
*
* File: Sinyal.java
*
* 2009
*/

package dataComm;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Sinyal extends JFrame{

public static float PI = 3.14159265358979323846f;
public static int freq = 1;
public static int amp = 10;
public static int har = 1;
public static boolean goster = false;
private JButton btnCiz;

private JPanel pnlKontrol;
private JPanel pnlBilgi;
private JPanel pnlTuslar;
private Grafik grafik;
private JTextField tfAmp;
private JLabel lbAmp;
private JTextField tfFreq;
private JLabel lbFreq;
private JTextField tfHar;
private JLabel lbHar;
private JCheckBox cbGoster;
private JLabel lbGoster;
private JLabel lbBilgi;

public static void main(String[] args)
{
new Sinyal("Data Communication / Sinyal Generator");
}

public Sinyal(String baslik)
{
super(baslik);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
Dimension ebat = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
setBounds(ebat.width/2-400,ebat.height/2-300,800,600);
setDefaultLookAndFeelDecorated(true);
setLayout(new BorderLayout());

initComponents();


setVisible(true);
}

private void initComponents()
{
pnlKontrol = new JPanel();
pnlKontrol.setPreferredSize(new Dimension(800,200));
pnlKontrol.setLayout(new BorderLayout());
this.getContentPane().add(pnlKontrol,BorderLayout.SOUTH);
pnlTuslar = new JPanel();
pnlTuslar.setPreferredSize(new Dimension(800,100));
pnlTuslar.setLayout(new FlowLayout());
pnlKontrol.add(pnlTuslar,BorderLayout.NORTH);
pnlBilgi = new JPanel();
pnlBilgi.setPreferredSize(new Dimension(800,100));
pnlKontrol.add(pnlBilgi,BorderLayout.SOUTH);

btnCiz = new JButton("ReDraw");
btnCiz.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent arg0) {
try
{
grafik.temizle();
Sinyal.amp=Integer.parseInt(tfAmp.getText());
Sinyal.freq=Integer.parseInt(tfFreq.getText());
Sinyal.har=Integer.parseInt(tfHar.getText());
if (cbGoster.isSelected())
goster=true;
else goster=false;
}catch(Exception e)
{
Sinyal.amp=10;
Sinyal.freq=1;
Sinyal.har=1;
System.err.println(e.getMessage());
}
drawCoordinates();
generateSinus();
}
});

tfAmp=new JTextField(5);
tfAmp.setText("10");
lbAmp=new JLabel("Amplitude:");
pnlTuslar.add(lbAmp);
pnlTuslar.add(tfAmp);

tfFreq=new JTextField(5);
tfFreq.setText("1");
lbFreq = new JLabel("Frequency:");
pnlTuslar.add(lbFreq);
pnlTuslar.add(tfFreq);

lbHar = new JLabel("Harmonics:");
tfHar = new JTextField(5);
tfHar.setText("1");

pnlTuslar.add(lbHar);
pnlTuslar.add(tfHar);

lbGoster = new JLabel("Show sinus elements?");
pnlTuslar.add(lbGoster);

cbGoster = new JCheckBox();
cbGoster.setSelected(false);

pnlTuslar.add(cbGoster);

pnlTuslar.add(btnCiz);

lbBilgi=new JLabel("Ramazan Bellek / 2009");
pnlBilgi.add(lbBilgi);

grafik = new Grafik();
grafik.setPreferredSize(new Dimension(800,400));
grafik.setBackground(Color.BLACK);
drawCoordinates();
generateSinus();
this.getContentPane().add(grafik,BorderLayout.CENTER);

}

private void drawCoordinates()
{
for(int i=0; i<800; i++)
{
grafik.noktaCiz(i, 200,Color.BLUE);
if (i%10==0)
{
grafik.noktaCiz(i+50, 50, Color.BLUE);
grafik.noktaCiz(i+50, 100, Color.BLUE);
grafik.noktaCiz(i+50, 150, Color.BLUE);
grafik.noktaCiz(i+50, 200, Color.BLUE);
grafik.noktaCiz(i+50, 250, Color.BLUE);
grafik.noktaCiz(i+50, 300, Color.BLUE);
grafik.noktaCiz(i+50, 350, Color.BLUE);

}
}
for(int i=0; i<400; i++)
grafik.noktaCiz(50, i,Color.RED);
grafik.yaziYaz("+15", 15, 50, Color.RED);
grafik.yaziYaz("+10", 15, 100, Color.RED);
grafik.yaziYaz("+5", 15, 150, Color.RED);
grafik.yaziYaz("0", 15, 200, Color.RED);
grafik.yaziYaz("-5", 15, 250, Color.RED);
grafik.yaziYaz("-10", 15, 300, Color.RED);
grafik.yaziYaz("-15", 15, 350, Color.RED);
grafik.yenile();

}

private void generateSinus()
{
double toplam=0;
double gecici=0;

for(double i=0.1; i<800; i+=1)
{
for(int j=1; j<=Sinyal.har; j+=2)
{

gecici=4*Sinyal.amp/(Sinyal.PI*j)*10*Math.sin(2*Sinyal.PI*Sinyal.freq*j*i/360);
toplam+=gecici;
if (goster)
grafik.noktaCiz((int)(50+i),(int)(200-gecici),Color.CYAN);

}
grafik.noktaCiz((int)(50+i),(int)(200-toplam),Color.MAGENTA);
toplam=0;
}


grafik.yenile();
}

}