13 Aralık 2021 Pazartesi

Camel Resequence

Giriş
İki çeşit resequence işlemi var
1. Batch resequencing
2. Stream resequencing

2. Stream resequencing
Örnek
Elimizde şöyle bir comparator olsun
import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.processor.resequencer.ExpressionResultComparator;

@NoArgsConstructor(staticName = "of")
class CustomPriorityComparator implements ExpressionResultComparator {

  @Override
  public void setExpression(Expression expression) {// do nothing}

  @Override
  public boolean predecessor(Exchange o1, Exchange o2) {return false;}

  @Override
  public boolean successor(Exchange o1, Exchange o2) {return false;}

  @Override
  public boolean isValid(Exchange exchange) {
    return exchange.getMessage().getBody() instanceof String;
  }

  @Override
  public int compare(Exchange exchange1, Exchange exchange2) {
    return getMessageAsString(exchange1).compareTo(getMessageAsString(exchange2));
  }

  private static String getMessageAsString(Exchange exchange) {
    return String.valueOf(exchange.getMessage().getBody());
  }
}
Şöyle yaparız
import org.springframework.stereotype.Component;

@Component
public class ResequenceRoute extends RouteBuilder {

  private static final String TOPIC_TO_CONSUME = "incoming_channel";
  private static final String TOPIC_TO_FORWARD = "outgoing_channel";
  private static final String BOOTSTRAP_URL = "localhost:9092";
  private static final String CONSUMER_GROUP = "resequencer";
  private static final Integer RESEQUENCER_CAPACITY = 100;
  private static final Long RESEQUENCER_TIMEOUT = 5000L;
   

  @Override
  public void configure() {
    from("kafka:" + TOPIC_TO_CONSUME + "?brokers=" + BOOTSTRAP_URL + "&groupId=" + CONSUMER_GROUP)
      .resequence()
      .body()
      .stream()
      .capacity(RESEQUENCER_CAPACITY)
      .timeout(RESEQUENCER_TIMEOUT)
      .comparator(CustomPriorityComparator.of())
      .to("kafka:" + TOPIC_TO_FORWARD + "?brokers=" + BOOTSTRAP_URL);
    }
}

28 Ekim 2021 Perşembe

POI Kullanımı

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>4.1.2</version>
</dependency>
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>4.1.2</version>
</dependency>
Yazma
Her şey XSSWorkbook sınıfı etrafında dönüyor.
Örnek
Şöyle yaparız
ByteArrayOutputStream bos = new ByteArrayOutputStream();

try (Workbook workbook = new XSSFWorkbook()) {
  ...
} catch (Exception e) {
  ...
} finally {
  bos.close();
}
return bos.toByteArray();
Yazarken Font ve fontların kullanılacağı CellStyle nesnelerini oluşturmak gerekir. Şöyle yaparız
//setting up the basic styles for the workbook Font boldFont = getBoldFont(workbook); Font genericFont = getGenericFont(workbook); CellStyle headerStyle = getLeftAlignedCellStyle(workbook, boldFont); CellStyle currencyStyle = setCurrencyCellStyle(workbook); CellStyle centerAlignedStyle = getCenterAlignedCellStyle(workbook); CellStyle genericStyle = getLeftAlignedCellStyle(workbook, genericFont);
Daha sonra bir Sheet oluşturulur. Şöyle yaparız
String sheetName = ...
Sheet sheet = workbook.createSheet(sheetName);
Daha sonra bir başlık oluşturulur. Şöyle yaparız
int tempRowNo = 0;

//set spreadsheet titles
Row mainRow = sheet.createRow(tempRowNo++);

for (int i = 0; i < columnTitles.length; i++) {
  Cell columnTitleCell = mainRow.createCell(i);
  columnTitleCell.setCellStyle(headerStyle);
  columnTitleCell.setCellValue(columnTitles[i]);
}
Daha sonra veriyi sütunlar halinde yazarız. Şöyle yaparız
//looping the dataset
for (T record : data) {
  
  Row mainRow = sheet.createRow(tempRowNo++);
  Cell compositeNewCell = mainRow.createCell(cellIndex);
  cell.setCellValue(...);
  Hyperlink link = workbook.getCreationHelper().createHyperlink(HyperlinkType.URL);
  link.setAddress(...);
  cell.setHyperlink(link);
  ...
}
Tabi bu işleri yaparken bir sürü yardımcı metod gerekiyor. Bunları hep kodlamak lazım

Örnek
Elimizde şöyle bir kod olsun
public class ExcelGenerator {
  private List < Student > studentList = ...;
  private XSSFWorkbook workbook = new XSSFWorkbook();
  private XSSFSheet sheet;

