30 Kasım 2022 Çarşamba

Confluent SchemaRegistryRestApplication Sınıfı

Giriş
Şu satırı dahil ederiz
import io.confluent.kafka.schemaregistry.rest.SchemaRegistryRestApplication;
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>io.confluent</groupId>
  <artifactId>kafka-schema-registry</artifactId>
  <version>6.2.2</version>
  <scope>test</scope>
</dependency>
constructor
Şöyle yaparız
import io.confluent.kafka.schemaregistry.rest.SchemaRegistryConfig;
import io.confluent.kafka.schemaregistry.rest.SchemaRegistryRestApplication;

Properties properties = new Properties();
//properties.put("listeners", "http://0.0.0.0:0");
properties.put(SchemaRegistryConfig.KAFKASTORE_BOOTSTRAP_SERVERS_CONFIG, ...);
properties.put(SchemaRegistryConfig.KAFKASTORE_TIMEOUT_CONFIG, "5000");
SchemaRegistryConfig config = new SchemaRegistryConfig(properties); SchemaRegistryRestApplication schemaRegistryApplication = new SchemaRegistryRestApplication(config); schemaRegistry = schemaRegistryApplication.createServer(); schemaRegistry.start();
Unit Test
 schemaregistry-junit kullanılabilir

Örnek - JUnit 5
Şöyle yaparız
@RegisterExtension
@Order(1)
static final SharedKafkaTestResource kafka = new
  SharedKafkaTestResource().withBrokers(1);
@RegisterExtension
@Order(2)
static final SharedSchemaRegistryTestResource schemaRegistry =
    new SharedSchemaRegistryTestResource()
        .withBootstrapServers(kafka::getKafkaConnectString);


29 Kasım 2022 Salı

BindException Sınıfı

Giriş
Şu satırı dahil ederiz.
import java.net.BindException;
Hata 1
Genellikle hata şöyle. Yani server socket tarafından alınmak istenilen port zaten kullanılıyor
java.net.BindException: Address already in use
Linux
Bu portu kullanan process'i bulmak için şöyle yaparız
lsof -i:8080
Hata 2
Bazen hata şöyle
java.net.BindException: Cannot assign requested address: bind
Wndows'ta buna sebep olan bir kod şöyle
InetAddress address = InetAddress.getByName("224.0.0.219");
DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET);
datagramChannel.bind(new InetSocketAddress(address, 10863));
Açıklaması şöyle
I am trying to write an application that listens to a number of multicast groups using Windows sockets.

The problem I'm running in to is that when I go to bind the socket, if I try to bind to the multicast group address and port this fails with WSAEADDRNOTAVAIL. If I instead bind to INADDR_ANY and the port, then I can still receive other unrelated traffic destined for the same port.

When I implemented the same thing in Linux, I didn't have any issues binding to the multicast address (in fact, I saw it recommended several places to avoid getting unrelated traffic for the port).

Is this just not available with Windows sockets? I assume I could filter traffic myself by using WSARecvFrom and peeking at the headers, but I'd rather a simple solution if one exists.

Also, this is running on Windows Server 2008.
Burada kişi sadece Multicast trafiği almak istiyor, Unicast trafiği istemiyor. Bu yüzden bind() çağrısına multicast address + port numarasını geçiyor. Ama bu kod Windows'ta çalışmıyor. 

Yani anladığım kadarıyla Windows'ta sadece Multicast trafiği dinlemek imkansız. Multicast + Unicast trafik olacak şekilde çalışıyor. Yani şöyle yapmak gerekir
datagramChannel.bind(new InetSocketAddress(10863));


LDAP Kullanımı

1. LDAP sunucu URL'si 
Şuna benzer.
ldap://xxxx.com:389
2. LDAP ve Encoding
LDAP v3 UTF-8 encoding kullanır.

3. LDAP ve Büyük Küçük Harf
LDAP ile harf farklılığına bakmayı zorlamak için şöyle yaparız 
cn: caseExactMatch:=Darth Vader
4. Object Class Nedir?
Açıklaması şöyle
Basically, the object classes determine what attributes an entry should/can have.
Daha detaylı açıklama şöyle
All LDAP entries are typed, meaning they all belong to a particular objectClass, which helps to identify the type of data represented by the entry. An object class will represent the mandatory and optional attributes associated with an entry of that class.

