23 Aralık 2021 Perşembe

Hamcrest

Giriş
Açıklaması şöyle
Hamcrest is an assertion library that helps to build a declarative pipeline of matchers.
assertThat 
Şu satırı dahil ederiz
import static org.hamcrest.MatcherAssert.assertThat;
Daha sonra hazır gelen Matchers.XX metodları ile kullanırız

Collection Matcher
empty(), hasSize(), arrayWithSize(),containsInAnyOrder(),contains(),hasItemInArray(),isOneOf(),isIn(),arrayContainingInAnyOrder(), arrayContaining(),hasKey(),hasValue(),hasEntry()

gibi bir sürü metod var

hasSize
Şu satırı dahil ederiz
import static static org.hamcrest.collection.IsCollectionWithSize.hasSize;
Örnek
Şöyle yaparız
assertThat(res, hasSize(3));
TypeSafeMatcher
matchesSafely() ve describeTo() metodlarını override etmek yeterli.
Örnek
Şöyle yaparız
Matcher<List<PostView>> hasComments(int count) {
  return new TypeSafeMatcher<>() {
    @Override
    protected boolean matchesSafely(List<PostView> item) {
      return item.stream()
            .allMatch(post -> post.comments().size() == count);
    }

    @Override
    public void describeTo(Description description) {
      description.appendText(count + " comments in each post");
    }

    @Override
    protected void describeMismatchSafely(List<PostView> item,
                                          Description mismatchDescription) {
      mismatchDescription.appendText(
        item.stream()
          .map(postView -> format(
                    "PostView[%d] with %d comments",
                    postView.id(),
                    postView.comments().size()
           ))
           .collect(joining(" ; "))
      );
    }
  };
}


22 Aralık 2021 Çarşamba

Mockito @MockitoSettings Anotasyonu

Giriş
Şu satırı dahil ederiz
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
Örneği ilk burada gördüm. Aslında bu çözümler sadece UnnecessaryStubbingException fırlatılmasını engelliyor. Testleri halen temizlemekte fayda var. Verilen hata şöyle
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at pl.nsn.railway.grkeepalive.MyTest.testLenient(MyTest.java:41)
  2. -> at pl.nsn.railway.grkeepalive.MyTest.testLenient(MyTest.java:42)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.

Örnek - JUnit 4
Şöyle yaparız. Böylece artık UnnecessaryStubbingException dikkate alınmaz
@RunWith(MockitoJUnitRunner.Silent.class)
public class FooTest {
  ...
}
Örnek - JUnit 5 
@MockitoSettings(strictness = Strictness.LENIENT) kullanırız. Böylece artık UnnecessaryStubbingException dikkate alınmaz
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class MyTest {

  public class MyFrameworkRuntimeProvider {
    String getContainer(String name) {
      return name;
    }
    String getComponentHandle() {
     return null;
    }
  }
  //@Mock
  //MyFrameworkRuntimeProvider mock;

  @Test
  public void testLenient(){

    MyFrameworkRuntimeProvider mock = Mockito.mock(MyFrameworkRuntimeProvider.class);
    Mockito.when(mock.getContainer("1")).thenReturn("1");
    Mockito.when(mock.getContainer("2")).thenReturn("2"); //not called
    Mockito.when(mock.getComponentHandle()).thenReturn(null);//not called
    
    mock.getContainer("1");

    Mockito.verify(mock,Mockito.atLeast(1)).getContainer(Mockito.anyString());
  }
}

16 Aralık 2021 Perşembe

args4j - Command Line (CLI) Parsing

Gradle
Şu satırı dahil ederiz
dependencies {
  implementation 'args4j:args4j:2.32'
}
Bu kütüphaneyi kullanmak Apache CLI kütüphanesine göre daha kolay.

Örnek
Elimizde şöyle bir kod olsun. 
- name ile parametrenin kısa ismi belirtilir
- alias ile parametrenin uzum ismi belirtilir
- usage ile yardım metni belirtilir. 
- required ile parametrenin zorunlu olup olmadığı belirtilir
import org.kohsuke.args4j.Option;

public class CLIParams {
  
  String user;
  String password;
  
  boolean help;

  @Option(name = "-u", aliases = "--user", usage = "user name", required = true,
                 metaVar = "<name>")
  public void setUser(String user) {
    this.user = user;
  }

