Saturday, September 19, 2020

Isimsiz kadinlara mektuplar II

                                                                                                                    21 Şubat Cumartesi
 
Sana daha hızlı gelebilmek için taksiye biniyorum. Tekrar kontrol ediyorum ellerimle, uzun uzun taradığım saçlarımı. Ne garip, seni tanımadan, kavuşmak istiyorum bir an önce. Gözlerim yokluğunu tararken sokaklarda, birden beliriyorsun karşı kaldırımdan. 
Sen konuşurken seni izliyorum hep. Tepki gösteremiyorum hiçbir şeye sadece seni izliyorum. 
Gözlerin aklıma kazınıyor daha ilk anda, kocaman bal rengi gözlerin, beyaz tenin ve ellerin. 
Saçlarınsa arsız, serseri bir aşık. 
Saçlarınla yarışıyorum gözlerin için. 
Saçlarını kıskanıyorum sanırım. 
Dokunabiliyorlar ısrarla, yanaklarına, gözlerine ve hatta dudaklarına. 
Yürümeyi unutuyorum seninle, çarpıp duruyorum sonra. 
Mimiklerim kayboluyor. 
Karşında çırılçıplak kaldım.

Isimsiz kadinlara mektuplar I

20 Şubat Cuma, belli berlisiz bir zaman.

Anlamsızca fotoğraflarına bakıyorum. 
Bir bir inceliyorum her birini. 
Sessiz kalamıyorum sana. Ayni anda hem Merhaba, hem Hoşçakal diyorum. 
Cevap vermeni ummuyorum yada bu konu uzerine düşünmüyorum. 
Mevzu ben ve fotoğrafların arasında kalacakken, uzadıkça uzuyor gecemiz. 
Seni görmek istiyorum yine, ne göreceğimi, nasıl birini görmeyi beklediğimi bilmeden. 
Sen de beni görmek istiyorsun. 
Şaşırıyorum. 
Gereksiz tum sözcükler kakıyor aradan

Monday, May 23, 2016

Vert.x EventBus Implementation

I came across Vert.x when I was looking for lightweight, easy to use event driven framework. Vert.x is a polyglot event-driven application framework that runs on the Java Virtual Machine. Tim Fox creator of Vert.x inspired by node.js.

Vert.x has modular hierarchy, most of the features presented with vertx-core jar. If you need web, data access, integration, authentication you can add necessary jar to the dependency. It also supports Java, JavaScript, Ruby, Groovy, Ceylon.

I want to show basic eventbus implementation with vert.x. You can find the codes at my github repo

first we need to add vert.x core as a dependency.

    io.vertx
    vertx-core
    3.2.0


We need to create a global Vertx object and EventBus.
Now we can create our consumer which will listen for an event, in this case "customer" event
public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    EventBus eventBus = vertx.eventBus();

    eventBus.consumer("customer").handler(message -> {
    System.out.println("I have received a message: " + message.body());
        message.reply("how interesting");
    });

    CustomerService customerService = new CustomerService();
    customerService.get("Josh", eventBus);
    customerService.get("Nathan", eventBus);

}

Consumer also replies with a "how interesting" message after it receives a message.

Let's write part which creates the messages.

public class CustomerService {

private List<Customer> customerList;

public CustomerService() {
    customerList = new ArrayList<>();
    customerList.add(new Customer(1l, "Josh"));
    customerList.add(new Customer(2l, "David"));
    customerList.add(new Customer(3l, "Peter"));
}


public Customer get(String name, EventBus eventBus) {
    
    System.out.println("searching for a customer " + name);
    List<Customer> customerList = this.customerList.stream().filter(c -> c.getName().equals(name)).collect(Collectors.toList());
    if (customerList.isEmpty()) {
        eventBus.send("customer", "customer not found", ar -> {
            if (ar.succeeded()) {
                System.out.println("Received reply: " + ar.result().body());
            }
        });
        return null;
    }

    eventBus.publish("customer", "yay found customer");

    return customerList.get(0);
}


When a customer has found "yay found customer" message thrown. If customer not found then "customer not found" message thrown and wait for an answer which is "how interesting" in this case.

searching for a customer Josh
searching for a customer Nathan
I have received a message: yay found customer
I have received a message: customer not found
Received reply: how interesting

As you can see from the output messages is not synchronous because vert.x is asynchronous and process is not blocked so it delivered the 2 messages then replies come. In synchronous application output would be like below

searching for a customer Josh
I have received a message: yay found customer
searching for a customer Nathan
I have received a message: customer not found
Received reply: how interesting

Like they say at documentation Vert.x is easy and fun to learn. If you're interested just follow the documentation or code examples at

Tuesday, November 24, 2015

Get rid of null checks

As a developer we do our best to catch the null values and fail fast. I was writing too much code lines like below.

if (user == null) {
    throw new IllegalArgumentException("user most not be null.");
} 


After a while codebase can become dirty with this lines copy/pasted everywhere. While I was reading some Spring source code I found that Spring uses `Assert` Util class for that purpose. And we started to use this class as a replacement. Now code become better with this one line.
Assert.notNull(user, "user must not be empty");

Assert class has many useful methods like
Assert.isTrue
Assert.isNull
Assert.notNull
Assert.hasLength
Assert.hasText
Assert.doesNotContain
Assert.notEmpty
...

If throwing IllegalArgumentException is not good for you then you can create your own Util class for that purpose.

Exposing Spring Data Repositories over REST with Spring Boot and Spring Data REST

Spring Boot let us quickly create projects. Spring Boot favors convention over configuration. Most of the time we start with writing domain Entities. To quickly look around Entities or to populate some data we can use Spring Data REST. With Spring Data REST we can easily expose JPA based repositories as RESTful endpoints.

Most of the time you'll need to write your own endpoints for adding validations etc. But for testing the entities or when we need to try something it is good tool.

First we need to create Spring Boot project and add spring-data-rest as maven dependency to pom.xml file