Object classes are also in the form of a hierarchy, with “top” and “alias” being at the root of the hierarchy. OrganizationalPerson is a subclass of Person object class, which is a subclass of top object class.

When creating an entry we need to include all the object classes the entry belongs to along with the superclasses. For example, with the inerOrgPerson object class we can assign the attributes such as givenName, cn, sn etc to an entry.
5. LDAP Hiyerarşisi
Şeklen şöyle


Bileşenler şöyle

Domain Component (DC) - DNS İsmi
Firmanın DNS isminin noktalar hariç ayrılmış hali olara düşünülebilir. Örneğin DNS ismi firma.com ise dc aşağıdaki gibi olacaktır.
dc=firma,dc=com.
Organizational Unit (OU) - Kullanıcının Ait Olduğu Grup
Kişinin ait olduğu gruplar olarak düşünülebilir. Örneğin ben personel ve muhasebe grubuna aitsem ou aşağıdaki gibi olacaktır.
ou=personel,ou=muhasebe
CN (Common Name) - Kullanıcı Ad Soyad
Bir nesneye verilen isim olarak düşünülebilir. Örneğin bir kullanıcı nesnesi için aşağıdaki gibi olacaktır. cn genellikle ad ve soyad bilgisini içerir.
cn = Cin Ali.
sAMAccountName
Kullanıcının login adı. Artık pek kullanılmıyor.

SN (Surname) - Kullanıcı Soyadı
Kullanıcının soyadı

Distinguished Name (DN)
DN bir nesneyi diğerlerinden ayırt edilebilir yapar. DN yukarıda belirtilen CN, OU ve DC'lerin bileşimidir. Yukarıdaki örneklere göre benim dn tanımım aşağıdaki gibi olacaktır.
cn=cin ali, ou=personel,ou=muhasebe,dn=firma,dn=com
Web adreslerinde önce DNS'ten başlanır sonra istenilen sayfa adresi gelir. Yani bir nevi büyükten küçüğe doğru gidilirken LDAP'te DN isminin oluşturulması için en küçükten en büyüğe doğru gidildiğine dikkat etmek lazım. Mastering LDAP Search sayfasında şöyle bi cümle geçiyordu.
objects “above” another object are notated as being to the right of the object in LDIF.


25 Kasım 2022 Cuma

OSGi Working Group

Giriş
Açıklaması şöyle
OSGI, started in 2000, aimed to provide versioned components that could be safely deployed and undeployed at runtime. It kept the JAR deployment unit but added metadata in its manifest. OSGi was powerful, but developing an OSGi bundle (the name for a module) was complex. Developers paid a higher development cost while the operation team enjoyed the deployment benefits. DevOps had yet to be born; it didn’t make OSGi as popular as it could have been.

In parallel, Java’s architects searched for their path to modularizing the JDK. The approach is much simpler compared to OSGI, as it avoids deployment and versioning concerns. Java modules, introduced in Java 9, limit themselves to the following data: a name, a public API, and dependencies to other modules.


SocketTimeoutException Sınıfı

