1 Kasım 2021 Pazartesi

Drools

Maven
Eğer parent pom istersek şu satırı dahil ederiz
<dependency>
<groupId>org.kie</groupId> <artifactId>kie-ci</artifactId> <version>7.45.0.Final</version> </dependency>
Eğer her şeyi ayrı ayrı kullanmak istersek şu satırı dahil ederiz
<properties>
  <drools.version>7.59.0.Final</drools.version>
</properties>

<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-core</artifactId>
  <version>${drools.version}</version>
</dependency>
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-compiler</artifactId>
  <version>${drools.version}</version>
</dependency>
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-decisiontables</artifactId>
  <version>${drools.version}</version>
</dependency>
Kullanım
Esas amaç bir KieSession nesnesi yaratmak. Bunu yaratmak için KieBase veya KieContainer kullanılıyor.

KieSession nesnesinin insert() metodu çağrılıp girdi veriliyor. Daha sonra fireAllRules() metodu çağrılır. KieSession sateless veya statefull olabilir. Açıklaması şöyle. statefull session newKieSession() çağrısı ile yaratılır
A stateful session allows to iteratively work with the Working Memory, while a stateless one is a one-off execution of a Working Memory with a provided data set. In other terms all the data that is inserted into stateful session will be there.
KieContainer Sınıfı
Şu satırı dahil ederiz
import org.kie.api.runtime.KieContainer;
Açıklaması şöyle. Yani aslında KieBase için cache gibi düşünülebilir.
KieBase is a repository of all the application’s knowledge definitions. It will contain rules, processes, functions, and type models. The KieBase itself does not contain data; instead, sessions are created from the KieBase into which data can be inserted and from which process instances may be started. Creating the KieBase can be heavy, whereas session creation is very light, so it is recommended that KieBase be cached where possible to allow for repeated session creation. However end-users usually shouldn’t worry about it, because this caching mechanism is already automatically provided by the KieContainer
Örnek
Şöyle yaparız. KieServices singleton nesnesi ile KieFileSystem elde ediliyor. Bu kuralları yükler.
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieModule;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
 
@Configuration
public class DroolsConfig {
 
  private static final String RULES_CUSTOMER_RULES_DRL = "rules/customer-discount.drl";
  private static final KieServices kieServices = KieServices.Factory.get();
 
  @Bean
  public KieContainer kieContainer() {
    KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
    kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_CUSTOMER_RULES_DRL));
    KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
    kb.buildAll();
    
    KieModule kieModule = kb.getKieModule();
    KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
    return kieContainer;
  }
}
getKieBase metodu
Örnek
Şöyle yaparız
private KieBase createKieBase(byte[] fileArray){
  KieServices kieServices = KieServices.Factory.get();
    
  
  Resource resource= ResourceFactory.newByteArrayResource(fileArray);
  resource.setSourcePath("src/main/resources/ruleFile");
  resource.setResourceType(ResourceType.DRL);
  
  KieFileSystem kieFileSystem=kieServices.newKieFileSystem();
  kieFileSystem.write(resource);
  
  KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
  kb.buildAll();
  
  KieModule kieModule = kb.getKieModule();
  KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());
  return kContainer.getKieBase();
}

KieBase Sınıfı
newKieSession metodu
Örnek
Şöyle yaparız
KieSession configStateful()
  KieBase kieBase = ...
  return kieBase.newKieSession();
}
KieSession Sınıfı
Şu satırı dahil ederiz
import org.kie.api.runtime.KieSession;
fireAllRules metodu
Örnek
Şöyle yaparız
public Integer executeRules(...) throws IOException {
  KieSession kieSession= ...;
  kieSession.insert(...);
  int rulesFired = kieSession.fireAllRules();
  kieSession.dispose();
  return rulesFired;
}

Örnek
Şöyle yaparız. Burada insert() ile girdi verilen nesne değiştiriliyor.
import com.ruleEngine.drools.demo.dto.*;

rule "If customer type is regular and quantity [76-100] , Set Price as 10"
when
  $product:Product(item=='apple' && customerType=='regular' && quantity>=76 &&
                   quantity<=100)
then
    $product.setCost(10);
end

rule "If customer type is premium and quantity [76-100] , Set Price as 8"
when
  $product:Product(item=='apple' && customerType=='premium' && quantity>=76 &&
                   quantity<=100)
then
  $product.setCost(8);
end
Örnek
Şöyle yaparız
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
 
import com.demo.example.model.OrderDiscount;
import com.demo.example.model.OrderRequest;
 
@Service
public class OrderDiscountService {
 
  @Autowired
  private KieContainer kieContainer;
 
  public OrderDiscount getDiscount(OrderRequest orderRequest) {
    OrderDiscount orderDiscount = new OrderDiscount();
    
    KieSession kieSession = kieContainer.newKieSession();
    kieSession.setGlobal("orderDiscount", orderDiscount);//Set global parameter
    kieSession.insert(orderRequest); //Pass object to DRL
    kieSession.fireAllRules(); //Execute rules
    kieSession.dispose();
  
    return orderDiscount;
  }
}
/src/main/resources/rules/customer-discount.drl dosyası şöyledir
import com.demo.example.model.OrderRequest;
import com.demo.example.model.CustomerType;
global com.demo.example.model.OrderDiscount orderDiscount;
 
dialect "mvel"
 
rule "Age based discount"
  when
    OrderRequest(age < 20 || age > 50)
  then
    orderDiscount.setDiscount(orderDiscount.getDiscount() + 10);
end
 
rule "Customer type based discount - Loyal customer"
  when
    OrderRequest(customerType.getValue == "LOYAL")
  then
    orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end
     
rule "Customer type based discount - others"
  when
    OrderRequest(customerType.getValue != "LOYAL")
  then
    orderDiscount.setDiscount(orderDiscount.getDiscount() + 3);
end
 
rule "Amount based discount"
  when
    OrderRequest(amount > 1000L)
  then
    orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end
Açıklaması şöyle. Eşleşen her kural biraz daha indirim ilave eder.
We are also using a global parameter with the name orderDiscount. The global parameter can be shared between multiple rules.

The DRL file can contain one or multiple rules. We can use the mvel syntax to specify the rules. Also, each rule can be described with a description using the rule keyword.

We can use when-then syntax to define the conditions for a rule.

Based on the input values of the Order request, we are adding discount to the result. Every rule adds additional discount to the global result variable if the rule expression matches.


31 Ekim 2021 Pazar

Log4j2 log4j2.xml RollingFile Tanımlama

Giriş
Policy olarak SizeBasedTriggeringPolicy veya TimeBasedTriggeringPolicy kullanılabilir.

