Sunday, December 16, 2018

Monitoring, SLA, and Alert in OSB

Di blog kali ini, saya akan berbicara tentang beberapa fitur Out of the Box yang disediakan oleh OSB sehubungan dengan monitoring, SLA agreements, dll. Disini saya akan menjelaskan dasarnya sehingga audiens yang dituju dapat menemukan manfaatnya. 

Pada saat ini saya yakin bahwa anda tahu bahwa ada banyak fungsi yang hanya dapat diterapkan pada console web OSB yang tidak dapat dilakukan melalui IDE.

OSB Monitoring

Digunakan untuk mendapatkan statistik pada format tabel, kita dapat menggunakannya dengan mengaktifkan monitoring pada Proxy Service dan Business Service

Configuring monitoring:

  • Setelah Proxy Service selesai didevelop dan dideploy, start server dan buka OSB Console untuk meng-enable monitoring. (Monitoring hanya dapat dienable melalui sbconsole)
  • Melalui Project Explorer, kemudian pilih Proxy Service yang ingin dienable monitoringnya.
  • Klik pada ProxyService dan kemudian klik pada "Operational Settings" tab.
  • Monitoring - Operational features.
  • Create session menggunakan Change Center.
  • Enable monitoring dengan klik checkbox "Monitoring". Aggregation Interval adalah periode dimana statistik agregat yang terkait dengan service dihitung untuk ditampilkan di dashboard Oracle Service Bus Console. Secara default disimpan pada 10 menit.
  • Update setting-an dan aktivasi session.
  • Setelah dienable, kita dapat melihat monitoring statistik dari dashboard. Klik Operations pada sbconsole, dan list dari semua entity ditampilkan di sisi kanan pada halam bawah tab Service Health.


Defining SLA (Service Level Agreement)

SLA adalah sebuah fitur dari OSB yang digunakan untuk memberikan informasi operasional ketika service berjalan atau tidaknya sesuai ketentuan SLA. Sebagai contoh, waktu eksekusi service tidak boleh berjalan lebih lama dari 50 ms atau service harus dijalankan 500 kali selama periode tertentu.

Manajer SLA memungkinkan pengguna untuk mengkonfigurasi aturan SLA. Hal ini digunakan untuk memonitor pelanggaran SLA dengan bantuan data yang disediakan oleh agregator dan mengirim pemberitahuan yang dikonfigurasi dalam tindakan aturan peringatan.

Berikut ini adalah tujuan dari peraturan peringatan SLA:
  • Peraturan peringatan SLA digunakan untuk menentukan kondisi apa yang akan memicu  sebuah peringatan.
  • SLA Alert Destination digunakan untuk menentukan apa yang harus dilakukan saat kita mendapat alert trigger.
Apa yang akan kita lakukan di bagian berikut adalah mengkonfigurasi aturan Alert (menentukan kondisi berdasarkan peringatan yang dipicu) dan tujuan siaga (yang akan memberitahu OSB apa yang harus dilakukan ketika mendapatkan sebuah peringatan). Sebelum menetapkan ketentuan untuk Alert Rule, penting bahwa kita harus mengkonfigurasi Alert Destination terlebih dahulu.

Sekarang, kita akan melakukan konfigurasi yang akan mengirimkan peringatan yang dipicu melalui email. Cara menetapkan Alert Destination adalah email jika ada pelanggaran SLA. Langkah pertama adalah mengkonfigurasi Alert Destination yang akan kita gunakan dalam peringatan SLA. Dan untuk pemberitahuan email yang berhasil dikirim, kita membutuhkan SMTP Server dalam melakukan konfigurasi. (Hal ini dapat dilakukan melalui IDE atau sbconsole)

Setelah SMTP Server diatur, langkah selanjutnya adalah membuat Alert Destination. Alert Destination pada dasarnya berisi daftar penerima yang akan dikonfigurasi dalam alur Proxy Service. Konfigurasikan Alert Destination dengan memberikan detail yang diperlukan. Di bagian penerima, kita dapat menyebutkan alamat email yang ingin dikirimi alertnya. Selanjutnya, kita menggunakan Alert Destination untuk Level Agreement Alerts. Kita dapat membuat rule pada Business Service.


References:
  • https://docs.oracle.com/middleware/1213/osb/administer/GUID-2EECE6E7-A783-465C-A041-A500CC93FD62.htm#OSBAG2056 
  • http://oraclesoaosbbpmapi.blogspot.com/2017/07/osb-monitoring-configurationslapipeline.html




Getting Started Using ZK Framework



ZK Framework

Hello everyone, Today i will be showing some ZK framework. ZK framework is an open source AJAX Web application framework written in java that enables graphic user interface for web application.

Here some of ZK components you can try at home:




The components above shows how to create user input, the code above shows how to implement it. Using textbox to create an input for user to type and also a button to submit what ever user have entered.






The Components above shows how to implement a textbox and a date field. To implement a textbox you will need <textbox> tag and for the date you will need a <dateBox> tag.





The components above shows how to implements a gird in ZK. First you need to define a <grid> tag, then inside that <grid> tag you will need to add <Columns> first  and inside that tag you will need to add the amount of column  you need. For this example i have 5 column. After the columns has been added, then you can implement the rows. The same way as you add the column you will first add a <rows> tag and inside that tag you will need a <rows> tag.