Giriş
Şu satırı dahil ederiz
import java.net.SocketTimeoutException;
Örnek - read time out
Elimizde şöyle bir kod olsun
URL url = new URL("https://...");
URLConnection urlConnection = url.openConnection(); urlConnection.setConnectTimeout(20_000); urlConnection.setReadTimeout(5_000); BufferedInputStream is = new BufferedInputStream(urlConnection.getInputStream()); byte[] buffer = new byte[1024]; int n = input.read(buffer);
Exception şöyle
java.net.SocketTimeoutException: Read timed out
Java 8 ile Exception stack trace şöyle
stackTrace = {StackTraceElement[46]@3885} 
 0 = {StackTraceElement@3887} "java.net.SocketInputStream.socketRead0(Native Method)"
 1 = {StackTraceElement@3888} "java.net.SocketInputStream.socketRead(SocketInputStream.java:116)"
 2 = {StackTraceElement@3889} "java.net.SocketInputStream.read(SocketInputStream.java:171)"
 3 = {StackTraceElement@3890} "java.net.SocketInputStream.read(SocketInputStream.java:141)"
 4 = {StackTraceElement@3891} "sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:476)"
 5 = {StackTraceElement@3892} "sun.security.ssl.SSLSocketInputRecord.readFully(SSLSocketInputRecord.java:459)"
 6 = {StackTraceElement@3893} "sun.security.ssl.SSLSocketInputRecord.decodeInputRecord(SSLSocketInputRecord.java:243)"
 7 = {StackTraceElement@3894} "sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:181)"
 8 = {StackTraceElement@3895} "sun.security.ssl.SSLTransport.decode(SSLTransport.java:110)"
 9 = {StackTraceElement@3896} "sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1426)"
 10 = {StackTraceElement@3897} "sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1391)"
 11 = {StackTraceElement@3898} "sun.security.ssl.SSLSocketImpl.access$300(SSLSocketImpl.java:73)"
 12 = {StackTraceElement@3899} "sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:978)"
 13 = {StackTraceElement@3900} "java.io.BufferedInputStream.read1(BufferedInputStream.java:284)"
 14 = {StackTraceElement@3901} "java.io.BufferedInputStream.read(BufferedInputStream.java:345)"
 15 = {StackTraceElement@3902} "sun.net.www.MeteredStream.read(MeteredStream.java:134)"
 16 = {StackTraceElement@3903} "java.io.FilterInputStream.read(FilterInputStream.java:133)"
 17 = {StackTraceElement@3904} "sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3471)"
 18 = {StackTraceElement@3905} "java.io.BufferedInputStream.fill(BufferedInputStream.java:246)"
 19 = {StackTraceElement@3906} "java.io.BufferedInputStream.read1(BufferedInputStream.java:286)"
 20 = {StackTraceElement@3907} "java.io.BufferedInputStream.read(BufferedInputStream.java:345)"
 21 = {StackTraceElement@3908} "java.io.FilterInputStream.read(FilterInputStream.java:107)"

23 Kasım 2022 Çarşamba

AtomicLongFieldUpdater Sınıfı

Giriş
Şu satırı dahil ederiz
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
Aslında soyut bir sınıf. Kalıtım şöyle
AtomicLongFieldUpdater 
  CASUpdater
  LockedUpdater

Bu sınıf Neden Lazım
Açıklaması şöyle. Yani performans yüzünden AtomicX yerine volatile X kullanıyoruz.
The class AtomicLongFieldUpdater is one of the three field updater classes. The field updater classes exist primarily for performance reasons. Instead of using atomic variables, one can use ordinary volatile variables that occasionally need to be get and then set atomically. 
Hangi Durumda Kullanılır
Açıklaması şöyle.
In the case where multi-threaded access is needed, but most operations are simple reads or writes, with only a few atomic operations needed, you can create one static instance of AtomicLongFieldUpdate and use this when atomic updates are needed. The memory/runtime overhead is then similar to a simple volatile variable, except for the atomic operations which are of the order of (or slightly more expensive than) the ordinary AtomicLong operations
Yani read işleminin çokça ancak write işleminin az olduğu bir durum düşünelim. write işlemi birden fazla thread tarafından yapılıyorsa volatile kullanamayız. Ancak AtomicLong'un maliyetini de istemiyoruz. İşte bu durumda AtomicLongFieldUpdater  birden fazla thread tarafından volatile nesnenin atomic olarak güncellenmesini sağlıyor.

Dolayısıyla maliyet şöyle
ordinary long: cheap, but unsafe for multi-threaded access
volatile long: more expensive, safe for multi-threaded access, atomic operations not possible
AtomicLongFieldUpdater : Bu aradaki boşluğu dolduruyor
AtomicLong: most expensive, safe for multi-threaded access, atomic operations possible
Örnek
Şöyle yaparız
public class Foo {

  private static final AtomicLongFieldUpdater<Foo> ENTRY_COUNT = 
    AtomicLongFieldUpdater.newUpdater(Foo.class,"entryCount");

  private volatile long entryCount;