  private void writeHeader() {
    sheet = workbook.createSheet("Student");
    Row row = sheet.createRow(0);
    CellStyle style = workbook.createCellStyle();
    XSSFFont font = workbook.createFont();
    font.setBold(true);
    font.setFontHeight(16);
    style.setFont(font);
    createCell(row, 0, "ID", style);
    createCell(row, 1, "Student Name", style);
    createCell(row, 2, "Email", style);
    createCell(row, 3, "Mobile No.", style);
  }
  private void createCell(Row row, int columnCount, Object valueOfCell,
    CellStyle style) {
    sheet.autoSizeColumn(columnCount);
    Cell cell = row.createCell(columnCount);
    if (valueOfCell instanceof Integer) {
      cell.setCellValue((Integer) valueOfCell);
    } else if (valueOfCell instanceof Long) {
      cell.setCellValue((Long) valueOfCell);
    } else if (valueOfCell instanceof String) {
      cell.setCellValue((String) valueOfCell);
    } else {
      cell.setCellValue((Boolean) valueOfCell);
    }
    cell.setCellStyle(style);
  }
  private void write() {
    int rowCount = 1;
    CellStyle style = workbook.createCellStyle();
    XSSFFont font = workbook.createFont();
    font.setFontHeight(14);
    style.setFont(font);
    for (Student record: studentList) {
      Row row = sheet.createRow(rowCount++);
      int columnCount = 0;
      createCell(row, columnCount++, record.getId(), style);
      createCell(row, columnCount++, record.getStudentName(), style);
      createCell(row, columnCount++, record.getEmail(), style);
      createCell(row, columnCount++, record.getMobileNo(), style);
    }
  }
}
Şöyle yaparız. Burada Excep direkt servlet cevabına yazılıyor
public class ExcelGenerator {
  
  public void generateExcelFile(HttpServletResponse response) throws IOException {
    writeHeader();
    write();
    ServletOutputStream outputStream = response.getOutputStream();
    workbook.write(outputStream);
    workbook.close();
    outputStream.close();
  }
}
Dosya İndirme
Örnek - SpringBoot
Şöyle yaparız
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

@Controller
public class UserController {

  @Autowired
  private UserService userService;

