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;
    ...
  }
}


Wildfly Logging Subsystem

Giriş
Uygulamamızdan log mesajları yazabilmek için iki seçenek var.

1. System Wide Logging
2. Per Deployment Logging

1. System Wide Logging
Bu kullanımda standalone.xml veya türevi olan bir dosyada değişiklik yapıyoruz. Loglarımız server.log dosyasına yazılıyor.

Örnek
Şöyle yaparız. xml dosyasında <logger category="com.foo"> logger ekler.
/subsystem=logging/logger=com.foo:add() \
/subsystem=logging/logger=com.foo:write-attribute(name=level, value=DEBUG)
Örnek
Şöyle yaparız.
/subsystem=logging/logger=com.foo.bar:add()
/subsystem=logging/logger=com.foo.bar:write-attribute(name=level, value=DEBUG) /subsystem=logging/logger=com.foo.bar:add-handler(name=CONSOLE)
2. Per Deployment Logging
Projemizin WEB-INF/classes dizinine bir logging.properties dosyası ekleriz
Veya log4j.xml dosyası ekleriz

18 Ekim 2021 Pazartesi

Wildfly Elytron Subsystem

Giriş
Açıklaması şöyle
Use of the Picketbox-based security vault is no longer supported. Elytron credential stores should be used instead.
Bir açıklama da şöyle
I couldn't find the exact point in time it happened but org.jboss.security.SecurityAssociation was renamed org.jboss.security.SecurityContextAssociation. Therefore by changing your references to org.jboss.security.SecurityAssociation in authorization-service-login-modules-jboss, you should be good to go.
Örnekler burada.

Ekran görüntüsü olarak gösteren bir örnek te burada
Örnek - jdbc authentication
Burada amaç FORM Login doğrulama işlemini Wildfly 'a yaptırmak
# Add a simple role decoder for the "roles" attribute mapping
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=roles)

# Add the JDBC security realm creation
./subsystem=elytron/jdbc-realm=my-jdbc-realm:add(principal-query=[ \
{sql="SELECT passwd FROM USER WHERE username=?",data-source="myDataSource",simple-digest-mapper={algorithm=simple-digest-sha-1,hash-encoding=hex,password-index=1}},\
{sql="SELECT R.ROLENAME, 'Roles' from ROLE R INNER JOIN USER U ON R.USER_ID = U.USER_ID WHERE U.USERNAME=?",data-source="myDataSource",attribute-mapping=[{index=1,to=roles}]}\
]) # Configure the servlet-security domain /subsystem=elytron/security-domain=my-security-domain:add(default-realm=my-jdbc-realm, realms=[{realm=my-jdbc-realm, role-decoder=from-roles-attribute}], permission-mapper=default-permission-mapper) # Configure the HTTP Authentication Factory /subsystem=elytron/http-authentication-factory=my-http-auth:add(http-server-mechanism-factory=global,security-domain=my-security-domain,mechanism-configurations=[{mechanism-name=FORM, mechanism-realm-configurations=[{realm-name=RealUserRoles}]}]) # Configure Undertow's application security domain /subsystem=undertow/application-security-domain=myapp:add(http-authentication-factory=my-http-auth)
web.xml dosyasında şöyle yaparız. Burada uygulanın hangi realm'i ile login olmak istediğimizi belirtiriz.
<login-config>
  <auth-method>FORM</auth-method>
  <realm-name>my-jdbc-realm</realm-name>
  <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/login_error.jsp</form-error-page>
    </form-login-config>
</login-config>
jboss-web.xml dosyasında şöyle yaparız. Burada security domain'i belirtiriz. İşte burada uygulama ile Wildfly security domain ve buna bağlı realm birleşiyor
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web version="11.0" xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_12_0.xsd">
  <context-root>/mygui</context-root>
  <security-domain>my-security-domain</security-domain>
</jboss-web>



Jakarta EE @Local Anotasyonu

Giriş
Eski kodlarda şu satırı dahil ederiz.
import javax.ejb.Local;
Şu satırı dahil ederiz
import jakarta.ejb.Local;
Belirtilen arayüzü JNDI üzerinden dışarıya açar. EJB türlerinin açıklaması şöyle. @Local anotasyonu Local Client View'a denk gelir.
- Local Client View: İstemcinin aynı JVM üzerinde koşması.
- Remote Client View: İstemcinin farklı bir JVM üzerinde koşması. Uygulamamız bunun üzerine olacak.
- No-Interface View: Local gibi istemci aynı JVM’de koşar fakat farklı olarak istemci ile EJB aynı projede olmak zorundadır. İstemci Local Client View’da farklı projelerde farklı EAR’larla deploy edilmiş bir EJB’yi aynı JVM’de koşmak şartıyla çağırabiliyorken, No-Interface’de farklı projede bulunamaz.
Transaction Özelliği
Açıklaması şöyle
If the transaction attribute type is not specified, it is assumed to be REQUIRED. The absence of a transaction attribute specification on the bean class is equivalent to the specification of TransactionAttribute(REQUIRED) on the bean class.
Yani eğer EJB'nin transaction özelliğini belirmezsek sınıf şöyle kabul edilir
@TransactionManagement(TransactionManagementType.CONTAINER)
Metodları ise  şöyle kabul edilir
@TransactionAttribute(TransactionAttributeType.REQUIRED)
Örnek
Şöyle yaparız
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class MyServiceBean  {...}
@Local Anotasyonu
Örnek
Eski kodlarda @Local arayüz üzerine yazılırdı.
@Stateless
public class MyEJB implements MyEJBLocal {
  public void myBusinessMethod() {
    //Implementation
  }
}

@Local
public interface MyEJBLocal {
  public void myBusinessMethod();
}
Ancak sınıfımız sadece tek arayüzden kalıtıyorsa bu gerekli değil. Açıklaması şöyle
Use of the Local annotation is only required when the bean class does not implement only a single interface other than any of the following: java.io.Serializable; java.io.Externalizable; any of the interfaces defined in javax.ejb.
Yani şöyle yazsak bile
public interface MyBeanIntf { void doStuff(); }

@Stateless
public class MyBean implements MyBeanIntf { public void doStuff(){ } }
Bu aslında şu kod gibi kabul edilebilir
@Local
public interface MyBeanIntf { void doStuff(); }

@Stateless
public class MyBean implements MyBeanIntf { public void doStuff(){ } }
Aslında @Local anotasyonunu kullanınca JNDI ismi de değişiyor. Şu hale geliyor
java:app/mymodule/FooBean //@Stateless için
java:app/mymodule/MyBean!com.foo.bar.MyBeanIntf @Local için