30 Haziran 2019 Pazar

maven Parent pom.xml

Giriş
Projenin yapısı şöyle olsun.
Parent Module
|
|---Child Module A
       |
       |--pom.xml (a.jar)
|---Child Module B
       |
       |--pom.xml (b.jar)
|pom.xml
A ve B projelerinin ortak kullandıkları şeyleri parent projedeki pom.xml'e koyarız. Şöyle yaparız.
Ortak Nexus ayarları
<distributionManagement>...</distributionManagement>

Ortak Svn ayarları
<scm>...</scm>

Ortak değerler
<properties>...</properties>

Ortak Pluginler
<build>...</build>

Ortak jarlar
<dependencyManagement>...</dependencyManagement>
Bazen de aggreate pom yapılmak istenirse
<modules>...</modules>
eklenir.

DependencyManagement Nedir?
Açıklaması şöyle.
A very important use of the dependency management section is to control, consolidate, and centralize the versions of artifacts used in dependencies and inherited by all children.
Conflict Resolution
Açıklaması şöyle. Parent pom'a yazılan jar'lar ilk olarak tercih edilir.
So, there are multiple ways of deciding the versions, which means there is an order of precedence.

1. Versions provided in the direct declaration in POM take the highest precedence.
2. Version provided in parent pom takes second precedence.
3. Version from imported pom takes third place
4. Lastly, whatever we get from dependency mediation


27 Haziran 2019 Perşembe

Selenium Select Sınıfı

Giriş
ComboBox'tan seçim yapmaya yarar.

selectByVisibleText metodu
İsmi place olan dropdown'daki Tokyo değerini seçmek için şöyle yaparız.
WebElement place = driver.findElement(By.id("place"));
Select placeSel = new Select(place);
placeSel.selectByVisibleText("Tokyo");

21 Haziran 2019 Cuma

Intellij Idea Refactoring

Giriş
Refactoring işlemleri şöyle


Replace Inheritance With Delegation
Kalıtım kullanan bir sınıfın kalıtımını kaldırır ve ata sınıfı üye alan haline getirir. Bir örnek burada. Ata sınıfın üzerine tıklarız ve "Replace Inheritance With Delegation" seçeneğini seçeriz.

Rename
Değişken, sınıf isimleri değiştirilebilir. Bir örnek burada

Move İşlemleri
1. Move Instance Method
Bir metodu sınıfın içinde değişken olarak tanımlı bir başka sınıfa taşır. Bu çok faydalı, böylece sınıfı daha küçük parçalara bölebiliyoruz.

Extract İşlemleri
Menü şöyle


1. Extract Method - Ctrl + Alt + M 
Refactor/Extract/Method menüsü kullanılarak sınıf içindeki seçili kod parçasını yine aynı sınıf içinde yeni bir metod haline getirir. Bir örnek burada Şeklen şöyle



2. Extract Variable - Ctrl + Alt + V 
Bir metodun sonucunu yeni bir değişkene atayan kodu üretir. Metodun sonuna "var" yazarsak ta aynı sonucu elde ederiz.


20 Haziran 2019 Perşembe

Binary Serialization

Giriş
Şu satırı dahil ederiz.
mport java.io.Serializable;
Nasıl Kullanılır
Java'nın kendi içinde serialization yapısı mevcut. Aynı C#'ta olduğu gibi serialize edilecek nesnenin Serializable arayüzünden türemesi gerekiyor. Bu arayüz bir marker interface. Herhangi bir metod içermez.
class MyClass implements Serializable
{
  private static final long serialVersionUID = 12345L;
}
Sınıfı Serializable Yapmadan Önce
İyi düşünmek lazım. Açıklaması şöyle.
"Library designers must think very carefully before publishing a serializable class --- as doing so potentially commits you to maintain compatibility with all the instances that have ever been serialized."
Eleştiriler
Serialization mekanizması için bazı eleştiriler var. Bir tanesi  serialization kodunun içinin bilinmemesi. Açıklaması şöyle. Yani kod magic olarak çalışıyor.
"..the choice to implement serialization by 'magic' rather than giving deconstruction and reconstruction a first-class place in the object model itself."
Bu yüzden, sınıfın constructor,setter(),getter() gibi metodları çağrılmıyor. Açıklaması şöyle.
"Serialization pretends to be a library feature. ... In reality, though, serialization extracts object state and recreate objects via privileged, extralinguistic mechanisms, bypassing constructors and ignoring class and field accessibility."
Exception
Eğer sınıf içinde Serializable arayüzünü gerçekleştirmeyen alanlar varsa şöyle bir exception alırız.
Caused by: java.io.NotSerializableException: java.io.FileOutputStream
Bu durumda ya o alan Serializable arayüzünü gerçekleştirmeli ya da transient olarak işaretlenmeli.