The components above shows how to create a list of data. Firstly you will need to create a <listhead>, this tag is for creating the title of the list. For this example i have put "Model", "Make" and "Type".
After the <listhead> tag, you will need to create a <listitem> tag. In that list item you will need a <listcell> tag in order to shows the information and also a "label".



The components above shows how to create a tab in ZK. First you need to define <tabbox> tag, inside that tag you will need a <tab> tag, you can implement as much tab as you want, for this example i have put in 3 which are "our product", "Live demo" and "Online Documentation". You can also add a <style> tag to make some customization in your tabs.



These are some components that is in ZK framework and there are plenty more by visiting the ZK official website.
In that website you can get different type of components and you can test them by using ZKfiddle.com or you can try using eclipse to show your result.

Thank you.







Eureka Service Registry Service Discovery


Eureka Serviced Registry and Service Discovery

Hello Everyone, in this blog i will be showing you how to setup Eureka Service Registry using spring-boot.

Eureka service registry and service discovery:

- Is a REST (Representational State Transfer) base service.
- This can used to connect Eureka Server and Eureka Client.
- Eureka can be used as a load balancer
- Being able to monitor your service that has been register

Eureka Architecture



Without Eureka

From the diagram above, this shows when the service is not being registered using Eureka. To obtain the information about the employee, the producer has to use HTTP.get in order to retrieve the information. If the Employee-consumer is down, then the producer would not be able to retrieve the information because the connection between the producer and the consumer has been cut.


With Eureka


From the diagram above, this shows when the services has been registered using Eureka Service Registry.
As you can observed that both services has been registered to Eureka service registry, by doing this method it will improve performance and also making less modification to your code. If for some reason that the Employee-Consumer has failed, then you still be able to retrieve the data because the service has been registry in Eureka Service registry and the Employee-produce still can obtain the data.

How to set up the Eureka Service Registry

For this example i will create 3 maven project:
- Employee Produce 
- Employee Consumer 
- Eureka Server

Each of the maven project, you will need to add these dependencies:





Also you will need to add this java annotation in your main class:




In your Employee-Producer and Employee-Consumer you have to add the following:


You must add a "properties" file in order to register the service to the Eureka Service Registry:


The port number must be the same as the Eureka server port in order to register the service.


And lastly, in your Employee producer and Employee discovery you must have a properties name called "bootsrap.properties" in order to name your service.



in your Eureka Server you need to add a properties file which contain the server port




Result




Once you have those 3 maven project running, you can see the registered service is your Eureka server. The image above shows the registered service that i created which is "EMPLOYEE-CONSUMER" and "EMPLOYEE-PRODUCER"




The code above is how you retrieve the data from the employee-consumer to the employee-customer. Instead of writing the URL Path, you can create this object

List<ServiceInstance> instances=discoveryClient.getInstances("employee-producer");
ServiceInstance serviceInstance=instances.get(0);

String baseUrl=serviceInstance.getUri().toString();

baseUrl=baseUrl+"/employee" 


and add the name of the service you have registered, so for this example i put in the "employee-produce" as the name of my service  and also add which method you wanted to call which is "employee" for this example.



This is the result that i tested using postman. In the employee consumer i made an employee object and added a couple of data. That data is then save in the Eureka Service registry waiting for the employee producer to consume.
Then using postman, i type in the address for the client server to retrieve all the employee data as shown and the retrieving method is by using Eureka Service Registry. 


Introduction Asynchronous Program with CompletableFuture

Apa itu Asynchronous Program?

Asynchronous program adalah cara menulis kode non-pemblokiran dengan menjalankan tugas pada thread yang terpisah (dimana unit kerja berjalan secara terpisah) dari thread aplikasi utama dan memberitahu thread utama tentang progres, penyelesaian, atau kegagalan.

Mari kita pahami dengan sebuah contoh....

Artikel Berita:
Misalnya, kita memiliki produk yang membawa informasi yang relevan kepada pelanggan seperti berita bisnis, informasi saham, dll. Salah satu modul produk ini adalah membuang berita dari berbagai sumber dan memahami kontennya, yang berarti kita akan mengekstraksi berbagai artikel berita, informasi saham dari berbagai sumber, Yahoo, Business Insider, Reuters, dll.

Disini kita perlu menghubungi banyak layanan di internet untuk mendapatkan berita yang relevan bagi pelanggan. Apa yang tidak ingin kita lakukan adalah memblokir proses perhitungan untuk mendapatkan informasi yang relevan dari layanan di atas. Misalnya, kita tidak perlu menunggu data dari Yahoo Finance untuk mulai memproses data yang berasal dari Business Insider. Ini merupakan sisi lain dari multitask-programming. Sebaliknya yang benar-benar ingin kita capai adalah menghindari pemblokiran thread dan membuang-buang komputasi resources sambil menunggu yang mungkin cukup lama untuk mendapatkan sebuah result dari remote service atau dari interogasi basis data.

CompletableFuture

Digunakan untuk pemrograman asynchronous di Java. CompletableFuture diperkenalkan di Java 8 yang menyediakan abstraksi untuk tugas async dalam pemrograman event driven. Ini biasanya ditujukan untuk menjalankan operasi yang berjalan lama (http request, query database, operasi file atau perhitungan yang rumit).