  @Option(name = "-p", usage = "password", required = true, metaVar = "<password>")
  public void setPassword(String password) {
    this.password = password;
  }

  @Option(name = "-h", usage = "help screen", required = false)
  public void setHelp(boolean help) {
    this.help = help;
  }
}
Şöyle yaparız
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;

public static void main(String[] args) {

  CLIParams params = new CLIParams();
  CmdLineParser cliParser = new CmdLineParser(params);
  try {
    cliParser.parseArgument(args);
    ...
  } catch (CmdLineException e) {
    showHelp();
    System.exit(1);
}

public void showHelp() {
  CLIParams params = new CLIParams();
  CmdLineParser cliParser = new CmdLineParser(params);
  cliParser.printUsage(System.out);
}


12 Aralık 2021 Pazar

CompactNumberFormat Sınıfı

Giriş
Şu satırı dahil ederiz
import java.text.CompactNumberFormat;
Açıklaması şöyle
CompactNumberFormat class is the subclass of NumberFormat class in java.text package, NumberFormat class formats a number in compact form. 

The NumberFormat Style, SHORT would display 1000 as 1K and 10000 as 10K. Whereas the Style LONG will display 1000 as 1 thousand and 10000 as 10 thousand.  
format metodu
Örnek
Şöyle yaparız
NumberFormat format = NumberFormat.getCompactNumberInstance(Locale.US,Style.SHORT);
System.out.println(format.format(1000);
//Output : 1K

format = NumberFormat.getCompactNumberInstance(Locale.US,Style.LONG);
System.out.println(format.format(1000);
//Output : 1 thousand
parse metodu
Örnek
Şöyle yaparız
NumberFormat format = NumberFormat.getCompactNumberInstance(Locale.US,Style.LONG);
System.out.println(format.parse("1 thousand"); //1_000 
System.out.println(format.parse("10 million"); //10_000_000


9 Aralık 2021 Perşembe

Java Server Pages - JSP

Giriş
JSP dosyası src/main/webapp/WEB-INF/jsp/ dizinine yerleştirilir
Jsp tag'leri şöyledir
<%= ...%>
Nesnelere şöyle erişilir.
<h1>${message}</h1>
JSTL - Jakarta Standard Tag Library
jsp içine yazılan Java kodunu html gibi yazabilmeyi sağlar. JSP ile kullanılan Java nesneleri bean olmak zorunda

Maven
Şu satırı dahil ederiz. Bu kütüphanelerden herhangisi birisi olur
<dependency>
  <groupId>org.glassfish.web</groupId>
  <artifactId>jakarta.servlet.jsp.jstl</artifactId>
  <version>2.0.0-M1</version>
</dependency>

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>apache-jstl</artifactId>
  <version>11.0.0.beta2</version>
</dependency>
Kütüphaneler şöyle
core Tags :  http://java.sun.com/jsp/jstl/core
fmt Tags : http://java.sun.com/jsp/jstl/fmt
function Tags : http://java.sun.com/jsp/jstl/functions
sql Tags : http://java.sun.com/jsp/jstl/sql
xml Tags  : http://java.sun.com/jsp/jstl/xml

core Tags variable,url management, flow control içindir
function Tags string manipulation içindir
fmt Tags message,number,date formatlama içindir

Core Tags
Core JSTL taglerini almak için şöyle yaparız.  Burada c ön eki core anlamına geliyor. Diğer kütüphanaler için fn, fmt, x, sql ön ekleri kullanılıyor. taglib ise bir JSP directive
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
...
Bazı metodlar şöyle
catch
choose
forEach
forTokens
if
import
otherwise
out
param
redirect
remove
set
url
when

c:cout
Örnek 
Elimizde şöyle bir kod olsun
<%
String name = request.getAttribute("label").toString(); out.println(name) %>
Buna erişmek için şöyle yaparız
<c:cout value="${label}"/>
Örnek
Şöyle yaparız
If you are using Java Server Pages (JSP), you need to be aware that JSP templates do not 
escape dynamic content by default. Let’s say that you want to display a message this way:

<h1>${message}</h1>

You will need to use the <c:out> tag or fn:escapeXml() function to escape potentially dangerous content in untrusted input:


<h1><c:out value="${message}"/></h1> <h1>${fn:escapeXml(message)}</h1>

c:forEach
Örnek 
students listesi üzerinde dolaşır
<c:forEach items="${students}" var="e">
  ${e.name}<br/>
</c:forEach>
c:if
Örnek 
Şöyle yaparız
<c:if test="${requestScope.isGeoRedEnabled && isAdmin}">
  ...
</c:if>


8 Aralık 2021 Çarşamba

Bouncy Castle

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.70</version>
</dependency>
RSA Provider
Bouncy Castle bir RSA provider. 
Örnek
Kullanmak için şöyle yaparız
import org.bouncycastle.jce.provider.BouncyCastleProvider;

   
// Load Bouncy Castle provider
Security.addProvider(new BouncyCastleProvider());

// Encrypt data using public key
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
Örnek
Elimizde şöyle bir kod olsun
KeyPair generateKeyPair() {
  try {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048, new SecureRandom());
    return keyPairGenerator.generateKeyPair();
  } catch (GeneralSecurityException var2) {
    throw new AssertionError(var2);
  }
}
Import'lar için şöyle yaparız
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
Şöyle yaparız
Security.addProvider(new BouncyCastleProvider());

String name = ...;
Map<String, String> labels = ...;
String host = ...;

X500Principal subject = new X500Principal("CN=" + host);
X500Principal signedByPrincipal = subject;

KeyPair keyPair = generateKeyPair();
KeyPair signedByKeyPair = keyPair;

long notBefore = System.currentTimeMillis();
long notAfter = notBefore + (1000L * 3600L * 24 * 365);

ASN1Encodable[] encodableAltNames = new ASN1Encodable[]{ alonew GeneralName(GeneralName.dNSName, host)};
KeyPurposeId[] purposes = new KeyPurposeId[]{KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth};

X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder( signedByPrincipal,
  BigInteger.ONE, new Date(notBefore), new Date(notAfter), subject, keyPair.getPublic());

certBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
certBuilder.addExtension(Extension.keyUsage, true, new KeyUsage( KeyUsage.digitalSignature + KeyUsage.keyEncipherment));
certBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(purposes));
certBuilder.addExtension(Extension.subjectAlternativeName, false, new DERSequence(encodableAltNames));

ContentSigner signer = new JcaContentSignerBuilder(("SHA256withRSA")) .build(signedByKeyPair.getPrivate());
X509CertificateHolder certHolder = certBuilder.build(signer);

1 Aralık 2021 Çarşamba

JasperReports

Giriş
Şu satırı dahil ederiz
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.export.SimpleCsvExporterConfiguration;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleWriterExporterOutput;
import net.sf.jasperreports.export.SimpleXlsxReportConfiguration;
Açıklaması şöyle
JasperReports is an open source reporting engine. It provides ability to deliver rich content onto to the printer, the screen, or into various formats such as PDF, HTML, XLS, RTF, ODT, CSV, TXT and XML files.

It is a Java library and can be used in a variety of Java-enabled applications to generate dynamic content. Its main purpose is to help create page-oriented, ready-to-print documents in a simple and flexible manner. JasperReports can also be used to provide reporting capabilities in our applications.

As it is not a standalone tool, it cannot be installed on its own. Instead, it is embedded into Java applications by including its library in the application’s CLASSPATH.

Features of JasperReports :
- Flexible report layout.
- Data can be presented either textually or graphically.
- Developers can supply data in multiple ways.
- Multiple data sources can be used to transfer data.
- Watermarks can also be applied.
- Sub reports can also be generated.

Various formats of reports can be exported.
Maven
Şöyle yaparız
<dependency>
  <groupId>net.sf.jasperreports</groupId>
  <artifactId>jasperreports</artifactId>
  <version>6.4.0</version>
</dependency>
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>4.1.1</version>
</dependency>
Örnek
Şöyle yaparız
private String reportPath;

public String generateReport() {
  List<Employee> employees = ...
  try {
    File file = ResourceUtils.getFile("classpath:employee-rpt.jrxml");
    InputStream input = new FileInputStream(file);
    // Compile the Jasper report from .jrxml to .japser
    JasperReport jasperReport = JasperCompileManager.compileReport(input);
    // Get your data source
    JRBeanCollectionDataSource source = new JRBeanCollectionDataSource(employees);
    // Add parameters
    Map<String, Object> parameters = new HashMap<>();
    parameters.put("createdBy", "JavaHelper.org");
    // Fill the report
    JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters,
    source);
    // Export the report to various formats
    JasperExportManager.exportReportToPdfFile(jasperPrint, reportPath + "\\Emp.pdf");
    System.out.println("PDF File Generated !!");
    JasperExportManager.exportReportToXmlFile(jasperPrint, reportPath + "\\Emp.xml",
    true);
    System.out.println("XML File Generated !!");
    JasperExportManager.exportReportToHtmlFile(jasperPrint, reportPath + "\\Emp.html");
    System.out.println("HTML Generated");
    
  } catch (Exception e) {
    ...
  }
}
Daha sonra JasperReport farklı formatlara dönüştürülür. Şöyle yaparız
void csv(JasperPrint jasperPrint) throws JRException {
  JRCsvExporter exporter = new JRCsvExporter();
  exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
  exporter.setExporterOutput(new SimpleWriterExporterOutput(reportPath +
    "\\Employee.csv"));
  SimpleCsvExporterConfiguration configuration = new SimpleCsvExporterConfiguration();
  configuration.setFieldDelimiter(",");
  exporter.setConfiguration(configuration);
  exporter.exportReport();
}


void xlsx(JasperPrint jasperPrint) throws JRException {
  // Exports a JasperReports document to XLSX format. 
  //It has character output type and exports the document to a grid-based layout.
  JRXlsxExporter exporter = new JRXlsxExporter();
  exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
  exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(reportPath +
    "\\Employee.xlsx"));
  SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
  configuration.setOnePagePerSheet(true);
  configuration.setRemoveEmptySpaceBetweenColumns(true);
  configuration.setDetectCellType(true);
  exporter.setConfiguration(configuration);
  exporter.exportReport();
} 
Raport xml şöyledir. title, columnHeader, detail alanlarından oluşur
<?xml ...>

  <property name="ireport.zoom" value="1.0"/>
  <property name="ireport.x" value="0"/>
  <property name="ireport.y" value="0"/>
  <parameter name="createdBy" class="java.lang.String"/>
  <field name="id" class="java.lang.Integer"/>
  <field name="name" class="java.lang.String"/>
  <field name="organization" class="java.lang.String"/>
  <field name="designation" class="java.lang.String"/>
  <field name="salary" class="java.lang.Integer"/>
  <background>
    <band splitType="Stretch"/>
  </background>
  <title>
    <band height="42" splitType="Stretch">
      <staticText>
        <reportElement x="64" y="0" width="481" height="42"/>
	  <textElement textAlignment="Center">
	    <font size="20" isBold="true"/>
	  </textElement>
	  <text><![CDATA[Employee Details]]></text>
      </staticText>
    </band>
  </title>
  <columnHeader>
    <band height="61" splitType="Stretch">
      <staticText>
        <reportElement x="0" y="41" width="111" height="20"/>
	  <box>
            ...
	  </box>
	  <textElement textAlignment="Center">
	    <font size="12" isBold="true" isItalic="false"/>
	  </textElement>
	  <text><![CDATA[ID]]></text>
      </staticText>
      ...
    </band>
  </columnHeader>
  <detail>
    <band height="20" splitType="Stretch">
      <textField>
        <reportElement x="0" y="0" width="111" height="20"/>
	  <box>
	    ...
          </box>
          <textElement textAlignment="Center"/>
	  <textFieldExpression><![CDATA[$F{id}]]></textFieldExpression>
      </textField>
      ...
    </band>
  </detail>
</jasperReport>



30 Kasım 2021 Salı

Kafka Streams API StreamsBuilder Sınıfı

Giriş
Şu satırı dahil ederiz
import org.apache.kafka.streams.StreamsBuilder;
Bu sınıf bir Topology nesnesi yaratır. Topology nesnesi KafkaStreams sınıfını yaratmak için gerekir.
Ayrıca bu sınıf stream() metodu sağlar. Böylece bir topic event'lerini işleyen KStream nesnesi yaratılır.
build metodu
Örnek
Şöyle yaparız
Topology createTopology() {
  StreamsBuilder builder = new StreamsBuilder();
  // Add your streams here.
  TradeStream.build(builder);
  Topology topology = builder.build();
  System.out.println(topology.describe());
  return topology;
}
Yeni stream ekleme şöyledir
public class TradeStream {
  private final static String TRADE_TOPIC = "ARCTYPE.public.trade";

  public static void build(StreamsBuilder builder) {
    Serde<TradeModel> tradeModelSerde = SerdeFactory.createSerdeFor(TradeModel.class,
      true);
    Serde<String> idSerde = Serdes.serdeFrom(new IdSerializer(), new IdDeserializer());

    KStream<String, TradeModel> tradeModelKStream =
      builder.stream(TRADE_TOPIC, Consumed.with(idSerde, tradeModelSerde));

    tradeModelKStream.peek((key, value) -> {
      System.out.println(key.toString());
      System.out.println(value.toString());
    });
    tradeModelKStream.map((id, trade) -> {
      TradeModel tradeDoubled = new TradeModel();
      tradeDoubled.price = trade.price * 2;
      tradeDoubled.quantity = trade.quantity;
      tradeDoubled.ticker = trade.ticker;
      return new KeyValue<>(id, tradeDoubled);
    }).to("ARCTYPE.doubled-trades", Produced.with(idSerde, tradeModelSerde));
  }
}
Key SerDe için deserializer şöyledir. Serializer da benzer şekilde yazılır
public class IdDeserializer implements Deserializer<String> {
  private ObjectMapper objectMapper = new ObjectMapper();

  @Override
  public void configure(Map<String, ?> props, boolean isKey) { }

  @Override
  public void close() { }

  @Override
  public String deserialize(String topic, byte[] bytes) {
    if (bytes == null)
      return null;

    String id;
    try {
      Map payload = objectMapper.readValue(new String(bytes), Map.class);
      id = String.valueOf(payload.get("id"));
    } catch (Exception e) {
      throw new SerializationException(e);
    }
    return id;
  }
}
Value SerDe için SerdeFactory sınıfı şöyledir
public class SerdeFactory {
  public static <T> Serde<T> createSerdeFor(Class<T> clazz, boolean isKey) {
    Map<String, Object> serdeProps = new HashMap<>();
    serdeProps.put("Class", clazz);

    Serializer<T> ser = new JsonSerializer<>();
    ser.configure(serdeProps, isKey);

    Deserializer<T> de = new JsonDeserializer<>();
    de.configure(serdeProps, isKey);

    return Serdes.serdeFrom(ser, de);
  }
}
JsonDeserializer şöyle
public class JsonDeserializer<T> implements Deserializer<T> {
  private ObjectMapper objectMapper = new ObjectMapper();
  private Class<T> clazz;

  @Override
  public void configure(Map<String, ?> props, boolean isKey) {
    clazz = (Class<T>) props.get("Class");
  }
  @Override
  public void close() { }
  @Override
  public T deserialize(String topic, byte[] bytes) {
    if (bytes == null)
      return null;

    T data;
    Map payload;
    try {
      payload = objectMapper.readValue(new String(bytes), Map.class);
      // Debezium updates will contain a key "after" with the latest row contents.
      Map afterMap = (Map) payload.get("after");
      if (afterMap == null) {
        // Non-Debezium payloads
        data = objectMapper.readValue(objectMapper.writeValueAsBytes(payload), clazz);
      } else {
        // Incoming from Debezium
        data = objectMapper.readValue(objectMapper.writeValueAsBytes(afterMap), clazz);
      }

    } catch (Exception e) {
      throw new SerializationException(e);
    }
    return data;
  }
}
Value nesnes şöyle
@JsonIgnoreProperties(ignoreUnknown = true)
public class TradeModel {
    public Integer id;
    public String ticker;
    public Integer price;
    public Integer quantity;
}
stream metodu
Örnek
Şöyle yaparız
StreamsBuilder streamsBuilder = new StreamsBuilder();
KStream<String,String> ks0 = streamsBuilder.stream(IAppConfigs.ORDER_RECEIVED_TOPIC);
...
Topology topology = streamsBuilder.build();
Properties streamConfig = ...;
KafkaStreams kafkaStreams = new KafkaStreams(topology, streamConfig);
kafkaStreams.start();

29 Kasım 2021 Pazartesi

Jakarta EE JBatch

Giriş 
Açıklaması şöyle
According to the description from the Jakarta Batch (JBatch) official website, the JBatch specification provides the following:

The Jakarta Batch project describes the XML-based job specification language (JSL), Java programming model, and runtime environment for batch applications for the Java platform.

The specification ties together the Java API and the JSL (XML) allowing a job designer to compose a job in XML from Java application artifacts and conveniently parameterize them with values for an individual job. This structure promotes application reuse of artifacts across different jobs.

The specification allows the flexibility for batch jobs to be scheduled or orchestrated in any number of ways, and stops short of defining any APIs or constructs regarding scheduling or orchestration of multiple or repeated jobs.
Açıklaması şöyle. Eğer Jakarta EE container kullanmak istemiyorsak, IBM Helidon kullanılabilir.
The usage of JBatch is really vast. Practically everywhere in the enterprise (EE) world there are millions of batch jobs running on millions of servers. The JBatch spec was created to make these types of tasks portable across the enterprise solutions in the Java/Jakarta EE world.

And yes, this is just a specification and not a complete implementation — every vendor has to provide its own implementation, but the specification itself is not standalone. It is very specific and depends heavily on other specs, like JTA and JPA, for example. This means if you want to run JBatch jobs, then you need an Enterprise Server that supports full EE spec.
AbstractBatchlet Sınıfı
Bir step'i temsil eder
Örnek
Şöyle yaparız
import javax.batch.api.AbstractBatchlet;
import javax.inject.Named;

@Named
public class MyBatchlet extends AbstractBatchlet {

  @Override
  public String process() {
    System.out.println("Running inside a batchlet");
   return "COMPLETED";
  }
}
AbstractItemReader Sınıfı
Örnek
Şöyle yaparız
import javax.batch.api.chunk.AbstractItemReader;
import javax.inject.Named;

public class MyInputRecord {
  ...
}

@Named
public class MyItemReader extends AbstractItemReader {

  private final StringTokenizer tokens;

  public MyItemReader() {
    tokens = new StringTokenizer("1,2,3,4,5,6,7,8,9,10", ",");
  }

  @Override
  public MyInputRecord readItem() {
    if (tokens.hasMoreTokens()) {
      return new MyInputRecord(Integer.valueOf(tokens.nextToken()));
    }
    return null;
  }
}
ItemProcessor Arayüzü
Örnek
Şöyle yaparız
import javax.batch.api.chunk.ItemProcessor;
import javax.inject.Named;

public class MyOutputRecord {
  ...
}

@Named
public class MyItemProcessor implements ItemProcessor {

  @Override
  public MyOutputRecord processItem(Object t) {
    System.out.println("processItem: " + t);
    MyInputRecord record = (MyInputRecord) t;
    return record.getId() % 2 == 0) ? null : 
      new MyOutputRecord(record.getId() * 2);
  }
}
AbstractItemWriter Sınıfı
Örnek
Şöyle yaparız
import javax.batch.api.chunk.AbstractItemWriter;
import javax.inject.Named;

@Named
public class MyItemWriter extends AbstractItemWriter {

  @Override
  public void writeItems(List list) {
    System.out.println("writeItems: " + list);
  }
}

24 Kasım 2021 Çarşamba

Kafka Producer API

Serializer ve Deserializer Arayüzleri
Örnek
Elimizde şöyle bir kod olsun
import com.kafka.message.ExchangeProtoMessage.ProtMessage;
import org.apache.kafka.common.serialization.Serializer;

public class ProtMessageSerializer implements Serializer<ProtMessage>{
    @Override
    public byte[] serialize(String topic, ProtMessage data) {
        return data.toByteArray();
    }
}


import com.google.protobuf.InvalidProtocolBufferException;
import com.kafka.message.ExchangeProtoMessage.ProtMessage;
import org.apache.kafka.common.serialization.Deserializer;

public class ProtMessageDeserializer implements Deserializer<ProtMessage>{
    @Override
    public ProtMessage deserialize(String topic, byte[] data) {
        try {
            return ProtMessage.parseFrom(data);
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
            throw new RuntimeException("excepiton while parsing");
        }
    }
}
Producer tarafında şöyle yaparız
import com.kafka.message.ExchangeProtoMessage.ProtMessage;
import com.kafka.model.ProtMessageSerializer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.IntegerSerializer;


