Friday, September 18, 2015

Iseng-iseng mantau GO-JEK di Twitter

Beberapa bulan terakhir ini di Jakarta lagi booming GO-JEK, biasanya kalo lagi seperti ini pasti di medsos juga lagi rame. Iseng-iseng mantauin Twitter searching pake kata kunci gojek dapetnya begini :
Hasil Pencarian di Twitter

Setelah pulang dari acara Hackathon Merdeka, jadi kepikiran untuk mantau gojek di Twitter pake ELK. Dannn... akhirnya buat juga deh. Berhubung masih punya free account di Google Cloud Platform (GCP),  bikin disana aja deh hehehe... Ini langkah-langkahnya :

  1. Buat 3 VM dengan OS Ubuntu 14.04 LTS dengan tipe g1-small (1 vCPU, 1.7 GB Memory)
  2. Download Elasticsearch & Logstash & Kibana di VM yang berbeda
  3. Install Elasticsearch & Logstash dengan perintah ubuntu sudo dpkg -i DEB_PACKAGE
  4. Untuk Kibana cukup ekstrak saja dari file yang sudah didownload
  5. Buat Twitter Apps di sini
    • Generate Consumer Key (API Key) & Consumer Secret (API Secret)
    • Generate Access Token & Access Token Secret
  6. Konfig Logstash sebagai pengumpul data dari Twitter
    • Buat file /etc/logstash/conf.d/01-twitter-input.conf
    input {
            twitter {
            consumer_key => "CONSUMER_KEY"
                consumer_secret => "CONSUMER_SECRET"
                keywords => "gojek"
                oauth_token => "ACCESS_TOKEN"
                oauth_token_secret => "ACCESS_TOKEN_SECRET"
            }
    }
    
    • Buat file /etc/logstash/conf.d/30-twitter-output.conf
    output {
        elasticsearch {
            protocol => "http"
            action => "index"
            host => "elasticsearch-01"
            index => "twitter-%{+YYYY.MM.dd}"
            workers => 1
        }
        stdout {}
    }
    
  7. Biarkan konfigurasi default dari Elasticsearch dan Kibana
  8. Jalankan Logstash sudo service logstash start
  9. Jalankan Elasticsearch sudo service elasticsearch start
  10. Jalankan Kibana dari folder bin hasil ekstrak ./kibana 

Berikut barbuk yang sudah berjalan :
Log dari Logstash
Sense (Chrome Plugin) untuk mencari data pada Elasticsearch
Tambahkan index yang berawalan 'twitter-*'

Menu Discover untuk menampilkan stream dari Twitter 
yang diambil oleh Logstash dan disimpan di Elasticsearch

Yup, sekarang saya bisa memantau Twitter lewat Kibana, Thanks ELK!

Memilih Full Framework untuk GO.

Beberapa waktu yang lalu saya dan rekan-rekan di berikan sebuah tantangan untuk membuat aplikasi menggunakan Go. Hal yang menjadi tantangan adalah bagaimana membangun aplikasi menggunakan GO yang scalable dan powerfull.