CompletableFuture memiliki 2 manfaat utama:
  • Ini dapat diselesaikan secara eksplisit dengan memanggil method complete() tanpa menunggu yang sinkron. Ini memungkinkan nilai jenis apapun avalaible in future dengan nilai kembalian default, meskipun komputasi tidak selesai, menggunakan hasil default/intermediate results.
  • Dengan puluhan metode baru, juga memungkinkan kita untuk membangun pipeline data process dalam serangkaian action. Kita dapat menemukan sejumlah pola untuk CompletableFutures seperti membuat CompletableFuture dari sebuah task.

Berikut intro dari pengertian Asynchronous dan CompletableFuture, sekarang kita akan memasuki demonstrasi dari Asynchronous Program with CompletableFuture.

Create representasi dari GitHub User

Untuk memodelkan representasi pengguna, kita membuat kelas representasi resources. Menyediakan objek Java biasa fields, constructors, and accessors:

src/main/java/hello/User.java


Spring menggunakan library Jackson JSON untuk mengonversi respon JSON GitHub ke dalam objek User. Anotasi @JsonIgnoreProperties digunakan untuk mengabaikan atribut apapun yang tidak tercantum di kelas. Ini akan membuat kita mudah untuk panggilan REST dan menghasilkan objek domain. Disini kita akan mengambil nama dan URL blog.

Create GitHubLookupService

Selanjutnya, kita perlu membuat sebuah service query GitHub untuk menemukan informasi user.

src/main/java/hello/GitHubLookupService.java


Kelas GitHubLookupService menggunakan Spring's RestTemplate untuk memanggil point REST, lalu mengonversi responnya menjadi objek User. Spring Boot secara otomatis menyediakan RestTemplateBuilder yang mengkustomisasi default dengan bit konfigurasi otomatis (yaitu MessageConverter).

Metode findUser ditandai dengan anotasi @AsyncSpring, yang menunjukkan bahwa proses akan berjalan pada thread yang terpisah. Jenis pengembalian method adalah CompletableFuture<User> sebagai pengganti User, persyaratan untuk asynchronous service. Code ini menggunakan metode completionFuture untuk  mengembalikan instance CompletableFuture yang sudah selesai dengan hasil query GitHub.

Ada juga CommandLineRunner yang meng-inject GitHubLookupService dan memanggil service tersebut 3 kali untuk menunjukkan bahwa method dijalankan secara asynchronous.

src/main/java/hello/AppRunner.java


Kesimpulan:

Kita baru saja mengembangkan service asinkron yang memungkinkan kita untuk meningkatkan multiple calls at once (dapat menjalankan beberapa proses sekaligus).

References:

Building Reactive Rest API using Spring Webflux Part 2

Setelah membahas teori pada blog sebelumnya, pada part 2 ini akan dijelaskan bagaimana membuat reactive rest api menggunakan Spring WebFlux. Pada contoh ini saya akan membuat blog service 

Buatlah project dengan membuka alamat Spring Initializr, dan tambahkan beberapa depedencies sebagai berikut :



  • Reactive Web : Dependency ini untuk Spring WebFlux
  • Reactive MongoDB : Dependency ini untuk reactive driver untuk database MongoDB (NoSQL)
  • Lombok : Dependency ini hanya optional yang digunakan agar tidak perlu membuat setter getter, constructor, toString(), hashCode(), equals() pada class tertentu seperti model atau DTO
Lalu generate project, dan project akan didownload berupa zip, kemudian  extract lalu buka menggunakan Intellij IDEA (Bisa juga eclipse atau NetBeans).

Saya akan membuat reactive rest api dengan 2 cara yaitu menggunakan annotations dan Functional

Menggunakan annotations

Dalam membangun reactive rest api menggunakan Spring WebFlux dapat juga mengikuti stye yang sama seperti Spring MVC yaitu dengan mengunakan annotasi.
Untuk membuat blog service, saya mendefiniskan beberapa kelas dan interface :
  • Blog: Sebuah model class yang merepresentasikan blog pada service ini
  • BlogRepository : Sebuah interface yang nantinya akan men-generate query-query untuk blog menuju dan dari MongoDB
  • BlogServiceImpl  : Sebuah class yang digunakan untuk berinteraksi dengan BlogRepository untuk CRUD ke MongoDB
  • BlogService : Ketika membuat aplikasi, direkomendasikan untuk membuat layer ini sebagai interface antara class controller dan class service impl
Membuat sebuah class model bernama Blog.java 


Class Blog adalah POJO class sederhana yang berisi id, title, content dan author. Ada beberapa anotasi yang digunakan pada class ini diantaranya :
  • @Document : digunakan untuk mengidentifikasi itu sebagai Document MongoDB, Spring Data akan memetakan Document ke Collection di MongoDB
  • @Data : digunakan untuk men-generate setter getter, tostring(), equals() dan hashCode()
Membuat sebuah interface yang bernama BlogRepository.java


BlogRepository adalah interface Spring Data, yang berarti bahwa kita mendefinisikan interface dan Spring Data akan menghasilkan kode yang mengimplementasi interface itu. Pada interface ini, interface ini meng-extends ReacticveMongoRepository, yang mendefiniskan metode-metode reactive yang mengembalikan mono atau flux.
  • Mono<Book> save()
  • Flux<Book> saveAll()
  • Flux<Book> findById()
  • Mono<Boolean> existById()
  • Flux<Book> findAll()
  • Flux<Book> findAllById()
  • Mono<Long> count()
  • Mono<Void> delete()
  • Mono<Void> deleteById()
  • Mono<Void> deleteAll()
  • Flux<Book> insert()