public class MyKafkaProducerWithProtobufModel {

  public static void main(String[] args) {

   Properties props = new Properties();
   props.put("bootstrap.servers", "localhost:9092");
   props.put("linger.ms", 1);
   props.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
   props.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");

   Producer<Integer, ProtMessage> producer = 
    new KafkaProducer<>(props, new IntegerSerializer(), new ProtMessageSerializer());
   for (int i = 1; i <= 10; i++){
     producer.send(new ProducerRecord<>("myFirstTopic", 0, i, 
      ProtMessage.newBuilder()
        .setId(i)
        .setName(i + "proto value")
        .build()));
   }
   producer.close();
  }
}
Consumer tarafında şöyle yaparız
import com.kafka.message.ExchangeProtoMessage.ProtMessage;
import com.kafka.model.ProtMessageDeserializer;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.IntegerDeserializer;

public class MyKafkaConsumerWithProtobufModel {

  public static void main(String[] args) {
    Properties props = new Properties();
    props.setProperty("bootstrap.servers", "localhost:9092");
    props.setProperty("group.id", "test");
    props.setProperty("enable.auto.commit", "true");
    props.setProperty("auto.commit.interval.ms", "1000");
    props.setProperty("key.deserializer", 
      "org.apache.kafka.common.serialization.StringDeserializer");
    props.setProperty("value.deserializer", 
      "org.apache.kafka.common.serialization.StringDeserializer");

    KafkaConsumer<Integer, ProtMessage> consumer = 
      new KafkaConsumer<>(props, new IntegerDeserializer(),
        new ProtMessageDeserializer());
    consumer.subscribe(Arrays.asList("myFirstTopic"));

    while (true) {
      ConsumerRecords<Integer, ProtMessage> records = consumer
        .poll(Duration.ofMillis(100));
      for (ConsumerRecord<Integer, ProtMessage> record : records) {
        System.out.println("Received message: (" + record.key() +  ", " + 
          record.value().toString() + ") at offset " + record.offset());
      }
    }
  }
}


