Bu Sayfayı Paylaş:

Kavram

Configuration

Tanım: Yapılandırma. Konfigurasyon

Kavram

Preference

Tanım: Yeğlenen, tercih

Kavram

Konfigürasyon (Configuration)

Tanım: Bir yazılımın düzgün çalışması (yapılandırılması) için tanımlanmış (çoğunlukla key-value şeklinde) değerlerin bütünü. Örneğin bir yazılımın hangi veritabanına bağlanacağı , loglama yapacağı klasör ile ilgili ayarlar vb yazılımın konfigürasyonudur

Kavram

Preference

Tanım: Bir kullanıcının bir uygulama üzerinde yapmış olduğu ve daha sonra kullanılmak üzere saklanan ayarlar, tercihler. Örneğin uygulama adı, renk ayarları vb.. gibi ayarların bütününe preference adı verilir. Preference Türkçe'ye yeğlenen, tercih edilen olarak çevrilebilir.

Kavram

Java Preferences API

Tanım: Java platformunda , uygulamaların konfigurasyonlarının, kullanıcının ayarlarının (preference) saklanması ve tekrar kullanılabilmesi için geliştirilmiş API. java.util.prefs paketi bu API'nin sınıflarını içerir.

Kavram

Commons Configuration API

Tanım: Apache kurumu tarafından geliştirilmiş , farklı kaynaklarda (property dosyası, veritabanı, JNDI gibi) key-value şeklinde konfigürasyon değerlerinin saklanmasını ve erişilmesini sağlayan kütüphane

Kavram

java.util.prefs Paketi

Tanım: Java Preferences API'nin (kullanıcının ayarlarının (preference) saklanması ve tekrar kullanılabilmesi , uygulama konfigurasyon ayarları için bir API) sınıflarını ve interface'lerini içeren paket.

İpucu

Basit Bir Konfigürasyon Kütüphanesi Geliştirilmesi



Bir uygulama için en basit konfigürasyon bilgileri Properties'den yüklendiği konfügürasyon sistemidir. Genellikle bir uygulama için tek bir konfigürasyon sınıfı kullanılır ve bilgiler uygulama açıldığında bir kere yüklenir. Bu nedenle Singleton mimarisi kullanılabilir ancak Properties dosyasının path'i başlangıçta verilmesi gerekir. Bu durum Singleton için doğru değildir çünkü farklı parametrelerle farklı nesneler yaratılırması gerekir ki singleton tasarım mantığına aykırıdır. Onun yerine aşağıdaki gibi yapmak tercih edilebilir:

SimpleConfiguration simpleConfiguration=SimpleConfiguration.getInstance();		
simpleConfiguration.load(path);


Bu şekilde tek bir SimpleConfiguration nesnesi olur. Ancak load işleminin unutulmaması gerekir. Ayrıca load yöntemi olur olmaz yerlerde çağrılabilir ve kontrol edilmesi mümkün değildir. Bunun yerine load yöntemi ve getInstance() yöntemi paket level yapıp (sadece paketten erişilsin dışarıdan erişilmesin) bir builder sınıfı kullanılabilir. Bunun için aşağıdaki şekilde SimpleConfiguration elde edilebilir:

SimpleConfigurationBuilder simpleConfigurationBuilder=new SimpleConfigurationBuilder(path);
SimpleConfiguration simpleConfiguration=simpleConfigurationBuilder.build();


Burada SimpleConfigurationBuilder'e properties dosyasının path'i verilir. build() yöntemi çağrıldığında SimpleConfiguration instance'ı yaratılır, load işlemi yapılır ve load edilmiş SimpleConfiguration nesnesi döndürülür. Bu şekilde load() yöntemini çağrılması unutulamaz aynı zamanda builder ile daha sonra istenilen kontroller eklenebilir. Yukarıdaki örneklerin sınıfları aşağıdaki gibi olabilir:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class SimpleConfiguration {
	private Properties properties;
	private static class SingletonHolder {
		public static final SimpleConfiguration instance
			= new SimpleConfiguration();
	}
	
	static SimpleConfiguration getInstance() {
		return SingletonHolder.instance;
	}
	
	public String getProperty(String key) {
		return properties.getProperty(key);
	}
	
	public String getProperty(String key, String defaultValue) {
		return properties.getProperty(key, defaultValue);
	}		
	
	void load(String path) 
			throws FileNotFoundException, IOException {
		properties=new Properties();
		try(InputStream is=new FileInputStream(path)){
			properties.load(is);
		}
	}
}


Builder sınıfı :

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class SimpleConfigurationBuilder {
	private String localfilePath;
	
	public SimpleConfigurationBuilder(String localfilePath) 
			throws FileNotFoundException {
		
		if(localfilePath==null) {
			throw new IllegalArgumentException("localfilePath is null");			
		}
		if(!Files.exists(Paths.get(localfilePath))) {
			throw new FileNotFoundException("localfilePath not found");
		}
		this.localfilePath=localfilePath;		
	}
	
	public synchronized SimpleConfiguration build() throws IOException {			
		
		SimpleConfiguration simpleConfiguration=SimpleConfiguration.getInstance();		
		simpleConfiguration.load(localfilePath);
		return simpleConfiguration;
	}
}


Bu iki sınıf aşağıdaki gibi JUnit 5 ile basitçe test edilebilir:

import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import io.github.glytching.junit.extension.folder.TemporaryFolder;
import io.github.glytching.junit.extension.folder.TemporaryFolderExtension;
@ExtendWith(TemporaryFolderExtension.class)
public class SimpleConfigurationTest {
	
	private static String path;
	
    @BeforeAll
    public static void prepare(TemporaryFolder givenTemporaryFolder)
	throws IOException {
        	
		File file = givenTemporaryFolder.createFile("test.properties");
		path=file.getAbsolutePath();
		
		Properties properties=new Properties();
		properties.put("test", "testvalue");
		
		try(OutputStream os =new FileOutputStream(file)){
			properties.store(os,"simple configuration");
		}
		
    }
	
	@Test
	public void loadAndGetPropertyTest() throws IOException {
			
		SimpleConfigurationBuilder simpleConfigurationBuilder=
			new SimpleConfigurationBuilder(path);
		SimpleConfiguration simpleConfiguration=simpleConfigurationBuilder.build();
		
		assertEquals("testvalue", simpleConfiguration.getProperty("test"));
	}
}
prepare() yöntemi ile önce TemporaryFolder içinde bir properties dosyası yaratılır. loadAndGetPropertyTest() ile de test edilebilir. Builder ve SimpleConfiguration için load ve getProperty() yöntemleri ayrı ayrı testler yapılabilirdi ancak basit olması için bu şekilde yapılmıştır.

Bir değil birden fazla Properties dosyasını yüklemek isteyebiliriz. Bunun için SimpleConfiguration sınıfına aşağıdaki gibi bir yöntem ekleyebiliriz :
void merge(String path) throws FileNotFoundException, IOException {
	Properties properties2 = new Properties();
	try (InputStream is = new FileInputStream(path)) {
		properties2.load(is);
	}
	
	Set<Entry<Object, Object>> entries = properties2.entrySet();
	for (Entry<Object, Object> entry : entries) {
	  if(!properties.containsKey(entry.getKey().toString())) {
		  properties.put(entry.getKey().toString(), entry.getValue().toString());	    	  
	  }
	}
}
Bu yöntem ile ikinci bir Properties dosyası ilk properties'e eklenmiş olacaktır. Eğer aynı key varsa dikkate alınmayacaktır. Builder'a ise yeni bir Properties dosyası path'i ekleyip aynı builder'ı dönecek şekilde bir yöntem ekleyelim:
public SimpleConfigurationBuilder withPath(String path){
	paths.add(path);
	return this;
}
builde() yönetimi de aşağıdaki gibi güncelleyelim:

public synchronized SimpleConfiguration build() throws IOException {			
	
	SimpleConfiguration simpleConfiguration=SimpleConfiguration.getInstance();		
	simpleConfiguration.load(localfilePath);
	
	for (String path : paths) {
		simpleConfiguration.merge(path);
	}
	return simpleConfiguration;
}


Bu şekilde build yöntemi ile Properties içerikleri toplanmış olacaktır. Test sınıfı aşağıdaki gibi olabilir:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import com.sca.configuration.simple.SimpleConfiguration;
import com.sca.configuration.simple.SimpleConfigurationBuilder;
import io.github.glytching.junit.extension.folder.TemporaryFolder;
import io.github.glytching.junit.extension.folder.TemporaryFolderExtension;
@ExtendWith(TemporaryFolderExtension.class)
public class SimpleConfigurationTest {
	
	private static String path;
	private static String path2;
	
    @BeforeAll
    public static void prepare(TemporaryFolder givenTemporaryFolder) throws IOException {
        	
		File file = givenTemporaryFolder.createFile("test.properties");
		path=file.getAbsolutePath();
		
		File file2 = givenTemporaryFolder.createFile("test2.properties");
		path2=file2.getAbsolutePath();
		
		Properties properties=new Properties();
		properties.put("test", "testvalue");
		
		try(OutputStream os =new FileOutputStream(file)){
			properties.store(os,"simple configuration");
		}
		
		Properties properties2=new Properties();
		properties2.put("test2", "testvalue2");
		
		try(OutputStream os =new FileOutputStream(file2)){
			properties2.store(os,"simple configuration 2");
		}
		
    }
	
	@Test
	public void loadAndGetPropertyTest() throws IOException {
			
		SimpleConfigurationBuilder simpleConfigurationBuilder=new SimpleConfigurationBuilder(path);
		SimpleConfiguration simpleConfiguration=simpleConfigurationBuilder.build();
		
		assertEquals("testvalue", simpleConfiguration.getProperty("test"));
	}
	@Test
	public void loadMultiplePropertiesAndGetPropertyTest() throws IOException {
			
		SimpleConfigurationBuilder simpleConfigurationBuilder=new SimpleConfigurationBuilder(path);		
		SimpleConfiguration simpleConfiguration=simpleConfigurationBuilder.withPath(path2)
				.build();
		
		assertEquals("testvalue", simpleConfiguration.getProperty("test"));
		assertEquals("testvalue2", simpleConfiguration.getProperty("test2"));
	}
	
}


Önce iki tane Properties dosyası yaratıyoruz. loadMultiplePropertiesAndGetPropertyTest() yöntemi içinde ikinci properties dosyası withPath ile verilmektedir. test key'i ana Properties dosyasındayken, test2 sonradan eklediğimiz Properties içindedir.



Bu Sayfayı Paylaş:

İletişim Bilgileri

Takip Et

Her Hakkı Saklıdır. Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir. Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir