5 Temmuz 2022 Salı

EJB @ConcurrencyManagement Anotasyonu

CONTAINER Managed
Açıklaması şöyle
If nothing else is specified, by default singleton session bean uses container managed concurrency. Further, if not specified, every business and timeout method have by default LockType.WRITE. Result is that there is not multiple threads concurrently executing methods in singleton and as consequence using regular java.util.HashMap is perfectly fine.
Örnek 
Şöyle yaparız
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.Local;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import java.util.HashMap;
import java.util.Map;

@Singleton
@Local(MapsAndQueuesSingletonBeanLocal.class)
public class MapsAndQueuesSingletonBean implements MapsAndQueuesSingletonBeanLocal {

    private Map<String String> maps = new HashMap<>();
    
    @Override
    public String getMap(String key) {
        return maps.computeIfAbsent(key, k -> ...);
    }

}
Açıklaması şöyle
If nothing else is specified, by default singleton session bean uses container managed concurrency. Further, if not specified, every business and timeout method have by default LockType.WRITE. Result is that there is not multiple threads concurrently executing methods in singleton and as consequence using regular java.util.HashMap is perfectly fine.
BEAN Managed
Açıklaması şöyle
@Singleton in the default configuration is the perfect bottleneck. Only one thread a time can access a @Singleton instance.
The annotation @ConcurrencyManagement(ConcurrencyManagementType.BEAN) deactivates this limitation and makes a Singleton instance accessible from multiple threads:
Örnek 
Şöyle yaparız
import javax.ejb.Singleton;
import javax.annotation.PostConstruct;
import javax.ejb.ConcurrencyManagement;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.ConcurrencyManagementType;

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class Hits {

  private ConcurrentHashMap hits = null;
	
  @PostConstruct
  public void initialize() {
    this.hits = new ConcurrentHashMap();
  }
  //cache accessors omitted
}


30 Haziran 2022 Perşembe

Jakarta EE Concurrency @ManagedExecutorDefinition

Giriş
Açıklaması şöyle
One of the most commonly used services in the Jakarta Concurrency API is the ManagedExecutorService. It is used to create a thread pool in the Jakarta EE environment to spawn threads in a more manageable way. Although it is pretty much the same as ExecutorService, we employ it in the Java SE environment.

To configure the thread pool, we had a vendor-specific setting. Now it can be defined with just annotation. This is a more standard way of configuring the thread pool.
Örnek
Şöyle yaparız
@Path("concurrency")
@RequestScoped public class GenericResource { @Context private UriInfo context; @Resource private ManagedExecutorService managedExecutor; @GET @Path("simplejob") @Produces(MediaType.TEXT_PLAIN) public String getText() { manageExecutor.submit(() -> { System.out.println("Job running..."); }); return "Job Sumitted"; } }
Örnek
Şöyle yaparız
import static jakarta.enterprise.concurrent.ContextServiceDefinition.APPLICATION;
import static jakarta.enterprise.concurrent.ContextServiceDefinition.SECURITY;

import jakarta.annotation.Resource;
import jakarta.ejb.Asynchronous;

import jakarta.enterprise.concurrent.ContextServiceDefinition;
import jakarta.enterprise.concurrent.ManagedExecutorDefinition;
import jakarta.enterprise.concurrent.ManagedExecutorService;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Named;
import java.time.Duration;
import java.time.LocalDate;
import java.util.concurrent.CompletableFuture;

@Named
@ApplicationScoped
@ManagedExecutorDefinition(
    name = "java:module/concurrent/MyExecutor",
    context = "java:module/concurrent/MyExecutorContext",
    hungTaskThreshold = 120000,
    maxAsync = 5)
@ContextServiceDefinition(
    name = "java:module/concurrent/MyExecutorContext",
    propagated = {SECURITY, APPLICATION})
public class WorkService {
  
  @Resource(name = "java:app/concurrent/MyExecutorService")
  private ManagedExecutorService executor;

  @Asynchronous
  public CompletableFuture<Long> hoursWorked(LocalDate from, LocalDate to) {

    return CompletableFuture.supplyAsync(() -> heavyAPICall(from, to), executor);
  }

  private static long heavyAPICall(LocalDate from, LocalDate to) {

    return Duration.between(from, to).toMillis();
  }
}

Jakarta EE Concurrency @Asynchronous Anotasyonu

Giriş
Açıklaması şöyle
There is a similar annotation available in EJB. A method annotated with this annotation is supposed to run asynchronously. Unfortunately, however, the EJB one is a bit out of date.

Also, in EJB, we can't specify the thread pool. It used to use the app server's default thread pool. Now the new annotation jakarta.enterprise.concurrent.Asynchronous comes with Jakarta EE Concurrency 3.0, which doesn't require using EJB, and we can specify the thread pool. It can be used with any CDI bean. Each asynchronous method execution corresponds to a managed java.util.concurrent.CompletableFuture instance that is backed by jakarta.enterprise.concurrent.ManagedExecutorService as its default asynchronous execution facility.
executor Alanı
Örnek
Şöyle yaparız
import jakarta.enterprise.concurrent.Asynchronous;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Named;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

@Named
@ApplicationScoped
public class PaymentService {

  @Asynchronous(executor = "java:app/concurrent/MyExecutorService")
  public CompletableFuture<Confirmation> processPayment(final Order order) {
    try {
      var status = processOrder(order);
      return CompletableFuture.completedFuture(status);
    } catch (PaymentException ex) {
      throw new CompletionException(ex);
    }
  }

  private Confirmation processOrder(Order order) {
    return new Confirmation();
  }
}

Jakarta EE @OpenIdAuthenticationDefinition Anotasyonu

Giriş
Açıklaması şöyle
Well, for many years, we have been using usernames and passwords for authenticating users in a web application. However, in modern applications, it has become widespread to log in using other services, e.g. Facebook, Google, Twitter, etc. The OpenID Connect protocol powers this kind of authentication. With the Jakarta Security 3.0, we now have a standard way to adhere to OpenID Connect by using just an annotation, which is @ OpenIdAuthenticationDefinition. Life is much simpler now; specify the required properties, such as Provider URI, clientId, clientSecret, redirect URI, etc.
Örnek
Şöyle yaparız
@OpenIdAuthenticationDefinition(
       providerURI = "https://sample-openid-server.com",
       clientId = "87068hgfg5675htfv6mrucov57bknst.apps.sample.com",
       clientSecret = "{my-secret}",
       redirectURI = "${baseURL}/callback",
       extraParameters = {
            "testKey=testValue", 
            "testKey2=testValue2"
       }
)

public class SecurityConfig {
}

20 Haziran 2022 Pazartesi

jboss-cli komutu

shutdown
Aynı şey Yönetim Ekranından (Management Console) da yapılabilir.

Örnek
Şöyle yaparız
jboss-cli.sh -- connect
[standalone@localhost:9990 /] shutdown
Örnek
Şöyle yaparız
jboss-cli.sh -- connect
[standalone@localhost:9990 /] shutdown --timeout=10
Örnek - restart
Şöyle yaparız
jboss-cli.sh -- connect
[standalone@localhost:9990 /] shutdown --restart=true 
HAL Management Console'dan şöyle yaparız
When running in Standalone mode, select the Runtime upper Tab and, from your Server name, click on the Combo Menu’s arrow. You should be able to Reload, Restart or Suspend the Server from there:
Şeklen şöyle



9 Haziran 2022 Perşembe

Jakarta NoSQL

Giriş
İki tane standart var
1. Jakarta NoSQL Standardı
2. Jakarta Data Standardı

Jakarta NoSQL Standardı
Açıklaması şöyle. Yani NoSQL veri tabanları ile çalışmak için
We have JPA for a while in the specification world to make your life easier in the relational database world. We're glad to work on a specification to make it easier to work with NoSQL: Jakarta NoSQL.

The core principle of the Jakarta NoSQL is to standardize behavior, to make a low cognitive load while changing among databases, and at the same time be extensible enough to allow specific behavior from a particular vendor. At this time we have the pleasure of announcing a new version, Jakarta NoSQL Version 1.0.0-b4.
Jakarta Data Standardı
Açıklaması şöyle
After several discussions to have more integration between JPA and NoSQL, the community has decided to create a new specification to apply those patterns around data: Jakarta Data. We've published it to the Jakarta EE Committee.
Jakarta NoSQL Kullanımı
Builder veya Fluent şekilde kullanılabilir. Açıklaması şöyle
... Jakarta NoSQL has two approaches to creating a database request: using a fluent API and using a builder pattern.
Maven
Şu satırı dahil ederiz
<dependency>
<groupId>org.eclipse.jnosql.mapping</groupId>
<artifactId>mongodb-extension</artifactId>
<version>${project.version}</version>
</dependency>
DocumentCollectionManager Sınıfı
Örnek
Şöyle yaparız
@ApplicationScoped
public class MongoDBProducer {

  @Inject
  @ConfigProperty(name = "document")
  private DocumentCollectionManager manager;

  @Produces
  public MongoDBDocumentCollectionManager getManager() {
    return (MongoDBDocumentCollectionManager) manager;
  }

  public void destroy(@Disposes DocumentCollectionManager manager) {
    manager.close();
  }
}
properties dosyası şöyledir
document=document
document.database=olympus
document.settings.jakarta.nosql.host=localhost:27017
document.provider=org.eclipse.jnosql.communication.mongodb.document.MongoDBDocumentConfiguration
DocumentTemplate Sınfı
delete metodu
Örnek
Şöyle yaparız
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

  Worker poliana = Worker.builder()
    .age(30).name("Poliana")
    .city("Salvador")
    .gender(Gender.FEMALE)
    .dailyHours(30).build();

  Worker otavio = Worker.builder()
    .age(35).name("Otavio")
    .city("Salvador")
    .gender(Gender.MALE)
    .dailyHours(30).build();

  DocumentTemplate template = container.select(DocumentTemplate.class).get();

  template.insert(Arrays.asList(otavio, poliana));
  ...
  template.delete(Worker.class, otavio.getId());
  template.delete(Worker.class, poliana.getId());
}
insert metodu
Örnek
Şöyle yaparız
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

  Worker poliana = Worker.builder()
    .age(30).name("Poliana")
    .city("Salvador")
    .gender(Gender.FEMALE)
    .dailyHours(30).build();

  Worker otavio = Worker.builder()
    .age(35).name("Otavio")
    .city("Salvador")
    .gender(Gender.MALE)
    .dailyHours(30).build();

  DocumentTemplate template = container.select(DocumentTemplate.class).get();

  template.insert(Arrays.asList(otavio, poliana));
  
}
select metodu
Örnek
Şöyle yaparız
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

  DocumentTemplate template = container.select(DocumentTemplate.class).get();

  DocumentCondition maleAfterThirty = and(eq("gender", Gender.MALE), gte("age", 30));

  DocumentCondition femaleAfterThirty = and(eq("gender", Gender.FEMALE),gte("age", 30));

  DocumentQuery query =  DocumentQuery.builder()
    .from("Worker")
    .sort(asc("name"))
    .where(or(maleAfterThirty, femaleAfterThirty))
    .build();

  Stream<Worker> stream = template.select(query);
  List<Worker> workers = stream.collect(Collectors.toList());
  workers.forEach(System.out::println);

}





6 Mayıs 2022 Cuma

Wildfly JNDI DataSource Ekleme

Giriş
Uygulamadan bir DataSource'a erişmek için 3 tane yöntem var.
1. Uygulama içinde tanımlanır
2. Wildfly Üzerinde Modul Olarak Tanımlanır Ancak Wildfly Ayarlarına Driver Eklenmez
3. Wildfly Üzerinde Modul Olarak Tanımlanır ve Wildfly Ayarlarına Driver + DataSource eklenir. Uygulama JNDI üzerinden erişir. Bir örnek burada.

Örnek - MySQL
WILDFLY_HOME/modules/system/layers/base/com/mysql/main/module.xml dosyasında şöyle yaparız
<module xmlns="urn:jboss:module:1.5" name="com.mysql">
  <resources>
    <resource-root path="mysql-connector-java-8.0.17.jar" />
  </resources>
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>
Daha sonra
1. Configuration -> Subsystems -> Datasources & Drivers -> JDBC Drivers menüsü ile bir driver eklenir. Ekrandaki bilgiler şöyle
Driver Name : mysql
Driver Module Name : com.mysql
Driver Class Name : com.mysql.cj.jdbc.Driver
Driver XA Datasourc Class Nam : com.mysql.cj.jdbc.MysqlXADataSource
2. Configuration -> Subsystems -> Datasources & Drivers -> Datasources menüsü ile bir XA olmayan datasource eklenir. Buradaki parametreleri veremiyorum. Kendi veri tabanınıza göre ayarlamanız gerekiyor.

Örnek - postgre
$WILDFLY_HOME\modules\org\postgres\main\module.xml dosyasında şöyle yaparız
<?xml version='1.0' encoding='UTF-8'?>
<module xmlns="urn:jboss:module:1.1" name="org.postgres">

    <resources>
        <resource-root path="postgresql-9.4-1204-jdbc4.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
        <module name="javax.servlet.api" optional="true"/>
    </dependencies>
</module>
DataSource olarak şöyle yaparız
<datasource jta="false" jndi-name="java:jboss/datasources/YourDS" pool-name="YourDS"
  enabled="true" use-ccm="false">
    <connection-url>jdbc:postgresql://localhost:5432/yourDB</connection-url>
    <driver>postgres</driver>
    <security>
        <user-name>user</user-name>
        <password>pass/password>
    </security>
    <validation>
        <validate-on-match>false</validate-on-match>
        <background-validation>false</background-validation>
    </validation>
    <statement>
        <share-prepared-statements>false</share-prepared-statements>
    </statement>
</datasource>

<drivers>
    <driver name="postgres" module="org.postgres">
        <driver-class>org.postgresql.Driver</driver-class>
    </driver>
</drivers>
Örnek - gridgain-community-8.8.9
Bunu 
JDK 8, Wildfly 25 ve standalone.xml ve ignite-core-8.8.9.jar ile denedim ve çalıştı
JDK 11, Wildfly 25 ve standalone.xml ve ignite-core-8.8.9.jar ile denedim ve çalıştı
JDK 16, Wildfly 25 ve standalone.xml ve ignite-core-8.8.9.jar ile denedim ve çalıştı.

jar dosyasına bakınca MANIFEST.MF dosyasında şunu görüyorum. Yani gridgain-community-8.8.9.jar JDK 8 ile derlenmiş.
Created-By: Apache Maven Bundle Plugin
Build-Jdk: 1.8.0_291
JDK 16 ile çalışması için bazı ayarlar yapmak gerekiyor. Şöyle yaparız
set JAVA_OPTS=--add-modules jdk.unsupported --add-opens=java.base/java.nio=ALL-UNNAMED
Eğer bunu yapmazsak hata olarak şunu veriyor.
 Operation ("add") failed - address: ([
    ("subsystem" => "datasources"),
    ("jdbc-driver" => "ignite")
]): java.lang.ExceptionInInitializerError
at org.apache.ignite@8.8.9//org.apache.ignite.internal.util.IgniteUtils.<clinit>(IgniteUtils.java:865)
at org.apache.ignite@8.8.9//org.apache.ignite.lang.IgniteProductVersion.fromString(IgniteProductVersion.java:311)
at org.apache.ignite@8.8.9//org.apache.ignite.internal.IgniteVersionUtils.<clinit>(IgniteVersionUtils.java:99)
at org.apache.ignite@8.8.9//org.apache.ignite.IgniteJdbcThinDriver.<clinit>(IgniteJdbcThinDriver.java:139)
 sebebi de sun.misc.Unsafe sınıfının artık jdk.unsupported içinde olması. Yani artık JDK 8'den sonra direkt kullanılamıyor.

sun.misc.unsafe JDK 11 src.zip dosyasının içinde "jdk.unsupported" dizininde halen bu sınıflar görülebilir. Ancak JDK 11 module' e bir şekilde erişim izni verirken, JDK 16 vermiyor.

JDK 8, Wildfly 12 ve standalone.xml ile denedim ve çalışmadı. Hata olarak şunu veriyor sebebini de bilmiyorum. Her şeyi aynı tutarak ignite-core-2.11.0.jar ile de denedim. Yine aynı hatayı aldım. Aslında Wildfly 12 eski olduğu için de daha fazla uğraşmadım.
Operation ("add") failed - address: ([
    ("subsystem" => "datasources"),
    ("jdbc-driver" => "ignite")
]): java.lang.NoClassDefFoundError: sun/misc/Unsafe
at org.apache.ignite.internal.util.IgniteUtils.unsafeByteArrayCopyAvailable(IgniteUtils.java:9413)
at org.apache.ignite.internal.util.IgniteUtils.<clinit>(IgniteUtils.java:344)
at org.apache.ignite.lang.IgniteProductVersion.fromString(IgniteProductVersion.java:311)
at org.apache.ignite.internal.IgniteVersionUtils.<clinit>(IgniteVersionUtils.java:99)
at org.apache.ignite.IgniteJdbcThinDriver.<clinit>(IgniteJdbcThinDriver.java:139)
$WILDFLY_HOME\modules\org\apache\ignite\main\module.xml dosyasında şöyle yaparız
<?xml version="1.0" ?>
<module xmlns="urn:jboss:module:1.1" name="org.ignite.jdbc">
    <resources>
        <resource-root path="ignite-core-8.8.9.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>
Şöyle yaparız. Kendi tanımımda use-java-context ve statistics-enabled yok ancak ekleyince de sorun çıkmıyor
<datasources>
  <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" 
    use-java-context="true" 
statistics-enabled="${wildfly.datasources.statistics-enabled: ${wildfly.statistics-enabled:false}}">
    <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1; DB_CLOSE_ON_EXIT=FALSE</connection-url>
    <driver>h2</driver>
    <security>
      <user-name>sa</user-name>
      <password>sa</password>
    </security>
  </datasource>
  
  <datasource jndi-name="java:jboss/datasources/IgniteDS" pool-name="ignitedatasource">
    <connection-url>jdbc:ignite:thin://localhost:10800/</connection-url>
    <driver>ignite</driver>
      <pool>
        <min-pool-size>1</min-pool-size>
      </pool>
  </datasource>
  
  <drivers>
    <driver name="h2" module="com.h2database.h2">
      <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
    </driver>
    <driver name="ignite" module="org.apache.ignite">
      <driver-class>org.apache.ignite.IgniteJdbcThinDriver</driver-class>
    </driver>
  </drivers>
</datasources>
Bunu test etmek için şöyle yaparız
>jboss-cli.bat --connect
[standalone@localhost:9990 /]/subsystem=datasources/data-source=ignitedatasource:
test-connection-in-pool
{
    "outcome" => "success",
    "result" => [true]
}
Data Source ve JTA
JTA transaction istiyorsak jta=true yapılmalı
Örnek
Şöyle yaparız
<datasource jta="false" jndi-name="java:/wt/testds" pool-name="testds" enabled="true"
  use-ccm="false">  
...  
</datasource> 
Data Source ve statistics-enabled
statistics-enabled true ise Runtime/Datasources altında connection pool için istatistiki bilgiler görülebilir
Örnek
Şöyle yaparız
datasource jndi-name="java:/fooDS" 
  pool-name="fooDS" 
  statistics-enabled="true">
  ..
</datasource>

Bean Validation @GroupSequence Anotasyonu

Örnek Elimizde şöyle bir kod olsun public class SampleRequest {   @NotNull   LocalDate startDate;   @NotNull   LocalDate endDate;   @AssertT...