1. Eksen#
EKSEN ismini verdiğimiz yazılım geliştirme altyapısı; mikro servis mimari prensiplerinden, modülerlik, sürekli otomasyon, gizli uygulama erişimi, merkezileştirmekten kaçınmak, bağımsız kurulum, hata durumlarının yönetimi, gözlenebilirlik ile ilgili entegre çözümler barındırmaktadır.
EKSEN, Tüm Kamu Kurum ve Kuruluşlarımızın yabancı ürünlere ödediği lisans maliyetlerinin sıfırlanması ve yurtdışı bağımlılıklarımızın yok edilmesi hedeflenerek, geniş kabul gören, olgunluğunu ispatlayarak defacto haline gelmiş açık kaynak kodlu yazılımları kullanarak geliştirmiş olduğumuz yazılım geliştirme altyapısıdır.
Genel İçerigi#
- Yerli ve milli yazılım vizyonu ile açık kaynak(open source) teknolojiler kullanılarak geliştirilmiştir.
- Programlama dili olarak Java dilinin güncel versiyonu kullanılmaktadır.
- Java uygulaması geliştirmek için Spring Boot Framework kullanılmaktadır.
- Mikro servis mimariye uygun uygulama geliştirmeler için Spring Cloud Framework kullanılmaktadır.
- Java dili ile geliştirme yapıldığında kullanılan popüler açık kaynak farklı kütüphaneler de kullanılmaktadır. (apache, querydsl, mapstruct vb.)
- Kendi teknoloji havuzumuzla entegre çalışması için özelleştirilmiş katmanlar(servis ve model contributer) eklenmiştir.
- Güvenlik mimarisi olarak OAuth standartları uygulanmaktadır.
- Veri tabanı işlemleri için JPA ve QueryDSL kullanılmaktadır.
- Cache ve veri tarihçesi gibi işlemler için altlıklar sağlanmaktadır.
Projelerin ortak yanları olan ve genelde en fazla kaynak harcanan parçaları olan altyapı bileşenleri her proje için tekrar geliştirilmekte ve test edilmektedir. Ekibimizin bir diğer ana görevi altyapı bileşenlerini küçük ve büyük proje farkı gözetmeksizin geliştirip test edilmiş güvenli bir altyapı hizmeti sunmaktır.
Kullanılan açık kaynak teknolojilerin yeni versiyonlarına hızlı bir şekilde geçiş yapılabilecek bir yapı sunulmaktadır. Aynı zamanda yeni çıkan açık kaynak yapılar incelenerek hızlı bir şekilde altyapımıza entegre edilmektedir.
Genel Yapı Ve Paketler#
Framework instance projelerinin genel yapısı hakkında detaylı bilgi Genel Yapı ve Paketler sayfasında verilmiştir.
Sağlanan Başlıca Anotasyonlar#
- @HvlFeignClientError
- @HvlPrivateFeignRestService
- @HvlPublicFeignRestService
- @HvlDynamicUpdateExclude
- @HvlTransactionalRollbackForCheckedException
- @HvlIdValid
- @HvlUuidValid
- @HvlEntitySequence
- @HvlView
- @HvlActuatorService
- @HvlExceptionHttpStatus
- @HvlTraceLog
Genel Bileşenler#
Framework#
Uygulama geliştirilirken başta Spring olmak üzere third-party temel bileşenleri gereksinimlere göre özelleştirilmiş olarak hizmete sunan altyapı bileşenidir. Actuator, configuration, context, crypto, exception, initializer, service, swagger, util gibi temel bileşenleri içermektedir. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.
Actuator#
import tr.com.havelsan.javarch.actuator.annotation.HvlActuatorService;
@HvlActuatorService(name = "hvlBpmnIntegrationRestService", groupName = "hvlBpmnIntegration")
Uygulamada rest uçların ve modellerin bilgilerinin dönülmesini sağlamaktadır. Bu bilgileri alabilmek için ilk olarak ip:port/actuator
adresine istek atılmalıdır.
Servis bilgilerinin alınabilmesi için aşağıdaki uçların kullanılması gerekmektedir.
Model bilgilerinin alınabilmesi için aşağıdaki uçların kullanılması gerekmektedir.
TS-Generator ürünümüz type-script sınıflarını üretmek için yukaridaki uçları kullanmaktadır. Java temel annotation, model ve servis sınıflarının type-script'i üretilmektedir.
hvl-infra altında bulunan 'application-management.yml' dosyasıyla konfigure edilebilmektedir.
Configuration#
import tr.com.havelsan.javarch.configuration.HvlBaseConfiguration;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Configuration extends HvlBaseConfiguration {
}
Temel konfigurasyon sınıfı sunulmaktadır. Bu sınıftan türeyen sınıflar context'e dahil edildiğinde log atılmaktadır. Aynı zamanda tarama işlemlerinde sadece konfigurasyon taranması için ayraç olarak kullanılabilmektedir.
Profile bağlı tarama yapabilmek için sağlanan HvlProfileComponentScanFilter
sınıfı bulunmaktadır. Bu sınıf kullanılarak sadece @Profile
içeren konfigürasyon sınıfları taranabilmektedir.
@Configuration
@ComponentScan(basePackages = {HvlLogServerConfigurationConstant.BASE_PACKAGE},
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, value = HvlProfileComponentScanFilter.class),
}
)
public class HvlLogServerConfiguration extends HvlBaseConfiguration {
}
Yaml veya properties dosyalarından konfigurasyonlarını ayrıştırmak için HvlPropertyParser
sınıfı kullanılmaktadır. Bu sınıf sayesinde iç içe konfigurasyon verilmesi sağlanmaktadır.
Konfigurasyonları jasypt kütüphanesi ile şifreleme yeteneği bulunmaktadır. Şifreleme yeteneği sağlanan algoritma türleri: HvlConfigurationEncryptorType
PBES
STANDART_PBES
POOLED_PBES
ASYMETRIC
NOT: Şifreleme işlemi StringEncryptor ile yapılmaktadır. Jasypt standartları ile şifreleme işlemi yapmak isterseniz StringEncryptor sınıfı kullanılabilir.
hvl-infra altında bulunan 'application-instance.yml' dosyasıyla konfigure edilebilmektedir.
group: 'tr.com.havelsan.framework', name: 'hvl-configuration'
group: 'tr.com.havelsan.framework', name: 'hvl-configuration-encryptor'
Context#
Uygulama içeriğinde Bean, Environment ve System enviroment'a ulaşmayı sağlamaktadır.
2 şekilde kullanılabilmektedir:
- DI (Dependency Injection) ile kullanılabilir.
import org.springframework.stereotype.Component;
import tr.com.havelsan.javarch.context.HvlApplicationContext;
@Component
public class SampleService {
private final HvlApplicationContext applicationContext;
public SampleService(HvlApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void test() {
applicationContext.getBean(SampleService.class);
applicationContext.getEnvironment();
applicationContext.getSystemLocale();
}
}
- Bean olmayan sınıflar statik olarak
Holder
üzerinden kullanılabilir.
import tr.com.havelsan.javarch.context.holder.HvlApplicationContextHolder;
import java.util.Objects;
public final class SampleService {
public static SampleService INSTANCE;
public static SampleService getInstance() {
if (Objects.isNull(INSTANCE)) {
INSTANCE = new SampleService();
}
return INSTANCE;
}
public static void test() {
HvlApplicationContextHolder.getBean(SampleService.class);
HvlApplicationContextHolder.getEnvironment();
HvlApplicationContextHolder.getSystemLocale();
}
}
Uygulama içerisinde Bean'ler arası event mekanizmasına destek sağlamaktadır. Bunun için HvlApplicationEventListener
ve HvlApplicationEventPublisher
sınıfları kullanılmaktadır.
hvl-infra altında bulunan 'application-hvl-context.yml' dosyasıyla konfigure edilebilmektedir.
Crypto#
Uygulamada şifreleme işlemlerinde kullanılmaktadır. (Örneğin veritabanı kolonlarında şifreleme vb.) Güncel sürümde AES destek verilmektedir.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.context.holder.HvlApplicationContextHolder;
import tr.com.havelsan.javarch.crypto.data.HvlCryptoType;
import tr.com.havelsan.javarch.crypto.service.HvlCryptoServiceBuilder;
/**
* @author javarch
*/
@SpringBootApplication
public class HvlSampleApplication {
public static void main(String[] args) {
SpringApplication.run(new Class[]{HvlSampleApplication.class}, args);
final HvlCryptoService aesCryptoService =
HvlCryptoServiceBuilder.create(HvlCryptoType.AES).setKey("mySecretKey").build();
final String encryptText = aesCryptoService.encrypt("test");
final String decryptText = aesCryptoService.decrypt(encryptText);
}
}
Exception#
Altyapıdan checked ve unchecked exception kullanımı sağlanmaktadır. Bu sınıflar HvlCheckedException
ve HvlUncheckedException
sınıflarıdır.
Exception sınıfları içerisinde HvlErrorDetail
nesnesi bulunmaktadır. Bir isteğin yaşam döngüsü boyunca hata alması durumunda HvlErrorDetail
alanı vasıtası ile bilgi dönülmektedir.
Initializer#
Uygulamaya ilklendirme özelliği kazandırmaktadır. İlklendirme belirli bir path üzerindeki script dosyaları ile yapılabildiği gibi aynı zamanda git üzerinden de script dosyalarını okuyup ilklendirme yapılabilmeyi sağlamaktadır.
hvl-infra altında bulunan 'application-hvl-data.yml' dosyasıyla konfigure edilebilmektedir.
Bağımlılık eklendikten sonra git ilklendirmesi için HvlInitializerGitProperties
sınıfından extend edip propertyler bağlanarak kullanıma hazır hale getirilebilir.
@ConfigurationProperties(prefix = HvlEnableRToolConfigurationConstant.REPORT_INITIALIZER_PROPERTIES_PREFIX)
public class HvlRToolReportInitializerGitProperties extends HvlInitializerGitProperties {
}
Git kullanmadan yalnızca path üzerinden ilklendirme özelliği kazandırılmak isteniyorsa aşağıdaki örnekteki gibi HvlInitializerProperties
sınıfı exten edilip propertyler bağlanabilir.
@ConfigurationProperties(prefix = HvlEnableRToolConfigurationConstant.REPORT_INITIALIZER_PROPERTIES_PREFIX)
public class HvlRToolReportInitializerProperties extends HvlInitializerProperties {
}
Sonrasında aşağıdaki gibi HvlInitializerGitServiceImpl
sınıfından extend eden bir ilklendirme komponenti ile ilklendirme süreci tamamlanabilir.
@Component
@ConditionalOnProperty(
prefix = HvlEnableRToolConfigurationConstant.REPORT_INITIALIZER_PROPERTIES_PREFIX,
name = HvlRToolReportInitializerProperties.ENABLED_PROPERTY_NAME,
havingValue = BooleanUtils.TRUE
)
public class HvlRToolReportInitializer
extends HvlInitializerGitServiceImpl implements InitializingBean {
private final HvlRToolReportInitializerProperties reportInitializerProperties;
private final HvlRToolBatchedReportImportProcessor batchedReportImportProcessor;
public HvlRToolReportInitializer(
HvlRToolReportInitializerGitProperties reportInitializerGitProperties,
HvlRToolReportInitializerProperties reportInitializerProperties,
HvlRToolBatchedReportImportProcessor batchedReportImportProcessor) {
super(reportInitializerGitProperties);
this.reportInitializerProperties = reportInitializerProperties;
this.batchedReportImportProcessor = batchedReportImportProcessor;
}
/**
* {@inheritDoc}
*/
@Override
public void afterPropertiesSet() throws Exception {
initialize();
}
/**
* {@inheritDoc}
*/
@Override
protected void doInit(String path) {
final Path batchedReportImportFilePath = Path.of(path)
.resolve(this.reportInitializerProperties.getBatchedReportImportFilePath());
batchedReportImportProcessor.importReportTemplatesFrom(batchedReportImportFilePath)
.block();
}
}
Service#
Uygulamadan dışarıya açılan servis uçları (Rest Controller) buradan konfigure edilmektedir. (Örneğin serialization kuralları, gzip, cors, cookie vb.)
HvlHttpHeader sınıfında altyapının isteklerde (Http request) ve cevaplarda (Http response) kullandığı özel 'header' alanları bulunmaktadır.
Uygulamada istekle (Http request) ilgili bilgilere anlık ulaşabilmek için HvlServiceContext
ve HvlServiceContextHolder
sınıfları bulunmaktadır.
HvlServiceContextHolder
kullanım örneği:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.service.context.holder.HvlServiceContextHolder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author javarch
*/
@SpringBootApplication
public class HvlSampleApplication {
public static void main(String[] args) {
SpringApplication.run(new Class[]{HvlSampleApplication.class}, args);
final HttpServletRequest servletRequest = HvlServiceContextHolder.getServletRequest();
final HttpServletResponse servletResponse = HvlServiceContextHolder.getServletResponse();
}
}
HvlServiceContext
kullanım örneği:
import org.springframework.stereotype.Service;
import tr.com.havelsan.javarch.service.context.HvlServiceContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Service
public class SampleService {
private final HvlServiceContext serviceContext;
public SampleService(HvlServiceContext serviceContext) {
this.serviceContext = serviceContext;
}
public void test() {
final HttpServletRequest servletRequest = serviceContext.getServletRequest();
final HttpServletResponse servletResponse = serviceContext.getServletResponse();
}
}
Uygulamadan dışarıya açılan servis uçlarının (Rest Controller) döneceği verileri standartlaştırmak için HvlResponse
ve HvlResponseEntity
sınıfları bulunmaktadır. Bu sınıflar sayesinde payload, header, errorDetail gibi alanlar istemciye standart olarak dönülmektedir. HvlResponseEntity
objelerin byte array gibi yapılarda geriye dönülmesinin istendiği durumlarda kullanılmaktadır.
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tr.com.havelsan.javarch.service.data.HvlResponse;
import tr.com.havelsan.javarch.service.data.HvlResponseEntity;
@RestController
@RequestMapping("/sample")
public class SampleController {
@GetMapping(path = "/response", produces = MediaType.APPLICATION_JSON_VALUE)
public HvlResponse<String> response() {
return new HvlResponse<>("Response sample");
}
@GetMapping(path = "/response-entity", produces = MediaType.APPLICATION_JSON_VALUE)
public HvlResponseEntity<String> responseEntıty() {
return new HvlResponseEntity<>("Response entity sample");
}
}
Uygulamadan dışarıya açılan servis uçlarının (Rest Controller) hata fırlatması (throw) durumunda hataya özgü HttpStatus
bilgisini cevaba (Http response) eklemeyi sağlayan yapı bulunmaktadır. Bu yetenek @HvlExceptionHttpStatus
anotasyonu ile sağlanmaktadır.
import org.springframework.http.HttpStatus;
import tr.com.havelsan.javarch.exception.HvlCheckedException;
import tr.com.havelsan.javarch.exception.model.HvlErrorDetail;
import tr.com.havelsan.javarch.service.annotation.HvlExceptionHttpStatus;
@HvlExceptionHttpStatus(code = HttpStatus.BAD_REQUEST)
public class SampleInvalidRequestException extends HvlCheckedException {
public static final String ERROR_CODE = "code";
public static final String ERROR_MESSAGE = "message";
public SampleInvalidRequestException() {
super(ERROR_MESSAGE, new HvlErrorDetail(ERROR_CODE, ERROR_MESSAGE));
}
public SampleInvalidRequestException(HvlErrorDetail errorDetail) {
super(errorDetail);
}
}
HvlRestExceptionHandler sınıfı ile sistemde handle edilen veya edilmeyen hatalar filtrelenip gerekli standartlara göre istemciye dönülmektedir. (HvlResponse
ve HvlResponseEntity
olarak) Burada geliştirici tarafında yutulan hatalar ele alınmamaktadır.
HvlCookieUtil
sınıfı ile 'cookie' ile ilgili hizmetler sunulmaktadır. Örnek kullanım:
import org.springframework.stereotype.Service;
import tr.com.havelsan.javarch.service.configuration.properties.HvlCookieProperties;
import tr.com.havelsan.javarch.service.context.HvlServiceContext;
import tr.com.havelsan.javarch.service.util.HvlCookieUtil;
@Service
public class SampleService {
private final HvlServiceContext serviceContext;
public SampleService(HvlServiceContext serviceContext) {
this.serviceContext = serviceContext;
}
public void test() {
HvlCookieUtil.addCookie(serviceContext.getServletResponse(),
"cookieName",
"cookieValue",
new HvlCookieProperties());
}
}
ÖNERİ: Bean kullanımlarında servis arayüz sınıflarında @Validated ve @Valid annotationları kullanılmalıdır. Arayüz içerisindeki metotlara da gerekli validasyon annotationları konulmalıdır. Böylece metot içerisindeki iş mantığı çalışmadan ve kaynak tüketmeden önce validasyondan geri döner.
import org.springframework.validation.annotation.Validated;
import tr.com.havelsan.javarch.data.commons.pageable.HvlPage;
import tr.com.havelsan.javarch.samples.jpa.data.entity.HvlJpaSample;
import tr.com.havelsan.javarch.samples.jpa.data.model.HvlJpaSampleModel;
import tr.com.havelsan.javarch.samples.jpa.data.model.query.HvlJpaSampleQueryModel;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import java.util.List;
@Validated
public interface HvlSampleService {
HvlJpaSampleModel save(@Valid @NotNull HvlJpaSampleModel sampleModel);
HvlJpaSampleModel update(@Valid @NotNull HvlJpaSampleModel sampleModel);
void deleteById(@NotNull @Positive Long id);
List<HvlJpaSampleModel> getList();
List<HvlJpaSampleModel> queryList(HvlJpaSampleQueryModel sampleQueryModel);
List<HvlJpaSampleModel> queryList(HvlJpaSampleQueryModel queryModel, String locale);
HvlPage<HvlJpaSampleModel> queryPage(HvlJpaSampleQueryModel sampleQueryModel);
List<HvlJpaSample> getAllSample();
void saveAll();
void updateAll();
void deleteAll(List<HvlJpaSample> entities);
}
hvl-infra altında bulunan 'application-hvl-service.yml' dosyasıyla konfigure edilebilmektedir.
Swagger#
Uygulamaya swagger yeteneği kazandırmak için kullanılmaktadır. Cloud ve Boot için destek sağlanmaktadır.
hvl-infra altında bulunan 'application-swagger.yml' dosyasıyla konfigure edilebilmektedir.
Util#
Uygulama geliştirirken genel destek sınıfları sunulmaktadır. Destek sınıfları:
- Dil ve ortak kullanılacak sabitler için
HvlCommonConstant
,HvlLanguageConstant
- Sertifika işlemleri için
HvlCertificateUtil
- Cron işlemleri için
HvlCronUtil
- IP ayrıştırma işlemleri için
HvlIPUtil
- String işlemleri için
HvlStringUtil
Cloud Framework#
Uygulamaları cloud yapısına uygun şekilde geliştirmek için hizmete sunulan altyapı bileşenidir. Temel teknoloji bileşenleri olarak OpenFeign, Spring Cloud kullanılmaktadır. Exception handling, tracing, registry integration vb. bileşenleri içermektedir. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.
Configuration#
Mikro servis mimaride çok sayıda uygulama dağıtık mimaride bulunmaktadır. Bu durum uygulamalar ayağa kalkarken gerekli konfigurasyonu nasıl vereceğimiz problemini doğurmaktadır. EKSEN; config-server entegrasyonu ile konfigurasyonlar için tek kaynaktan beslenme sağlamaktadır.
config-server kullanılırken dikkat edilmesi gereken konular bulunmaktadır. Bunlar;
- config-server üzerinden gelen özellikler ve dosyalar baskınlık göstermektedir. Uygulamada resources altında bulunan .yml uzantılı dosyalar ve içerisindeki özellikler eğer config-server üzerinden gelmiyorsa kullanılabilir. Aksi takdirde **config-server**dan gelen ezecektir.
- Uygulama ayağa kaldırılırken enviroment olarak verilen özellikler config-server üzerinden gelen özellikleri ezmektedir.
- config-server üzerinden override edilmiş özellikler herhangi bir şekilde ezilemez. Özelliğin her uygulama için aynı olması isteniyorsa bu kullanım tavsiye edilmektedir. Bu yeteneğin kullanılması için config-server ayağa kaldırılırken environment'ların önüne 'SPRING_CLOUD_CONFIG_SERVER_OVERRIDES_' ön ekinin eklenmesi gerekmektedir. Örnek:
version: '2.1'
services:
config-server-service:
.
.
environment:
SPRING_CLOUD_CONFIG_SERVER_OVERRIDES_HVL_OAUTH_SESSION_SERVICE_URL: http://hvlsessionserver:9080
SPRING_CLOUD_CONFIG_SERVER_OVERRIDES_HVL_OAUTH_SESSION_SERVICE_PATH: /
Uygulamalarda config-server bağlantısı bootstrap.yml üzerinden sağlanmaktadır.
spring:
config:
import:
- optional:configserver:${spring.cloud.config.uri}
cloud:
config:
uri: ${SERVER_CONFIGURATION_REMOTE_URL:http://localhost:8888/config}
profile: ${SERVER_CONFIGURATION_CLOUD_PROFILE:cloud-eureka,cloud-tracing,hvl-context,hvl-data,hvl-logger,hvl-mail,hvl-security,hvl-service,hvl-session,database-datasource,instance,kafka,management,swagger,apm}
label: ${SERVER_CONFIGURATION_LABEL:framework(_)spring}
enabled: ${SERVER_CONFIGURATION_REMOTE_ENABLED:true}
username: ${CONFIG_AUTH_USERNAME:admin}
password: ${CONFIG_AUTH_PASSWORD:123456}
logging:
auth:
username: ${LOGGING_AUTH_USERNAME:${spring.cloud.config.username}}
password: ${LOGGING_AUTH_PASSWORD:${spring.cloud.config.password}}
config: ${LOGGING_CONFIG:${spring.cloud.config.uri}/${spring.application.name}/default/framework(_)log4j2(_)instance(_)oauth/log4j2.yml}
EKSEN olarak loglama ve genel bütün konfigürasyonları config-server üzerinden almaktayız. Burada profile mantığı kullanılarak parçalama yapılmıştır. Konfigürasyon dosyalarını ve config-server dosyalarını hvl-infra adresinden inceleyebilirsiniz.
Eureka Web Starter#
Mikro servis mimaride dağıtık servisler hakkında bilgi almak için service-registry olarak Eureka kullanılmasına destek sağlamaktadır. Eureka entegrasyonu için gerekli temel yapıları sağlamaktadır.
hvl-infra altında bulunan 'application-cloud-eureka.yml' dosyasıyla konfigure edilebilmektedir.
Kubernetes Web Starter#
Mikro servis mimaride dağıtık servisler hakkında bilgi almak için service-registry olarak Kubernetes kullanılmasına destek sağlamaktadır. Kubernetes entegrasyonu için gerekli temel yapıları sağlamaktadır.
hvl-infra altında bulunan 'application-cloud-kubernetes.yml' dosyasıyla konfigure edilebilmektedir.
Service#
Mikro servis yapılarda uygulamaların birbirlerine declarative yapıda istek (Http request) atabilmesini sağlamaktadır. Yani geliştirici istek atacağı interface'i tanımladıktan sonra java üzerinden implementasyon yapmadan istek atabilmektedir. Burada teknoloji olarak OpenFeign kullanılmaktadır.
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "", url = "", path = "")
public interface SampleRestService {
@GetMapping(path = "/sample", produces = MediaType.APPLICATION_JSON_VALUE)
String sample();
}
Declarative yapıları injection yapmadan oluşturmak için HvlFeignClientBuilder
sınıfını kullanılabilir.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.cloud.service.builder.HvlFeignClientBuilder;
import tr.com.havelsan.javarch.samples.jpa.data.logic.SampleRestService;
/**
* @author javarch
*/
@SpringBootApplication
public class HvlSampleApplication {
public static void main(String[] args) {
SpringApplication.run(new Class[]{HvlSampleApplication.class}, args);
final SampleRestService sampleRestService = HvlFeignClientBuilder.create().target(SampleRestService.class);
}
}
FeignClient sınıflarının decoder, encoder, interceptor, logger alanlarını da konfigure edebilirsiniz.
EKSEN, decoder işlemi için HvlDecoder
interface'inden türeyen HvlFeignClientDecoder, HvlFeignClientErrorDecoder, HvlFeignResponseDecoder
sınıfları ile destek sağlamaktadır.
EKSEN, encoder işlemi için HvlFeignEncoder
sınıfı ile destek sağlamaktadır.
EKSEN, interceptor işlemi için HvlCloudServiceRequestInterceptor
sınıfı ile destek sağlamaktadır.
EKSEN, logger işlemi için HvlFeignClientLogger
sınıfı ile destek sağlamaktadır.
NOT: Yukarıda sağlanan desteklerin kullanımı zorunlu değildir. Uygulamaya göre özelleştirilebilir hatta arttırılabilir. FeignClient özelinde bile yazılabilir. Fakat burada özelleştirme yapılırken altyapının sağladığı destekler incelenmeli ve isteğin yaşam döngüsü bozulmamalıdır.
Http isteği için FeignClient declarative yapısının kullanılmasının en büyük problemi, mikro servis mimaride uygulamalar dağıtık mimaride farklı JVM de çalıştığı için hatanın ele alınmasıdır.
EKSEN, FeignClient kullanımında istek sonucunda hatayı JVM'de ele alınmasını sağlanmıştır. Bunun için FeignClient uçlarında kullanılacak hataların @HvlFeignClientError
annotation'ı ile işaretlenmesi gerekmektedir.
EKSEN, Feign client uçları için @HvlPrivateFeignRestService
ve @HvlPublicFeignRestService
sağlamaktadır. Bu uçların şuan için bir işlevi yoktur ancak dışarıya açılmak istenen uçlar ve gizli kalması istenen uçların kod okunaklılığı açısından bu anotasyonlarla işaretlenmesi önerilir.
import org.springframework.http.HttpStatus;
import tr.com.havelsan.javarch.cloud.service.annotation.HvlFeignClientError;
import tr.com.havelsan.javarch.exception.HvlCheckedException;
import tr.com.havelsan.javarch.exception.model.HvlErrorDetail;
import tr.com.havelsan.javarch.service.annotation.HvlExceptionHttpStatus;
@HvlFeignClientError
@HvlExceptionHttpStatus(code = HttpStatus.BAD_REQUEST)
public class SampleInvalidRequestException extends HvlCheckedException {
public static final String ERROR_CODE = "code";
public static final String ERROR_MESSAGE = "message";
public SampleInvalidRequestException() {
super(ERROR_MESSAGE, new HvlErrorDetail(ERROR_CODE, ERROR_MESSAGE));
}
public SampleInvalidRequestException(HvlErrorDetail errorDetail) {
super(errorDetail);
}
}
NOT: FeignClient hatalarının sistem tarafından taranması gerekmektedir.
hvl.core.service.cloud.feign.client.exception.scan-path
özelliğine hatanın bulunduğu package verilmesi gerekmektedir.ÖNERİ: FeignClient kullanımlarında arayüz sınıflarında @Validated ve @Valid annotationları kullanılmalıdır. Arayüz içerisindeki metotlarada gerekli validasyon annotationları konulmalıdır. Böylece istek atılmadan validasyondan geri döner.
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import javax.validation.constraints.NotEmpty;
@FeignClient(name = "", url = "", path = "")
@Validated
public interface SampleRestService {
@GetMapping(path = "/sample", produces = MediaType.APPLICATION_JSON_VALUE)
String sample(@NotEmpty String plainText);
}
hvl-infra altında bulunan 'application-hvl-service.yml' dosyasıyla konfigure edilebilmektedir.
Session#
Uygulama içerisinde istek yaşam döngüsünde session bilgisinin taşınmasını ve kullanılmasını sağlayan altyapı bileşenidir. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.
Context#
Uygulamada isteğin yaşam döngüsü boyunca Session bilgisi burada tutulmaktadır. HvlSession
sınıfı ile tutulmaktadır.
İki şekilde kullanılabilmektedir:
- DI (Dependency Injection) ile kullanılabilir.
import org.springframework.stereotype.Service;
import tr.com.havelsan.javarch.session.common.model.HvlSession;
import tr.com.havelsan.javarch.session.context.HvlSessionContext;
@Service
public class SampleService {
private final HvlSessionContext sessionContext;
public SampleService(HvlSessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public void test() {
final HvlSession session = sessionContext.currentSession();
}
}
- Bean olmayan sınıflar statik olarak 'Holder' üzerinden kullanılabilir.
import tr.com.havelsan.javarch.session.common.model.HvlSession;
import tr.com.havelsan.javarch.session.context.HvlSessionContextHolder;
import java.util.Objects;
public final class SampleService {
public static SampleService INSTANCE;
public static SampleService getInstance() {
if (Objects.isNull(INSTANCE)) {
INSTANCE = new SampleService();
}
return INSTANCE;
}
public static void test() {
final HvlSession session = HvlSessionContextHolder.currentSession();
}
}
Uygulamada header ve cookie'den alınan bilgiler HvlSessionContextFilter
sınıfında ayrıştırılarak HvlSession
sınıfı ile session bilgisi tutulmaktadır.
NOT:
HvlSession
sınıfı içerisindeattributeMap
alanı bulunmaktadır. Yani istenildiği zaman bu alan kullanılarak session genişletilebilir.Session genişletilmesinin 2 yöntemi bulunmaktadır: *
HvlSessionContextManagerImpl
sınıfı extend edilerek değiştirilmek istenen metotlar değiştirilebilir. *HvlSessionContextFilter
filtesi yerine uygulamaya özgü filtre yazılabilir. Bu filtre sonrasında çalıştırılarakattributeMap
alanına ekleme yapılabilir.
hvl-infra altında bulunan 'application-hvl-session.yml' dosyasıyla konfigure edilebilmektedir.
Security#
Uygulama içerisinde istek yaşam döngüsünde güvenlik ile ilgili bilgilerin taşınmasını ve kontrolünün yapılmasını sağlayan altyapı bileşenidir. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.
ÖNERİ:
@PreAuthorize
gibi annotationlar'ın RestController üzerine konulması tavsiye edilmektedir. Servise yetkisi olan kişi RestController'dan geçtikten sonra güvenliğe takılmamalıdır. Karmaşık yetki havuzlarının oluşmasını önlemektedir.
@RestController
@RequestMapping("${hvl.system.service.menu-item.controller-path:/menu}")
public class HvlMenuItemRestController implements HvlMenuItemOperationalRestService, HvlMenuItemRestService {
private final HvlMenuItemService menuItemService;
/**
* Instantiates a new HvlMenuItemRestController.
*
* @param menuItemService the menu item service
*/
public HvlMenuItemRestController(HvlMenuItemService menuItemService) {
this.menuItemService = menuItemService;
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("hasAuthority('keysys')")
public HvlResponse<Void> save(@NotNull @Valid @RequestBody HvlMenuItemModel menuItemModel) {
menuItemService.save(menuItemModel);
return new HvlResponse<>();
}
}
JWT#
CSRF (Cross Site Request Forgery) saldırılarını önlemek amacı ile kullanılmaktadır. Yani dışarıdan gelen isteklerin authentication (kimlik doğrulama) kısmından geçmiş olduğunu teyit etmek içindir. EKSEN, authentication ile ilgili verileri HVL_SESSION_ID
ve HVL_TOKEN
alanları ile taşımaktadır. (Daha detaylı bilgi için: https://jwt.io/)
NOT:
HVL_TOKEN
değişkeni application-hvl-security.yml alanı içerisindehvl.core.security.jwt.header.token
alanından değiştirilebilir. Değiştirilmesi durumunda alana bağlı durumlar da düzenlenmelidir.
JWT üretmek için HvlJwtGeneratorBuilder
sınıfı kullanılmaktadır. JWT üretirken şifreleme imzası (signature) önem taşımaktadır. HvlJwtAlgorithm
sınıfı ile şifreleme algoritması seçilmektedir.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.jwt.generator.builder.HvlJwtGeneratorBuilder;
import tr.com.havelsan.javarch.jwt.parser.algorithm.HvlRS256Algorithm;
import tr.com.havelsan.javarch.jwt.parser.model.HvlRSKeyPair;
/**
* @author javarch
*/
@SpringBootApplication
public class HvlJpaServerApplication {
public static void main(String[] args) {
SpringApplication.run(new Class[]{HvlJpaServerApplication.class}, args);
HvlJwtGeneratorBuilder.create()
.setAlgorithm(new HvlRS256Algorithm(new HvlRSKeyPair()))
.build();
}
}
JWT içerisine konulan bilgiyi ayrıştırmak (parse) için HvlJwtParserBuilder
sınıfı kullanılmaktadır. Burada önemli olan üretim yapılan algoritma ile ayrıştırma yapılan algoritmanın türünün aynı olması gerekmektedir. (HvlJwtAlgorithm
aynı olmalıdır.)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.jwt.parser.algorithm.HvlRS256Algorithm;
import tr.com.havelsan.javarch.jwt.parser.builder.HvlJwtParserBuilder;
import tr.com.havelsan.javarch.jwt.parser.model.HvlRSKeyPair;
/**
* @author javarch
*/
@SpringBootApplication
public class HvlJpaServerApplication {
public static void main(String[] args) {
SpringApplication.run(new Class[]{HvlJpaServerApplication.class}, args);
HvlJwtParserBuilder.create()
.setAlgorithm(new HvlRS256Algorithm(new HvlRSKeyPair()))
.build();
}
}
NOT: EKSEN, JWT üretimi için varsayılan olarak
HvlRS256Algorithm
(hvl.core.security.jwt.key-provider.algorithm
) algoritması kullanmaktadır. RSA algoritmasının kullanılabilmesi için private ve public key olması gerekmektedir.EKSEN'de varsayılan olarak
hvl.pem
vehvl.public.pem
dosyaları bulunmaktadır. Bu dosyalarhvl.core.security.jwt.key-provider.file.public-file-path
vehvl.core.security.jwt.key-provider.file.private-file-path
alanları ile değiştirilebilmektedir.
hvl-infra altında bulunan 'application-hvl-security.yml' dosyasıyla konfigure edilebilmektedir.
group: 'tr.com.havelsan.framework.security', name: 'hvl-jwt-generator'
group: 'tr.com.havelsan.framework.security', name: 'hvl-jwt-parser'
group: 'tr.com.havelsan.framework.security', name: 'hvl-jwt-security'
Session Provider#
Sisteme giriş yapmış (authenticated) bir istemcinin her bir isteğinde herhangi bir uygulama (Örneğin session-server) ile kimlik doğrulaması yapabileceği arayüz sunulmaktadır. HvlSecuritySessionProvider
sınıfı implement edilerek oturum veya istek bilgileri güvenlik katmanına özelleştirilerek aktarılabilir.
NOT: Mikro servis mimarilerde uygulamalar stateless olduğu için sisteme giriş yapan kullanıcıların oturum bilgileri bir sistemde tutulması gerekmektedir.
HvlSecuritySessionProvider
sınıfı implement edilerek herhangi bir uygulama ile entegre olunabilir.
Context#
Uygulama güvenlik ile ilgili verilere ulaşmamızı sağlamaktadır.
İki şekilde kullanılabilmektedir:
- DI (Dependency Injection) ile kullanılabilir.
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import tr.com.havelsan.javarch.security.common.model.HvlAuthenticationToken;
import tr.com.havelsan.javarch.security.context.HvlSecurityContext;
import java.util.Collection;
@Service
public class SampleService {
private final HvlSecurityContext securityContext;
public SampleService(HvlSecurityContext securityContext) {
this.securityContext = securityContext;
}
public void test() {
final HvlAuthenticationToken authentication = securityContext.getAuthentication();
final Collection<GrantedAuthority> authorities = authentication.getAuthorities();
}
}
- Bean olmayan sınıflar statik olarak 'Holder' üzerinden kullanılabilir.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.security.common.model.HvlAuthenticationToken;
import tr.com.havelsan.javarch.security.context.HvlSecurityContextHolder;
/**
* @author javarch
*/
@SpringBootApplication
public class HvlJpaServerApplication {
public static void main(String[] args) {
SpringApplication.run(new Class[]{HvlJpaServerApplication.class}, args);
final HvlAuthenticationToken authentication = HvlSecurityContextHolder.getAuthentication();
}
}
NOT: Hiyerarşik yetki desteği sağlanmaktadır. Yetki Ekleme sayfasından detaylı bilgi edinilebilir.
hvl-infra altında bulunan 'application-hvl-security.yml' dosyasıyla konfigure edilebilmektedir.
Web Starter#
EKSEN thymeleaf ile geliştirilen giriş ekranını sağlamaktadır. Uygulamalarda kullanılarak login işlemi gerçekleştirilebilir.
@Bean
@ConditionalOnMissingBean
AuthenticationProvider authenticationProvider(HvlWebSecurityProperties webSecurityProperties){
return new HvlWebSecurityInmemoryAuthenticationProvider(webSecurityProperties);
}
Sağlanan altyapı ekranı ile herhangi bir sisteme entegre olmak istenirse yukarıdaki Bean ezilmesi yeterli olacaktır. Varsayılan olarak inmemory çalışmaktadır. Kullanıcı bilgileri 'application-hvl-web-security.yml' içerisinden tanımlanmaktadır.
hvl-infra altında bulunan 'application-hvl-web-security.yml' dosyasıyla konfigure edilebilmektedir.
Cloud Security#
Security paketinin cloud yapısına uygun entegre edilmesi ile oluşan altyapı bileşenidir. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.
JWT Session Provider#
HvlSecuritySessionProvider
sınıfının cloud entegrasyonunu sağlamaktadır. HvlCloudJwtSessionProviderImpl
implementasyonu ile kimlik doğrulama yapılacak uygulama ile entegre olmaktadır.
NOT: EKSEN varsayılan olarak KEYSIS ürünü ile entegre çalışmaktadır.
hvl-infra altında bulunan 'application-hvl-security.yml' dosyasıyla konfigure edilebilmektedir.
Session Provider#
Güvenlik katmanında kimlik doğrulama işlemi için entegrasyon arayüzü sağlanmaktadır. Güvenlik katmanı ile entegre olacak uygulamanın bu arayüze uygun servis ucu açması gerekmektedir.
NOT: KEYSIS ürününde 'session-server' kimlik yönetimi için entegre durumdadır.
hvl-infra altında bulunan 'application-hvl-security.yml' dosyasıyla konfigure edilebilmektedir.
Cache#
Uygulamalarda in-memory ve distributed cache yeteneklerini sağlayan altyapı bileşenidir. Caffeine cache ve redis cache destekleri sağlanmaktadır. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.
ÖNERİ: Cache kullanımının DTO üzerinden yapılması tavsiye edilmektedir. Gereksiz ve çok değişecek veriler cache'e konulmamalıdır.
Core#
Uygulamada cache yönetimi için HvlCacheManager
sınıfı sunulmaktadır. Böylece uygulama içerisinde annotion dışında cache yönetimi yapılmaktadır.
NOT: hvl-cache-core kütüphanesi kullanılan sağlayıcıya göre entegrasyon göstermektedir. (Redis, EhCache, Caffeine vb...)
Redis#
Java dünyasında Redis ile entegrasyon için kullanılan en popüler teknolojiler Jedis ve Lettuce'dur. EKSEN tarafından bu iki teknolojiye de destek verilmektedir.
hvl-infra altında bulunan 'application-redis.yml' dosyasıyla konfigure edilebilmektedir.
Caffeine#
EKSEN, in memory olarak çalışan caffeine cache desteği sağlamaktadır. In memory cache kullanımları için oldukça performanslı çalışır.
Data#
Uygulamalarda veri katmanında kullanılacak fonksiyonların sağlandığı altyapı bileşenidir. ORM işlemleri için JPA ve QueryDSL teknolojileri tercih edilip bu teknolojiler üzerinde özelleştirmeler yapılmıştır. Auditing altyapısı için Javers ve Envers teknolojilerine destek verilmektedir. Aynı zamanda sorgulama, view, auditing için özelleştirilmiş yetenekler sağlamaktadır ve ldap, redis gibi teknolojilerin veri katmanı destekleri de bu bileşende bulunmaktadır. Başlıca sağlanan katmanlar:
- Javers, Envers
- Model
- Entity
- JDBC İlklendirme
- PreLiquibase
- Model Çeviricileri
- Hibernate Anotasyonları
Converter#
Converter bileşeni Hibernate, JPA teknolojilerine bağlı olmadan nesneler arası dönüştürücüleri sağlamaktadır. Aynı zamanda enum sınıfların ordinal dışında veritabanı işlemleri için dönüştürücüsünü sağlamaktadır.
NOT:
HvlGenericConverter
veHvlGenericHibernateConverter
sınıfları runtime anında reflection ile çalıştığı için performansal olarak önerilmemektedir.HvlGenericHibernateConverter
dönüştürücüsü hibernate annotation'larına göre davranış göstermektedir. Herhangi bir veritabanı bağlılığı gerekmemektedir.
JPA#
Veritabanı işlemlerini sağlayan altyapı bileşenidir. Veritabanı işlemlerini yapacak olan sınıflar declarative olarak sağlanmaktadır.
Hibernate enhancement plugin desteği ile varsayılan olarak 'dynamic update' aktif sunulmaktadır. Eğer sınıfta 'dynamic update' çalışması istenmiyorsa @HvlDynamicUpdateExclude
annotation kullanılmalıdır.
NOT: 'dynamic update' performans için önemlidir. Varitabanı işlemlerinde 'update' işleminde sadece değişen alanların gönderilmesini sağlamaktadır.
JPA kullanırken transaction kullanımı önemlidir. Transaction için @Transactional
annotation'ını kullanılmaktadır. @Transactional
annotation'ını unchecked exception'larda direkt rollback almaktadır. Fakat checked işlemleri için geliştiricinin bu durumu ele alması beklenmektedir. Altyapıda bütün checked hatalar için rollback aktif olması için @HvlTransactionalRollbackForCheckedException
annotation'ı bulunmaktadır.
Altyapıda veritabanı işlemlerinde kolon bazlı şifreleme yeteneği bulunmaktadır. @Convert
annotation'ı ile kullanılmaktadır.
import javax.persistence.Convert;
@Convert(converter = HvlStringCryptoConverter.class)
private String identityNumber;
NOT: Kolon şifreleme aktif etmek için 'application-database-datasource.yml' içerisinde
spring.jpa.properties.hibernate.encryption_enabled
alanınıntrue
yapılması gerekmektedir. Altyapı olarak şifreleme algoritması olarak şu anda AES desteklenmektedir. AES üzerinden şifreleme işleminde kullanılacak olankey
değerispring.jpa.properties.hibernate.encryption_key
alanından verilmesi gerekmektedir.
Altyapı kullanılarak yapılan veritabanı işlemlerinde işlemi kimin yaptığı, tarihi gibi işlem sırasında otomatik verilmesi gereken değerler HvlJpaAwareProvider
sınıfı ile yönetilmektedir. Geliştiriciler tarafından özelleştirilebilir.
JPA ile ilgili içeriğe ulaşmak için HvlJpaContext
veya HvlJpaContextHolder
sınıfı kullanılmalıdır.
Veritabanı işlemleri için altyapıdan PostgreSQL ve Oracle veritabanları için dialect bulunmaktadır. Bu dialect'ler özelleştirilmiştir. Örneğin; PostgreSQL için ilike vb. fonksiyonlar eklenmiştir.
NOT: Dialect, 'application-database-datasource.yml' içerisinde
spring.jpa.properties.hibernate.dialect
alanınından yönetilmektedir. Kullanılmak istenen dialect paket bilgisi ile verilmelidir. Postgresql içintr.com.havelsan.javarch.data.jpa.dialect.postgresql.HvlPostgreSQL10Dialect
ve Oracle içintr.com.havelsan.javarch.data.jpa.dialect.oracle.HvlOracleSQL12cDialect
altyapıdan sağlanan dialect'lerdir.
Altyapının sağladığı declarative repository sınıflarını kullanabilmek için konfigurasyon sınıfına aşağıdaki annotation eklenmelidir.
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import tr.com.havelsan.javarch.data.jpa.factory.HvlJpaRepositoryFactoryBean;
@EnableJpaRepositories(basePackages = {"base_package"},
repositoryFactoryBeanClass = HvlJpaRepositoryFactoryBean.class)
Veritabanı sorguları için Querydsl teknolojisi kullanılmaktadır. Altyapıya özgü alanların varsayılan değerlerinin verildiği ve sorgu (predicate) oluşturmaya yarayan HvlBaseQueryGenerator
sınıfından türeyen HvlEntityQueryGenerator
ve HvlViewQueryGenerator
sınıfı bulunmaktadır.
NOT: Sorgulama işlemi için bu sınıflardan türeyen sınıfları kullanmak önerilmektedir. 'Soft delete' gibi özel yapılar için yapılan değişiklikler desteklenmektedir. Geliştiricinin ekstra kontrol veya ekleme yapmasına gerek yoktur.
Veritabanı işlemleri için altyapı tarafından 4 tane arayüz sağlanmaktadır:
HvlJpaRepository
:HvlEntity
sınıfından türeyen sınıflar için kullanılan arayüzdür.HvlJpaSearchRepository
: Sorgulama ile ilgili fonksiyonların sağlandığı arayüzdür.HvlJpaSimpleRepository
:HvlSimpleEntity
sınıfından türeyen sınıflar için kullanılan arayüzdür.HvlJpaViewRepository
:HvlView
annotation'a sahip entity sınıfları için persist yeteneklerinin bulunmadığı arayüzdür.
Validasyon işlemleri için 2 adet anotasyon sağlanmaktadır:
@HvlIdValid
: Model ve entity içerisindeki obje alanlarda id alanı validasyonu yapmak için kullanılır.@HvlUuidValid
: Model ve entity içerisindeki obje alanlarda uuid alanı validasyonu yapmak için kullanılır.
hvl-infra altında bulunan 'application-database-datasource.yml, application-hvl-data.yml' dosyasıyla konfigure edilebilmektedir.
Envers#
Veritabanı işlemlerinin izini tutmak için Envers teknolojisi kullanılmaktadır. Envers, nesnenin üzerinde yapılan işlemleri nesnenin tablo isminin sonuna _AUD
eklediği tablo üzerinde tutmaktadır.
Altyapıdan gelen declarative repository kullanımı için aşağıdaki konfigurasyon eklenmelidir.
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import tr.com.havelsan.javarch.data.jpa.envers.factory.HvlEnversJpaRepositoryFactoryBean;
@EnableJpaRepositories(basePackages = {"base_package"},
repositoryFactoryBeanClass = HvlEnversJpaRepositoryFactoryBean.class)
EKSEN, envers veritabanı işlemleri için altyapı tarafından 4 tane arayüz sağlanmaktadır:
HvlEnversJpaRepository
:HvlEntity
sınıfından türeyen sınıflar için kullanılan arayüzdür.HvlEnversJpaLocalizedRepository
:HvlLocalizedEntity
sınıfından türeyen sınıflar için kullanılan arayüzdür.
hvl-infra altında bulunan 'application-database-datasource.yml, application-hvl-data.yml' dosyasıyla konfigure edilebilmektedir.
group: 'tr.com.havelsan.framework.data', name: 'hvl-data-jpa-envers'
group: 'tr.com.havelsan.framework.data', name: 'hvl-data-jpa-envers-redis-service'
group: 'tr.com.havelsan.framework.data', name: 'hvl-data-jpa-envers-service'
Session Aware#
Veritabanı işlemleri sırasında mevcut session'daki kullanıcı bilgisini ve işlem yapılan tarih saat bilgisini sağlayan EKSEN bileşenidir. Bu bilgilerin veritabanı kayıtlarına otomatik olarak eklenmesi isteniyorsa bu bileşen kullanılmalıdır.
NOT: Özelleştirilmesi gereken durumlarda bu bileşen devreden çıkarılmalı ve
HvlJpaAwareProvider
arayüzü implement edilmelidir.
Redis Second Level Cache#
hvl-infra altında bulunan 'application-database-datasource.yml, redisson-slc.yaml' dosyasıyla konfigure edilebilmektedir.
Redis#
Redis'in manuel olarak kullanılması gerektiği durumlar için EKSEN tarafından sağlanan bileşendir. RedisTemplate
sınıfı bean olarak EKSEN tarafından konfigüre edilerek sağlanır.
Domain Model#
EKSEN tarafından sağlanan Entity sınıflarının sunulduğu bileşendir. Aynı zamanda UUID generator, Sequence generator, veritabanı işlemi esnasında UUID ayarlama özellikleri bu bileşenden sağlanmaktadır. hvl-data-jpa bileşeninin kullanıldığı durumlarda bu bileşen de gelmektedir.
Sağlanan Entity sınıfları şunlardır:
- HvlEntity: Temel entity sınıfıdır.
- HvlHardDeleteEntity
- HvlSoftDeleteEntity
- HvlLocalizedEntity
- HvlLookupEntity
- HvlSimpleEntity: id bilgisi içermeyen entity sınıfıdır.
Sağlanan UUID Generator strategy sınıfları şunlardır:
- HvlEntityDCESecurityBasedUUIDGeneratorStrategy
- HvlEntityDCESecurityBasedUUIDGeneratorStrategy
- HvlEntityRandomBasedUUIDGeneratorStrategy
- HvlEntityTimeBasedUUIDGeneratorStrategy
- HvlEntityTimeOrderedBasedUUIDGeneratorStrategy
- HvlEntityTimeOrderedWithMACBasedUUIDGeneratorStrategy
- HvlEntityTimeWithMACBasedUUIDGeneratorStrategy
DTO Model#
EKSEN tarafından sağlanan Model sınıflarının sunulduğu bileşendir.
Sağlanan modeller şunlardır:
- HvlModel: Temel model sınıfıdır.
- HvlLocalizedModel
- HvlLookupModel
- HvlSimpleModel: id bilgisi içermeyen modeldir.
- HvlQueryModel: Sorgulama işlemleri için kullanılan temel modeldir.
Hibernate Annotations#
EKSEN tarafından Hibernate için sağlanan özelliklerin kullanılması için oluşturulmuş olan anotasyonların sağlandığı altyapı bileşenidir. Şu anotasyonlar sağlanmaktadır:
@HvlEntitySequence
: Bu anotasyon kullanılarak özel sequence isimlendirilmesi yapılabilir. Kullanılmadığı durumlarda veritabanı nesnesindeki tablo ismi ile isimlendirme yapılır.@HvlView
: Veritabanında view olarak kullanılacak nesnelerin işaretlenmesini ve maplenmesini sağlayan anotasyondur.
JDBC Initializer#
Veritabanı ilklendirmesinin dosya üzerinden yapılmasını sağlayan bileşendir. Bu bileşen sayesinde veritabanı ilklendirmeleri için senaryolar yazılarak farklı durumlar için ilklendirmeler tetiklenebilmektedir. Senaryo dosyaları içerisinde type bilgisi sql ve ya scenario değerlerini alabilir.
Senaryo içerisindeki elementler sırayla çalışmaktadır ve çalışan elementlerin bilgisi console'a log basılmaktadır.
NOT: Hata alan bir script olursa console'a error logu basılmaktadır ancak diğer scriptler çalışmaya devam etmektedir. Bu yüzden hata durumlarında dikkatli olunmalıdır.
prod.scenario
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Scenario>
<ScenarioElement type="sql" path="[path]/uniqueConstraint.sql"/>
<ScenarioElement type="sql" path="[path]/functionalIndex.sql"/>
</Scenario>
dev.scenario
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Scenario>
<ScenarioElement type="scenario" path="[path]/prod.scenario"/>
<ScenarioElement type="sql" path="[path]/userType.sql"/>
<ScenarioElement type="sql" path="[path]/userDetail.sql"/>
<ScenarioElement type="sql" path="[path]/eventType.sql"/>
<ScenarioElement type="sql" path="[path]/user.sql"/>
</Scenario>
hvl-infra altında bulunan 'application-hvl-data.yml' dosyasıyla konfigure edilebilmektedir.
Liquibase Initializer#
Liquibase, veritabanı şeması üzerindeki değişiklikleri yönetmeyi ve versiyonlamayı sağlayan açık kaynaklı bir Java kütüphanesidir. Veritabanı şeması üzerindeki değişikliklerin izlenmesini, yönetilmesini ve uygulanmasını sağlar. Kaba tabirle veritabanı üzerinde versiyon kontrol sistemi kurmamıza yardımcı olur.
Preliquibase ise liquibase scriptlerinden önce çalışarak gerekli veritabanı şemasını oluşturmak gibi işlemleri yapmaktadır.
EKSEN, preliquibase ile varsayılan veritabanı şemalarını otomatik olarak oluşturmaktadır.
hvl-infra altında bulunan 'application-database-liquibase.yml' dosyasıyla konfigure edilebilmektedir.
Konfigürasyonları spring.liquibase
ve preliquibase
altında bulunmaktadır.
spring:
liquibase:
default-schema: ${spring.jpa.properties.hibernate.default_schema}
change-log: ${LIQUIBASE_CHANGE_LOG:db/changelog-root.yaml}
enabled: ${LIQUIBASE_ENABLED:false}
drop-first: ${LIQUIBASE_DROP_FIRST:false}
url: ${LIQUIBASE_DB_URL:${spring.datasource.url}}
user: ${LIQUIBASE_DB_USER:${spring.datasource.username}}
password: ${LIQUIBASE_DB_PASSWORD:${spring.datasource.password}}
clear-checksums: ${LIQUIBASE_CLEAR_CHECKSUMS:false}
contexts: ${LIQUIBASE_CONTEXTS:dev}
preliquibase:
default-schema: ${spring.liquibase.default-schema}
# sqlScriptReferences: classpath:/db/preliquibase/schema.sql
dbPlatformCode: postgresql
default-schema
: Liquibase scriptleri çalıştırırken şema verilmemiş scriptlerde kullanıacak varsayılan veritabanı şema bilgisidir.change-log
: Liquibase scriptleri çalıştırırken ilk olarak bakacağı change-log dosyasıdır. Bu dosyanın içerisindeki bilgilere göre sırası ile scriptler çalıştırılmaktadır.enabled
: Uygulama ayağa kalkarken liquibase'in devreye girip girmeyeceğini yöneten konfigürasyon bilgisidir.drop-first
: Uygulama ayağa kalkarken liquibase'in tüm tabloları temizleyip herşeyi en baştan çalıştırmasını sağlayan konfigürasyon bilgisidir.url
: Liquibase'in scriptlerini çalıştıracağı veritabanı url bilgisidir.user
: Liquibase'in scriptlerini çalıştıracağı veritabanının kullanıcı adı bilgisidir.password
: Liquibase'in scriptlerini çalıştıracağı veritabanının şifre bilgisidir.clear-checksums
: Liquibase'in scriptlerinde değişiklik olduğu durumda güncel scriptlerin baz alınacağını belirleyen konfigürasyon bilgisidir. Normal koşullarda liquibase çalıştırdığı bir script değişmişse hata vererek uygulamayı kapatır. Bu konfigürasyon true olduğu durumlarda mevcut checksum ı günceller ve hata atmadan devam eder.NOT: Canlı ortamlarda kurulum yapılmışsa çalışmış scriptleri güncellemek son derece tehlikelidir.
contexts
: Liquibase'in scriptlerini çalıştırırken kullanacağı context bilgisidir. Context ile belirtilmiş changeset leri bu konfigürasyon kapsamında çalıştıracaktır. Virgül kullanılarak birden fazla değer verilebilir.
Preliquibase:
default-schema
: Şemanın olmadığı durumlarda preliquibase tarafından oluşturulacak şema bilgisidir.sqlScriptReferences
: Şema oluşturulması için çalışacak script dosyasının path bilgisidir.dbPlatformCode
: Veri tabanı platform bilgisidir. Varsayılan olarak postgresql olarak ayarlanmıştır.
Proje içerisinden örnek liquibase kullanım yapısı aşağıdaki gibidir.
Model Converter#
Model ve domain nesnesi (entity) arasındaki dönüşümü sağlayan EKSEN bileşenidir. Ek olarak mapstruct için HvlGenericMapStructMapper
sınıfını sağlar.
Message Broker#
Uygulamalarda message queue yapısının kullanmasını sağlayan altyapı bileşenidir. Kafka desteği sağlanmaktadır.
Kafka#
Kafka ile ilgili detaylı bilgiye ve hvl-kafka kullanımına Kafka sayfasından ulaşılabilir.
hvl-infra altında bulunan 'application-kafka.yml' dosyasıyla konfigure edilebilmektedir.
Support#
Uygulama mimarisinde ihtiyaç duyulan destek paketlerini içeren altyapı bileşenidir.
- Elasticsearch Apm Support
- Spring Batch
- File System
- Mail Sender
- Micrometer Prometheus
- Multitenancy
- Tracing
Apm Support#
EKSEN, bu bileşen ile APM agentlarını instance içerisine ekleyerek Elasticsearch - APM entegrasyonu desteği sağlamaktadır.
hvl-infra altında bulunan 'application-apm.yml' dosyasıyla konfigure edilebilmektedir.
Batch Support#
hvl-infra altında bulunan 'application-batch.yml' dosyasıyla konfigure edilebilmektedir.
File System Support#
Belirli bir path üzerinde dosya işlemleri yapmak için sağlanan bileşendir. HvlFileSystemResourceService
sınıfı kullanılarak işlemler yapılmaktadır.
public interface HvlFileSystemResourceService {
void persistDocument(InputStream document, HvlFileSystemInfoModel resourcePersisterInfo) throws HvlFileSystemException;
void deleteDocument(HvlFileSystemInfoModel resourcePersisterInfo) throws HvlFileSystemException;
InputStream readDocument(HvlFileSystemInfoModel resourcePersisterInfo) throws HvlFileSystemException;
String getDocumentName(HvlFileSystemResourcePathStrategy hvlFileSystemResourcePathStrategy);
}
Yapılacak dosya işlemleri resourcePath'e verilen path üzerinde gerçekleştirilir.
Mail Support#
EKSEN, mail atmak için gerekli altyapıyı sağlamaktadır. Başlıca yetenekler:
- Fake mail: Geliştirme ortamları için tüm maillerin sahte bir adrese yönlendirilmesi yapılabilir. Böylece tek bir mail adresi hesabından tüm mailler kontrol edilebilir.
- Html mail desteği
- Takvim/Toplantı davetli mail desteği
- Ekli mail gönderme desteği
Ek olarak mail template'leri ile daha kompleks mailler atılmak isteniyorsa EKSEN tarafından sağlanan ve EKSEN altyapısını kullanan Notification ürünü incelenebilir.
hvl-infra altında bulunan 'application-hvl-mail.yml' dosyasıyla konfigure edilebilmektedir.
Micrometer Prometheus Support#
EKSEN, micrometer kütüphanelerini kullanarak prometheus'a veri basılmasını sağlamaktadır. Böylece Grafana gibi monitoring uygulamaları kullanılarak uygulamalar hakkında detaylı bilgi edinilebilmektedir.
Multi Tenancy Support#
EKSEN, aynı uygulama üzerinden farklı müşterilere destek verilmesi durumları için multi tenancy support bileşenini sağlamaktadır. Bu bileşen ile aşağıdaki türlerde tenancy sağlanabilmektedir.
- Veritabanı
- Veritabanı Şeması
- Veritabanı Tablo Kolonu
- Gateway
Veritabanı düzeylerinden birinde multi tenancy yapılmak istendiğinde aşağıdaki entity sınıfları kullanılmalıdır:
- HvlHardDeleteTenantEntity
- HvlLookupTenantEntity
- HvlSimpleTenantEntity
- HvlSoftDeleteTenantEntity
hvl-infra altında bulunan 'application-hvl-multi-tenancy.yml' dosyasıyla konfigure edilebilmektedir.
Tracing Support#
EKSEN, cloud ortamlar için tracing yapabilmek amacıyla Micrometer ve Brave desteği sağlamaktadır. Bu teknolojiler kullanılarak, instancelar arasındaki network izlenebilir ve requestlerin hangi uygulamalardan geçtiği gözlenebilir. Monitoring tool olarak Zipkin kullanılarak uygulamalar arası network izlenebilir.
Sağlanan @HvlTraceLog
anotasyonu ile çalışan methodların da trace edilmesi sağlanmaktadır. Takip edilmek istenen methodların tepesine eklenmesi gerekmektedir.
Konsol log seviyesi trace yapılarak request ve response'lar detaylı olarak görülebilmektedir.
hvl-infra altında bulunan 'application-cloud-tracing.yml' dosyasıyla konfigure edilebilmektedir.