  public void bar() {
    ENTRY_COUNT.incrementAndGet(this);
    ..   
}


22 Kasım 2022 Salı

Kafka Admin API

Admin Sınıfı
Şu satırı dahil ederiz
import org.apache.kafka.clients.admin.Admin;
createTopics metodu
Örnek
Şöyle yaparız
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.clients.admin.CreateTopicsResult;

public void createTopic(String topicId, int partitionCount) {
  List<NewTopic> newTopics = Collections.singletonList(new NewTopic(topicId, 
     partitionCount, (short) 1));
  CreateTopicsResult createTopicsResult = admin.createTopics(newTopics);
  try {
    createTopicsResult.all().get();
  } catch (InterruptedException | ExecutionException e) {
    throw new RuntimeException(e);
  }
}


21 Kasım 2022 Pazartesi

SDKMan - Java Sürümlerini Yönetir

Giriş
sdk komutu TAB ile tamamlamayı destekliyor

Kurulum
Örnek - MacOS
Şöyle yaparız. Otomatik olarak .zshrc dosyasına kendisini ekler
curl -s "https://get.sdkman.io" | bash
Örnek - Windows .GitBash
Şöyle yaparız. Benim .GitBash ile zip geliyordu ayrıca kurmaya gerek kalmadı. Sonra .GitBash tekrar başlatılır
export SDKMAN_DIR="/d/Kurulumlar/sdkman" && curl -s "https://get.sdkman.io" | bash


1. default seçeneği
Söz dizimi şöyle. Java seçimini kalıcı olarak değiştirir. 
sdk default java <version>
Örnek
Şöyle yaparız
sdk default java 11.0.20-amzn
2. install seçeneği
Söz dizimi şöyle
sdk install java <version>
Örnek - MacOS
Şöyle yaparız
sdk install java 22.3.r17-grl
Örnek 
Şöyle yaparız
sdk install java 19.0.2-oracle
Örnek
Şöyle yaparız
$ sdk install springboot
3. list seçeneği
Kurulabilecek ve kurulu sürümleri listeler. 
Örnek
Şöyle yaparız
sdk list java
4. use seçeneği
Açık olan kabukta java sürümünü değiştirir. Yani Java seçimini geçici olarak değiştirir
Örnek
Şöyle yaparız
sdk use java 19.0.2-oracle








12 Kasım 2022 Cumartesi

SonarQube Create Project

Giriş
Not : Bu yazı SonarQube yazısının bir bölümü

From Azure, From Bitbucket, From GitHub, From GitLab, Manually gibi seçenekler var

Create a Project Sayfası
Projeyi yarattıktan sonra CI/CD pipeline'a dahil olmak için bir token yaratmak gerekiyor. Bu token sonar plugin ayarlarına giriliyor. Böylece plugin koşturduğu test sonuçlarını Sonar'a gönderebiliyor. Şeklen şöyle

Proje Nerede Çalışacak
Şeklen şöyle. Burada Locally seçiliyor


Provide a Token - Token Yaratma
Şeklen şöyle

Bir başka şekil şöyle

token sonar.login alanında kullanılır.

Run Analysis on your project
Burada sadece ne yapılacağına dair açıklama gösteriliyor. Java + maven için açıklama şeklen şöyle

SonarQube Code Sekmesi - İstatistik Gösterir

Giriş
Not : Bu yazı SonarQube yazısının bir bölümü

Şeklen şöyle


SonarQube Security Hotspots Sekmesi

Giriş
Not : Bu yazı SonarQube yazısının bir bölümü

Şeklen şöyle
Burada Math.random() günli olmadığı için uyarı gösteriliyor.

SonarQube Issues Sekmesi

Giriş
Not : Bu yazı SonarQube yazısının bir bölümü

- Bug sekmesinde bariz şekilde hatalı şeyler gösterilir. Önce bunlar düzeltmek gerekir, çünkü sayıları 
Code Smell sekmesine göre genellikle daha az oluyor.
- Code Smell sekmesinde düzeltilmesi gereken kodlar gösterilir. 

Code Smells
Şeklen şöyle


Bir başka şekil şöyle

Eğer Open menüsüne tıklarsak Resolve as false positive seçeneğini görebiliriz. Nadiren de olsa Sonar hata yapıyor. Bunları false positive olarak işaretleyip bu madde kapatılabilir. Şeklen şöyle






SonarQube Overview Sekmesi - Quality Gate Status Alanı

Giriş
Not : Bu yazı SonarQube yazısının bir bölümü

Overview sekmesinde  3 tane alan var

1. Quality Status Alanı

2. New Code Code Sekmesi
Burada yeni kodların durumu gösterilir. New Bugs, New Vulnerabilities, New Security Hotspots, Added Debt vs gibi alanlar var.

3. Overall Code Sekmesi
Burada tüm kodun durumu gösterilir. Bugs, Vulnerabilities, Security Hotspots, Debt vs gibi alanlar var.

Bu alan ve panellerin açıklaması şöyle
Quality gate status: Passed. You can set certain rules for quality gate and based on them, you’ll get a boolean, passed or not. Rule can be for example Test coverage 80%

New Code / Overall Code: In the Overall, you can get all the reports within the project code base. In New Code, you can see the diff after running a second analysis of the same branch. So you can see only the analysis of your latest changes.

Main reporting: Bugs, Vulnerabilities, Security issues, Code smells and technical debts. All with links included so you can dive in. Technical debt is measured by some average assumptions made by SonarQube, and it can give you the feeling how much time will you spent on solving these things.

Coverage: I do have 3 unit tests, and SonarQube detects them, which is nice. However, I remember there has to be some SonarQube plugins activated (or configured) so it can detect line coverage. As you can see, it’s 0.0% at the moment, which I know it’s not correct.

Duplication: This section can find and show how much duplicated code do you have in terms of line and percentage of your total code base.

Quality Gate Status Alanı
Soldaki panelin adı Quality Gate Status Alanı. Tüm projenin genel durumu gösterilir. Eğer projede sorun varsa FAILED olarak işaretlenir ve sebebi açıklanır. Şeklen şöyle. Burada testlerde ve kapsamada sorun yok. Code smell olsa bile Passed olarak gösteriliyor.

FAILED Durumu
Şeklen şöyle. Burada On New Code yani yeni kod için test yazılmadığı belirtiliyor ve proje FAILED olarak gösterilir.


Örnek
Şeklen şöyle



10 Kasım 2022 Perşembe

JDBC BatchUpdateException

Giriş
Şu satırı dahil ederiz
import java.sql.BatchUpdateException;
Açıklaması şöyle
BatchUpdateException: This type of exception will be thrown if any error has occurred while doing the batch update operation. Besides the SQLException information, BatchUpdateException provides the status of the statements which have been executed/updated before the error has occurred.
Kullanım Örneği
Yani kod şöyledir. addBatch() çağrısı yapılmaktadır
try(Connection conn = ...;
    Statement statement = conn.createStatement()) {
//Adding the 3 insert queries into the Statement object using addBatch method statement.addBatch(insert_query1);
statement.addBatch(insert_query2);
statement.addBatch(insert_query3);
int afffectedRows[] = statement.executeBatch();
} catch(BatchUpdateException exception) { ... }
Çeşitli Sürücüler İçin Notlar
1. MySQL Sürücüsü
BatchUpdateException içinde SQLIntegrityConstraintViolationException var ve SQLState "23000"

Örnek
Hata şöyle olabilir. Bath insert işleminde bir satır zaten mevcut.
java.sql.BatchUpdateException: Duplicate entry '0' for key 'foo.PRIMARY'

2. PostgreSQL Sürücüsü
BatchUpdateException içinde org.postgresql.util.PSQLException var ve SQLState "23505"

Örnek
Hata şöyle olabilir. Bath insert işleminde bir satır zaten mevcut.
java.sql.BatchUpdateException: Batch entry 0 INSERT INTO foo ( "id","name" )  VALUES (0, 'updated') was aborted: ERROR: duplicate key value violates unique constraint "..."
  Detail: Key (id)=(0) already exists.  Call getNextException to see other errors in the batch.

3. H2
org.h2.jdbc.JdbcBatchUpdateException zaten java.sql.BatchUpdateException sınıfından kalıtıyor
SQLState "23505"
Örnek
Hata şöyle olabilir. Bath insert işleminde bir satır zaten mevcut.
org.h2.jdbc.JdbcBatchUpdateException: Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.foo(id) ( /* key:0 */ 0, 'name-0')"; SQL statement:
INSERT INTO foo ( "id","name" )  VALUES (?, ?) [23505-214]

Eğer bunları bir string şeklinde isteseydik şöyle olurdu
String H2_PK_VIOLATION = "Unique index or primary key violation";
String PG_PK_VIOLATION = "ERROR: duplicate key value violates unique constraint";
String MYSQL_PK_VIOLATION = "Duplicate entry";
Integrity Violation Kontrolü
İki yöntem var. Burada gördüm

1. Spring gibi vendor kodlarını XML içinde toplamak
2. Kodla SQLState değerine bakmak. 23XX şeklinde olmalı

Örnek
Şöyle yaparız
Throwable findSQLException(Throwable throwable) {
  Throwable rootCause = throwable;
  while (rootCause.getCause() != null && rootCause.getCause() != rootCause) {
    rootCause = rootCause.getCause();
    if (rootCause instanceof SQLException) {
      return rootCause;
    }
  }
  return null;
}

// SQLException returns SQL state in five digit number.
// These five-digit numbers tell about the status of the SQL statements.
// The SQLSTATE values consists of two fields.
// The class, which is the first two characters of the string, and
// the subclass, which is the terminating three characters of the string.
// See https://en.wikipedia.org/wiki/SQLSTATE for cate
boolean isIntegrityConstraintViolation (Exception exception) {
  boolean result = false;
  Throwable rootSQLException = findSQLException(exception);
  if (rootSQLException != null) {
    SQLException sqlException = (SQLException) rootSQLException;
    String sqlState = sqlException.getSQLState();
    if (sqlState != null) {
      result = sqlState.startsWith("23");
    }
  }
  return result;
}
getUpdateCounts() metodu
İmzası şöyle
int[] getUpdateCounts()
Açıklaması şöyle
How to find which statement failed in a JDBC Batch Update?
However, we can pinpoint the failing statements by introspecting the result of the getUpdateCounts method on the java.sql.BatchUpdateException that is thrown by the JDBC Driver.

Because the getUpdateCounts method returns an int[] array with two entries, we know that only two statements were successfully processed. So, the third statement was the one causing the failure.



JDBC SQLTransientConnectionException

Giriş
Şu satırı dahil ederiz
import java.sql.SQLTransientConnectionException;
Örnek
Çıktı şöyledir
Caused by: java.sql.SQLTransientConnectionException: 
  HikariPool-1 - Connection is not available, request timed out after 30000ms.


8 Kasım 2022 Salı

Stream Arayüzü Neden Lazy

Giriş
Bir çok stream metodu StatelesOp nesnesi döndürür. Şeklen şöyle

Stream metodlarının gerçekleştirimi ReferencePipeline sınıf içinde. ReferencePipeline da aslında kalıtım sebebiyle bir Stream nesnesi.

Bu sınıfın map metoduna bakalım. Kod şöyle. Yeni bir StatelessOp döndürüyor . StatelessOp sınıfı abstract olduğu için davranışını onWrapSink() ile belirterek yeni bir ReferencePipeline yani Stream oluşturdu
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
  Objects.requireNonNull(mapper);
  return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE, <- Pass upstream
                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
    @Override
    Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
      return new Sink.ChainedReference<P_OUT, R>(sink) {
        @Override
        public void accept(P_OUT u) {
          downstream.accept(mapper.apply(u)); <- Call next stream
        }
      };
    }
  };
}
StatelessOp constructor şöyle. Burada ilk parametrenin isminin upstream olduğu görülebilir.
StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
            StreamShape inputShape,
            int opFlags) {
  super(upstream, opFlags);
  assert upstream.getOutputShape() == inputShape;
}
super() ile çağrılam kod şöyle
ReferencePipeline(AbstractPipeline<?, P_IN, ?> upstream, int opFlags) {
  super(upstream, opFlags);
}
ve tekrar super ile çağrılam kod şöyle. Burada upstream'in ismi birden previousStage oldu. Yani her stream arayüzünün sağladığı her metod çağrısı aynı zamanda bir stage olarak düşünülüyor.
AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
  if (previousStage.linkedOrConsumed)
    throw new IllegalStateException(MSG_STREAM_LINKED);
  previousStage.linkedOrConsumed = true;
  previousStage.nextStage = this;

  this.previousStage = previousStage;
  this.sourceOrOpFlags = opFlags & StreamOpFlag.OP_MASK;
  this.combinedFlags = StreamOpFlag.combineOpFlags(opFlags, previousStage.combinedFlags);
  this.sourceStage = previousStage.sourceStage;
  if (opIsStateful())
    sourceStage.sourceAnyStateful = true;
  this.depth = previousStage.depth + 1;
}
Elimizde şöyle bir kod olsun
Stream<Integer> integerStream = Arrays.asList(Integer.valueOf(1), Integer.valueOf(2))
  .stream().
  map(Scratch::multiply);