serialVersionUID Alanı
serialVersionUID Alanı yazısına taşıdım.

Kendi Sınıfımdaki static ve transient Alanlar
Bu alanlar serialization işlemine girmezler. Yani yazılıp okunmazlar.

Alanları transient olarak işaretlemek için şöyle yaparız.
private transient FileInputStream fis ; 
private transient FileOutputStream fos ; 
 İstisnai tek bir durum var.
There is just one exception to this rule, and it is when the transient final field member is initialized to a constant expression as those defined in the JLS 15.28. Hence, field members declared this way would hold their constant value expression even after deserializing the object.
Constant expression'dan kasıt ise
A constant expression is an expression denoting a value of primitive type or a String
Yani aşağıdaki gibi tanımlı primitive a aslında serialization işlemine giriyor.
transient final int a = 10;
transient Alanları deserialize işleminden sonra tekrar ilklendirmek gerekir.

Ata Sınıfıtaki Alanlar
Eğer ata sınıf Serializable değilse alanları yazılıp okunmaz. Açıklaması şöyle
... the defaultWriteObject can only write the non-static and non-transient fields of the current class. Once the superclass does not implements the Serializable interface, the fields in the superclass can not be serialized into the stream

Serializable Arayüzünün Davranışını Değiştirmek - Custom Serialization
Binary Custom Serialization yazısına taşıdım.

ObjectStream Bu Metodları Nasıl Çağırır
ObjectStream sınıfı yansıma (reflection) vasıtasıyla bu metodları çağırır.
...
private Method writeObjectMethod;
private Method readObjectMethod;
private Method readObjectNoDataMethod;

...

writeObjectMethod = getPrivateMethod(cl, "writeObject",
                            new Class<?>[] { ObjectOutputStream.class },
                            Void.TYPE);
readObjectMethod = getPrivateMethod(cl, "readObject",
                            new Class<?>[] { ObjectInputStream.class },
                            Void.TYPE);
readObjectNoDataMethod = getPrivateMethod(
                            cl, "readObjectNoData", null, Void.TYPE);
...
No-Arg Constructor Gerekir mi ?
Bu hep kafa karıştıran bir soru. Bazı cevaplar aşağıda

1. Kalıtım Yoksa Kendi Sınıfıma No-Arg Constructor Gerekir mi ?
Serialize edilen nesne kalıtmıyorsa, no-arg constructor  gerekmez.

2. Kalıtım Varsa Hangi Sınıfa No-Arg Constructor Gerekir?
Eğer kalıtım varsa, hiyerarşide Serializable arayüzünü gerçekleştirmeyen ilk ata sınıfın no-arg constructor metoduna sahip olması gerekir. Sebep olarak ta kalıtılan field'ları ilklendirmek için no-arg constructor'ının çağırılması gösterilmiş. Açıklaması şöyle
During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class. A no-arg constructor must be accessible to the subclass that is serializable. The fields of serializable subclasses will be restored from the stream.
Örneğin nesnemiz direkt Object'ten türüyorsa, Object Serializable arayüzünü gerçekleştirmez ancak no-arg constructor metoduna sahip olduğu için sorun çıkmaz.

3. Deserialize İşleminden Sonra Kendi Nesnemin No-Arg Constructor'ı Çağırılır mı?
Deserialize işleminden sonra kendi nesnemin no-arg constructor metodu çağırılmaz. Ancak yukarıdaki madded belirtildiği gibi ata sınıflarımdan Serializable olmayan nesnenin no-arg constructor metodu çağrılır. Çağırılması isteniyorsa aşağıdaki Serialization Proxy kullanılmalıdır.