  @RequestMapping(method = RequestMethod.POST, value = "/download-users")
  public ResponseEntity downloadUsersExcel() {
    try {
      final byte[] data = userService.getUserXlsData();
      HttpHeaders header = new HttpHeaders();
      header.setContentType(MediaType.parseMediaType(
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"));
      header.set(HttpHeaders.CONTENT_DISPOSITION, "inline; filename= users.xlsx");
      header.setContentLength(data.length);
      return new ResponseEntity<>(data, header, HttpStatus.OK);
    } catch (Exception e) {
      return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}


26 Ekim 2021 Salı

DbUtils

Giriş
Bu kütüphanede az sınıf var. Kullanması kolay. Tasarım açısından 2 çeşit API sağlıyor
1. JDBC kaynaklarını DbUtils'in yönettiği API. Bu kullanımda Connection, PreparedStatement ve ResultSet'i kütüphane kapatır.
2. Connection'ın dışarıdan verildiği API. Bu kullanımda Connection nesnesini bizim kapatmamız gerekir.

Kötü Tasarım
Bir seferinde Connection, PreparedStatement ve ResultSet'i sarmalayıp dışarı veren bir kütüphane görmüştüm. Bu sarmalanan nesneyi kapatmayı unutunca bir sürü resource leak oluyor ve "ORA-01000: Maximum Open Cursors Exceeded" hatası geliyordu.

Yani en güzeli, kaynakları kapatma işini kütüphanenin kendisinin yapması

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>commons-dbutils</groupId>
  <artifactId>commons-dbutils</artifactId>
  <version>1.6</version>
</dependency>
QueryRunner Sınıfı
insert metodu
Örnek
Şöyle yaparız
QueryRunner runner = new QueryRunner();
    String insertSQL
      = "INSERT INTO employee (firstname,lastname,salary, hireddate) "
        + "VALUES (?, ?, ?, ?)";

int numRowsInserted = runner.update(connection, insertSQL, "Leia", "Kane", 60000.60,
  new Date());
query metodu - String sql, ResultSetHandler<T> rsh, Object... params
Şöyle yaparız
// Create a ResultSetHandler implementation to convert the first row into an Object[].
ResultSetHandler<Object[]> h = new ResultSetHandler<>() {
  public Object[] handle(ResultSet rs) throws SQLException {
    ...
  }
};

// Create a QueryRunner that will use connections from the given DataSource
QueryRunner run = new QueryRunner(dataSource);

// Execute the query and get the results back from the handler
Object[] result = run.query("SELECT * FROM Person WHERE name=?", h, "John Doe");
query metodu - Connection + String sql, ResultSetHandler<T> rsh, Object... params
Şöyle yaparız
ResultSetHandler<Object[]> h = ... // Define a handler the same as above example

// No DataSource so we must handle Connections manually
QueryRunner run = new QueryRunner();
Connection conn = ... // open a connection try { Object[] result = run.query(conn, "SELECT * FROM Person WHERE name=?", h, "John Doe");
// do something with the result } finally { // Use this helper method so we don't have to check for null DbUtils.close(conn); }
update metodu
Örnek
Şöyle yaparız
double salary = 35000;

QueryRunner runner = new QueryRunner();
String updateSQL = "UPDATE employee SET salary = salary * 1.1 WHERE salary <= ?";
int numRowsUpdated = runner.update(connection, updateSQL, salary);
BeanListHandler Sınıfı
Şu satırı dahil ederiz
import org.apache.commons.dbutils.handlers.BeanListHandler;
Örnek
Elimizde şöyle bir kod olsun
public class EmployeeHandler extends BeanListHandler<Employee> {

  public EmployeeHandler() {
    super(Employee.class,
          new BasicRowProcessor(new BeanProcessor(getColumnsToFieldsMap())));
    // ...
  }
  protected Map<String, String> getColumnsToFieldsMap() {
    Map<String, String> columnsToFieldsMap = new HashMap<>();
    columnsToFieldsMap.put("FIRST_NAME", "firstName");
    columnsToFieldsMap.put("LAST_NAME", "lastName");
    columnsToFieldsMap.put("HIRED_DATE", "hiredDate");
    return columnsToFieldsMap;
  }

}
Şöyle yaparız
EmployeeHandler employeeHandler = new EmployeeHandler();

QueryRunner runner = new QueryRunner();
String query = "SELECT * FROM employee_legacy";
List<Employee> employees = runner.query(connection, query, employeeHandler);
MapListHandler Sınıfı
Şu satırı dahil ederiz
import org.apache.commons.dbutils.handlers.MapListHandler;
Örnek
Şöyle yaparız
MapListHandler beanListHandler = new MapListHandler();

QueryRunner runner = new QueryRunner();
List<Map<String, Object>> list = runner.query(connection, 
                                               "SELECT * FROM employee", 
                                               beanListHandler);


6 Ekim 2021 Çarşamba

Apache Shiro - Role-Based Access Control (RBAC) İçindir

Giriş
Açıklaması şöyle. Framework yani çatı olarak kullanılır.
Apache Shiro is a powerful and flexible open-source security framework that cleanly handles authentication, authorization, enterprise session management and cryptography.
Şeklen şöyle

Daha gelişmiş bir şekil şöyle

Bölümlerin amacı şöyle
Authentication: Sometimes referred to as ‘login’, this is the act of proving a user is who they say they are.
Authorization: The process of access control, i.e. determining ‘who’ has access to ‘what’.
Session Management: Managing user-specific sessions, even in non-web or EJB applications.
Cryptography: Keeping data secure using cryptographic algorithms while still being easy to use.
Maven
Spring ile kullanmak için şöyle yaparız
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-starter</artifactId>
    <version>1.8.0</version>
</dependency>
Spring ile tümleşim için bir örnek burada


26 Eylül 2021 Pazar

CXF İle SOAP

Giriş
CFX sadece bir kütüphane değil. Yanında bir sürü araçla birlikte geliyor
JAX-RS ve JAX-WS (yani SOAP) için kullanılabilir.

Örnek
Maven ile şöyle yaparız
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
       
<dependency>
  <groupId>org.glassfish.jaxb</groupId>
  <artifactId>jaxb-runtime</artifactId>
</dependency>
       
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
  <version>${cxf.version}</version>
</dependency>
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-features-logging</artifactId>
  <version>${cxf.version}</version>
</dependency>
Elimizde şöyle bir kod olsun
@WebService
public interface HelloWorldWS {
    @WebMethod
    String createMessage(@WebParam(name = "createMessageRequest", mode = WebParam.Mode.IN)
String name);
}

@Component
public class HelloWorldWSImpl implements HelloWorldWS{
    @Override
    public String createMessage(String name){
        return "Hello "+name;
    }
}
Şöyle yaparız. Spring uygulamasını çalıştırınca "http://localhost:8080/ws/helloWorldWS?wsdl" adresinde WSDL çıktısı görülebilir.
import javax.xml.ws.Endpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import com.cfxconsumer.soapcxfconsumer.ws.HelloWorldWS;

@Configuration
@ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class CxfWebServiceConfig {
  @Autowired
  private Bus cxfBus;

  @Bean
  public ServletRegistrationBean cxfServlet() {
    org.apache.cxf.transport.servlet.CXFServlet cxfServlet =
new org.apache.cxf.transport.servlet.CXFServlet();
    ServletRegistrationBean def = new ServletRegistrationBean<>(cxfServlet, "/ws/*");
    def.setLoadOnStartup(1);
    return def;
  }

  @Bean
  public Endpoint helloWorldWebService(HelloWorldWS helloWorldWS) {
    EndpointImpl endpoint = new EndpointImpl(cxfBus, helloWorldWS);
    endpoint.setAddress("/helloWorldWS");
    endpoint.publish();
    return endpoint;
  }
}


19 Eylül 2021 Pazar

Tika

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.apache.tika</groupId>
  <artifactId>tika-core</artifactId>
  <version>1.26</version>
</dependency>
AutoDetectParser Sınıfı
parse metodu
Örnek
Şöyle yaparız
InputStream stream = ...;

FileOutputStream fileOutputStream = ...;
ContentHandler handler = new BodyContentHandler(new WriteOutContentHandler(fileOutputStream));

Metadata metadata = new Metadata();

ParseContext context = new ParseContext();

Parser parser = new AutoDetectParser();

parser.parse(stream, handler, metadata, context);

8 Eylül 2021 Çarşamba

Lang3 StringUtils strip metodları

Giriş
strip işlemi için eğer düz Java kullanıyorsak String sınıfının replaceFirst() metodu kullanılabilir.
Örnek
Şöyle yaparız
"00000050.43".replaceFirst("^0+(?!$)", "")
Guava'nın CharMatcher sınıfı kullanılabilir.
Örnek
Şöyle yaparız
CharMatcher.is('0').trimLeadingFrom("00000050.43")
Bence en kolayı halen StringUtils sınıfı

stripEnd metodu
Sağdaki belirtilen diziye uyan karakterleri siler.
Örnek
Şöyle yaparız. null boşluk anlamına gelir.
StringUtils.stripEnd("abc  ", null)    = "abc"
Örnek
Şöyle yaparız.
private String rTrim(String str) {
  return StringUtils.stripEnd(str, /*stripChars*/" ");
}
stripStart metodu
Soldaki whitespace karakterlerini siler
Örnek
Şöyle yaparız.
private String lTrim(String str) {
  return StringUtils.stripStart(str, /*stripChars*/" ");
}
Örnek
Şöyle yaparız
StringUtils.stripStart("00000050.43","0");

13 Ağustos 2021 Cuma

CLI Option Sınıfı

setArgs metodu
Örnek
Açıklaması şöyle. Eğer seçenek birden fazla değer alıyorsa kullanılır
You have to set maximum the number of argument values the option can take, otherwise it assumes the option only has 1 argument value
Şöyle yaparız
Options options = new Options();
Option option = new Option("c", "c desc");
// Set option c to take maximum of 10 arguments
option.setArgs(10);
options.addOption(option);

3 Ağustos 2021 Salı

Camel ve SpringBoot

Giriş
Spring ile kullanmak için şu satırı dahil ederiz
<dependency>
  <groupId>org.apache.camel.springboot</groupId>
  <artifactId>camel-spring-boot-starter</artifactId>
  <version>3.4.0</version>
</dependency>
Spring + JSON kullanmak için Jackson kütüphanesini dahil etmek gerekir. Şöyle yaparız
<dependency>
  <groupId>org.apache.camel.springboot</groupId>
  <artifactId>camel-jackson-starter</artifactId>
  <version>3.8.0</version>
</dependency>
Test
Bir yazı burada

application.properties
Tüm alanlar camel.springboot.XXX şeklinde başlar

main-run-controller Alanı
Örnek
Şöyle yaparız
camel.springboot.main-run-controller=true
Açıklaması şöyle
To ensure the Spring Boot application keeps running until being stopped or the JVM terminated, typically only need when running Spring Boot standalone, i.e. not with spring-boot-starter-web when the web container keeps the JVM running, set the camel.springboot.main-run-controller=true property in your configuration.
RouteBuilder
RouteBuilder yazısına bakabilirsiniz. RouterBuilder sınıfı bir Spring component'i dir.

Örnek
Şöyle yaparız
import org.apache.camel.builder.RouteBuilder;

@SpringBootApplication
public class SpringBootWithCamelApplication extends RouteBuilder {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootWithCamelApplication.class);
  }
  @Override
  public void configure() throws Exception {
    from("file:C:/test1/test.txt").
    to("file:C/test2/test.txt")
  }
}

11 Mayıs 2021 Salı

NTPUDPClient Sınıfı

Giriş
Şu satırı dahil ederiz
<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.8.0</version>
</dependency>
Windows 10 ile NTP sunucusunu bulmak için şöyle  yaparız
w32tm /query /peers
Örnek 
Şöyle yaparız
NTPUDPClient ntpudpClient = new NTPUDPClient();
ntpudpClient.setDefaultTimeout(5000);

try {
  InetAddress inetAddress = InetAddress.getByName("192.168.43.32");
  TimeInfo timeInfo = ntpudpClient.getTime(inetAddress);

  TimeStamp timeStamp = timeInfo.getMessage().getTransmitTimeStamp();
  Date date = timeStamp.getDate();
  SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
  simpleDateFormat.format(date);
} catch (UnknownHostException e) {
 ...
}
ntpudpClient.close();
TimeInfo ile şöyle yaparız
timeInfo.computeDetails();
if (timeInfo.getOffset() != null) {
  this.timeInfo = timeInfo;
  this.offset = timeInfo.getOffset();
}

// This system NTP time
TimeStamp systemNtpTime = TimeStamp.getCurrentTime();
System.out.println("System time:\t" + systemNtpTime + " " + systemNtpTime.toDateString());

// Calculate the remote server NTP time
long currentTime = System.currentTimeMillis();
TimeStamp atomicNtpTime = TimeStamp.getNtpTime(currentTime + offset).getTime()

System.out.println("Atomic time:\t" + atomicNtpTime + " " + atomicNtpTime.toDateString());
TimeInfo ile şöyle yaparız
TimeInfo info = client.getTime(hostAddr);
info.computeDetails(); // compute offset/delay if not already done
Long offsetValue = info.getOffset();
Long delayValue = info.getDelay();
String delay = (delayValue == null) ? "N/A" : delayValue.toString();
String offset = (offsetValue == null) ? "N/A" : offsetValue.toString();

System.out.println(" Roundtrip delay(ms)=" + delay
                + ", clock offset(ms)=" + offset); // offset in ms