Debugger'daki object'ler şöyle
//sourceStage yerine source
//nextStage yerine sink diyelim

//Pipeline nesnesi. sink null, source @839 
integerStream = ReferencePipeline$3@836
  mapper = Scratch$lambda@838
  sourceStage = ReferencePipeline$Head@839
  previousStage = ReferencePipeline$Head@839
  nextStage = null
  sourceSplitIterator = null;
  sourceSupplier = null;

  //source kendisi sink @836, 
  sourceStage = ReferencePipeline$Head@839
    sourceStage = ReferencePipeline$Head@839
    previousStage = null;
    nextStage = ReferencePipeline$3@836
    sourceSplitIterator = SplitIteratos$ArraySpliterator@840;
    sourceSupplier = null

     //source @839, sink null
      nextStage = ReferencePipeline$3@836
        mapper = Scratch$lambda@838
        sourceStage = ReferencePipeline$Head@839
        previousStage = ReferencePipeline$Head@839 
        nextStage = null
        sourceSplitIterator = null;







Java Microbenchmark Harness (JMH) Kullanımı

Gradle
Şu satırı dahil ederiz
plugins {
...
  id "me.champeau.gradle.jmh" version "0.5.3"
...
}
Çalıştırmak için şöyle yaparız
gradle jmh
@State Anotasyonu
Scope.Benchmark
Açıklaması şöyle. Tek bir nesneyi multi-threaded olarak test etmek içindir
By using benchmark scope, all of the threads used on the benchmark scope will share the same object. 
@OutputTimeUnit Anotasyonu
Açıklaması şöyle.
We would like our results to be reported in microseconds, therefore we shall use @OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode Anotasyonu
Açıklaması şöyle.
On JMH, we have various benchmark modes depending on what we want to measure.

Throughput is when we want to measure the number of operations per unit of time.
AverageTime is when we want to measure the average time per operation.
SampleTime is when we want to sample the time for each operation including min, max time, and more than just the average.
SingleShotTime is when we want to measure the time for a single operation. This can help when we want to identify how the operation will do on a cold start.
All We also have the option to measure all of the above with @BenchmarkMode(Mode.All)
@Threads Anotasyonu
Kaç thread ile koşacağını belirtir

@Warmup Anotasyonu
Kaç defa ısınma yapılacağını belirtir

@Fork Anotasyonu
Benchmark testin kaç defa yapılacağını belirtir

@Measurement
Kaç yineleme yapılacağını belirtir. Çıktıda count sütununda gösterilir.

Kullanım
Örnek
Şöyle yaparız. Test sonucu nano saniyedir ve ortalaması alınır. Multi-threaded test yapar. Test 2 defa fork edilir ve her birisi 2 yineleme yapar. 
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@State(Scope.Benchmark)
@Fork(value = 2)
@Measurement(iterations = 2)
@Warmup(iterations = 1)
public class MyBenchmark {

  @Benchmark
  public long foo() {
   ...
  }

  @Benchmark
  public long bar() {
      ...
  }
}

Örnek
Şöyle yaparız
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.All)
public class RateLimiterBenchmark {
  private static final int FORK_COUNT = 2;
  private static final int WARMUP_COUNT = 10;
  private static final int ITERATION_COUNT = 10;
  private static final int THREAD_COUNT = 2;
 
