17 Şubat 2022 Perşembe

GraalVM Truffle - Polyglot Runtime

Giriş
Bu bileşen aynı zamanda Espresso Project olarak ta biliniyor. Açıklaması şöyle. Yani GraalVM iki şekilde kullanılabiliyordu. 
1. Ya Native Image oluşturuluyor 
2. Ta da kendi içinde barındırdığı Java HotSpot VM için JIT yapıyordu. 

Artık JVM olarak ta kullanılabilir
Up until now, GraalVM has offered two ways to run Java programs: using the Java HotSpot VM with the GraalVM JIT (just-in-time) compiler, and compiled to a native executable using GraalVM Native Image.

Today, we’re happy to announce a new way to run Java on GraalVM. GraalVM 21.0 introduces a new installable component, named espresso, which provides a JVM implementation written in Java.
Açıklama şöyle. Yani Truffle diğer dilleri de çalıştırabiliyor
One of the newer VMs is GraalVM. I'm not sure it's completely correct to call it a JVM because it can (supposedly) also run other languages such as Python, Ruby, C, and C++.
Espresso bileşeni "Truffle Language Implementation Framework" kullanılarak yazılmış bir JVM. Şeklen şöyle
Şeklen şöyle


Bazı yeni özellikler şöyle
Java on Truffle enables some interesting use cases. You can embed Java bytecode of a different version in your main Java application (given you have both distributions), dynamically execute Java code in native executable built with Native Image, use it for advanced class redefinition, get access to all Truffle tools and interoperability, and more.

Over the year we’ve done a lot of work on Java on Truffle in terms of both features, like the new Hotswap Plugin API, which allows reloading the code without the need for restarting a running application, and performance — most recently on startup performance in a wide range of benchmarks. Stay tuned for more updates in 2022!
Truffle Artık Ayrıca İndirilebiliyor
Açıklaması şöyle
GraalVM’s polyglot language runtime, Truffle, and language runtimes are now decoupled from the GraalVM JDK. Standalone language runtimes are available for download in native and JVM standalone versions. For embedding in Java applications, you can download all artifacts from Maven Central, which will work for GraalVM JDK and any other compatible JDK.
Polyglot Embedding
Açıklaması şöyle
Previously, to embed GraalVM languages in Java applications, you had to install them using the gu tool. Now all languages are available as Maven dependencies. 
Örnek
Java içinde Python kullanmak için şöyle yaparız
<dependency>
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>polyglot</artifactId>
  <version>23.1.0</version>
</dependency>
<dependency>
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>python</artifactId>
  <version>23.1.0</version>
  <type>pom</type>
</dependency>
Örnek
Java içinde Javascript kullanmak için şöyle yaparız
<dependency>
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>js</artifactId>
  <version>23.1.0</version>
  <type>pom</type>
</dependency>


15 Şubat 2022 Salı

System.Logger Arayüzü

Giriş
Açıklaması şöyle
System.Logger is a façade over your logging engine. Instead of using, say, SFL4J's API and the wanted implementation, you'd use System.Logger instead of SLF4J. It's available since Java 9,
log metodu
Bu sınıf sadece log metodu sağlıyor. Level parametresi bu metoda geçiliyor. Diğer bazı kütüphaneler ise farklı seviyeler için farklı metodlar sunuyorlar

Örnek
Şöyle yaparız
public class LoggerExample {

  private static final System.Logger LOGGER = System.getLogger("c.f.b.DefaultLogger"); // 1

  public static void main(String[] args) {
    LOGGER.log(DEBUG, "A debug message");
    LOGGER.log(INFO, "Hello world!");
  }
}
Log4J
Şöyle yaparız
<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>            <!-- 1 -->
    <version>2.17.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>    <!-- 2 -->
    <artifactId>log4j-jpl</artifactId>
    <version>2.17.0</version>
  </dependency>
</dependencies>
Açıklaması şöyle
1. Log4J implementation.
2. Bridge from System.Logger to Log4J.
SLF
Şöyle yaparız
<dependencies>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>               <!-- 1 -->
    <version>2.0.0-alpha5</version>
  </dependency>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk-platform-logging</artifactId> <!-- 2 -->
    <version>2.0.0-alpha5</version>
  </dependency>