Örnek
Elimizde şöyle bir kod olsun. Bar sınıfını i = 20 ile ilklendirip kaydedelim. Daha sonra okuma yapınca i = 10 sonucunu alırız. Çünkü Foo sınıfının no-arg constructor metodu çağrılır ve i 10 yapılır
public class Foo {

  private int i;
  Foo(){
    i=10;
  }
  public void setVal(int i){this.i = i;}
}

class Bar extends Foo implements Serializable {

  private String s;
  private Foo foo;

  Bar(String s) {
    this.s = s;
    setVal(20);
  }
  ...
}
Serialization Proxy Nedir?
Serialization Proxy yazısına taşıdım

Binary Serialization - Serialization Proxy

Giriş
Bu örüntünün kullanılmasının iki sebebi var.
1. Nesnemiz Immutable ise
2. Nesnemiz Serializable olmayan bir başka sınıftan kalıyor ve ata sınıf parameterless (default) constructor sağlamıyorsa.

İlk örüntüyü defa burada gördüm.

Nasıl Çalışır
Java bir nesneyi yazmadan önce writeReplace() metodunun override edilip edilmediğine bakar. Eğer edilmişse writeReplace() metodunun döndürdüğü nesne serialize edilir. Bu nesne bizim Serialization Proxy nesnemizdir.

Okurken, Java yazılmış olan Serialization Proxy  nesnesini okur. İşlemden sonra readResolve () metodunun override edilip edilmediğine bakar. Eğer edilmişse nesnenin - ki bizim Serialization Proxy nesnesidir - readResolve() metodu çağırılır. Bu metod kendi immutable nesnemizi yaratır ve döndürür.

Örnek
Şöyle yaparız.
public class Organization implements Serializable {
  private static final long serialVersionUID = 28484399283838343L;
   
  private Object writeReplace() {
    return new SerializationProxy(this);
  }

  private void readObject(final ObjectInputStream stream) 
  throws InvalidObjectException {
    throw new InvalidObjectException("Proxy required");
  }

  private static class SerializationProxy implements Serializable {
    private static final long serialVersionUID = 484894399233454L;

    
    private Object readResolve() {
      return new Organization(...);
    }
  }
}



ThreadPoolExecutor Sınıfı

Giriş
ThreadPoolExecutor sınıfı karmaşık bir constructor'a sahip. Bu yüzden ExecutorService.xyz() şeklindeki factory metodlar ile yaratıp kullanması daha kolay.

Kalıtım hiyerarşisi şöyle

ExecutorService <--ThreadPoolExecutor

Bu sınıfa bir iş verilince şu adımlar izlenir.
When a task is submitted

1.If poolSize is less than corePoolSize, a new thread is created, even if there are idle threads.
2.If poolSize is equal to the corePoolSize then task is added to the queue. It won't create new threads until queue is exhausted.
3.if workQueue is exhausted then new thread is created till poolSize becomes maximumPoolSize.
4.If poolSize is equal to the maximumPoolSize throw RejectedExecutionException
constructor
Parametreler şöyle

1. corePoolSize
Bu parametre kaç tane thread ile çalışmamız gerektiğini belirtir

CPU-Intensive Tasks
Açıklaması şöyle
A common rule of thumb is to use the number of CPU cores available
Örnek
Şöyle yaparız
int numThreads = Runtime.getRuntime().availableProcessors(); // the number of CPU cores
ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
Eğer başka işler için de işlemci zamanı bırakmak istersek mevcut çekirdek sayısından daha az bir değer kullanırız. Şöyle yaparız
int availableCores = Runtime.getRuntime().availableProcessors();
int numberOfThreads = Math.max(availableCores - 1, 1); // Adjust as needed

ExecutorService threadPool = Executors.newFixedThreadPool(numberOfThreads);
IO-intensive tasks
Sayısı hesaplamak için yardımcı olabilecek bir açıklama şöyle. Burada 100% işlemci kullanımı düşünülüyor
In order to calculate the ideal number of threads for an IO-bound task, we can use the following formula provided by Brian Goetz. If the threads spend S units of service time (running and utilizing CPU) and W units of waiting time (blocked in IO operation) and there are N processor cores, then