  public static void main(String[] args) throws RunnerException {
    Options options = new OptionsBuilder().addProfiler(GCProfiler.class).build();
     new Runner(options).run();
  }
 
  @Setup
  public void setUp() {
    ...
  }
 
  @Benchmark
  @Threads(value = THREAD_COUNT)
  @Warmup(iterations = WARMUP_COUNT)
  @Fork(value = FORK_COUNT)
  @Measurement(iterations = ITERATION_COUNT)
  public String refillPermission() {
    ...
  }
}
Çıktı şöyle. Score sütunu değeri daha düşük olan daha hızlıdır
Benchmark                                                         Mode       Cnt      Score   Error   Units
RateLimiterBenchmark.refillPermission                            thrpt        20     13.594 ± 0.217  ops/us
RateLimiterBenchmark.refillPermission                             avgt        20      0.147 ± 0.002   us/op
RateLimiterBenchmark.refillPermission                           sample  10754462      0.711 ± 0.025   us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.00    sample                  ≈ 0           us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.50    sample                0.084           us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.90    sample                0.125           us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.95    sample                0.125           us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.99    sample                0.209           us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.999   sample              139.008           us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.9999  sample              935.936           us/op
RateLimiterBenchmark.refillPermission:refillPermission·p1.00    sample            20709.376           us/op
RateLimiterBenchmark.refillPermission    
Cnt ile kaç yineleme yapıldığı belirtilir.@Measurement ile count yani iteration/yineleme değeri belirtilir. Açıklaması şöyle
Count is the number of iterations. Apart from throughput where we measure the operations by time, the rest is the time per operation. Throughput, Average, and Single shot are straightforward. Sample lists the percentiles. Error is the margin of error.
Örnek
Şöyle yaparız. Burada @Warmup ile @Setup ile işaretli kod çalıştırılıyor
import org.openjdk.jmh.annotations.Benchmark;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@State(Scope.Benchmark)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 20, time = 1)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@OperationsPerInvocation
public class MapBenchmark {
  private static final int SIZE = 10;