</dependencies>
Açıklaması şöyle
1. Basic SLF4J implementation. Any other implementation will do, e.g. Logback.
2. Bridge from System.Logger to Log4J.




10 Şubat 2022 Perşembe

Testcontainers Kullanımı

Giriş
Test Containers iki şekilde kullanılabilir.
1. Using a specially modified JDBC URL. Testcontainers JDBC URL Kullanımı yazısına taşıdım
2. Anotasyonlar ile kullanılır
3. Tüm container'lar GenericContainer sınıfından kalıtır. Bu yüzden GenericContainer yazısına bakmakta fayda var

JUnit 5 Kullanımı
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>testcontainers</artifactId>
  <scope>test</scope>
</dependency>

<!-- JUnit 5 extension --> 
<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>junit-jupiter</artifactId>
  <scope>test</scope>
</dependency>

1. Test sınıfına @TestContainers anotastonu eklenir
2. Teste static veya static olmayan @Generic anotasyonuna sahip bir container eklenir. 
 -- Static ise container tüm testler için bir kere yaratılır, yani paylaşılır. 
-- Static değilse her test için yeni bir container yaratılır

JUnit 4 Kullanımı
JUnit 4 için @Rule/@ClassRule anotayonları kullanılır 

@Testcontainers Anotasyonu
Şu satırı dahil ederiz
import org.testcontainers.junit.jupiter.Testcontainers;
Açıklaması şöyle. Jupiter anotasyonudur. @Container olarak işaretli container'ın start() metodunu çağırır.
Jupiter integration is provided by means of the @Testcontainers annotation.

The extension finds all fields that are annotated with @Container and calls their container lifecycle methods (methods on the Startable interface). Containers declared as static fields will be shared between test methods. They will be started only once before any test method is executed and stopped after the last test method has executed. Containers declared as instance fields will be started and stopped for every test method.

Note: This extension has only been tested with sequential test execution. Using it with parallel test execution is unsupported and may have unintended side effects.

Her Test İçin Yeni Container
Örnek
Şöyle yaparız
private RedisBackedCache underTest;

  @Container
  public GenericContainer redis = new GenericContainer("redis:5.0.8-alpine3.11")
    .withExposedPorts(6379);

  @BeforeEach
  public void setUp() {
    String address = redis.getHost();
    Integer port = redis.getFirstMappedPort();

    underTest = new RedisBackedCache(address, port);
  }

Diğer