Query method yang mengembalikan satu elemen seperti contohnya findById mengembalikan Mono<Blog>, Query metho yang mengembalikan lebih dari satu elemen seperti findAll mengembalikan Flux<Book> dam metode untuk delete blog mengembalikan Mono<Void> yang artinya tidak ada pengembalian tetapi ketika operasi selesai akan mempublikasikan pemberitahuan jika operasi telah diselesaikan.

Membuat sebuah interface yang bernama BlogService.java


Membuat class bernama BlogServiceImpl.java yang mengimplementasi Blogservice



Anotasi @Service digunakan untuk mengidentifikasi bahwa class ini adalah class service yang mewakili fungsi bisnis Dalam contoh  service diatas, fungsi bisnis hanya melakukan operasi crud ke repository, Jika kita perlu menambahkan logika yang lebih kompleks pada query atau pada object, disinilah kita melakukannya.

Membuat class bernama BlogController.java


Dari code diatas, sekilas tidak ada perbedaan yang signifikan jika dibanding dengan Spring MVC. Satu-satunya perbedaan adalah pada semua method mengembalikan tipe reactive yaitu mono dan flux dan juga menggunakan driver MongoDB yang reactive. Meskipun nyaris tidak ada perbedaan tetapi implementasinya sangat berbeda. Spring WebFlux akan memanggil metode handler, akan menangkap respons secara reactive dan kemudian memanfaatkan Reactor untuk menunggu respons yang akan di publikasikan, semua secara asynchronous.


Kesimpulan :
Spring WebFlux adalah Spring Reactive Framework yang menggunaan library Reactor untuk mengolah request dari web secara asynchronous atau non-blocking. Spring WebFlux diperkenalkan di Spring Framework 5, framework ini akan terus berkembang namun framework dan library-library cukup untuk membangun aplikasi web yang sangat scalable dan reactive.

Sekian pembahasan tentang membangun reactive rest api menggunakan Spring WebFlux, semoga membantu bagi teman-teman yang sedang mempelajari framework ini. Terimakasih :))


Referensi :

Typed.js

Typed js adalah sebuah plugin JavaScript yang memberikan efek menulis secara otomatis pada website sesuai tujuan kita. JavaScript yang menjadikan website kita menjadi interaktif. Typed.js ini di buat oleh MATT BOLDT di Texas , US

Untuk mendapatkan Typed.js kita dapat Inject dari https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.8/typed.min.js atau npm install typed.js

1. Selanjutnya kita buat file html , Inject Typed.js


2. Setelah kita membuat struktur htmlnya , sekarang kita bermain dengan Typed.js nya 


Penjelasan : 
  1. Buat variable typed yang berisi method var typed = new Typed
  2. Pada inisiasi object typed() buat dua parameter yang di panggil pada #typed berisi List object
  3. typeSpeed adalah seberapa cepat text di ketik
  4. startDelay : seberapa lama jeda text berulang
  5. Loop  : kondisi dimana akan di ulang atau tidak




Elasticsearch Part 2: Contoh Sederhana Elasticsearch Search Query

Tulisan ini merupakan lanjutan dari tulisan sebelumnya. Pada tulisan ini akan dijelaskan cara membuat sebuah service pencarian data menggunakan elasticsearch node menggunakan elasticsearch template dan search query.
Sebenarnya seperti JpaRepository untuk mengakses data pada elasticsearch dapat digunakan pula ElasticsearchRepository. Pada interface ElasticsearchRepository juga sudah terdapat beberapa built in method untuk melakukan pencarian, seperti findAll(), findById(), dll. Namun kemampuan querynya sangat terbatas.
Kemudian sebenarnya kita juga dapat mengakses data elasticsearch seperti kita menggunakan JPQL atau native query, yaitu dengan membuat sebuah method di interface repositorynya lalu memberi annotation Query dan mendefinisikan querynya. Namun hal ini berbeda untuk elasticsearch yang menurut saya querynya cukup rumit, silahkan baca tentang elasticsearch Query DSL
Sehingga saya menyarankan untuk menggunakan elasticsearch template dan search query, yang menurut saya cukup mirip dengan JpaSpecification. Dengan search query ini kita dapat mengoperasikan query dsl tanpa "string declaration".

Tanpa memperpanjang penjelasan metode query, selanjutnya saya akan menjelaskan praktikalnya.
Misalnya kita akan membuat sebuah service untuk mencari Driver (supir). data ini akan disimpan ke MySQL dan elasticsearch.
  • Data Driver dapat dicari berdasarkan beberapa id yang kita inginkan dan didefinisikan dalam sebuah collection of integer, 
  • Dapat dicari berdasarkan string full name, nick name, gender, dan vehicle. Namun string yang digunakan untuk pencarian harus toleran terhadap fuzziness dan sloppiness (secara sederhana dapat kita sebut dengan typo).
  • Data dicari berdasarkan rentang price-nya, yang didefinisikan dengan batas minimum price dan batas maximum price.
  • Dapat dicari dari jaraknya terhadap suatu lokasi yang didefinisikan dengan nilai latitude dan longitude tertentu.
  • Dan dapat dicari berdasarkan letaknya dalam suatu daerah (misal dalam satu kota), yang didefinisikan dengan nilai south west latitude, south west longitude, north east latitude, dan north east longitude.
Driver Class

@Entity@Table(name = "driver")
@Data@Document(indexName = "driver", type = "driver")
public class Driver implements Serializable {

    @Id    @GeneratedValue    private Integer id;
    @Field(type = FieldType.Keyword)
    private String fullName;
    @Field(type = FieldType.Keyword)
    private String nickName;
    @Field(type = FieldType.Keyword)
    private Gender gender;
    @Field(type = FieldType.Keyword)
    private String vehicle;
    private Integer price;
    @Transient    @GeoPointField    private GeoPoint location;}
Annotation yang berkaitan langsung dengan elasticsearch adalah annotation Document, sedangkan Entity, dan Table berkaitan dengan MySQL database dan annotation Data merupakan plugin lombok. Pada Document terdapat parameter indexName yang secara sederhana dapat dikatakan sebagai database name di elasticsearch. Sedangkan parameter type secara sederhana dapat dikatan sebagai table name di elasticsearch.
Selanjutanya annotation Id perlu didefinisikan pula untuk elasticsearch. Meskipun annotation GeneratedValue tidak bekerja pada elasticsearch, tapi Id tetap diperlukan untuk menjelaskan ElasticsearchRepository bahwa data Driver dapat dikenali dengan field Id "private Integer id".
Lalu terdapat annotation Field pada sebagian besar String data type. Pada spring data elasticsearch data type String akan di mapping ke type text secara default. Namun type data ini memiliki banyak batasan, misalnya field terkait jadi sulit untuk digunakan sebagai parameter sorting. Sedangkan keyword lebih flexible dan dapat digunakan untuk sorting.
Kemudian terpadat annotation Transient yang meng-ignore field location untuk dipetakan ke table di MySQL, karena jika tidak akan menyebabkan error yang disebabkan type data GeoPoint yang tidak dapat dipetakan dalam table MySQL. Sedangkan annotation GeoPointField mirip dengan annotation field, tetapi digunakan secara khusus untuk type data yang berhubungan dengan geospatial (geografis).
catatan:
Type data GeoPoint yang digunakan berasal dari org.springframework.data.elasticsearch.core.geo. yang saya ketahui terdapat 2 GeoPoint data type, yang satu lagi berasalah dari org.elasticsearch.common.geo yang dapat digunakan untuk sorting data berdasarkan jarak.
Driver Repositories
Dikarenakan data Driver disimpan pada elasticsearch dan MySQL, maka terdapat 2 interface repository untuk class Driver.

public interface DriverElasticRepository extends ElasticsearchRepository<Driver, Integer> {
}
 dan
public interface DriverRepository extends JpaRepository<Driver, Integer>{
}
Driver Mapping
Dikarenakan kita menggunakan custome mapping (annotation field) pada Driver class, maka kita perlu memberi tahu elasticsearch template untuk menggunakan mapping yang telah kita tentukan. Proses ini disebut put mapping dan proses ini sebaiknya cukup dilakukan sekali, sehingga saya melakukannya pada post construct.
@Componentpublic class Init {

    @Autowired    ElasticsearchTemplate elasticsearchTemplate;
    @PostConstruct    public void init(){
        elasticsearchTemplate.putMapping(Driver.class);        elasticsearchTemplate.putMapping(Regency.class);    }
}
Driver Service
Rancangan Query dengan BoolQueryBuilder
Misal secara default service pencarian melakukan pencarian berdasarkan price, dan batas penentunya (minimum price dan maximum price) tidak pernah null, karena telah diinisialisasi.

BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder()
        .filter(new RangeQueryBuilder("price")
                .gte(minimumPrice)
                .lte(maximumPrice));
Dengan begitu kita membuat sebuah "container" yang akan menampung Query kita, dan fitur yang mempu menjadi penampung adalah BoolQueryBuilder. berdasarkan source code di atas juga cukup jelas, bahwa proses yang dilakukan adalah melakukan pencarian "price" yang lebih dari sama dengan (greater than equal) minimumPrice dan kurang dari sama dengan (less than equal) maximumPrice.

Kemudian untuk memenuhi pencarian berdasarkan id yang kita tentukan pada collection of integers dan melakukan sorting berdasarkan urutannya pada collection of integers.
if (ids != null && ids.size() > 0){
    float score = ids.size()*scoreThreshold;    for (Integer id : ids){
        boolQueryBuilder = boolQueryBuilder
                .should(new TermQueryBuilder("id", String.valueOf(id)).boost(score));        score = score - scoreThreshold;    }
}
potongan source code di atas menjelaskan bahwa setiap data yang nilai id-nya sama dengan yang ada dalam ids diberi score tertentu. Scoring ini menyebabkan data ter-sortir secara otomatis, karena sistem pencarian dan pengurutan data dalam elasticsearch bekaitan dengan scorenya. Score sendiri merupakan nilai yang ditambahkan untuk setiap data yang telah memenuhi query yang telah ditentukan. sehingga berdasarkan source code di atas, data pertama yang ada dalam collection ids akan ditempatkan pada posisi pertama.

Lalu untuk memenuhi pencarian menggunakan String untuk full name, nick name, gender, dan vehicle, serta toleransinya terhadap fuzziness dan sloppiness digunakan source code berikut.
if (!StringUtils.isEmpty(words)){
    boolQueryBuilder = boolQueryBuilder
            .filter(new MultiMatchQueryBuilder(words)
                    .field("fullName")
                    .field("nickName")
                    .field("gender")
                    .field("vehicle")
                    .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)
                    .fuzziness(Fuzziness.TWO));}
Source code di atas menjelaskan bahwa query "container" ditambahkan dengan query pencarian String pada field fullName, nickName, gender, dan vehicle dan dipilih yang nilainya paling sesuai dengan nilai words. Pada query ini digunakan sloppiness default, dan fuzziness edit distance 2. Saya menyarankan untuk membaca istilah fuzziness edit distance, slop, prefix_length, max_expansions, dan tranpositions, karena istilah ini cukup penting untuk membuat string query yang baik.

Kemudian berkaitan dengan pencarian Driver di suatu daerah yang ditentukan dengan south west latitude, south west longitude, north east latitude, dan north east longitude (keempatnya dapat disebut dengan bounding box) digunakan object Regency (data Kota) yang bounding boxnya dapat diambil dari nominatin.
if (regencyId != null){
    Regency regency = regencyElasticRepository.findById(regencyId).get();    boolQueryBuilder = boolQueryBuilder
            .filter(new GeoBoundingBoxQueryBuilder("location")
                    .setCorners(regency.getNorthEastLat(), regency.getSouthWestLng(),                             regency.getSouthWestLat(), regency.getNorthEastLng()));}
Meskipun proses aslinya cukup rumit, deklarasi pada source code cukup sederhana. Kita cukup memberikan parameter nama field "location" dengan nilai bounding box. Kemudian query akan mencari data yang location-nya ada di dalam daerah yang dibatasi bounding box.
Terakhir untuk memenuhi pencarian Driver yang berada pada jarak tertentu dapat digunakan source code berikut.
if (currentLatitude != null && currentLongitude != null && radius != null){
    boolQueryBuilder = boolQueryBuilder
            .filter(QueryBuilders.geoDistanceQuery("location")
                    .point(currentLatitude, currentLongitude)
                    .distance(radius, DistanceUnit.KILOMETERS));}
Mirip dengan GeoBoundingQueryBuilder, proses geoDistanceQuery ini juga sebenarnya cukup rumit, tetapi dikarenakan kita menggunakan search query kita cukup fokus pada deklarasinya saja, dan deklarasinya juga sangat sederhana. Kita cukup memberikan parameter nama field "location" beserta dengan point komparasi jaraknya (point) dan batas jarak yang diinginkan (distance).

Realisasi Rancangan Query dengan SearchQuery
Dengan begitu semua kondisi pencarian telah terpenuhi. Namun yang telah kita lakukan barulah perancangan query. Rancangan query ini perlu dijalankan (direalisasikan). Caranya adalah dengan menggunakan Search Query dan elasticsearch template. Berikut deklarasinya dalam source code yang telah saya buat.
SearchQuery searchQuery;if (ids != null && ids.size() > 0){
    searchQuery = new NativeSearchQueryBuilder()
            .withMinScore(scoreThreshold)
            .withQuery(boolQueryBuilder)
            .build();} else if (currentLatitude != null && currentLongitude != null && radius != null){
    searchQuery = new NativeSearchQueryBuilder()
            .withQuery(boolQueryBuilder)
            .withPageable(new PageRequest(page, limit))
            .withSort(SortBuilders
                    .geoDistanceSort("location", new org.elasticsearch.common.geo
                            .GeoPoint(currentLatitude, currentLongitude))
                    .order(SortOrder.ASC))
            .build();} else {
    searchQuery = new NativeSearchQueryBuilder()
            .withQuery(boolQueryBuilder)
            .withPageable(new PageRequest(page, limit, new Sort(sortDirection, sortBy)))
            .build();}
Berdasarkan source code di atas terdapat 3 deklarasi nilai Search Query. Kondisi pertama membuat rancangan query direaslisasikan dengan melakukan sorting berdasarkan score minimum yang telah ditentukan. kondisi kedua melakukan sorting berdasarkan jarak terdekat ke terjauh terhadap point yang telah di definisikan currentLatitude dan currentLongitude. Kondisi ketiga melakukan sorting berdasarkan field yang ditentukan String sortBy dan directionnya ASC atau DESC, tergantung nilai sortDirection.

Fetch Data Hasil SearchQuery
Proses terakhir adalah mengambil data yang telah ditentukan oleh search query. Pada source code berikut data diambil kedalam Page, karena kita telah mengimplementasikan pagination sejauh ini.
catatan:
Jika kita mengambil data kedalam List atau Collection lain dari elasticsearch, maka elasticsearch hanya akan memberikan 10 data. Oleh karena itu kita sebaiknya mendefinisikan nilai limit, dan nilai maximum limit secara default adalah 10000, lebih dari itu kita perlu melakukan konfigurasi khusus pada elasticsearch.

elasticsearchTemplate.createIndex(Driver.class);Page<Driver> resultPage = elasticsearchTemplate.queryForPage(searchQuery, Driver.class);List<Driver> resultList = resultPage.getContent();
Perlu diketahui createIndex sebenarnya cukup dilakukan sekali saja, dapat saja dideklarasikan pada post construct.

Repository project dapat dilihat di sini.

React Components that implement Material UI


Haii.. mungkin ini bukan hal yang baru apalagi front-end engineer, pasti udah tau yang namanya Material Design product dari raksasa teknologi yaitu google, pada kesempatan kali ini saya akan coba membahas penerapan Material UI pada React Component.


Material UI muncul sebagai alternative Component untuk memudahkan developer dalam membuat website atau aplikasi. Material UI menerapkan component yang umum digunakan di beberapa platform google lainnya seperti Gmail, Youtube, dll.

Penjelasan lebih detailnya mampir di official websitenya https://material-ui.com/

Sebelum menggunakan Material UI, install terlebih dahulu framework react js di direktori kalian, untuk lebih jelas silahkan liat ke official website react js https://reactjs.org/docs/getting-started.html

Setelah project react selesai di install, silahkan install Material UI pada package project kalian dengan command
 $ npm install @material-ui/core

Untuk penggunaannya seperti dibawah ini
  import React, { Component } from 'react';
 import './App.css';
 import Button from '@material-ui/core/Button';

 class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <Button variant="contained" color="primary">
            Hello World
          </Button>
        </header>
      </div>
    );
  }
 }

 export default App;


ini hanya sebagian kecil dari component yang disediakan oleh Material UI, cukup mudah bukan? Dokumentasi di official websitenya sangat lengkap dan mudah di mengerti


References

Auto Register EC2 domain name to AWS Route53

Halo Sobat Nostra,
kali ini saya akan berbagi tutorial tentang route53 aws. Amazon Route 53 adalah layanan web Sistem Nama Domain (DNS) cloud dengan ketersediaan dan penskalaan tinggi. Amazon Route 53 dirancang untuk memberikan pengembang dan bisnis cara yang sangat tepercaya dengan biaya hemat untuk merutekan pengguna akhir ke aplikasi internet dengan menerjemahkan nama seperti www.example.com ke alamat IP numerik seperti 192.0.2.1 yang digunakan komputer untuk saling menghubungkan. Amazon Route 53 juga sangat sesuai dengan IPv6.