Membangun aplikasi menggunakan GO sangatlah mudah kita bisa menggunakan beberapa framework berikut untuk membuat aplikasi rest api, contohnya:

  1. Gorilla Mux (http://www.gorillatoolkit.org/pkg/mux)
  2. Gin (https://gin-gonic.github.io/gin/)
  3. Atau, Martini (https://github.com/go-martini/martini)
Tapi, ada beberapa feature yang tidak disediakan oleh framework diatas, misalnya: 

  1. Session management
  2. Caching
  3. Logging
  4. Database access
  5. Asynchronous job queue
  6. Development and deployment tools
  7. MVC or other architectural pattern
Untuk mendapatkan beberapa feature diatas saya membutuhkan sebuah full framework yang sudah menginclude feature diatas. Berikut 2 framework yang sekarang sedang saya riset:

  1. Revel
  2. BeeGo

REVEL
Sebuah Web Framework seperti Django dan Rails. Memiliki banyak utility dan Patterns yang bisa digunakan untuk mendukung pembuatan aplikasi menggunakan GO.

Kelebihan.
  1. Memiliki tools revel. (tool yang bisa kita gunakan untuk mengenerate aplikasi go , menjalankan server dan lain-lain)
  2. Logging. (Revel memungkinkan kita untuk membuat log yang dipisahkan ke bebrapa type seperti: error, info, dll)
  3. Interceptors and filters

BEEGO

Sama halnya Web Framework seperti Revel, teteapi memiliki komunitas dan memiliki built-in feature yang lebih baik dari Revel.

Kelebihan.
  1. bee tool
  2. Filter middleware
  3. SQL/ORM support
  4. Swagger.


Keamanan Jaringan - Serangan, Proteksi & Pertahanan

Security breach atau kasus pelanggaran keamanan jaringan yg terjadi baru-baru ini mengingatkan kita terhadap pentingnya isu yg satu ini, terlebih bagi perusahaan atau Enterprise. Kerugian yg dialami oleh korban tidak hanya dapat berdampak pada ketidak-stabilan ekonomi perusahaan, tetapi juga pada publik/konsumen mereka dari segi privasi dan materi.

Berikut beberapa kasus pelanggaran keamanan yg pernah terjadi:
  1. Heartland Payment Systems (2008)
    Dampak yg terjadi: 134 juta kartu kredit bocor ke tangan yg tidak bertanggung jawab akibat spyware yg ditanam di datacenter Heartland.
  2. Stuxnet (2007)
    Dampak yg terjadi: Virus ini ditujukan untuk menghancurkan program nuklir Iran, namun juga ber-efek kepada gangguan servis publik seperti jaringan listrik, persediaan air, dan sistem transportasi.
  3. Sony’s Playstation Network (2011)
    Dampak yg terjadi: 77 juta akun Playstation Network dibajak. Sony dikabarkan merugi hingga jutaan dolar amerika. Sistem tidak beroperasi hingga sebulan lamanya.
Bicara tentang keamanan jaringan atau network security tidak jauh dengan yg namanya Hacker/Cracker. Kriteria seorang hacker biasanya adalah seseorang yg sangat antusias pada apa yg dilakukannya, memiliki keahlian diatas rata-rata, cenderung tidak mudah patah semangat dan akan terus berusaha hingga menemukan apa dicarinya.


Secara garis besar, terdapat beberapa langkah yg dilakukan oleh seorang hacker dalam melakukan serangan, yaitu:
  1. Pengintaiain (Reconnaissance)
  2. Scanning
  3. Pencacahan (Enumeration)
  4. Mendapatkan Akses (Gaining Access)
  5. Mempertahankan Akses (Maintaining Access)
  6. Menghapus Jejak (Clearing Tracks)
Untuk melakukan semua ini tentunya seorang hacker juga harus mempunyai keahlian yg mumpuni yg tersebar dibeberapa disiplin ilmu antara lain:
  • Sistem Operasi
  • Jaringan dan Protokol Jaringan
  • Pemrograman
  • Perangkat Keras
  • Kreatifitas dan Kesabaran
  • Rekayasa Sosial (Social Engineering)

Tipe serangan


Berdasarkan lokasi terjadinya, tipe serangan dapat dibedakan menjadi yaitu Internal dan Eksternal. Ancaman internal terjadi apabila ada orang dari dalam jaringan anda yg bertanggung jawab atas terjadinya serangan. Penelitian menunjukkan bahwa 60% dari perusahan-perusahaan yg mengalami kebocoran kemanan terjadi karena ancaman dari dalam. Ancaman eksternal terjadi apabila ada orang dari luar jaringan anda yg melakukan serangan. Jika perusahaan anda memakai alat untuk mendeteksi intrusi (Intrusion Detection System), yg dapat mendeteksi serangan saat terjadi, anda akan kaget betapa banyaknya aktifitas (probes) dan serangan terhadap jaringan anda setiap harinya.

Teknik-teknik Serangan


Eavesdropping


Eavesdropping adalah aktifitas mendengarkan (listening) terhadap konversasi yg dilakukan pihak lain dengan tidak diketahui oleh pihak tersebut. Umumnya dapat terjadi pada media Telepon, Email, Instant Messaging, dan media komunikasi lainnya.

Identity Spoofing



Si penyerang menyamar seakan-akan adalah korban dengan memalsukan data yg dengan demikian memiliki hak akses yg legal terhadap sistem.


Password-based attack

Memecahkan password dengan bantuan program spesial dengan teknik brute-force.


Denial of Service

Tindakan untuk memblokir akses user ke sistem dengan meng-konsumsi trafik jaringan, cpu, disk space. Biasanya tidak dilakukan secara langsung tetapi oleh komputer-komputer yg telah terinfeksi yg biasa disebut bot. Bot-bot ini akan menyerang sistem secara bersamaan sehingga sistem akan kehabisan resource.

Zero day Exploit

Mengambil keuntungan dari kelemahan perangkat lunak, sehingga dapat memanipulasi sistem seusai keinginan si penyerang.

Social Engineering

Dalam konteks kemanan jaringan, mengacu kepada tindakan yg memanipulsai psikologis seseorang sehingga melakukan aksi yg berujung kepada pemberian informasi rahasia (confidential). Beberapa teknik yg dipakai antara lain Baiting, Phising, Pretexting, Quit pro quo, Spam, Tailgating.

Pertahanan



Tidak ada sistem yg benar-benar 100% aman. Yang dapat kita lakukan adalah meminimalisir serangan dengan melakukan audit yg sistematis, melakukan pembaharuan sistem (updates & security patch), memonitor sistem secara kesuluruhan terhadap segala macam kemungkinan kebocoran, memasang firewall yg disesuaikan dengan keperluan sistem sehingga lebih optimal dan pembinaan terhadap karyawan sehingga timbul kesadaran dan kewaspadaan.


Dan juga perlu disadari bahwa tidak memungkinkan untuk mencapai keamanan dan kegunaan/kenyamanan dalam memakai sistem (usability) secara maksimum bagi kedua-duanya. Inilah mengapa mengamankan sebuah sistem adalah pekerjaan yg tidak akan pernah ada ujungnya, karena sistem, orang yg ada didalamnya dan lingkungan sekitarnya selalu mengalami perubahan oleh karena itu meningkat pula resiko keamanan sistem/jaringan tersebut.

ZK Framework - Introduction Part 2

MVC

Di era saat ini hampir semua aplikasi menggunakan model MVC, dan ZK sudah siap digunakan untuk sebuah aplikasi MVC. ZK memiliki lingkup pada bagian View dan Controller dalam MVC. Untuk bagian view ini adalah berupa file zul, sedangkan untuk bagian controller merupakan sebuah java class.

Pada kali ini akan di bahas beberapa contoh penggunaan komponen dalam zul dan inplementasi zk pada bagian class controller nya.

Pertama-tama buat sebuah class java dengan nama IndexController.

Dan buat juga sebuah file zul bernama index.zul

Komponen pada file zul

edit isi file zul menjadi seperti berikut:
<?page title="Hello world" contentType="text/html;charset=UTF-8"?>
<zk>
    <window border="normal" apply="com.coba.zkoss.controller.IndexController">
        <grid>
            <columns>
                <column width="100px" align="right"/>
                <column />
            </columns>
            <rows>
                <row>
                    <label id="labelId" value="Input :" />
                    <textbox id="textboxId" />
                </row>
                <row>
                    <cell />
                    <button id="btnSubmit" label="Submit" />
                </row>
            </rows>
        </grid>
    </window>
</zk>

Dalam code diatas bisa dilihat ada sebuah komponen window yang terdapat 3 komponen yaitu Label, Textbox, dan Button yang berada didalam sebuah Grid.
Pada komponen label dan textbox terdapat properti id. Properti id ini penting agar nantinya komponen ini bisa menjadi programmatic. Id ini tidak boleh ada yang sama (duplicate) dalam suatu file zul.
Pada komponen window terdapat sebuah property apply, ini bertujuan untuk mengimplement sebuah kelas controller. Dengan demikian perilaku dan action yang terjadi dalam halaman zul ini bisa diatur dalam kelas controller tersebut.

Kelas Controller

Buka file IndexController.java yang tadi sudah dibuat, dan edit isinya menjadi seperti berikut:

package com.coba.zkoss.controller;

import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Button;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;


public class IndexController extends SelectorComposer<Window>{
    
    @Wire
    private Label labelId;
    @Wire
    private Textbox textboxId;
    @Wire
    private Button btnSubmit;
    
    @Override
    public void doAfterCompose(Window comp) throws Exception {
        // TODO Auto-generated method stub
        super.doAfterCompose(comp);
        
        labelId.setValue("Username :");
        textboxId.setValue("your name");
        
    }
    
    @Listen("onClick = button#btnSubmit")
    public void onSubmit(){
        String message = "Username "+ textboxId.getValue() +" Successfully Saved";
        Messagebox.show(message, "Title Messagebox", Messagebox.OK, Messagebox.INFORMATION);
    }
}

Kelas ini perlu meng-extends SelectorComposer untuk bisa melakukan Wire terhadap komponen yang berada pada file zul. SelectorComposer merupakan salah satu Composer yang tersedia dalam ZK.

Annotation @Wire merupakan anotasi yang digunakan untuk mem-binding sebuah komponen UI di zul. Bisa dilihat di atas ada 3 buah komponen yang di wire dengan nama yang sama dengan id masing-masing type komponen pada file zul.

Override doAfterCompose merupakan method yang di panggil oleh engine ZK setelah komponen pada file zul selesai di generate. Jadi kita bisa menambahkan logic untuk memanipulasi komponen yang berada pada file zul sebelum user bisa melakukan input.

Annotation @Listen merupakan anotasi untuk menghandle action yang terjadi pada UI zul. pada contoh di atas kita gunakan untuk menghandle action onClick pada komponen button dengan id btnSubmit. Apabila button tersebut di klik maka akan muncul popup (Messagebox) yang berisi value dari inputan user pada textbox.


Berikut penampakan UI zul pada browser:

dan kita tesdengan menginput sebuah nama "Supardi" kedalam textbox, lalu klik button Submit.
Maka akan muncul popup seperti berikut:


Didalam method onSubmit kita bisa menambahkan code yang meneruskan data dari UI ke database. Jadi tinggal ditambahkan pemanggilan framework atau coding yang mengatur bagian persistance atau Model dalam sebuah MVC.

Demikianlah Introduce ZK Framework kali ini,
Sekian dan terima kasih...

bermain-main dengan java reflection

dalam posting ini saya hanya ingin mencoba java.lang.reflect.* dalam men-set property dari sebuah object. ada 2 cara yang saya coba yaitu dengan langsung men-set field-nya dan satu lagi yaitu dengan meng-invoke method setter-nya.

saya punya 2 class:

Model1.java:
 public class Model1 {  
        
      private String code;  
      private BigDecimal amount;  
        
      public String getCode() {  
           return code;  
      }  
      public void setCode(String code) {  
           this.code = code;  
      }  
      public BigDecimal getAmount() {  
           return amount;  
      }  
      public void setAmount(BigDecimal amount) {  
           this.amount = amount;  
      }  
        

dan Model2.java, yang meng-extend Model1.java
 public class Model2 extends Model1 {  
        
      private String name;  
   
      public String getName() {  
           return name;  
      }  
   
      public void setName(String name) {  
           this.name = name;  
      }  
   
      @Override  
      public String toString() {  
           return "Model2 [name=" + name + ", getCode()=" + getCode()  
                     + ", getAmount()=" + getAmount() + "]";  
      }  
        
 }  

dan saya punya class TestReflection.java yang saya gunakan untuk test-nya:
 public class TestReflection {  
        
      public static void main(String[] args) {  
           Model2 model2_1 = new Model2();  
             
           String[] fieldNames = {"code", "amount", "name"};  
             
           Date start = new Date();  
           for(String fieldName : fieldNames){  
                  
                Field field = getField(model2_1.getClass(), fieldName);  
                  
                //set directly to the field  
                if(field != null){  
                     field.setAccessible(true);  
                     if(field.getType().getName().equals("java.lang.String")){  
                          setField(field, model2_1, "asdf");  
                     }else if(field.getType().getName().equals("java.math.BigDecimal")){  
                          setField(field, model2_1, BigDecimal.valueOf(1234));  
                     }  
                }  
                  
                //set via setter method invocation  
                Method methodSet = getMethod(model2_1.getClass(), getMethodName("set", fieldName), field.getType());  
                if(methodSet != null){  
                     methodSet.setAccessible(true);  
                     if(fieldName.equals("amount")){  
                          invokeSetterMethod(methodSet, model2_1, BigDecimal.valueOf(1234));  
                     }else{  
                          invokeSetterMethod(methodSet, model2_1, "fdsa");  
                     }  
                }  
                  
           }  
             
           System.out.println("\n");  
           System.out.println(new Date().getTime() - start.getTime());  
             
           System.out.println("\n");  
           System.out.println("2_1 -> " + model2_1);  
             
      }  
        
      private static Field getField(Class clz, String fieldName){  
           Field field = null;  
             
           try {  
                field = clz.getDeclaredField(fieldName);  
                System.out.println("field " + fieldName + " in " + clz + " found");  
           } catch (NoSuchFieldException e) {  
                System.out.println("no field " + fieldName + " in " + clz);  
                if(clz.getSuperclass() != null){  
                     field = getField(clz.getSuperclass(), fieldName);  
                }  
           } catch (SecurityException e) {  
                e.printStackTrace();  
           }  
             
           return field;  
      }  
        
      private static void setField(Field field, Object object, Object value){  
           if(field != null){  
                try {  
                     field.set(object, value);  
                } catch (IllegalArgumentException e) {  
                     e.printStackTrace();  
                } catch (IllegalAccessException e) {  
                     e.printStackTrace();  
                }  
           }  
      }  
        
      private static String getMethodName(String setOrGet, String fieldName){  
           String methodName = setOrGet + StringUtils.capitalize(fieldName);  
           return methodName;  
      }  
        
      private static Method getMethod(Class clz, String methodName, Class argumentClass){  
           Method method = null;  
           try {  
                argumentClass = argumentClass == null ? (Class) null : argumentClass;  
                method = clz.getDeclaredMethod(methodName, argumentClass == null ? (Class) null : argumentClass);  
                System.out.println("method " + methodName + "(" + (argumentClass == null ? "" : argumentClass.getCanonicalName()) + ") in " + clz + " found");  
           } catch (NoSuchMethodException e) {  
                System.out.println("no method " + methodName + "(" + (argumentClass == null ? "" : argumentClass.getCanonicalName()) + ") in " + clz);  
                if(clz.getSuperclass() != null){  
                     method = getMethod(clz.getSuperclass(), methodName, argumentClass);  
                }  
           } catch (SecurityException e) {  
                e.printStackTrace();  
           }  
           return method;  
      }  
        
      private static void invokeSetterMethod(Method method, Object object, Object argument){  
           if(method != null){  
                try {  
                     method.invoke(object, argument);  
                } catch (IllegalAccessException e) {  
                     e.printStackTrace();  
                } catch (IllegalArgumentException e) {  
                     e.printStackTrace();  
                } catch (InvocationTargetException e) {  
                     e.printStackTrace();  
                }  
           }  
      }  
        
 }  

di main method class di atas, ada 2 bagian yang men-set value utk field, yaitu:
 //set directly to the field  
 if(field != null){  
      field.setAccessible(true);  
      if(field.getType().getName().equals("java.lang.String")){  
           setField(field, model2_1, "asdf");  
      }else if(field.getType().getName().equals("java.math.BigDecimal")){  
           setField(field, model2_1, BigDecimal.valueOf(1234));  
      }  
 }  
yang men-set dengan langsung men-set field-nya, dan
 //set via setter method invocation  
 Method methodSet = getMethod(model2_1.getClass(), getMethodName("set", fieldName), field.getType());  
 if(methodSet != null){  
      methodSet.setAccessible(true);  
      if(fieldName.equals("amount")){  
           invokeSetterMethod(methodSet, model2_1, BigDecimal.valueOf(1234));  
      }else{  
           invokeSetterMethod(methodSet, model2_1, "fdsa");  
      }  
 }  
yang men-set melalui pemanggilan method setter-nya.

keduanya berhasil, bisa dicoba sendiri. saya mencoba mencari perbedaan dari kedua cara di atas, salah satunya adalah dengan membandingkan waktu prosesnya. saya men-comment salah satu cara dan mencatat durasi prosesnya, masing-masing saya akan ambil datanya sebanyak 10 kali.

dan inilah hasilnya


terlihat selisihnya sangat jauh.

saya coba untuk mencatat durasi masing-masing getField dan getMethod:
 Date start = new Date();  
 Field field = getField(model2_1.getClass(), fieldName);  
 System.out.println("getField duration: " + (new Date().getTime() - start.getTime()));  
   
 ...  
   
 start = new Date();  
 Method methodSet = getMethod(model2_1.getClass(), getMethodName("set", fieldName), field.getType());  
 System.out.println("getMethod duration: " + (new Date().getTime() - start.getTime()));  

kurang lebih seperti inilah hasil print-nya:
 no field code in class org.mazb.usemefortesting.reflection.Model2  
 field code in class org.mazb.usemefortesting.reflection.Model1 found  
 getField duration: 2  
 no method setCode(java.lang.String) in class org.mazb.usemefortesting.reflection.Model2  
 method setCode(java.lang.String) in class org.mazb.usemefortesting.reflection.Model1 found  
 getMethod duration: 11  
   
 no field amount in class org.mazb.usemefortesting.reflection.Model2  
 field amount in class org.mazb.usemefortesting.reflection.Model1 found  
 getField duration: 0  
 no method setAmount(java.math.BigDecimal) in class org.mazb.usemefortesting.reflection.Model2  
 method setAmount(java.math.BigDecimal) in class org.mazb.usemefortesting.reflection.Model1 found  
 getMethod duration: 0  
   
 field name in class org.mazb.usemefortesting.reflection.Model2 found  
 getField duration: 0  
 method setName(java.lang.String) in class org.mazb.usemefortesting.reflection.Model2 found  
 getMethod duration: 0  

dari beberapa kali percobaan, saya mendapatkan invokasi getMethod pertama selalu memakan waktu lama, tapi berikut-berikutnya tidak. hal ini juga terjadi pada durasi getField, namun nilainya tidak jauh selisihnya, antara 2 dan 0.



awalnya saya menduga ini terkait dengan field/method-nya, tapi walaupun urutannya saya ubah-ubah, tetap yang pertama akan memakan waktu jauh lebih lama. begitu pula jika field 'name' (field dimiliki oleh Model2, tidak perlu mengambil dari Model1) yang pertama diproses, dia tetap memakan waktu paling lama, dengan kisaran nilai yang sama.

ini menarik. saya belum bisa menjelaskan kenapa ini bisa terjadi, apakah ada mekanisme tertentu dari jvm terkait hal ini atau mungkin ada alasan lain.

sampai saat ini yang bisa saya simpulkan dari percobaan di atas adalah, jika ingin memanfaatkan java reflection, maka set field secara langsung ke field-nya akan menghasilkan waktu proses yang jauh lebih cepat daripada dengan invokasi method setter.


Android - Adaptive Color

Dengan rilisnya Android Lollipop, beberapa support libraries pun telah release. Salah satu library-nya adalah Palette API. Palette membantu kita untuk mempermudah mengekstrak warna yang menonjol dari gambar bitmap.

Google telah mempermudah kita untuk melakukan adaptive theming di Android berdasarkan warna dalam gambar dan sangat mudah untuk di implementasikan. Yang kita butuhkan adalah gambar bitmap dan Palette API. Dengan ini Android aplikasi kita bisa memiliki banyak warna sesuai dengan pedoman Material Design. Contoh seperti gambar dibawah:



Tambahkan dependecy di gradle anda:
compile 'com.android.support:palette-v7:21.0.0'
Untuk men-generate warna menggunakan Palette hanya berlaku untuk Bitmap. Dan dapat di generate secara synchronous dan asynchronous.
 // Synchronous
 Palette p = Palette.from(bitmap).generate();
 // Asynchronous
 Palette.from(bitmap).generate(new PaletteAsyncListener() {
     public void onGenerated(Palette p) {
         // Use generated instance
     }
 });
 


Secara default Palette object(Swatch) akan mencari 16 warna dari sebuah gambar dan ada 6 method untuk mendapatkan warna, yaitu:
Dan setiap Swatch memiliki method:
Catatan:
The different text colors roughly match up to the material design standard styles of the same name. The title text color will be more translucent as the text is larger and thus requires less color contrast. The body text color will be more opaque as text is smaller and thus requires more contrast from color. (source https://chris.banes.me/2014/10/20/palette-v21)

Oke, saya akan memberikan contoh penggunaannya:

1. Buat Activity dan desain layout seperti dibawah dan siapkan dua bawah gambar untuk kita dapatkan nilai warnanya.
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_marginBottom="10dp"
            android:orientation="vertical"
            android:background="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="@dimen/abc_action_bar_default_height_material"
                android:title="@string/app_name"
                />
    
            <ImageView
                android:id="@+id/image"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/gambar1"
                android:scaleType="fitXY"
                />
    
        </LinearLayout>
    
        <LinearLayout
            android:orientation="vertical"
            android:background="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            >
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar2"
                android:layout_width="match_parent"
                android:layout_height="@dimen/abc_action_bar_default_height_material"
                android:title="@string/app_name"
                />
    
            <ImageView
                android:id="@+id/image2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/gambar2"
                android:scaleType="fitXY"
                />
    
        </LinearLayout>
    </LinearLayout>
    
    

2. Buka kelas Activity. Disini class saya bernama PaletteActivity


3. Hasilnya seperti ini:

Menarik bukan ? mau sesuatu yang lebih keren ? nantikan blog saya berikutnya. Sekian dan terima kasih.


Sumber:
https://chris.banes.me/2014/10/20/palette-v21/
http://blog.brightinventions.pl/playing-with-material-design-toolbar-palette/
http://code.tutsplus.com/tutorials/coloring-android-apps-with-palette--cms-24096

Log Handler Pada Oracle BPM 11g

Beberapa waktu yang lalu saya mendapatkan kendala ketika mengerjakan Oracle BPM 11g. Dengan minim nya informasi log payload menyebabkan saya kesulitan mengecek input maupun output apakah sudah sesuai dengan yang saya inginkan. Setelah beberapa saat googling, saya menemukan hal menarik yaitu menggunakan log handler untuk mengatasi permasalahan yang saya alami. 

Caranya cukup mudah. Kalian bisa buat bpm process apapun bentuknya, kalau saya menggunakan Asynchronous Process dan di dalam nya hanya tersedia script task saja.


Pada bagian Start Message, saya mendefine 1 string name


Kemudian pada data asosiation nya saya memaping name tadi ke dataObjectName. Setelah selesai klik log handler.


Klik tanda tambah kemudian isi seperti berikut.




Pada bagian ini saya melakukan logging pada sebelum output association dan after association.
Jika sudah kalian bisa deploy hasilnya. Kemudian buka Enterprise Manager dan kalian pilih BPM Process yang sudah kalian buat. Klik Setting dan pilih Composite Audit level nya : Development.
Dan juga pilih Payload Validation nya Enable.




Jika sudah kalian bisa test webservice nya. Jika sudah, kalian jalan kan flow trace nya. Pada bagian Start Message yang tadi kalian akan melihat logging data yang kalian sudah buat diawal.





Sekian dahulu pada kesempatan kali ini. Semoga membantu !




menguji atomisitas redis - INCR command

post ini ditujukan untuk menguji sifat atomisitas command INCR redis.

kebutuhannya adalah, misalnya di aplikasi saya membutuhkan sebuah generator kode unik. cara termudah untuk membuat kode unik adalah dengan melakukan increment yang dimulai dari suatu angka, dan seterusnya. nantinya ini bisa dikombinasikan dengan character lain.

jika kita melihat dari 1 jvm, hal ini mudah saja, misalnya kita bisa buat sebuah variable static yang menampung angka tertentu dan menyiapkan sebuah method synchronized bagi thread yang hendak mengambil value tersebut (dan meng-increment-nya).

kira-kira seperti ini gambarannya


namun hal ini akan menjadi masalah saat aplikasi kita semakin besar dan membutuhkan scaling ke lebih dari 1 jvm. karena static variable dan synchronized hanya berlaku di 1 jvm saja. anggaplah kita punya 2 jvm, jika menggunakan static variable dan synchronized method, maka masing-masing jvm akhirnya akan menyimpan angka incrementnya sendiri-sendiri.



sehingga jika digabungkan, misalnya kita hendak menyimpan value itu dalam sebuah database yang sama dimana field tersebut dibuat unique, besar kemungkinannya kita akan kena ConstraintViolationException.

lalu bagaimana solusinya?

idenya adalah kedua jvm tersebut harus mengakses memory yang sama. sebuah cache bisa kita manfaatkan, mari kita coba dengan redis. kita letakkan instance redis di sebuah tempat, bisa di vm yang sama atau berbeda, untuk pengujian ini semuanya berada di 1 vm yang sama. tetapi untuk production jelas sebaiknya masing-masing memiliki vm-nya sendiri-sendiri.

kira-kira seperti ini skema umumnya


dalam percobaan ini, kita akan menggunakan command INCR milik redis,
"The counter pattern is the most obvious thing you can do with Redis atomic increment operations. The idea is simply send an INCR command to Redis every time an operation occurs." -http://redis.io/commands/INCR

command ini bersifat atomic, sehingga aman untuk proses multithread.

skema ini yang akan saya coba


saya akan aktifkan 1 jvm dulu, berkomunikasi dengan redis, memanfaatkan command INCR untuk mendapatkan sebuah value, dan value tersebut akan saya simpan di database. penyimpanan di database ini hanya bertujuan untuk mempermudah pengecekan, nantinya saya akan cek dengan menggunakan query

 select * from (  
     select value, count(1) n from redis_result group by value  
 ) a where a.n>1;  

jika INCR berjalan dengan benar, maka query tersebut akan menghasilkan result kosong.

saya menggunakan springboot 1.2.5 dengan library spring data, orm hibernate, database connection pool menggunakan apache commons-dbcp 1.4, redis connection pool dengan jedis 2.5.2.

skenarionya, saya akan menyiapkan 1 controller untuk memudahkan akses (tadinya saya mau menggunakan junit tapi junit tidak memungkinkan untuk test multithread). controller tersebut akan memanggil suatu class service yang akan mengeksekusi 5 thread. di dalam masing-masing thread tersebut saya akan melakukan looping sebanyak 2000 iterasi yang akan memanggil command INCR ke redis dan menyimpan value-nya ke database (table redis_result).

dengan skenario ini, maka akan ada sebanyak 5*2000 record yang tersimpan di table.

berikut ini configurasi redis connection pool nya:
 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">  
     <property name="testOnBorrow" value="true"/>  
     <property name="testOnReturn" value="true"/>  
     <property name="testWhileIdle" value="true"/>  
     <property name="numTestsPerEvictionRun" value="10"/>  
     <property name="maxTotal" value="5000" />  
     <property name="minIdle" value="100" />  
   </bean>  
   <!-- for pooling the publisher -->  
   <bean id="redisConnectionPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy">  
     <constructor-arg index="0" ref="jedisPoolConfig"/>  
     <constructor-arg index="1" value="localhost" type="java.lang.String"/>  
     <constructor-arg index="2" value="6379" type="int"/>  
   </bean>  

configurasi db connection pool:
 <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">  
     <property name="driverClassName" value="${database.driverClassName}"/>  
     <property name="url" value="${database.url}"/>  
     <property name="username" value="${database.username}"/>  
     <property name="password" value="${database.password}"/>  
     <<property name="validationQuery" value="SELECT version();"/>  
     <property name="initialSize" value="100"/>  
     <property name="maxActive" value="200"/>  
     <property name="maxIdle" value="100">  
   </bean>  

RedisUtil.java, yaitu class yang berfungsi sebagai redis client
 @Component  
 public class RedisUtil {  

   private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);  

   @Autowired  
   @Qualifier(value = "redisConnectionPool")  
   JedisPool redisConnectionPool;  

   private void releaseJedisConnection(Jedis jedis){  
     if(null != jedis) {  
       LOGGER.debug("Return redis connection to pool");  
       redisConnectionPool.returnResource(jedis);  
     }  
   }  

   /**  
    * INCR key  
    * @param key  
    * @return  
    */  
   public Long increment(String key){  
        Long result = null;  
        Jedis jedis = null;  
     try {  
          jedis = redisConnectionPool.getResource();  
       result = jedis.incr(key);  
     } catch (JedisConnectionException jce) {  
          LOGGER.error("Failed add set to {} :: {}", key, jce.getMessage());  
     } finally {  
          releaseJedisConnection(jedis);  
     }  
     return result;  
   }  

   /**  
    * SET key  
    * @param key  
    * @return  
    */  
   public void set(String key, String value){  
        Jedis jedis = null;  
     try {  
          jedis = redisConnectionPool.getResource();  
       jedis.set(key, value);  
     } catch (JedisConnectionException jce) {  
          LOGGER.error("Failed add set to {} :: {}", key, jce.getMessage());  
     } finally {  
          releaseJedisConnection(jedis);  
     }  
   }  
 }  

RedisTask.java, yaitu class yang meng-increment key di redis dan menyimpan di database (dalam skema di atas, ini sama dengan thread01, thread02, dst..)
 public class RedisTask implements Runnable {  
        
      RedisUtil redisUtil;  
      RedisResultRepository redisResultRepository;  
        
      private static final String INCR_KEY = "incrKey";  
        
      public RedisTask(){  
           redisUtil = ApplicationContextHolder.getApplicationContext().getBean(RedisUtil.class);  
           redisResultRepository = (RedisResultRepository) ApplicationContextHolder.getApplicationContext().getBean("redisResultRepository");  
      }  
        
      public String getIncrValue() {  
           String result = null;  
   
           Long val = redisUtil.increment(INCR_KEY);  
           if (val == null || val.intValue() == 0) {  
                redisUtil.set(INCR_KEY, 1 + "");  
                result = getIncrValue();  
           } else {  
                result = val.toString();  
           }  
   
           return result;  
      }  
   
      @Override  
      public void run() {  
           for(int i=0; i<2000; i++){  
                String value = getIncrValue();  
                RedisResult result = new RedisResult(value);  
                redisResultRepository.save(result);  
           }  
      }  
        
 }  

RedisDemoService.java, yaitu class yang akan mengeksekusi 5 instance RedisTask secara concurrent
 @Service  
 public class RedisDemoService {  
        
      private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(5);  
        
      public void redisIncrTest(){  
             
           for(int i=0; i<5; i++){  
                System.out.println("execute redis task " + i);  
                EXECUTOR.execute(new RedisTask());  
           }  
             
      }  
        
 }  

RedisResult.java, yaitu POJO model domainnya
 @Entity  
 public class RedisResult extends BaseEntity {  
        
      private static final long serialVersionUID = -4902968469441816467L;  
        
      @Column(name = "value")  
      private String value;  
        
      public RedisResult(){  
             
      }  
        
      public RedisResult(String value){  
           this.value = value;  
      }  
   
      public String getValue() {  
           return value;  
      }  
   
      public void setValue(String value) {  
           this.value = value;  
      }  
 }  

RedisResultRepository.java, yaitu interface dari springdata yang akan menjadi akses komunikasi ke db
 @Repository  
 public interface RedisResultRepository extends JpaRepository<RedisResult, Long> {  
   
 }  

dan yang terakhir adalah controller-nya untuk kita akses dengan REST, RedisDemoController.java
 @RestController  
 @RequestMapping(value = "/redis")  
 public class RedisDemoController {  
        
      @Autowired  
      private RedisDemoService redisDemoService;  
   
      @RequestMapping(value = "/demo", method = RequestMethod.GET)  
      @ResponseBody  
      public boolean calculate() throws Exception {  
   
           redisDemoService.redisIncrTest();  
   
           return true;  
      }  
        
 }  

jika aplikasi kita nyalakan pada port 8181, kemudian kita bisa akses dia dengan
 curl -XGET http://localhost:8181/redis/demo  

setelah prosesnya selesai, kita count apakah jumlahnya benar

lalu kita cek apakah ada duplikasi value


oke, aman. sejauh ini tidak ada masalah.
lalu kita harus coba dengan menggunakan 2 jvm, saya menggunakan code yang sama tetapi saya nyalakan pada port yang berbeda, aplikasi kedua ini menggunakan port 8182.

kita coba secara bersama-sama
 curl -XGET http://localhost:8181/redis/demo  
 curl -XGET http://localhost:8182/redis/demo  

kemudian kita cek apakah jumlah recordnya benar


apakah ada duplikasi


woohoo, hasilnya baik-baik saja.

jadi kesimpulannya adalah command INCR redis dapat digunakan untuk kasus seperti di atas. untuk lebih meyakinkan diri mungkin perlu dilakukan lagi dengan 10 atau lebih jvm, tentunya jika memiliki environment yang sesuai.

thanks.

RESTFul web service dengan RESTEasy

Apa yang dibutuhkan untuk membuat API web service berbasis Restful?
Jika kita menggunakan java banyak sekali framework yang bisa digunakan untuk membuat Restful dari web application. Contohnya : Apache CFX, JAX-RS, Jersey, Spring MVC.
Yang paling populer menurut saya adalah Spring MVC. Karena  Spring Framework sudah cukup lengkap. Sudah menyediakan banyak fitur, seperti dependency injection, ORM support, MVC dan lain lain.
Tapi kalau kita hanya ingin membuat webservice API yang skalanya kecil. Menurut saya agak cukup rumit karena library dependency yang cukup banyak apalagi harus configurasi juga di ApplicationContext xml.
Ada sebuah library java yang biasa digunakan untuk membangun web application yang bisa mengekspose RestFull webservice API.
Kita akan mencoba Menggunakan RESTEasy. Library ini termasuk dalam JBoss project. Aplikasi kita tidak harus dijalankan diatas JBoss App server, bisa dijalankan di app server yang lain seperti (tomcat, jetty, dan lainnya). Sudah memenuhi standart spesifikasi JAX-RS.
Dokumentasinya ada di sini : https://jax-rs-spec.java.net/nonav/2.0-rev-a/apidocs/index.html
Intinya JAX-RS membantu kita untuk melakukan mapping java class (POJO) menjadi web resource
JAX-RS memiliki beberapa standar annotasi seperti berikut ini :
  • @Path specifies the relative path for a resource class or method.
  • @GET, @PUT, @POST, @DELETE and @HEAD specify the HTTP request type of a resource.
  • @Produces specifies the response Internet media type
  • @Consumes specifies the accepted request Internet media types.
Secara garis besar kita hanya membuat class java yang diberikan anotasi jax-rs dan didaftarkan di web.xml

Tambahkan maven dependency
 <dependency>  
       <groupId>org.jboss.resteasy</groupId>  
       <artifactId>resteasy-jaxrs</artifactId>  
       <version>3.0.4.Final</version>  
     </dependency>  
     <dependency>  
       <groupId>org.jboss.resteasy</groupId>  
       <artifactId>resteasy-jackson-provider</artifactId>  
       <version>3.0.4.Final</version>  
     </dependency>  

Sebagai contoh buat class pojo yang akan kita ekspos sebagai JSON di api kita
 public class Employee extends Base {  
   private String name;  
   private String email;  
   private String phone;  
   private String address;  
   public Employee() { }  
   public Employee(Integer id, String name, String email, String phone, String address) {  
     this.id = id;  
     this.name = name;  
     this.email = email;  
     this.phone = phone;  
     this.address = address;  
   }  
   public String getName() {  
     return name;  
   }  
   public void setName(String name) {  
     this.name = name;  
   }  
   public String getEmail() {  
     return email;  
   }  
   public void setEmail(String email) {  
     this.email = email;  
   }  
   public String getPhone() {  
     return phone;  
   }  
   public void setPhone(String phone) {  
     this.phone = phone;  
   }  
   public String getAddress() {  
     return address;  
   }  
   public void setAddress(String address) {  
     this.address = address;  
   }  
 }  

Buat class service employee yang bertugas untuk mengekpose endpoint yang kita perlukan. Misalnya kita akan membuat fungsi add, find, delete employee.
 import javax.ws.rs.*;  
 import javax.ws.rs.core.Response;  
 import java.util.ArrayList;  
 import java.util.List;  
 import java.util.logging.Logger;  
 @Path("/person")  
 public class EmployeeService {  
   private static final Logger LOGGER = Logger.getLogger(EmployeeService.class.getSimpleName());  
   private List<Employee> listEmployee = new ArrayList<Employee>();  
   public EmployeeService(){  
     listEmployee.add(new Employee(1, "budi", "budi@gmail.com", "081901444", "jakarta"));  
   }  
   @Path("/")  
   @Consumes("application/json")  
   @Produces("application/json")  
   @PUT  
   public Response addEmployee(Employee employee){  
     listEmployee.add(employee);  
     return Response.status(200).entity("new employee id "+employee.getId()).build();  
   }  
   @Path("/")  
   @Produces("application/json")  
   @GET  
   public Response findAllEmployee(){  
     return Response.status(200).entity(listEmployee).build();  
   }  
   @Path("/{id}")  
   @Produces("application/json")  
   @GET  
   public Response findById(@PathParam("id") Integer id){  
     Employee employee = listEmployee.get(id);  
     if(employee != null) return Response.status(200).entity(employee).build();  
     return Response.status(Response.Status.NOT_FOUND).build();  
   }  
   @Path("/{id}")  
   @Produces("application/json")  
   @DELETE  
   public Response DeleteById(@PathParam("id") int id){  
     Employee result = listEmployee.remove(id);  
     if(result != null) return Response.status(200).build();  
     return Response.status(Response.Status.NOT_FOUND).build();  
   }  
 }  

Register class service employes tadi ke dalam class jax-rs application (misalnya kita beri nama RestApplication).
 import javax.ws.rs.core.Application;  
 import java.util.HashSet;  
 import java.util.Set;  
 
 public class RestApplication extends Application {  
   private Set<Object> singletons = new HashSet<Object>();  
   public RestApplication() {  
     singletons.add(new EmployeeService());  
   }  
   @Override  
   public Set<Object> getSingletons() {  
     return singletons;  
   }  
 }  

Daftar class application tadi ke web.xml
 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">  
   <!-- restEasy servlet config -->  
   <servlet-mapping>  
     <servlet-name>resteasy-servlet</servlet-name>  
     <url-pattern>/rest/*</url-pattern>  
   </servlet-mapping>  
   <!-- this should be the same URL pattern as the servlet-mapping property -->  
   <context-param>  
     <param-name>resteasy.servlet.mapping.prefix</param-name>  
     <param-value>/rest</param-value>  
   </context-param>  
   <servlet>  
     <servlet-name>resteasy-servlet</servlet-name>  
     <servlet-class>  
       org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher  
     </servlet-class>  
     <init-param>  
       <param-name>javax.ws.rs.Application</param-name>  
       <param-value>com.nostratech.gcm.notification.rest.RestApplication</param-value>  
     </init-param>  
   </servlet>  
   <session-config>  
     <session-timeout>  
       30  
     </session-timeout>  
   </session-config>  
 </web-app>  

Kita run web application kita (bisa dideploy diatas application server).

- GET /person/0
 {  
   "id": 1,  
   "version": null,  
   "name": "budi",  
   "email": "budi@gmail.com",  
   "phone": "081901444",  
   "address": "jakarta"  
 }  

- PUT /person/  (application/json)
 {  
   "id": 2,  
   "name": "andri",  
   "email": "andri@gmail.com",  
   "phone": "08190166",  
   "address": "bandung"  
 }  

- GET /person/

Referensi :
http://resteasy.jboss.org/ dan http://resteasy.jboss.org/docs
jax-rs spesifications : https://jax-rs-spec.java.net/nonav/2.0-rev-a/apidocs/index.html
source code (web app project yang menggunakan RestEasy) : https://bitbucket.org/andri_khrisharyadi/sample-gcm-sever

Terima kasih dan selamat belajar dan mencoba :)