number of threads = N * (1 + Wait time / Service time)
Açıklama şöyle. Burada 100% işlemci kullanımı değil bir başka yüzde düşünülüyor. O yüzden Target CPU utilization ile çarpım var.
Number of threads = Number of Available Cores * Target CPU utilization * (1 + Wait time / Service time)
Örnek 
S yani service time veya hesaplama süresi 1 saniye olsun. 
W yani wait time yani IO 2 saniye olsun. 
N yani 4 çekirdek olsun.
Bu durumda 4 * (1 + 2/1) = 12 thread lazım

Sayı çalışma esnasında şöyle değiştirilir ancak bu metod çok iyi çalışmayabiliyor.
ThreadPoolExecutor es = new ThreadPoolExecutor(1, 100, 30, TimeUnit.DAYS, 
new LinkedBlockingQueue<Runnable>());
es.setCorePoolSize(2);   
Örnek
Açıklaması şöyle
The I/O-intensive tasks have a blocking coefficient of 0.5, meaning that they spend 50% of their time waiting for I/O operations to complete.

Number of threads = 4 cores * 0.5 * (1 + 0.5) = 3 threads

2. maximumPoolSize
En fazla kaç thread ile çalışmamız gerektiğini belirtir. I/O kullanmayan işlerde en fazla sayı sanırım işlemci sayısı + 1 kadar olmalı.

3. keepAliveTime
Thread sayısı coroPoolSize'dan fazlaysa idle thread'in ne kadar yaşayacağınız gösterir.

4. BackingQueue
SynchronousQueue : Direct handoff
LinkedBlockingQueue : Unbounded
ArrayBlockingQueue : Bounded

gibi sınıflar olabilir.

Örnek
Thread sayısı 10-50 arasında olan, ve en fazla 20 tane işi kuyrukta bekleten bir şey yaratmak istersek şöyle yaparız. Bence en ideal kod bu!
new ThreadPoolExecutor(10, // core size
    50, // max size
    10*60, // idle timeout
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<Runnable>(20)); // queue with a size
Örnek
Bir başka örnek'te kuyruk sınırsız olduğu için thread sayısı 10-50 olsa bile yeni işleri kuyruğa ekleyerek kabul etmeye devam eder. FixedThreadPool'a çok benziyor. Tek farkı thread'lerin idle süresi biraz daha uzun tutulmuş.
BlockingQueue<Runnable>  queue = new LinkedBlockingQueue<>();
new ThreadPoolExecutor(10, 50, 10 * 60, TimeUnit.SECONDS, queue);
Örnek
Şöyle yaparız.
//core 5 max 10 with 60 second idle time
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,60,TimeUnit.SECONDS,
  new LinkedBlockingQueue<Runnable>());
afterExecute metodu
ThreadPoolExecutor Kullanımı yazısına taşıdım

beforeExecute metodu
Şöyle yaparız.
Semaphore semaphore = new Semaphore(1000);
ThreadPoolExecutor executor = new ThreadPoolExecutor(...){
  protected void beforeExecute(Runnable r, Throwable t) { 
    semaphore.release();
  }
}
getActiveCount metodu
İstatistik amacıyla o an çalışmakta olan thread sayısını döner.

getCompletedTaskCount metodu
İstatistik amacıyla o ana kadar bitmiş iş sayısını döner.

getQueue metodu
Kuyruğa erişime izin verir.
Örnek
Şöyle yaparız.
BlockingQueue<Runnable> coreQueue = es.getQueue();
getTaskCount metodu
İstatistik amacıyla o ana kadar eklenmiş toplam (bitmiş veya beklemekte olan) iş sayısını döner.
Örnek
Şöyle yaparız.
long submitted = executor.getTaskCount();
long completed = executor.getCompletedTaskCount();
long notCompleted = submitted - completed; // approximate
isTerminated metodu
Şöyle kullanırız.
ThreadPoolExecutor es = new ThreadPoolExecutor(...);
...
x.shutdown();
while (!x.isTerminated()) {...}
setCorePoolSize metodu
Sayı çalışma esnasında şöyle değiştirilir. Ancak bu metod çok iyi çalışmayabiliyor.
ThreadPoolExecutor x = new ThreadPoolExecutor(1, 100, 30, TimeUnit.DAYS, 
new LinkedBlockingQueue<Runnable>());
x.setCorePoolSize(2);   
setRejectedExecutionHandler metodu
Şöyle yaparız.
threadPool.setRejectedExecutionHandler(rejectedHandler);