Keuntungannya adalah kita tidak perlu menghapal IP lagi apabila ingin masuk ke server atau mengetaui karena kita sudah memberikan penamaan untuk masing2 ec2 instance. Hal ini juga mempermudah kita dalam pemetaan infrastruktur kita pada aws. Sangat disarankan anda harus memahami tentang aws terlebih dahulu sebelum memulai tutorial dibawah ini.
  1. Buka dashboard aws, pilih service lalu cari route53, kemudian create hosted zone. Setelah mengisi keterangan domain. Cari hosted zone id yang akan kita gunakan nanti pada script register domain.
  2. Buat Custom IAM Policy untuk akses ke route53 aws.

  3. {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "route53:GetHostedZone",
                    "route53:ChangeResourceRecordSets",
                    "route53:ListResourceRecordSets"
                ],
                "Resource": "arn:aws:route53:::hostedzone/ZH3L54A2ZOHEN"
            },
            {
                "Sid": "VisualEditor1",
                "Effect": "Allow",
                "Action": [
                    "route53:ListHostedZones",
                    "route53:ListHostedZonesByName"
                ],
                "Resource": "*"
            }
        ]
    

  4. Buat IAM Policy DescribeTagEC2

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "ec2:DescribeInstances",
                    "ec2:DescribeAggregateIdFormat",
                    "ec2:DescribeVolumesModifications",
                    "ec2:DescribeSnapshots",
                    "ec2:DescribePlacementGroups",
                    "ec2:DescribeHostReservationOfferings",
                    "ec2:DescribeInternetGateways",
                    "ec2:DescribeVolumeStatus",
                    "ec2:DescribeScheduledInstanceAvailability",
                    "ec2:DescribeSpotDatafeedSubscription",
                    "ec2:DescribeVolumes",
                    "ec2:DescribeFpgaImageAttribute",
                    "ec2:DescribeExportTasks",
                    "ec2:DescribeAccountAttributes",
                    "ec2:DescribeNetworkInterfacePermissions",
                    "ec2:DescribeReservedInstances",
                    "ec2:DescribeKeyPairs",
                    "ec2:DescribeNetworkAcls",
                    "ec2:DescribeRouteTables",
                    "ec2:DescribeReservedInstancesListings",
                    "ec2:DescribeEgressOnlyInternetGateways",
                    "ec2:DescribeSpotFleetRequestHistory",
                    "ec2:DescribeLaunchTemplates",
                    "ec2:DescribeVpcClassicLinkDnsSupport",
                    "ec2:DescribeVpnConnections",
                    "ec2:DescribeSnapshotAttribute",
                    "ec2:DescribeVpcPeeringConnections",
                    "ec2:DescribeReservedInstancesOfferings",
                    "ec2:DescribeIdFormat",
                    "ec2:DescribeFleetInstances",
                    "ec2:DescribeVpcEndpointServiceConfigurations",
                    "ec2:DescribePrefixLists",
                    "ec2:DescribeVolumeAttribute",
                    "ec2:DescribeInstanceCreditSpecifications",
                    "ec2:DescribeVpcClassicLink",
                    "ec2:DescribeImportSnapshotTasks",
                    "ec2:DescribeVpcEndpointServicePermissions",
                    "ec2:DescribeScheduledInstances",
                    "ec2:DescribeImageAttribute",
                    "ec2:DescribeFleets",
                    "ec2:DescribeVpcEndpoints",
                    "ec2:DescribeReservedInstancesModifications",
                    "ec2:DescribeElasticGpus",
                    "ec2:DescribeSubnets",
                    "ec2:DescribeVpnGateways",
                    "ec2:DescribeMovingAddresses",
                    "ec2:DescribeFleetHistory",
                    "ec2:DescribePrincipalIdFormat",
                    "ec2:DescribeAddresses",
                    "ec2:DescribeInstanceAttribute",
                    "ec2:DescribeRegions",
                    "ec2:DescribeFlowLogs",
                    "ec2:DescribeDhcpOptions",
                    "ec2:DescribeVpcEndpointServices",
                    "ec2:DescribeSpotInstanceRequests",
                    "ec2:DescribeVpcAttribute",
                    "ec2:DescribeSpotPriceHistory",
                    "ec2:DescribeNetworkInterfaces",
                    "ec2:DescribeAvailabilityZones",
                    "ec2:DescribeNetworkInterfaceAttribute",
                    "ec2:DescribeVpcEndpointConnections",
                    "ec2:DescribeInstanceStatus",
                    "ec2:DescribeHostReservations",
                    "ec2:DescribeIamInstanceProfileAssociations",
                    "ec2:DescribeTags",
                    "ec2:DescribeLaunchTemplateVersions",
                    "ec2:DescribeBundleTasks",
                    "ec2:DescribeIdentityIdFormat",
                    "ec2:DescribeImportImageTasks",
                    "ec2:DescribeClassicLinkInstances",
                    "ec2:DescribeNatGateways",
                    "ec2:DescribeCustomerGateways",
                    "ec2:DescribeVpcEndpointConnectionNotifications",
                    "ec2:DescribeSecurityGroups",
                    "ec2:DescribeSpotFleetRequests",
                    "ec2:DescribeHosts",
                    "ec2:DescribeImages",
                    "ec2:DescribeFpgaImages",
                    "ec2:DescribeSpotFleetInstances",
                    "ec2:DescribeSecurityGroupReferences",
                    "ec2:DescribeVpcs",
                    "ec2:DescribeConversionTasks",
                    "ec2:DescribeStaleSecurityGroups"
                ],
                "Resource": "*"
            }
        ]
    }
    

  5. Buat EC2 user dan group only read access, kemudian assign group pada langkah ke 4 diatas
  6. Buat ec2 instance dengan tag seperti dibawah ini:

    Name : test.nostra.local
    Service: test
  7. Install python, pip, awscli, ec-metadata and cli53 in the EC2 instance
    yum install python
    curl -O https://bootstrap.pypa.io/get-pip.py
    python3 get-pip.py 
    pip install awscli --upgrade 
    cd
    wget http://s3.amazonaws.com/ec2metadata/ec2-metadata
    chmod u+x ec2-metadata
    wget https://github.com/barnybug/cli53/releases/download/0.8.7/cli53-linux-amd64
    sudo mv cli53-linux-amd64 /usr/local/bin/cli53
    sudo chmod +x /usr/local/bin/cli53
  8. Buat script register domain to route53
    sudo touch /usr/sbin/update-route53-dns
    sudo chmod +x /usr/sbin/update-route53-dns
    sudo nano /usr/sbin/update-route53-dns
    

  9. Isi file tersebut seperti dibawah ini:
    
    #!/bin/sh
    
    # Load configuration and export access key ID and secret for cli53 and aws cli
    . /etc/route53/config
    export AWS_ACCESS_KEY_ID
    export AWS_SECRET_ACCESS_KEY
    #export ZONE="AKIAJJX2XQNEA4D6UTPQ"
    
    # The TimeToLive in seconds we use for the DNS records
    TTL="300"
    
    # Get the private and public hostname from EC2 resource tags
    REGION=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | grep region | awk -F\" '{print $4}')
    INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
    INTERNAL_HOSTNAME=$(aws ec2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=Service" --region=$REGION --output=text | cut -f5)
    #PUBLIC_HOSTNAME=$(aws ec2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=Name" --region=$REGION --output=text | cut -f5)
    
    # Get the local and public IP Address that is assigned to the instance
    LOCAL_IPV4=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)
    #PUBLIC_IPV4=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4)
    
    # Create a new or update the A-Records on Route53 with public and private IP address
    cli53 rrcreate --replace "$ZONE" "$INTERNAL_HOSTNAME $TTL A $LOCAL_IPV4"
    
    hostnamectl set-hostname ${INTERNAL_HOSTNAME}.nostra.local
    #cli53 rrcreate --replace "$ZONE" "$PUBLIC_HOSTNAME $TTL A $PUBLIC_IPV4"

  10. Sesuaikan onfigurasi file ~/.aws/credentials untuk route53 profile yang sudah dibuat sebelumnya
    nano .aws/credentials
    
    [default]
    aws_access_key_id = EC2 user Key Id
    aws_secret_access_key = EC2 user Secret Key
    
    [route53user]
    aws_access_key_id = Route53user Key Id
    aws_secret_access_key = Route53user secret key
    

  11. Sesuaikan konfigurasi zone pada file ~/.aws/config
    nano ./aws/config
    
    [default]
    region=your region
    output=json
    

  12. Untuk membuatnya otomatis run saat ec2 server reboot:
    chmod +x /etc/rc.local
    
    
    cat /etc/rc.local
    
    # # THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
    #
    # It is highly advisable to create own systemd services or udev rules
    # to run scripts during boot instead of using this file.
    #
    # In contrast to previous versions due to parallel execution during boot
    # this script will NOT be run after all other services.
    #
    # Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
    # that this script will be executed during boot.
    
    touch /var/lock/subsys/local
    # Add this line before exit 0
    
    /usr/sbin/update-route53-dns
  13.  Instalasi telah selesai, untuk mencoba nya dapan menjalankan script:
    /usr/sbin/update-route53-dns
Sekian Tutorial kali ini semoga bermanfaat :)