  org.springframework.boot
  spring-boot-starter-parent
  1.3.0.RELEASE
 
 
  
   org.springframework.boot
   spring-boot-starter-data-rest
  
  
   mysql
   mysql-connector-java
   runtime
  
 

Let's create basic Entity
import javax.persistence.*;

@Entity
public class Customer {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Spring Data's JpaRepository interface adds CRUD operations without adding any code. Spring Data REST will use this repository to generate REST endpoints.

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}

Then all we need to do is add @EnableJpaRepositories annotation
@EnableJpaRepositories
@SpringBootApplication
public class SpringDataRestDemo {

    public static void main(String[] args) {
        SpringApplication.run(SpringDataRestDemo.class, args);
    }

}

When you start the application at the root of your url you'll see HATEOS supported endpoints response like below. You can make GET/POST/DELETE/PATCH/PUT requests to this endpoints.
{
  "_links": {
    "customers": {
      "href": "http://localhost:8080/customers{?page,size,sort}",
      "templated": true
    },
    "profile": {
      "href": "http://localhost:8080/profile"
    }
  }
}

Let's check the customers
{
  "_embedded": {
    "customers": [
      {
        "name": "ugur",
        "_links": {
          "self": {
            "href": "http://localhost:8080/customers/1"
          },
          "customer": {
            "href": "http://localhost:8080/customers/1"
          }
        }
      },
      {
        "name": "Luke",
        "_links": {
          "self": {
            "href": "http://localhost:8080/customers/2"
          },
          "customer": {
            "href": "http://localhost:8080/customers/2"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "http://localhost:8080/customers"
    },
    "profile": {
      "href": "http://localhost:8080/profile/customers"
    }
  },
  "page": {
    "size": 20,
    "totalElements": 2,
    "totalPages": 1,
    "number": 0
  }
}

{
  "name": "Luke",
  "_links": {
    "self": {
      "href": "http://localhost:8080/customers/2"
    },
    "customer": {
      "href": "http://localhost:8080/customers/2"
    }
  }
}

Sunday, November 22, 2015

Using Java 8 Time API with JPA

We were using the Joda-Time API for replacement of Java Date API. After improvements on the Java 8 Time API we decided to move on to the Java 8 Time API. But JPA 2.1 does not have built in support for Java 8 time API because Java 8 released after. But we can still use Java 8 API using the attribute converters.

Here the example code for converting LocalDate to java.sql.Date for persisting to db.



With autoApply = true property this converter will be apply to all LocalDates so entities can be clean. If you don't want this feature then you can add @Convert(converter = LocalDateConverter.class) annotation to the fields.

Thursday, January 15, 2015

Spring Data MongoDB ile Spring MongoDB entegrasyonu

Spring Data projesi ile MongoDB'ye erişmek kolay bir hal alıyor.

Kodlara GitHub üzerinden erişebilirsiniz.

spring-boot-starter-data-mongodb'yi dependency olarak ekliyoruz.
pom.xml dosyası:

    org.springframework.boot
    spring-boot-starter-parent
    1.1.10.RELEASE


    
        org.springframework.boot
        spring-boot-starter-data-mongodb
    



    
    UTF-8
    UTF-8
    org.guneriu.springboot.mongo.Application



    
        
            org.springframework.boot
            spring-boot-maven-plugin
        
    


MongoDB üzerinde CRUD işlemlerini yapabilmek için Spring-Data-MongoDB bize MongoRepository sınıfını sunuyor. Bu sınıf ile birlikte
"count, delete, delete, delete, deleteAll, exists, findAll, findOne, save" operasyonları hazır halde geliyor. Bununla birlikte bu metodlara geçirebileceğimiz "Pageable" ve "Sort" parametreleri ile paging ve sorting işlemlerini de yapabiliyoruz.

Customer sınıfı:
import org.springframework.data.annotation.Id;

public class Customer {

    @Id
    private String id;
    private String firstName;
    private String lastName;

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return String.format("Customer[id=%s, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }
}

CustomerRepository sınıfı.
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

public interface CustomerRepository extends MongoRepository<Customer string=""> {

    public List<Customer> findByFirstName(String firstName);
    public List<Customer> findByLastName(String lastName);

    @Query(value = "{}", count = true)
    public int customerCount();

    @Query(value = "{$or:[{'firstName': '?0'}, {'lastName': '?0'}]}", count = true)
    public int customersCountByFirstNameOrLastName(String name);
}

Buradaki findByFirstName ve findByLastName için bir kod bloğu yazmadım. Spring property expression ile sınıf üzerindeki alanlar ile metod ismini eşleştirip bizim için sorguları oluşturuyor. Aşağıdaki örnek kullanımlar Spring-Data-Mongo referans dökümanından. Bazen kompleks sorgular yazmanız gerektiğinde native sorgular yazıp çalıştırabilirsiniz. Bunun için yukarıdaki örnekte görüldüğü gibi @Query annotasyonu içerisine sorguyu yazıyoruz '?0' parametre yerine geçen placeholder.

// Enabling ignoring case for an individual property
    List<Person> findByLastnameIgnoreCase(String lastname);
    // Enabling ignoring case for all suitable properties
    List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

    // Enabling static ORDER BY for a query
    List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
    List<Person> findByLastnameOrderByFirstnameDesc(String lastname);

MongoDB üzerinde işlem yapabilmek için Spring'in sunduğu diğer sınıf ise MongoTemplate. Bu örnek için MongoRepository yeterli geliyor ancak kullanımını göstermek için MongoTemplate yapılandırması aşağıdaki gibi.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;

import com.mongodb.Mongo;
import com.mongodb.MongoClient;

@Configuration
public class MongoConfig {

    @Bean
    public Mongo mongo() throws Exception {
        return new MongoClient();
    }

    @Bean
    public MongoOperations mongoTemplate() throws Exception {
        return new MongoTemplate(mongo(), "test");
    }

}

Uygulamayı çalıştıracağımız main metodumuzu yazdığımız Application sınıfı aşağıdaki gibi.

import java.util.Arrays;
import java.util.List;

import org.guneriu.springboot.mongo.config.MongoConfig;
import org.guneriu.springboot.mongo.customer.Customer;
import org.guneriu.springboot.mongo.customer.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

@EnableAutoConfiguration
@Import(MongoConfig.class)
public class Application implements CommandLineRunner {

    @Autowired
    private CustomerRepository customerRepository;

    @Autowired
    private MongoOperations mongoOperations;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

     Customer customer1 = new Customer("James", "Gosling");
     Customer customer2 = new Customer("James", "Joyce");
     Customer customer3 = new Customer("Joshua", "Bloch");

     customerRepository.save(Arrays.asList(customer1, customer2, customer3));

     List<Customer> customers = customerRepository.findAll();

     System.out.println("listing all customers");

     for (Customer customer : customers) {
        System.out.println(customer);
     }

     List<Customer> customersByFirstName = customerRepository.findByFirstName("James");

     System.out.println("customers with firstName James");

     for (Customer customer : customersByFirstName) {
        System.out.println(customer);
     }

     List<Customer> customersByFirstNameAndLastName =
            mongoOperations.find(
                    new Query(new Criteria().andOperator(
                            Criteria.where("firstName").is("Joshua"),
                            Criteria.where("lastName").is("Bloch"))),
                            Customer.class);

     System.out.println("customers with firstName Joshua and lastName Bloch");

     for (Customer customer : customersByFirstNameAndLastName) {
         System.out.println(customer);
     }

     System.out.println("all costumer counts: " + customerRepository.customerCount());
     System.out.println("customer count firstName or lastName is James :"
             + customerRepository.customersCountByFirstNameOrLastName("James"));
    }
}

Uygulamayı terminal'den spring-boot maven eklentisini kullanarak yada "Run As Java Application" diyerek çalıştırabiliriz.
Uygulamayı çalıştırdığımızda aldığımız çıktı aşağıdaki gibi.

ugur@ugur-PC:~/dev/workspace/spring-boot-mongo$ mvn spring-boot:run
listing all customers
Customer[id=54b7062544aefa551023948f, firstName='James', lastName='Gosling']
Customer[id=54b7062544aefa5510239490, firstName='James', lastName='Joyce']
Customer[id=54b7062544aefa5510239491, firstName='Joshua', lastName='Bloch']
customers with firstName James
Customer[id=54b7062544aefa551023948f, firstName='James', lastName='Gosling']
Customer[id=54b7062544aefa5510239490, firstName='James', lastName='Joyce']
customers with firstName Joshua and lastName Bloch
Customer[id=54b7062544aefa5510239491, firstName='Joshua', lastName='Bloch']
all costumer counts: 3
customer count firstName or lastName is James :2