23 Ekim 2017 Pazartesi

JAXB @XmlID Anotasyonu

Giriş
Foo sınıfı Bar sınıfını içeriyor olsun.

@XmlID Anotasyonu
Bar sınıfı şöyledir.
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {

  @XmlID
  @XmlAttribute
  private String id;

}
@XmlIDREF Anotasyonu
Foo sınıfı şöyledir.
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

  @XmlID
  @XmlAttribute
  private String id;

  @XmlIDREF
  @XmlAttribute
  private Bar reference;

}
XMl şöyledir. Foo sınıfı XML'den okurken reference alanını değeri C ise C değerine sahip Bar nesnesini okur. B ise B değerine sahip Bar nesnesini okur. Yoksa Bar alanı null olur.
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <foos>
    <foo id="B" reference="C"/>
    <foo id="A" reference="B"/>
  </foos>
  <bars>
    <bar id="C"/>
  </bars>
</root>

22 Ekim 2017 Pazar

javapackager komutu - Native Launcher Executable Yaratır, JDK 8 İle Geliyor

Giriş
JDK 8'den sonra ile jpackage kullanılıyor. Native launcher executable yaratır. Bu executable içine JDK da dahil ediliyor. Yani ortaya büyük bir executable çıkıyor. Açıklaması şöyle.  
The Java packaging tools provide built-in support for several formats of self-contained application packages.
The basic package is a single folder on your hard drive that includes all application resources and the JRE. The package can be redistributed as is, or you can build an installable package (for example, EXE or DMG format.)
deploy seçeneği
Şöyle yaparız.
javapackager -deploy -native -outdir OUTPUT_DIR -outfile APPLICATION_NAME 
    -srcdir PACKAGE_SRC_DIR -srcfiles APPLICATION.jar -appclass MAIN_CLASS
    -name "YourApplication" -title "SelfContained"


jlink komutu - Java 9 İle Gelen Java Platform Module System- JPMS İle Custom JRE Yaratır

Giriş
Açıklaması şöyle
Along with modularity, Java 9 includes a tool called jlink. The main purpose of this tool is to assist us in creating custom JRE based on our needs. This tool offers a few options for fine-tuning JRE and the required modules, but it also offers the option of creating a generic JRE that includes all of the modules.
Açıklaması şöyle
For example, if an application does not use audio, image, or JavaBeans-related features, we can remove the java.desktop module entirely
...
The main philosophy is that instead of providing a generic JRE that meets everyone’s needs, everyone should be able to create their own JRE. Many JDK image providers follow the same philosophy by omitting JRE distributions.
Eğer bir jar için gereken modül isimlerini bilmiyorsak jdeps komutu ile bu bulunabilir

add-modules seçeneği
Açıklaması şöyle
--add-modules names the module(s) that you want your runtime image to contain - all of its (their) transitive dependencies are included
Örnek - ALL-MODULE-PATH
Açıklaması şöyle. Yani custom JRE yaratmıyor
if <module> is ALL-MODULE-PATH then all observable modules found on the relevant module paths are added to the root set. 
Şöyle yaparız. Bu bir docker dosyası
# greetings.Dockerfile

FROM amazoncorretto:17-alpine as corretto-jdk

# required for strip-debug to work
RUN apk add --no-cache binutils

# Build small JRE image
RUN jlink \
         --add-modules ALL-MODULE-PATH \
         --strip-debug \
         --no-man-pages \
         --no-header-files \
         --compress=2 \
         --output /jre

FROM alpine:latest
ENV JAVA_HOME=/jre
ENV PATH="${JAVA_HOME}/bin:${PATH}"

COPY --from=corretto-jdk /jre $JAVA_HOME

EXPOSE 8080
COPY ./greetings/build/libs/greetings.jar /app/
WORKDIR /app

CMD ["java", "-jar", "greetings.jar"]
Açıklaması şöyle
- In this case, we used Docker multi-staged builds.
- We use the same amazoncorretto:17-alpine Docker image as the base image in the first stage.
- Following that, we install binutils, which is required by the jlink tool. The jlink tool is then used to create a custom JRE. The most important part of this command is --add-modules ALL-MODULE-PATH, which adds all the modules to JRE. On the Oracle documentation page, you can learn more about all of the options.
- The alpine:latest image is used as the base image in the second stage.
- Then we copy the newly created custom JRE from the previous stage.
- Finally, we are running our application jar file.
Örnek - Modül Listesi
Şöyle yaparız
# Build small JRE image
RUN jlink \
  --verbose \
  --add-modules \
    java.base,java.compiler,java.desktop,java.instrument,java.management,java.naming, \
    java.prefs, java.rmi,java.scripting,java.security.jgss,java.sql,jdk.httpserver, \
    jdk.jfr,jdk.unsupported, jdk.crypto.ec,jdk.crypto.cryptoki \
  --strip-debug \
  --no-man-pages \
  --no-header-files \
  --compress=2 \
  --output /jre
Örnek - Tüm Modüller
Şöyle yaparız.
jlink
    --module-path $JAVA_HOME/jmods:mods
    --add-modules your.app
    --launcher launch-app=your.app
    --output your-app-image
Örnek - jdeps
Şöyle yaparız
FROM maven:3-eclipse-temurin-17 as build
RUN mkdir /usr/src/project
COPY . /usr/src/project
WORKDIR /usr/src/project
RUN mvn package -DskipTests
RUN jar xf target/JavaCoffeeShop.jar
RUN jdeps --ignore-missing-deps -q  \
    --recursive  \
    --multi-release 17  \
    --print-module-deps  \
    --class-path 'BOOT-INF/lib/*'  \
    target/JavaCoffeeShop.jar > deps.info
RUN jlink \
    --add-modules $(cat deps.info) \
    --strip-debug \
    --compress 2 \
    --no-header-files \
    --no-man-pages \
    --output /myjre
FROM debian:bookworm-slim
ENV JAVA_HOME /user/java/jdk17
ENV PATH $JAVA_HOME/bin:$PATH
COPY --from=build /myjre $JAVA_HOME
RUN mkdir /project
COPY --from=build /usr/src/project/target/JavaCoffeeShop.jar /project/
WORKDIR /project
ENTRYPOINT java -jar JavaCoffeeShop.jar
Açıklaması şöyle
In the example above, I utilized a multistage Docker build. The initial building stage is based on an eclipse-temurin JDK 17 image containing Maven. This stage is used to:

- Create the Java artifact. Using Maven, I create the fat executable JAR file that contains the complete application.
- Unpack the JAR file to have all the dependencies. This is only needed if you don’t use the maven-dependency-plugin as described earlier. If you included it, you can skip this step
- Use jdeps to get the necessary modules. Point to the file containing all the dependency JAR files and the final artifact, and save the list in deps.info.
- Run JLink to create a custom Java Runtime. Using the deps.info as input and storing it in /myjre. We only add the modules needed to JLink and remove debug info, manual pages, and header files.

The second and final stage builds the production image based on a debian:stable-slim image.

- Set environment variables. Set the JAVA_HOME to the path I’ll copy myjre to, and add JAVA_HOME to the PATH.
- Copy the Java Runtime created by JLink. Reference the first stage and copy the custom Java Runtime to the location defined as JAVA_HOME.
- Copy the created Java artifact. The created fat executable Spring Boot JAR is copied to the dedicated project directory.
- Set Entrypoint
launcher
Açıklaması şöyle
--launcher is optional, but very handy; it creates an OS-specific launcher (e.g. a .bat on Windows) with the given name (launch-app) that launches the specified module (your.app; in this case assuming the main class is defined for it)
module-path seçeneği
Açıklaması şöyle
--module-path lists the folders that contain modules - this needs to include the platform modules shipped with the JDK you want to use (in $JAVA_HOME/jmods) and your application modules (mods)
Örnek
Şöyle yaparız
$ jlink --module-path $JAVA_HOME/jmods:mlib --add-modules my.module --output myRunTime
Açıklaması şöyle
In the above command, my.module is your module, and myRuntime is the custom runtime image that JLink will create.
output seçeneği
Açıklaması şöyle
--output specifies where to create the runtime image

19 Ekim 2017 Perşembe

javaw komutu

Giriş
java komutu ile aynıdır. Windows'ta bulunur

SelectionKey Sınıfı

Giriş
Şu satırı dahil ederiz.
import java.nio.channels.SelectionKey;
Bu sınıf soyuttur (abstract) ve Selector ilgilidir.

attach metodu
Açıklaması şöyle
Attaches the given object to this key. An attached object may later be retrieved via the attachment method. Only one object may be attached at a time; invoking this method causes any previous attachment to be discarded. The current attachment may be discarded by attaching null."
Örnek
Şöyle yaparız
try {
  Selector selector = Selector.open();
  ServerSocketChannel serverSocket = ServerSocketChannel.open();
  serverSocket.bind(new InetSocketAddress("localhost", 10_000));  
  serverSocket.configureBlocking(false);

  HashMap<String, Object> attr = ...;

  SelectionKey selectionKey = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
  // attach a object
  selectionKey.attach(attr);

  while (true) {
    selector.selectNow();
    Set<SelectionKey> selectionKeySet = selector.selectedKeys();
    Iterator<SelectionKey> iter = selectionKeySet.iterator();
    while (iter.hasNext()) {
      selectionKey = iter.next();
      // Get the attachment object again from selectionKey 
      HashMap attr = (HashMap)selectionKey.attachment();  
      if(selectionKey.isAcceptable()){
        ...
      }
      iter.remove();
    }
  }
}
catch(Exception e) {...}
cancel metodu
Bu sınıf ile Selector arasındaki ilişkiyi koparmak istersek şöyle yaparız.
SelectionKey key = channel.register(mySelector,
    SelectionKey.OP_READ | SelectionKey.OP_WRITE);
...
key.cancel();
channel metodu
SelectableChannel döndürür. Eğer isAcceptable() true dönerse şöyle yaparız.
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
Eğer isConnectable true dönerse şöyle yaparız
if (key.isConnectable()) {
  SocketChannel sc = (SocketChannel) key.channel();
  ...
}
Eğer isReadable true dönerse şöyle yaparız
if (key.isReadable()) {
  SocketChannel sc = (SocketChannel) key.channel();
  ...
}
Eğer isWritable true dönerse şöyle yaparız
if (key.isWritable()) {
  SocketChannel sc = (SocketChannel) key.channel();
  ...
}
isAcceptable metodu
Şöyle yaparız.
if (key.isAcceptable()) {
  ...
} 
Sunucu socketimiz yeni bir bağlantı almıştır.

isConnectable metodu
Şöyle yaparız.
if (key.isConnectable()) {
  ...
} 
İstemci socketimiz bağlanmıştır.

isReadable metodu
Şöyle yaparız.
if (key.isReadable()) {
  ...
} 
Socketimize veri gelmiştir. Burada gıcık bir durum var. key.channel() ile doğru socket tipini elde edemiyoruz. Açıklaması şöyle
SelectionKey.channel() always returns a SelectableChannel. The assigned type of the channel is not really relevant at this point, so you'll have to cast it.
TCP istemcisi ise şöyle yaparız
SocketChannel sc = (SocketChannel) key.channel();
...
TCP istemcisinden okumak için şöyle yaparız. Hata varsa socket kapatılır.
if (sc.read(myByteBuffer) == -1) 
  close(key);
Kapatma işlemi şöyledir.
private void close(SelectionKey key) throws IOException {
  key.cancel();
  key.channel().close();
}
isValid metodu
Şöyle yaparız.
SelectionKey key = ...;

if (!key.isValid()) 
  continue;
isWritable metodu
Şöyle yaparız.
if (key.isWritable()) {
  ...
} 
Socketimiz yazmak için müsaittir.