  private Map<Integer, String> mapOf;
  private Map<Integer, String> hashMap;

  @Setup
  public void setup() {
    mapOf = Map.of(
                0, "value0",
                1, "value1",
                2, "value2",
                3, "value3",
                4, "value4",
                5, "value5",
                6, "value6",
                7, "value7",
                8, "value8",
                9, "value9"
    );
    hashMap = new HashMap<>();
    hashMap.put(0, "value0");
    hashMap.put(1, "value1");
    hashMap.put(2, "value2");
    hashMap.put(3, "value3");
    hashMap.put(4, "value4");
    hashMap.put(5, "value5");
    hashMap.put(6, "value6");
    hashMap.put(7, "value7");
    hashMap.put(8, "value8");
    hashMap.put(9, "value9");
  }
  @Benchmark
  public void testMapOf(Blackhole blackhole) {
    Map<Integer, String> map = Map.of(
                0, "value0",
                1, "value1",
                2, "value2",
                3, "value3",
                4, "value4",
                5, "value5",
                6, "value6",
                7, "value7",
                8, "value8",
                9, "value9"
    );
    blackhole.consume(map);
  }
  @Benchmark
  public void testHashMap(Blackhole blackhole) {
    Map<Integer, String> hashMap = new HashMap<>();
    hashMap.put(0, "value0");
    hashMap.put(1, "value1");
    hashMap.put(2, "value2");
    hashMap.put(3, "value3");
    hashMap.put(4, "value4");
    hashMap.put(5, "value5");
    hashMap.put(6, "value6");
    hashMap.put(7, "value7");
    hashMap.put(8, "value8");
    hashMap.put(9, "value9");
    blackhole.consume(hashMap);
  }
  @Benchmark
  public void testGetMapOf() {
    for (int i = 0; i < 10; i++) {
      mapOf.get(i);
    }
  }
  @Benchmark
  public void testGetHashMap() {
    for (int i = 0; i < SIZE; i++) {
      hashMap.get(i);
    }
  }
}
Çıktı şöyle. Score sütunu değeri daha düşük olan daha hızlıdır
Benchmark                    Mode  Cnt   Score   Error  Units
MapBenchmark.testGetHashMap  avgt   20  14.999 ± 0.433  ns/op
MapBenchmark.testGetMapOf    avgt   20  16.327 ± 0.119  ns/op
MapBenchmark.testHashMap     avgt   20  84.920 ± 1.737  ns/op
MapBenchmark.testMapOf       avgt   20  83.290 ± 0.471  ns/op