Örnek - Testcontainers GCloud Module
Şöyle yaparız
//TestContainers
testImplementation 'org.testcontainers:testcontainers:1.17.3'
testImplementation group: 'org.testcontainers', name: 'junit-jupiter', version: '1.17.3'
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.0'
implementation 'org.testcontainers:gcloud:1.17.3'
Şöyle yaparız
@Container
private static final SpannerEmulatorContainer spannerEmulatorContainer =
  new SpannerEmulatorContainer(
    DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.1.1"));

//for testing, there is no need to use credentials
@TestConfiguration
static class EmulatorConfiguration {
  @Bean
  NoCredentialsProvider googleCredentials() {
    return NoCredentialsProvider.create();
  }
}

@DynamicPropertySource
static void emulatorProperties(DynamicPropertyRegistry registry) {
  registry.add(
    "spring.cloud.gcp.spanner.emulator-host", 
    spannerEmulatorContainer::getEmulatorGrpcEndpoint);
}
Yardımcı metodlar için şöyle yaparız
private InstanceId createInstance(Spanner spanner) throws InterruptedException, ExecutionException {
  InstanceConfigId instanceConfig = InstanceConfigId.of(PROJECT_ID, "emulator-config");
  InstanceId instanceId = InstanceId.of(PROJECT_ID, INSTANCE_ID);
  InstanceAdminClient insAdminClient = spanner.getInstanceAdminClient();
  Instance instance = insAdminClient
    .createInstance(
      InstanceInfo
        .newBuilder(instanceId)
        .setNodeCount(1)
        .setDisplayName("Test instance")
        .setInstanceConfigId(instanceConfig)
        .build()
       )
   .get();
  return instanceId;
}

private void createDatabase(Spanner spanner) throws InterruptedException, ExecutionException {
  DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
  Database database = dbAdminClient
    .createDatabase(
      INSTANCE_ID,
      "order_schema",
      Arrays.asList("CREATE TABLE Orders (orderId INT64 NOT NULL, name STRING(255), order_status STRING(255)) PRIMARY KEY (orderId)")
    )
    .get();
}

private Spanner spanner(){
  SpannerOptions options = SpannerOptions
    .newBuilder()
    .setEmulatorHost(spannerEmulatorContainer.getEmulatorGrpcEndpoint())
    .setCredentials(NoCredentials.getInstance())
    .setProjectId(PROJECT_ID)
    .build();
  Spanner spanner = options.getService();
  return spanner;
}
Test için şöyle yaparız
@Test
public void testOrders() throws ExecutionException, InterruptedException {
    //Create Spanner Instance, DB, Table
    Spanner spanner = spanner();
    InstanceId instanceId = createInstance(spanner);
    createDatabase(spanner);

    //Create Order and Save
    Order order = new Order();
    order.setOrder_status("COMPLETED");
    order.setName("Order1");
    String message = this.orderService.save(order);
    assertEquals("Order Saved Successfully", message);

    //Validate
    List<Order> orders = this.orderService.findOrdersByName("Order1");
    assertTrue(orders.size() == 1);
    assertTrue(orders.get(0).getOrder_status().equals("COMPLETED"));
 }

9 Şubat 2022 Çarşamba

Hikari API

Giriş
Hikari'yi tek başına kütüphane olarak ta kullanmak mümkün. MySQL ip uçları burada

Loglama
Hikari SLF4J kullanıyor. 
- SLF+J kullanımı ile ilgili örnekler burada
- Adaptörler ile ilgili genel açıklama SLF4J sayfasında burada
- Eğer kendi adaptörümüzü yazmak istersek bir örnek burada
- Eğer hiç bir adaptör tanımlı değilse şu çıktıyı alırız
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Açıklaması şöyle
If no logging dependency is provided on the classpath, it will default to a no-operation implementation and nothing gets logged.
Hikari Uyarı Mesajları
Eğer şöyle bir hata alıyorsak, 
 Executed rollback on connection ... due to dirty commit state on close().
1. connection.rollback() yapmayı unutmuşuzdur.
2. Ya da şöyle yapmışızdır. setAutoCommit(false); getMetaData() çağrısından sonra yapılmalı
// See https://github.com/brettwooldridge/HikariCP/issues/866
connection.setAutoCommit(false);
boolean supportsBatch = connection.getMetaData().supportsBatchUpdates();
Maven
Java 8 için şöyle yaparız
<dependency>
  <groupId>com.zaxxer</groupId>
  <artifactId>HikariCP</artifactId>
  <version>4.0.3</version>
</dependency>
Java 11+ için şöyle yaparız
<dependency>
  <groupId>com.zaxxer</groupId>
  <artifactId>HikariCP</artifactId>
  <version>5.0.1</version>
</dependency>
Gradle
Java 8-11 için şöyle yaparız
implementation 'com.zaxxer:HikariCP:3.4.5'
Java 17 için şöyle yaparız
implementation 'com.zaxxer:HikariCP:5.01'
Örnek - En Basit Kullanım
Gradle ile şöyle yaparız
implementation 'com.zaxxer:HikariCP:5.01'
implementation 'mysql:mysql-connector-java:8.0.27'
Ayarları okumak için şöyle yaparız
public HikariConfig getHikariConfig() {
  HikariConfig hikariConfig = new HikariConfig();

  String jdbCUrl = getJdbcUrl();
  hikariConfig.setJdbcUrl(jdbCUrl);

  Optional<String> userName = getUserName();
  userName.ifPresent(hikariConfig::setUsername);

  Optional<String> password = getPassword();
  password.ifPresent(hikariConfig::setPassword);

  Optional<Integer> maxPoolSize = getMaxPoolSize();
  maxPoolSize.ifPresent(hikariConfig::setMaximumPoolSize);

  hikariConfig.addDataSourceProperty("cachePrepStmts", "true");
  hikariConfig.addDataSourceProperty("prepStmtCacheSize", "250");
  hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");

  return hikariConfig;
}
Daha sonra şöyle yaparız. Artık bundan sonra elimizde bir DataSource vardır.
HikariConfig hikariConfig = getHikariConfig();

HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
HikariConfig Sınıfı
HikariConfig Sınıfı yazısına taşıdım

HikariPool Sınıfı
HikariPool Sınıfı yazısına taşıdım


Örnek - Custom Logger
Şöyle yaptım
public class MyLogger extends MarkerIgnoringBase {
  private final String name;
  public SLF4JUnifiedLogger(String name) {
    this.name = name;
  }
  private void formatAndLog(int level, String format, Object arg1, Object arg2) {
    FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
    log(level, tp.getMessage(), tp.getThrowable());
  }
  private void formatAndLog(int level, String format, Object... arguments) {
    FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
    log(level, tp.getMessage(), tp.getThrowable());
  }
  private void log(int level, String message, Throwable throwable) {
    String levelStr = renderLevel(level);

    StringBuilder stringBuilder = new StringBuilder(32);
    stringBuilder.append(levelStr);
    stringBuilder.append(' ');
    // Append the message
    stringBuilder.append(message);
    if (throwable != null) {
      PrintWriter printWriter = ...
      throwable.printStackTrace(printWriter);
      stringBuilder.append(stringWriter);
    }
    ...
  }
 
  @Override
  public void trace(String msg) {
    log(LOG_LEVEL_TRACE, msg, null);
  }
  ...
}
renderLevel şöyle
protected String renderLevel(int level) {
  switch (level) {
    case LOG_LEVEL_TRACE:
      return "TRACE";
    case LOG_LEVEL_DEBUG:
      return ("DEBUG");
    case LOG_LEVEL_INFO:
      return "INFO";
    case LOG_LEVEL_WARN:
      return "WARN";
    case LOG_LEVEL_ERROR:
      return "ERROR";
    }
    throw new IllegalStateException("Unrecognized level [" + level + "]");
  }
Factory şöyle
public class MyLoggerFactory implements ILoggerFactory {

  final ConcurrentMap<String, MyLogger> loggerMap;

  public MyLoggerFactory() {
    loggerMap = new ConcurrentHashMap<>();
  }

  public void setTracer(ITracer tracer) {
    this.tracer = tracer;
    loggerMap.forEach((k, v) -> v.setTracer(tracer));
  }

  @Override
  public Logger getLogger(String name) {
    return loggerMap.computeIfAbsent(name, k -> {
      MyLogger myLogger = new MyLogger(name);
      myLogger.setTracer(tracer);
      return myLogger;
    });
  }
}
StaticLoggerBinder şöyle
public class StaticLoggerBinder implements LoggerFactoryBinder  {

  private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

  public static final StaticLoggerBinder getSingleton() {
    return SINGLETON;
  }
  
  //Declare the version of the SLF4J API this implementation is compiled against.
  //The value of this field is modified with each major release.
  public static String REQUESTED_API_VERSION = "1.6.99"; // !final
  
  private static final String loggerFactoryClassStr = MyLoggerFactory.class.getName();
  
  private final MyLoggerFactory loggerFactory;
private StaticLoggerBinder() { loggerFactory = new MyLoggerFactory();
} public void setTracer(ITracer tracer) { loggerFactory.setTracer(tracer); } @Override public ILoggerFactory getLoggerFactory() { return loggerFactory; } @Override public String getLoggerFactoryClassStr() { return loggerFactoryClassStr; } }





2 Şubat 2022 Çarşamba

java komutu Permanent Space İçin -XX Seçenekleri - Kaldırıldı

Giriş
Permanent Space seçenekleri Java 8'den itibaren deprecate edildi. Java 17 ile de kaldırıldı. Açıklaması şöyle
... Permgen has been replaced by Metaspace to address some of PermGen's drawbacks (as you were able to see for yourself, one of those drawbacks is that it had a fixed size).
Yani 
-XX:PermSize ve -XX:MaxPermSize yerine 
-XX:MetaspaceSize=size ve -XX:MaxMetaspaceSize=size geldi

-XX:MaxPermSize
Permanent Space için en büyük alanı belirtir. Şöyle yaparız.
"%JAVA_HOME%\bin\java" ... -XX:MaxPermSize=256m ...
-XX:PermSize
Permanent Space için en küçük alanı belirtir. Şöyle yaparız.
%JAVA_HOME%\bin\java" ... -XX:PermSize=256m ...