OnStartupTriggeringPolicy 
Örnek
Şöyle yaparız
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Liquid Technologies Online Tools 1.0 (https://www.liquid-technologies.com) -->
<Configuration status="WARN"
               monitorInterval="30"
               shutdownHook="disable">
  <Properties>
    <Property name="baseDir">$${env:HOME}/logs</Property>
    <Property name="applicationName">my-application</Property>
  </Properties>
  <Appenders>
    <RollingFile
       name="RollingFile"
       fileName="${baseDir}/${applicationName}.log"
       filePattern="${baseDir}/${applicationName}.%d{yyyy-MM-dd}-%i.log">
      <PatternLayout pattern="%-5p|%d{ISO8601}{GMT}|%X{token}|%c{1}|%X{Principal}|%m%ex%n" />
      <Policies>
        <OnStartupTriggeringPolicy />
        <SizeBasedTriggeringPolicy size="20 MB" />
        <TimeBasedTriggeringPolicy />
      </Policies>
      <DefaultRolloverStrategy max="10">
        <Delete basePath="${baseDir}">
          <IfFileName glob="${applicationName}.*.log">
            <IfAny>
              <IfAccumulatedFileSize exceeds="200 MB" />
              <IfAccumulatedFileCount exceeds="10" />
            </IfAny>
          </IfFileName>
        </Delete>
      </DefaultRolloverStrategy>
      <RegexFilter regex=".*@ConfigurationProperties.*"
                   onMatch="DENY"
                   onMismatch="ACCEPT" />
    </RollingFile>
   
  </Appenders>
  <Loggers>
    <Root level="WARN">
      <AppenderRef ref="RollingFile" />
       </Root>
    <Logger name="org.springframework"
            level="WARN" />
    <Logger name="com.my.app"
            level="INFO" />
  </Loggers>
</Configuration>

TimeBasedTriggeringPolicy 
Örnek
Şöyle yaparız. interval gün cinsinden. Her gün dosyayı değiştirir.  Eğer her hafta yapmak isteseydik interval="7" yaparız
<Policies>
    <TimeBasedTriggeringPolicy interval="1" />
</Policies>

SizeBasedTriggeringPolicy 
Örnek
Şöyle yaparız
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" monitorInterval="30"> <Properties> <Property name="LOG_PATTERN"> %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex </Property> </Properties> ... </Configuration> <!-- Rolling File Appender --> <RollingFile name="FileAppender" fileName="logs/log4j2-demo.log" filePattern="logs/log4j2-demo-%d{yyyy-MM-dd}-%i.log"> <PatternLayout> <Pattern>${LOG_PATTERN}</Pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="10MB" /> </Policies> <DefaultRolloverStrategy max="10"/> </RollingFile>
Örnek
Şöyle yaparız
<Appenders>
  <RollingFile name="file" 
    fileName="${sys:mule.home}${sys:file.separator}logs${sys:file.separator}log.log"
    filePattern="${sys:mule.home}${sys:file.separator}logs${sys:file.separator}log-%i.log">
    <PatternLayout pattern="%-5p %d [%t] [%MDC] %c: %m%n"/>
    <SizeBasedTriggeringPolicy size="10 MB"/>
    <DefaultRolloverStrategy max="10"/>
  </RollingFile>
</Appenders>

28 Ekim 2021 Perşembe

Bean Validation @Email Anotasyonu

Giriş
Şu satırı dahil ederiz.
import javax.validation.constraints.Email;
Kullanım
Örnek
Şöyle yaparız,
@Data
public class MyApiContract {
  ...
  @Email
  String emailAddress;
}
flags Alanı
Örnek
Normalde düzenli ifade küçük harf farkı gözetir. Bu olmasın istersek şöyle yaparız
@Data
public class MyApiContract {
  ...
  @Email(regexp = "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,3}",
         flags = Pattern.Flag.CASE_INSENSITIVE)
  String emailAddress;
}
regexp Alanı
Örnek
Şöyle yaparız
@Data
public class MyApiContract {
  ...
  @Email(regexp = "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,3}")
  String emailAddress;
}


Launch4j - Cross-platform Java executable wrapper

Giriş
Açıklaması şöyle
Launch4j is a cross-platform tool for wrapping Java applications distributed as jars in lightweight Windows native executables. The executable can be configured to search for a certain JRE version or use a bundled one, and it’s possible to set runtime options, like the initial/max heap size.
Şeklen şöyle

Açıklaması şöyle
Start by filling the details
- Output file: The name of your exe file.
- Jar: The path to your jar file.

There are a lot of other options which I will let you explore yourself. Some of the features are
- Adding icon
- Allowing only one instance of the app to be opened at a time
- Embedding JRE to your application
- Adding an admin manifest etc.
Daha sonra çark simgesine tıklar ve ayarlarımızı kaydederiz. Run simgesine tıklayarak çıktımızı oluştururuz





21 Ekim 2021 Perşembe

java komutu Module Seçenekleri

Giriş
Açıklaması şöyle. Eğer bir module içindeki reserved veya internal bir sınıfa erişmeye çalışırsak hata alırız.
Due to the new module system, Java 9 does not allow an application by default to see all classes from the JDK, unlike all previous versions of Java. If we try to access some reserved module, we obtain an error like this:
module <module-name> does not "opens <package-name>" to unnamed module.

Everyone knows that we can solve this exception by using the JVM parameters --add-exports or -add-opens ...
Çözüm
1. -add-modules ile module eklenir
2. --add-opens veya add-exports ile module içindeki sınıfa erişim açılır

Örnek - classpath
Şöyle yaparız. Burada module classpath içinde
java --add-modules java.se \
  --add-exports java.base/jdk.internal.ref=ALL-UNNAMED \
  --add-opens java.base/java.lang=ALL-UNNAMED \
  --add-opens java.base/java.nio=ALL-UNNAMED \
  --add-opens java.base/sun.nio.ch=ALL-UNNAMED \
  --add-opens java.management/sun.management=ALL-UNNAMED \
  --add-opens jdk.management/com.ibm.lang.management.internal=ALL-UNNAMED \
  --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED \
  -jar hazelcast-5.2.3.jar
Örnek - classpath
Şöyle yaparız. Burada --module-path ile module belirtiliyor
java --add-modules java.se \
  --add-exports java.base/jdk.internal.ref=com.hazelcast.core \
  --add-opens java.base/java.lang=com.hazelcast.core \
  --add-opens java.base/java.nio=com.hazelcast.core \
  --add-opens java.base/sun.nio.ch=com.hazelcast.core \
  --add-opens java.management/sun.management=com.hazelcast.core \
  --add-opens jdk.management/com.ibm.lang.management.internal=com.hazelcast.core \
  --add-opens jdk.management/com.sun.management.internal=com.hazelcast.core \
  --module-path lib \ 
  --module com.hazelcast.core/com.hazelcast.core.server.HazelcastMemberStarter
--add-exports vs --add-opens
Açıklaması şöyle. Yani --add-opens ile public olan olmayan her şeye erişiliyor. --add-exports ile sadece public olanlara erişiliyor.
- With --add-exports the package is exported, meaning all public types and members therein are accessible at compile and run time.
- With --add-opens the package is opened, meaning all types and members (not only public ones!) therein are accessible at run time.

So the main difference at run time is that --add-opens allows "deep reflection", meaning access of non-public members. You can typically identify this kind of access by the reflecting code making calls to setAccessible(true).
1. --add-exports seçeneği
reserved bir sınıfa erişmek için kullanılır
Örnek
Elimizde şöyle bir kod olsun. Burada reflection yok, sadece eskinde yazılmış bir kod, yeni Java ile çalıştırılıyor ve artık BuddhistCalendar sınıfın dışarıya açılmadığı için yani reserverd/internal olduğu için hata veriyor.
BuddhistCalendar calendar = new BuddhistCalendar();


// Output
error: package sun.util is not visible
  (package sun.util is declared in module java.base, which does not export it)
Düzeltmek için şöyle yaparız
javac --add-exports java.base/sun.util=ALL-UNNAMED Foo.java
Örnek
Şöyle yaparız.
java --add-exports java.security.jgss/sun.security.krb5.internal.ktab=ALL-UNNAMED
  your-class
2. --add-opens
reserved bir module'e erişmek için kullanılır

Örnek
Elimizde şöyle bir kod olsun. Burada reflection var ve yeni Java ile çalıştırılıyor.  Artık BuddhistCalendar  sınıfın dışarıya açılmadığı için yani reserverd/internal olduğu için hata veriyor.
Class.forName("sun.util.BuddhistCalendar").getConstructor().newInstance();

//Output
Exception in thread "main" java.lang.IllegalAccessException:
  class Internal cannot access class sun.util.BuddhistCalendar (in module java.base)
  because module java.base does not export sun.util to unnamed module @1f021e6c
    at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException
      at java.base/java.lang.reflect.AccessibleObject.checkAccess
      at java.base/java.lang.reflect.Constructor.newInstanceWithCaller
      at java.base/java.lang.reflect.Constructor.newInstance
Düzeltmek için şöyle yaparız
java \
  --add-opens java.base/sun.util=ALL-UNNAMED \
  --class-path com.bar.foo.jar \
  com.bar.foo.Foo
Örnek
Şöyle yaparız.
set JAVA_OPTS=--add-modules jdk.unsupported --add-opens=java.base/java.nio=ALL-UNNAMED
3. -add-modules seçeneği
Bazı module isimleri şöyle
- java.se
- jdk.unsupported
- java.xml.bind

Örnek
Java 9 ile geçilen modül sisteminden sonra Java EE jar'larını classpath'e dahil edebilmek için şöyle yaparız.
java --add-modules java.xml.bind <class file>
Örnek
Şöyle yaparız.
java --add-modules java.se.ee -jar myspringbootproject.jar
4. --module-path veya -p seçeneği
-p ile aynıdır. Açıklaması şöyle. Yani --module-path modulepath veya -p modulepath şeklindedir.
Searches for directories from a semicolon-separated (;) list of directories. Each directory is a directory of modules.
Örnek
Şöyle yaparız.
java --module-path mymods -m com.test/com.test.HelloWorld
Örnek
jar dosyasındaki modülleri listelemek için şöyle yaparız.
java -p yourModular.jar --list-modules

19 Ekim 2021 Salı

Jakarta EE @MessageDriven Anotasyonu

Giriş
Eski kodlarda şu satırı dahil ederiz.
import javax.ejb.MessageDriver;
Şu satırı dahil ederiz
import jakarta.ejb.MessageDrive;
Message Driven Bean (MDB) asenkron ve stateless çalışır. Çoğunlukla JMS ile kullanılsa da farklı mesajlaşma ara katmanlarını da destekler

Örnek
Şöyle yaparız
@JMSDestinationDefinition(name = "queue/PayaraMessageQueue", 
                          interfaceName = "javax.jms.Queue", 
                          destinationName = "PayaraMessageQueue")
@MessageDriven(activationConfig = {
  @ActivationConfigProperty(propertyName = "destinationLookup", 
                            propertyValue = "queue/PayaraMessageQueue"),
  @ActivationConfigProperty(propertyName = "destinationType", 
                            propertyValue = "javax.jms.Queue") })
public class MDBean implements MessageListener  {

  @Override
  public void onMessage(Message msg) {
    TextMessage message = (TextMessage) msg;
    ...
  }
}