ProducerRecord Sınıfı
Şu satırı dahil ederiz
import org.apache.kafka.clients.producer.ProducerRecord;
constructor 
Örnek - topic + key + value
Şöyle yaparız
KafkaProducer<Integer, String> producer;

private KafkaProducer<Integer, String> getProducer() {
  if (producer == null) {
    Properties producerProps = new Properties();
    producerProps.setProperty("bootstrap.servers", ...);
    producerProps.setProperty("key.serializer", 
      IntegerSerializer.class.getCanonicalName());
    producerProps.setProperty("value.serializer", 
      StringSerializer.class.getCanonicalName());
    producer = new KafkaProducer<>(producerProps);
  }
  return producer;
}

public Future<RecordMetadata> produce(String topic, Integer key, String value) {
  return getProducer().send(new ProducerRecord<>(topic, key, value));
}
constructor - topic + partition + timestamp + key + value
Örnek
Şöyle yaparız
Future<RecordMetadata> produce(String topic, int partition, Long timestamp, 
  Integer key, String value) {
  return getProducer().send(new ProducerRecord<>(topic, 
    partition, timestamp, key, value));
}



RediSearch Sınıfı

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>com.redislabs</groupId>
  <artifactId>jredisearch</artifactId>
  <version>2.0.0</version>
</dependency>
createIndex metodu
Şöyle yaparız
import io.redisearch.Schema;
import io.redisearch.client.Client;
import io.redisearch.client.IndexDefinition;
import redis.clients.jedis.Jedis;

JedisPool pool = ...;
Client redisearch = = new Client"tweets-index",pool);

 Schema sc = new Schema()
  .addTextField"id", 1.0)
  .addTextField("user", 1.0)
  .addTextField("text", 1.0)
  .addTextField("location", 1.0)
  .addTagField("hashtags");

IndexDefinition def = new IndexDefinition()
  .setPrefixes(new String[] { "tweet:" });

boolean indexCreated = redisearch
  .createIndex(sc, 
               Client.IndexOptions.defaultOptions().setDefinition(def));

redisearch.close();