Tuesday, December 15, 2015

Aplikasi OSGi berbasis Web - Part 2

Seperti janji saya sebelumnya, pada kesempatan kali ini saya kan menjelaskan cara menggunakan module OSGi pada aplikasi WAB yg telah kita buat sebelumnya.
Seperti aplikasi OSGi pada umumnya kita dapat me-registrasi module kita melalui BundleActivator. Tetapi sebelumnya mari kita membuat module sederhana. Misal, untuk menhitung zakat fitrah. Seperti yg kita ketahui, rumus perhitungan Zakat Fitrah adalah 3.5 x harga beras dipasaran perliter, dimana merupakan variable yg dapat berubah-ubah.
Let say kita mempunyai class utama bernama ZakatFitrahCalculator, dan class ini membutuhkan class lain untuk mengetahui harga beras di pasaran, mari kita namakan class ini DecemberRiceExchange. Class ini mengimplement interface RiceExchange sehingga kita dapat mengganti implementasinya.
Sementara class ZakatFitrahCalculator meng-koordinir semuanya kurang lebih seperti di bawah:
Agar semua module dapat ber-interaporabilitas antar satu dengan lainnya kita ubah BundleActivator seperti berikut:
Selanjutnya adalah merubah servlet untuk memanggil ZakatFitrahCalculator untuk melakukan kalkulasi.
Sekian tutorial singkat ini, semoga bermanfaat dan terima kasih.

Rapid development bersama Django Rest



Iseng iseng googling baca - baca artikel teknologi macam apa yang digunakan oleh aplikasi terkenal seperti Instagram dan jawabannya adalah Django Framework. Apa itu django ? web framework yang menggunakan python (no python no django) untuk info lebih lanjut bisa baca blog saya yang sebelumnya klik disini.

Apakah cuma Instagram ? kalian bisa cek link dibawah:
https://www.quora.com/What-are-some-well-known-sites-running-on-Django

Untuk story-nya tentang django Instagram
http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances

Oke, langsung aja..
Pada kali ini saya akan membahas membuat aplikasi rest service menggunakan module django-rest-framework. Pertama - tama harus mempunya basic pengetahuan tentang struktur project di django dan melakukan konfigurasi django admin site tutorial kalian bisa baca tutorial-django-administration-site.

Install
pip install djangorestframework

Lanjut ke intinya dan pastikan kalian sudah berhasil konfigurasi django admin site. Lalu buat new file /projectname/appname/serializer.py

serializer.py
from django.contrib.auth.models import User, Group
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')

Buka file /projectname/appname/view.py dan tambahkan kode dibawah:
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from donate.serializers import UserSerializer, GroupSerializer
class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

Register ke /projectname/url.py
from django.conf.urls import url, include
from rest_framework import routers
from projectname.appname import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

Langkah terakhir register ke setting.py
INSTALLED_APPS = (
    ...
    'rest_framework',
)

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
    'PAGE_SIZE': 10
}

Selesai!. Run server

python manage.py runserver
Buka aplikasi dan login menggunakan user admin site:
List API
Testing Api
List User halaman admin

Kesimpulanya django adalah:

Sekian blog dari saya! Semoga bermanfaat

Sumber:
http://www.django-rest-framework.org/

ADF LOV with Sub-Query parameter

Pada ADF biasanya sebuah LOV (List Of Value) berasal dari sebuah VO (View Object).
Apabila sebuah LOV memiliki dependensi parameter dari field lainnya pada UI, maka biasanya query pada VO nya akan memiliki :param.

Misalnya seperti berikut:
select distinct xx.kolom_1, xx.kolom_2
from table_xx xx, (
    select kolom_a, kolom_b
    from table
    where kolom_c = :param1
) yy
where 
xx.kolom_3 = yy.kolom_a
yy.kolom_b = :param2 

pada umumnya untuk menghandle masalah depedensi ini kita akan menggunakan view criteria atau bindParameter.

Cara kerja dari view criteria adalah membungkus query vo dan menambahkan where clause menjadi seperti berikut:

select * from (
    select distinct xx.kolom_1, xx.kolom_2
    from table_xx xx, (
        select kolom_a, kolom_b
        from table
        where kolom_c = :param1
    ) yy
    where 
    xx.kolom_3 = yy.kolom_a
    yy.kolom_b = :param2
    )
where ....
 
dan sebuah viewcriteria membutuhkan query yang memiliki kolom yang akan menjadi filter.
jadi untuk query yang menggunakan distinct akan bermasalah, karena mungkin saja kolom yang akan menjadi filter tersebut mempengaruhi jumah data hasil query

select * from (
    select distinct xx.kolom_1, xx.kolom_2, yy.kolom_b
    from table_xx xx, (
        select kolom_a, kolom_b
        from table
        where kolom_c = :param1
    ) yy
    where 
    xx.kolom_3 = yy.kolom_a
    yy.kolom_b = :param2
    )
where kolom_b = :parameter

Tidak hanya untuk query DISTINCT saja, karena ada beberapa sql lainnya yang tidak bisa dibungkus oleh where clause contohnya seperti START WITH dan CONNECT BY 

Sedangkan bind parameter untuk parameter pada where clause itu sejauh yang saya coba tidak bisa di implement pada sebuah LOV dengan VO yang memiliki query seperti diatas.

Lalu apa bagaimana caranya?
VO di ADF kan hanya bisa menggunakan viewcriteria dan bind parameter untuk mengisi parameter pada query?

Setelah bertukar pikiran dalam diskusi masalah ini, akhirnya di temukan sebuah trik untuk menyelesaikan masalah ini.
Yaitu dengan mengganti query dari VO tersebut secara programmatic pada saat pop-up dialog LOV muncul, atau dengan kata lain adalah meng-harcode parameter kedalam query tersebut.

berikut gambarannya :

select distinct xx.kolom_1, xx.kolom_2
from table_xx xx, (
    select kolom_a, kolom_b
    from table
    where kolom_c = 'ABCDEF'
) yy
where 
xx.kolom_3 = yy.kolom_a
yy.kolom_b = 'GHIJK' 


Oke diatas adalah overview dari apa yang akan di jelaskan secara detail selanjutnya.

Pertama-tama akan saya berikan contoh untuk mengganti query dari sebuah VO.
Pada contoh berikut query VO diganti didalam sebuah method di dalam ViewObjectImpl

public class VoTableSearchImpl {
  /**
   * This is the default constructor (do not remove).
   */
  public VoTableSearchImpl() {
  }

  public void execSearchQuery(String param1, String param2) {
   
    setFullSqlMode(FULLSQL_MODE_AUGMENTATION); 
    setQuery("select distinct xx.kolom_1, xx.kolom_2
            from table_xx xx, (
                select kolom_a, kolom_b
                from table
                where kolom_c = '"+ param1 +"'
            ) yy
            where 
            xx.kolom_3 = yy.kolom_a
            yy.kolom_b = "+ param2 +"'");
    executeQuery();
  }

}

yang perlu diperhatikan adalah semua nama kolom, jumlah kolom, dan type data nya harus sama antara query awal dengan query yang baru


selanjutnya adalah mengimplementasikannya kedalam sebuah LOV

akan ditaruh dalam sebuah method listener pada LOV yaitu launchPopupListener
dan ada satu method tambahan yang diperlukan untuk bisa mendapatkan VO dari suatu LOV

private ViewObject getLovVo(String attributeBinding) {
        BindingContext bctx = BindingContext.getCurrent();
        BindingContainer bindings = bctx.getCurrentBindingsEntry();
        FacesCtrlLOVBinding lov = (FacesCtrlLOVBinding)bindings.get(attributeBinding);
        return lov.getListIterBinding().getViewObject();
    }

dan berikut adalah isi dari method launchPopupListener

public void onLaunchLovNama(LaunchPopupEvent launchPopupEvent) {
    String param1 = (String)getAttrBinding("param1").getAttributeValue();
    String param2 = (String)getAttrBinding("param2").getAttributeValue();
   
    VoTableSearchImpl vo = (VoTableSearchImpl)getLovVo("lovNama");           
    vo.setFullSqlMode(VoTableSearchImpl.FULLSQL_MODE_AUGMENTATION);
    vo.setQuery("select distinct xx.kolom_1, xx.kolom_2
            from table_xx xx, (
                select kolom_a, kolom_b
                from table
                where kolom_c = '"+ param1 +"'
            ) yy
            where 
            xx.kolom_3 = yy.kolom_a
            yy.kolom_b = "+ param2 +"'");
    vo.executeQuery();
}

Sekian dulu dan selamat mencoba.

web bitbucket merge pull request

saya mau berbagi sedikit pengalaman kurang enak terkait merging pull request melalui web bitbucket.

saya menggunakan web bitbucket dalam mengolah pull request di dalam tim. untuk merge, saya menggunakan button 'merge' yang ada di halaman pull request. kasusnya, saya memiliki sebuah pull request yang targetnya untuk di-merge ke salah satu branch. branch yang menjadi target merge saya ini juga menjadi target merge dari pull request branch lain. kebetulan saat itu branch lain itu lah yang di-merge terlebih dahulu. selang beberapa detik kemudian saya melakukan merge.

web bitbucket memiliki sistem notifikasi jika target merge kita mengalami perubahan dan menimbulkan conflict dengan pull request kita, tetapi notifikasi itu tentunya membutuhkan waktu untuk sampai di halaman saya.

karena proses merge dari branch lain tadi hanya selisih beberapa detik dengan ketika saya meng-klik merge branch saya, notifikasi belum sampai sehingga saya belum mengetahui adanya conflict. dan untuk efisiensi, ketika saya merge, saya men-centang 'Close source branch' agar branch saya langsung terhapus.

seperti yang seharusnya, bitbucket menolak merge saya karena adanya conflict. namun yang tidak diharapkan, ternyata branch saya tetap terhapus dari origin walaupun proses merge-nya gagal.

saya coba untuk me-reproduce kasus tersebut dengan repo baru.

sederhana saja, saya membuat sebuah repo, dan saya isi dengan sebuah text file test.txt, yang isinya hanya 1 baris:

 this is just test. nothing serious.  

kemudian saya push dia pada branch master.

lalu saya buat sebuah branch, branch-01, dengan base dari master. di branch-01 saya tambahkan line 2, sehingga test.txt menjadi

 this is just test. nothing serious.  
 just to add another line.  

lalu saya push dan saya buat pull requestnya (belum di-merge).



setelah itu saya kembali ke branch master dan meng-update kembali test.txt menjadi
 this is just test. nothing serious.  
 just wanna make some conflict.  

dan saya push.

kemudian secepatnya saya masuk ke halaman pull request kembali dan melakukan merge untuk pullrequest tadi, dengan men-centang 'Close source branch'.



setelah loading, maka merge saya ter-reject



tetapi kemudian ketika saya cek branch yang ada di origin repo tersebut, branch-01 telah hilang.



ketika saya coba lagi untuk merge, baru keluar pesan yang seharusnya tampil sejak awal



mengambil pelajaran dari kejadian ini, saya pikir lebih baik merge dilakukan tanpa meng-close source branch melalui web bitbucket dan melakukan delete branch secara manual setelah proses merge selesai dengan sukses.

bug ini bisa sangat merugikan, misalnya jika pada saat melakukan merge tersebut ada salah seorang anggota tim baru saja melakukan update pada branch yang sama dengan kita, dan kebetulan pada saat itu kita belum mem-pull source terbaru sehingga yang ada pada local kita bukan yang ter-update. dalam kasus demikian, walaupun branch tersebut di local kita masih ada sehingga kita bisa push lagi branch tsb dari local kita ke origin, namun tentu itu bukan versi yang kita harapkan.

semoga segera di-solve oleh tim bitbucket.

Raw SQL to Query using Beego

Masih seputar Beego, dimana sebelumnya kita membahas develop REST API sekarang kita akan membahas ORM di Beego. Kita tidak akan membahas ORM di Beego secara mendetail, karena cukup luas dan mendalam. Yang akan kita bahas disini hanya Raw SQL-nya.

Istilah Raw disini bisa kita artikan sebagai mentah (belum tersentuh), dengan kata lain Raw SQL adalah syntax-syntax query yang dipergunakan. Contoh SELECT, UPDATE, DELETE ataupun yang lainnya.

Sebagai study kasus disini, kita akan membaca table view dari database. Berikut struktur view-nya


Buat file test_orm.go di workspace golang, lalu ketik source code berikut ini :

Penjelasaanya adalah

  • Bagian import
    • Ada 2 library yang kita gunakan, yaitu beego/orm dan mysql sebagai driver database
  • Bagian struct
    • Disini kita define struktur data dari tabel view kita
  • Bagian fungsi init
    • Fungsi ini digunakan untuk connect ke database kita. Contoh, connect ke database mysql.
  • Bagian fungsi main
    • Yang pertama kita lakukan adalah mendaftarkan orm kita dengan syntax orm.NewOrm()
    • Kemudian kita jalankan Raw SQL-nya
    • Setelah itu dicetak semua datanya

Hasilnya adalah sebagai berikut :











Raw SQL jarang sekali kita gunakan, namum ada beberapa kasus lebih mudah penyelesaiinnya lewat Raw SQL seperti akses ke table view.

Ok, sementara itu dulu pengunaan Raw SQL di Beego. Nantikan ulasan-ulasan Beego lainnya di blog ini. Terima kasih.

Mengatur UIView dengan Auto Layout pada iOS

Salah satu isu yang saya temui ketika memulai mengembangkan aplikasi mobile, khususnya pada iOS, adalah dalam hal pengaturan layout antarmuka. Seringkali saya sudah meletakkan dengan rapih, namun ketika dijalankan di iOS Simulator layout-nya menjadi berantakan pada device tertentu. Misalnya saya ingin meletakkan 2 label dengan pasangan text field-nya seperti UIView berikut ini:
UIView pada Storyboard

Terlihat pada Storyboard, UIView tersebut sudah rapih. Tetapi setelah dijalankan di iOS Simualtor, hasilnya berantakan tidak sesuai seperti yang saya bayangkan ketika menuangkannya di Storyboard:
UIView ketika runtime di iOS Simulator

Apple telah menyediakan fitur Auto Layout pada iOS untuk mengkalkukasikan secara dinamis jarak dan posisi dari masing-masing komponen antarmuka, sehingga layout dapat tetap rapih dan dinamis pada device apapun. Awalnya saya kurang memahami perilaku dari Auto Layout, sehingga saya merasa menggunakan Auto Layout justru malah mempersulit pengembangan. Ternyata setelah berulang kali saya mencoba, Auto Layout tidak sesulit itu. Bahkan terasa sangat natural dan logis. Pada artikel ini saya ingin berbagi cara memahami dan memanfaatkan Auto Layout dalam pengembangan aplikasi iOS.

Pertama-tama, pastikan "Use Auto Layout" dan "Use Size Classes" pada property Main.storyboard dalam kondisi terpilih. Kemudian ketika kita sedang mendisain UIView di Storyboard, Size Classes berada di posisi "w Any h Any". 
Size Classes Default

Size Classes "w Any h Any" memiliki arti UIView yang sedang diedit akan diaplikasikan secara universal. Artinya kita hanya cukup mendisain layout sekali untuk berbagai ukuran model device maupun orientasi device. Faktor penting lainnya adalah dalam Auto Layout, kita membutukan sebuah object atau batasan untuk menjadi patokan utama. Misalnya pada contoh di atas, hasil akhir yang kita inginkan adalah keseluruhan disain berada tepat di tengah layar bagian atas. Untuk itu kita membutuhkan sebuah object tambahan sebagai patokan titik tengah horizontal. Ambil saja sebuah label baru dan kita letakkan di antara Name dan text field sebelahnya hinggap snap to horizontal centre grid.
Penambahan Komponen Dummy Posisi Tengah Horizontal

Kecilkan ukurannya, kemudian ketika dalam kondisi memilih label tersebut pilih "Pin" di sudut kanan bawah Storyboard dan pilih "Width" dan "Height", kemudian pilih "Align" dan pilih "Horizontally in Container". Tampilannya akan menjadi seperti ini:

Garis merah ini pertanda ada sebuah contraint yang masih tidak benar. Target kita adalah membuat garis merah ini hilang dan menjadi garis biru yang menandakan layout sudah tidak ambigu. Tahan tombol "Ctrl" dan tarik cursor mouse dari label tersebut ke arah atas container dan lepaskan. Kemudian pilih "Vertical Spacing to Top Layout Guide". Seharusnya garis sudah menjadi biru sekarang. 

Kita sudah memiliki patokan titik horizontal sekarang, yaitu label dummy yang telah dibuat sebelumnya.  Sekarang saatnya memanfaatkan titik tersebut. Geser text field ke kanan, label Name ke kiri. Tahan tombol Ctrl dan mouse dari text field ke titik horizontal, begitu pula dengan label Name. Tarik pula dari masing-masing label dan text field ke arah atas ke top container. Jangan lupa untuk membuat fix width pada textfield. Coba jalankan kembali ke iOS Simulator. Seharusnya sekarang posisinya sudah lebih dinamis dan rapih, baik pada oritivertikal maupun horizontal.
Lakukan hal serupa pada label Role dan textfield-nya, kemudian hide titik horizontal. Hasil akhirnya kurang lebih seperti ini:

Selamat mencoba! :)

ADF fileDownloadActionListener custom validation (ADF Auto Click Button)

Pada adf ada komponen <af:fileDownloadActionListener> yang biasanya digunakan untuk menggenerate mendownload suatu file.
<af:fileDownloadActionListener> biasanya di pasang pada sebuah button.

fileDownloadActionListener bisa dibilang memiliki kelemahan, yaitu saat button di klik maka fileDownloadActionListener akan langsung ter-trigger, tanpa peduli dengan validasi pada form input yang ada, padahal ada field-field mandatory yang harus diisi dengan value yang benar (misalnya sesuai dengan data yang ada pada database). Tetapi asalkan field tersebut tidak di isi kosong maka fileDownloadActionListener akan langsung merespon, padahal field tersebut di isi dengan data yang tidak ada di database.

Dan sepertinya dari sananya (oracle) memang tidak membuat <af:fileDownloadActionListener> ini bisa di intercept begitu ter-trigger.
Jadi untuk mencegah hal ini terjadi kita akan menggunakan sebuah trick, yaitu dengan menggunakan hidden button dan script auto click.

Button yang dipasang <af:fileDownloadActionListener> akan kita hidden (kita sebut saja button H), dan menambahkan button lain (kita sebut saja button D).
Pada saat button D di klik maka akan tervalidasi field-field mandatory yang ada pada form, jika validasi lolos selanjutnya akan di running script untuk mengklik button hidden yang dipasang <af:fileDownloadActionListener>
File akan digenerate dan proses download bisa dilakukan


Berikut penjelasan lebih lanjutnya:

  • Ini adalah gambar structure komponen dari Button dan fileDownloadListener nya


  • Code untuk Button Hidden
<af:commandButton text="Button Hidden"
    clientComponent="true" visible="false"
    binding="#{backingBeanScope.backing_view1.cb2}"
    id="cb2" partialSubmit="false">
    <af:fileDownloadActionListener filename="asdasd"
           method="#{backingBeanScope.backing_view1.downloadMe}"
           contentType="text/plain; charset=utf-8"/>
</af:commandButton>

  • Code untuk Button Download
<af:commandButton text="Button Download" id="cb1"
    binding="#{backingBeanScope.backing_view1.cb1}"
    action="#{backingBeanScope.backing_view1.prepareForDownloadAction}"
    clientComponent="true"
    partialSubmit="true"/>

  • Code javascript untuk file jspx. Ini adalah script Auto Click nya, nanti akan di panggil melalui java code
<af:resource type="javascript">
            function customHandler(event) {
                var exportCmd = AdfPage.PAGE.findComponentByAbsoluteId("cb2");
                var actionEvent = new AdfActionEvent(exportCmd);
                actionEvent.forceFullSubmit();
                actionEvent.noResponseExpected();
                actionEvent.queue();
            }
</af:resource> 

  • dan berikut adalah method action pada Button Download
public String prepareForDownloadAction() {

    // ---- logic validasi ---- //

    // ---- memanggil function javascript ---- //
    FacesContext context = FacesContext.getCurrentInstance();
    ExtendedRenderKitService erks = Service.getService(context.getRenderKit(), 
                                        ExtendedRenderKitService.class);
    erks.addScript(context, "customHandler();");
    return null;
}


Cukup sekian dan silahkan dicoba.












Building Web API using Beego

Di dalam blog ini saya masih berbicara tentang golang. Sama dengan bahasa pemrograman lainnya, golang memiliki banyak framework untuk membuatnya segalanya menjadi rapid.

Yang akan kita bahas disini adalah Beego, salah satu HTTP Framework yang menggunakan golang. Kenapa disebut sebagai HTTP Framework, karena Beego bukan hanya sekedar web framework tapi bisa digunakan untuk develop API backend service secara rapid.

Mari kita mulai dari persyaratannya :
  1. Pastikan environment kita sudah terinstall golang. Jika belum bisa lihat disini sebagai acuan.
  2. Install Beego dengan cara :

Setelah itu, kita siapkan sisi database-nya. Contoh tabel yang kita pake adalah :
Setelah semua lengkap mari kita mulai membuat program dari workspace golang :
  • cd $GOPATH/src





Kemudian ikuti langkah-langkah dibawah ini :
  • bee api testing-app -tables="roles" -conn=yuki:welcome1@tcp\(127.0.0.1:3306\)/testing
  • cd testing-app
  • bee run -downdoc=true -gendoc=true
  • buka di browser dan jalankan http://localhost:8080/swagger/swagger-1/

Done. Begitu mudahnya kita membuat REST API dengan Beego dengan ditambahkan swagger akan mempermudah kita untuk testing REST API yang telah kita buat.

Dari sini kita bisa lihat Beego menawarkan fitur yang keren dan rapid. Rapid sangat dibutuhkan mengingat informasi selalu berubah dalam tiap detiknya.

Ok, sementara itu dulu ulasan tentang Beego, tunggu kita di blog-blog Beego lainnya.

Android ButterKnife

Apa yang kalian rasakan jika melakukan development android ? interface untuk onclick/ontouch listener dan inflation view (findviewbyId) di mana - mana. Jika kalian merasa capek melakukan pengerjaan berulang - ulang untuk melakukan hal tersebut. Maka solusinya adalah menggunakan ButterKnife. ButterKnife akan meng-inject kode pada saat compile time dengan cara memberikan anotasi pada variabel/method.

Tambahkan dependency
MAVEN:
<dependency>
  <groupId>com.jakewharton</groupId>
  <artifactId>butterknife</artifactId>
  <version>7.0.1</version>
</dependency>
GRADLE:
compile 'com.jakewharton:butterknife:7.0.1'

Conventional:
Button button = (Button)findViewById(R.id.button);
TextView textView = (TextView)findViewById(R.id.textView);
RadioButton radioButton  = (RadioButton)findViewById(R.id.radioButton);
CheckBox checkBox= (CheckBox)findViewById(R.id.checkbox);
EditText editText = (EditText)findViewById(R.id.editText);

Butterknife Android:
@Bind(R.id.button)
Button button;
@Bind(R.id.textView)
TextView textView;
@Bind(R.id.radioButton)
RadioButton radioButton;
@Bind(R.id.checkBox)
CheckBox checkBox;
@Bind(R.id.editText)
EditText editText;
// Register pada onCreateView pada activity. Contoh:
Butterknife.bind(this);

Hasillnya lebih singkat dan terstruktur. Berikut pada onClickListener:

Conventional:
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
//do something
             } });

Butterknife Android:
@OnClick(R.id.sign_in_button)
public void attemptLogin() {
         // do something       
}

Selain itu juga bisa digunakan untuk melakukan bind resources seperti dibawah:
class ExampleActivity extends Activity {
@BindString(R.string.title) String title; @BindDrawable(R.drawable.graphic) Drawable graphic; @BindColor(R.color.red) int red; // int or ColorStateList field @BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field   // ...
}

Kesimpulannya ButterKnife membuat code jadi lebih terstruktur dan clean. Dan banyak top aplikasi android yang menggunakan library ini. Dan beri kredit untuk Jakewarthon sang initiate project ini!.

Sumber:
http://jakewharton.github.io/butterknife/
http://www.thekeyconsultant.com/2013/09/5-reasons-you-should-use-butterknife.html

java class mocking dengan mockito

unit test sebaiknya dilakukan dengan menghilangkan dependency terhadap sistem lain. lalu bagaimana jika di dalam class/method yang hendak kita test mengandung komunikasi dengan sistem lain misalnya menembak API dari sistem lain?

kita bisa memalsukan method dari service yang menembak ke API sistem lain tersebut, sehingga seolah-olah sistem kita telah merequest dan menerima response. atau dengan kata lain, kita me-mock service tersebut, dan menentukan sendiri (berdasarkan asumsi dan/atau kondisi yang diinginkan dalam unit test tersebut) response yang diharapkan dari method tersebut.

mari kita coba dengan menggunakan library mockito. aplikasi menggunakan framework spring, unit test dengan junit.

misalkan kita punya class yang akan kita test:
 @Service  
 public class UseMeForTesting {  
        
      @Autowired  
      BidEngineRemoteService bidEngineRemoteService;  
        
      public String someTransaction() throws BidException{  
             
           String refNo = null;  
             
           BidEngineResponse response = bidEngineRemoteService.apiGet("/api/test");  
           if(response == null){  
                throw new BidException("no response.");  
           }else if(response.isError || response.getJsonResponse() == null){  
                throw new BidException("error response.");  
           }else if(response.getJsonResponse() != null){  
                refNo = response.getJsonResponse().get("refNo").toString();  
                refNo = refNo.replace("\"", "");  
           }  
             
           return refNo;  
             
      }  
        
      /**  
       * for mock injection purpose  
       * @param bidEngineRemoteService  
       */  
      public void setBidEngineRemoteService(BidEngineRemoteService bidEngineRemoteService){  
           this.bidEngineRemoteService = bidEngineRemoteService;  
      }  
        
 }  

di dalamnya memanggil service yang menembak api dari service lain.
 @Service  
 public class BidEngineRemoteService {  
   
   private static final Logger LOGGER = LoggerFactory.getLogger(BidEngineRemoteService.class);  
   
   @Autowired  
   private HttpRequest httpRequest;  
   
   @Value(value = "${bid.host}")  
   private String bidHost;  
   
   private final int MAX_REQUEST = 3;  
   
   public BidEngineResponse apiGet(String endpoint) {  
     return executeWithRetry(new ApiRequest() {  
       @Override  
       protected HttpRequest.HttpRequestResult doRequest() throws IOException {  
         return httpRequest.doGetRequestAndGetResult(createUrl(endpoint));  
       }  
     });  
   }  
   
   private String createUrl(String endpoint) {  
     if (!endpoint.substring(0, 1).equals("/")) {  
       endpoint = "/" + endpoint;  
     }  
     return bidHost + endpoint;  
   }  
   
   private BidEngineResponse executeWithRetry(ApiRequest apiRequest) {  
     int count = MAX_REQUEST;  
     while (count-- > 0) {  
       if (apiRequest.execute()) {  
         return apiRequest.getResult();  
       }  
     }  
     return null;  
   }  
   
   static abstract class ApiRequest {  
     private BidEngineResponse response;  
   
     protected abstract HttpRequest.HttpRequestResult doRequest() throws IOException;  
   
     public boolean execute() {  
       response = run();  
       return response != null;  
     }  
   
     private BidEngineResponse run() {  
       BidEngineResponse bidEngineResponse = null;  
       HttpRequest.HttpRequestResult result;  
   
       try {  
         result = doRequest();  
         bidEngineResponse = new BidEngineResponse(result);  
   
       } catch (IOException e) {  
         bidEngineResponse = new BidEngineResponse();  
         bidEngineResponse.isError = true;  
   
         if (e instanceof java.net.ConnectException) {  
           bidEngineResponse.setError("Could not connect to bid engine");  
         } else {  
           bidEngineResponse.setError(e.getMessage());  
         }  
   
         e.printStackTrace();  
       }  
   
       return bidEngineResponse;  
     }  
   
     public BidEngineResponse getResult() {  
       return response;  
     }  
   }  
   
   public static class BidEngineResponse extends HttpRequest.HttpRequestResult {  
   
     public static final String FIELD_ERROR = "Error";  
     private JsonObject root = null;  
   
     public BidEngineResponse() {  
       super();  
     }  
   
     public BidEngineResponse(HttpRequest.HttpRequestResult result) {  
       this.response = result.response;  
       this.isError = result.isError;  
   
       JsonElement jsonElement = result.response;  
       if (null != jsonElement && !jsonElement.isJsonNull()) {  
         if (jsonElement.isJsonObject()) {  
           root = jsonElement.getAsJsonObject();  
         } else {  
           root = new JsonObject();  
         }  
       } else {  
         root = new JsonObject();  
       }  
     }  
   
     public JsonObject getJsonResponse() {  
       return root;  
     }  
   
     public void setError(String message) {  
       root = null;  
       root = new JsonObject();  
       root.addProperty(FIELD_ERROR, message);  
     }  
   
     public String getError() {  
       return getValueFromErrorMap(FIELD_ERROR);  
     }  
   
     public String getValueFromErrorMap(String field) {  
       if (isError) {  
         JsonElement jsonElement = root.get(field);  
         if (null != jsonElement) {  
           return jsonElement.getAsString();  
         }  
       }  
       return null;  
     }  
       
     /**  
      * mock injection purpose  
      * @param isError  
      */  
     public void setError(boolean isError){  
          this.isError = isError;  
     }  
       
     /**  
      * mock injection purpose  
      * @param root  
      */  
     public void setRoot(JsonObject root){  
          this.root = root;  
     }  
   
   }  
        
 }  

untuk menghindari dependency, maka kita bisa membuat 'mock' untuk service di atas dengan menggunakan asumsi response yang diharapkan dari service tersebut. berikut contoh implementasi mocking dengan mockito pada jUnit test class.

 @RunWith(SpringJUnit4ClassRunner.class)  
 @ContextConfiguration(locations = {"/spring/applicationContext.xml"})  
 public class UseMeForTestingTest {  
        
      @Mock  
      BidEngineRemoteService bidEngineRemoteService;  
        
      @Autowired  
      UseMeForTesting useMeForTesting;  
        
      @Before  
      public void setUp() throws Exception {  
           MockitoAnnotations.initMocks(this);  
      }  
        
      private static final String REFNO = "test123";  
        
      @Test  
      public void someTransactionTest(){  
             
           JsonObject obj = new JsonObject();  
           obj.addProperty("refNo", REFNO);  
           obj.addProperty("message", "pesan");  
             
           BidEngineRemoteService.BidEngineResponse bidResponse = new BidEngineRemoteService.BidEngineResponse();  
           bidResponse.setError(false);  
           bidResponse.setRoot(obj);  
             
           Mockito.doReturn(bidResponse)  
                .when(bidEngineRemoteService)  
                .apiGet("/api/test");  
             
           useMeForTesting.setBidEngineRemoteService(bidEngineRemoteService);  
             
           try {  
                String result = useMeForTesting.someTransaction();  
                Assert.assertTrue(REFNO.equals(result));  
           } catch (BidException e) {  
                Assert.assertTrue(false);  
           }  
             
      }  
        
 }  

pada contoh di atas, kita mengasumsikan bidEngineRemoteService.apiGet("/api/test") akan meresponse dengan root object obj dan error=false. sehingga method UseMeForTesting.someTransaction() akan memberikan hasil refNo, sesuai dengan mock yang kita set.

silakan lihat http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html untuk contoh-contoh lainnya.

Extreme Programming VS Real Programming di Indonesia

Beberapa saat yang lalu saya tidak sengaja membaca mengenai Extreme programming atau biasa disebut XP. Apakah itu XP? Singkatnya XP adalah sebuah metodologi yang terlihat menyenangkan dalam kegiatan mengembangkan software. XP merupakah salah satu dasar dari agile dimana metedologi ini cenderung mengunakan pendekatan Object-Oriented. Dalam praktiknya, medetologi ini hanya terdiri dari 2-9 orang di setiap team. Metedologi ini cocok di gunakan untuk anggota team yang pro dan user mengetahui betul apa yang di inginkannya. 

Sebelumnya saya akan membahas sedikit mengenai metedologi XP, yaitu Core Value dari XP dan XP Practice.

XP Core Value : 

  • Communication 
    • Komunikasi menjadi kunci keberhasilan dalam pengembangan software pada XP
  • Simplicity
    • Code yang dibuat sesimple mungkin untuk memenuhi kebutuhan saat ini tanpa memikirkan kebutuhan di masa depan. 
  • Feedback
    • Feedback baik dari user maupun sesama anggota akan membantu mempercepat peningkatan kualitas system. Karena jika system sudah 90% jadi baru ada feedback, akan menghabiskan waktu lama untuk memperbaikinya.
  • Courage
    • Keberanian untuk melalukan observasi dan membuat ulang apabila ada kesalahan pada system.

XP Practice :

  • Planning 
    • Planning pada XP dilakukan dalam waktu yang singkat dan tidak mendetail. Disini progammer hanya menentukan garis besar tugas tidak mendetail hingga setiap fungsi- fungsi ataupun parameternya.
  • Testing
    • Testing pada XP lebih kearah small testing per module.
  • Pair Programming
    • Dua orang programmer mengerjakan sebuah proyek pada sebuah device. Sehingga lebih cepat dan lebih baik dalam menemukan solusi sebuah masalah.
  • Simple Design
    • Code yang dibangun sesimple mungkin.
  • Refactoring the Code
    • Berani merefactor code untuk membuatnya lebih simple dan lebih efisien.
  • Owning the Code Collectively
    • Setiap orang dapat memperbaiki code karena memiliki komunikasi yang baik antar anggota team sehingga semua anggota mengetahui cara kerja dan struktur kode tersebut.
  • Continuous Integration
    • Setiap service yang sudah dibuat oleh masing-masing team di tes secara continue.
  • On-Site Customer
    • Customer harus siap untuk berinteraksi dengan programmer sehingga mempermudah apabila ada kesalahan atau kekurangan dari system yang ada. XP tidak memiliki planning yang detail sehingga customer berperan besar dalam pengembangan.
  • System Metaphorp
    • Sebuah deskripsi mengenai system yang dibuat untuk memudahkan anggota team dan customer mengenal cara kerja system secara naratif.
  • Small Releases
    • Merilis setiap versi dalam waktu yang singkat.  
  • Forty-Hour Week
    • Jam kerja tidak melebihi 40jam perminggu untuk mencegah tingginya tingkat setres. Karena tingkat setres yang tinggi akan memperhambat kinerja.
  • Coding Standards
    • Naming conversion sangat penting untuk mempermudah anggota team lain memperbaiki dan mengerti code yang ada

Dari definisi di atas, XP menitik beratkan pada simple , cepat dan efisien. Untuk mencapai hal tersebut dibutuhkan orang- orang expert yang memiliki core value tersebut diatas dan melakukan XP praktik. Selain itu XP akan berjalan dengan baik apabila client bersedia terlibat dan mengerti dengan baik apa yang mereka inginkan. Serta tidak memiliki sifat tamak :D 

XP sendiri sebenarnya menarik untuk dilakukan dan sangat efisien. Tetapi pada kenyataan programming di Indonesia kebanyakan client tidak mengerti apa yang diinginkan sehingga sulit untuk menerapkan hal tersebut. 

Core ValueKenyataan di Real
Communication
Jarang terjadi komunikasi antara user dengan team developer dikarenakan client yang tidak terlalu mengerti mengenai apa yang mereka inginkan. Tidak jarang client meminta spesifikasi yang tidak memungkinkan padahal batas waktu pengerjaan tidak berubah. Hal itu membuat team developer enggan untuk melakukan komunikasi kepada pihak client.
Simplicity
Tidak jarang team developer membuat fitur yang mungkin akan terjadi di masa depan untuk membuat nilai jual software telihat lebih baik. Tetapi ketika ada kesalahan dalam flow utama, fitur berlebih itu ada kalanya memperlambat perbaikan. Sedangkan setelah dirilis, fitur tersebut ternyata tidak pernah digunakan, Itu sering kali hanya memperlambat pengembangan project
Feedback
Rendahnya komunikasi dengan client membuat jarang ada feedback yang diterima oleh pihak developer. Hal tersebut sering kali membuat developer kesulitan untuk memperbaikinya. Ada kalanya team developer sudah mengharapkan feedback tetapi pihak client tidak mengerti dengan baik apa yang diinginkan oleh pihak mereka sehingga tidak dapat memberikan feedback untuk memperbaiki system.
CourageBeberapa developer tentunya memiliki keberanian untuk merombak code. Karena memperbaiki code untuk kesalahan atau untuk mendapatkan hasil yang lebih efisien. 



XP Practice Kenyataan di Real 
PlanningPlaning memang sering dibuat sangat simple baik pembagian tugas maupun service yang akan dikerjakan
TestingTesting biasa baru dilakukan setelah banyak service telah siap digunakan.
Pair Programming 
Hal ini sangat jarang terjadi. Kebanyakan setiap developer memiliki tugasnya sendiri- sendiri. Menurut saya mungkin akan efisien ketika 2 orang mmelakukan pekerjaan pada 1 laptop. Karena mereka akan berfokus pada pekerjaannya tanpa melakukan selingan. Dan akan lebih cepat selesai karena solusi sangat cepat ditemukan. Serta akan membantu menemukan code yang lebih efisien.
Simple Design
Code yang dibangun sesuai dengan pribadi developernya. Tidak memadahinya resource IT membuat programmer- programmer baru tidak diperhatikan dan tidak mendapatkan nasihat mengenai simple code. Sehingga tidak jarang ada code- code yang tidak efisien di buat oleh programmer muda.
Refactoring the CodeTidak banyak team developer yang bersedia dengan ikhlas merefactor code mereka. Faktor- faktornya karena code mereka kebanyakan tidak simple dan sudah komplek sehinnga bila di refaktor mereka tidak tau apa ada module lain yang terkena imbas.
Owning the Code Collectively Tidak jarang developer satu sama lain tidak mengerti dengan detail pekerjaan yang lain. Sehingga memperbaiki code orang akan sangat beresiko. 
Continuous Integration Hal ini sudah cukup baik di terapkan pada keadaan saat ini. Integrasi dilakukan setelah system siap digunakan untuk melihat kesuksesan pengembangan system
On-Site CustomerHal ini juga sudah terjadi pada beberapa keadaan dan hal tersebut memudah dalam mendapat penjelasan. Karena walaupun menggunakan messanger, ada kalanya susah mendapatkan pemahaman yang tepat sesuai keinginan user.
System Metaphorp Rendahanya proses dokumentasi membuat hal ini jarang sekali dilakuka. Tidak jarang developer tidak mengetahui alur system keseluruhan dengan baik.
Small ReleasesHal ini sudah cukup sering dilakukan, ada kalanya developer team melakukan release per module sehingga progress bisa terlihat lebih jelas.
Forty-Hour Week Pada dasarnya jam kerja di kantor Indonesia adalah 8 jam sehari. Tetapi di XP mengharapkan 8 jam yang efisian. Tetapi ada kalanya developer tidak melakukannya dengan baik sehingga membuat pekerjaan tidak selesai pada waktunya. 
Coding StandardNaming sudah cukup sering dilakukan. Bahkan kebanyakan framework saat ini juga membantu dalam hal naming conversion. Hal itu tentunya sangat membantu dalam develop sebuah system.


Walaupun banyak dari perusahaan di Indonesia berusaha menerapkan agile metodology, tetapi masih banyak juga yang tidak menjalankan XP yang merupakan dasar dari metodology agile sebagai best praktiknya.
Masih berkembangnya IT di Indonesia masih membuat pengembangannya mengalami pasang surut kebahagiaan baik dari segi developer maupun client.

Semoga tulisan ini dapat menyadarkan kita sesama developer maupun client bahwa di dunia ini ada metodologi yang mendukung kebahagiaan client dan developer :D

Instalasi ruby menggunakan RVM

Beberapa waktu yang lalu saya sempat mengerjakan beberapa project yang menggunakan Ruby. Tapi disetiap project mewajibkan untuk menggunakan versi Ruby yang berbeda-beda. Salah satu solusi untuk masalah ini adalah menggunakan RVM.

RVM is a command-line tool which allows you to easily install, manage, and work with multiple ruby environments from interpreters to sets of gems. - https://rvm.io/

Kelebihan menggunakan RVM:

  1. RVM memungkinkan kita untuk menggunakan banyak versi Ruby didalam satu mesin. dan bisa dirubah berdasarkan project yang akan digunakan.
  2. RVM menginstall ruby di hidden folder sehingga tidak menggangu system Ruby yang sudah berjalan sebelumnya.
  3. Setiap gems yang di install melalui RVM bisa di kelompokan berdasarkan project yang membutuhkan.
  4. Tidak perlu menggunakan sudo untuk menginstall gem.  
INSTALLING RVM DAN RUBY

untuk kasus kali ini saya akan menggunakan versi stable dari RVM, cukup jalankan perintah berikut di terminal:

$ \curl -sSL https://get.rvm.io | bash -s stable --ruby

thats it, RVM akan terinstall di mesin kita.

Selanjutnya kita akan menginstall ruby menggunakan RVM, jalankan perintah berikut:

$ rvm install 2.2.3

disini saya menggunakan versi ruby 2.2.3. setelah menjalankan perintah diatas kita telah berhasil menginstall ruby di RVM.

USING RVM

untuk mengetahui versi ruby berapa saja yang sudah terinstall dimesin kita, jalankan perintah berikut:

$ rvm list


diatas kita bisa lihat apa saja versi ruby yang sudah terinstall.

selanjutnya untuk menggunakan ruby yang sudah kita install di project jalankan perintah berikut:

$ rvm use 2.2.3

USING GEMSET

Selanjutnya kita akan menggunakan gemset untuk mengelompokan gems di spesific project. 

untuk membuat gemset jalankan perintah berikut:

$ rvm gemset create [nama_gemset]

selanjutnya untuk menggunakan gemset tersebut menggunakan perintah berikut:

$ rvm use 2.2.3@[nama_gemset]

Thanks.

Oracle BPM Composer 12c - Create Process, Simulation, Deployment Part 2

Pada kesempatan sebelum nya kita sudah membuat NostraDemoProcess. Kali ini kita akan melanjutkan dengan membuat Simulation & Deployment nya.

Klik Play pada NostraDemoProcess. Kemudian buka tab Project Player dan pada bagian Organization kita akan meng-assign orang yang sesuai dengan Role yang sudah kita buat, pada kasus ini kita akan meng-assign jstein sebagai Manager & jcooper sebagai Employee.




Jika sudah, buka kembali tab NostraDemoProcess. Klik Start pada process tersebut. Tunggu beberapa saat, maka proses akan bergerak ke dalam Input Data Task, lalu klik Task tersebut maka akan terbuka popup yang berisi info user yang bisa mengakses form tersebut. Karena tadi kita hanya meng-assign jcooper, maka yang muncul hanyalah jcooper saja. Klik Run, kemudian pilih Launch Form.



Jika Form UI nya sudah terbuka, isi data nya kemudian pilih Submit.


Proses akan berlanjut pada Approval Task. Klik Approval Task kemudian pilih Run & pilih Lauch Form. Disini kita bisa lihat data yang sudah kita masukkan pada Form InputData sudah termapping ke dalam Form Approval. Jika sudah pilih Approve. Maka process sudah berhasil melalui conditional branch yang sudah kita buat.




Sampai step ini, proses simulation sudah selesai dilakukan. Selanjutnya kita akan mendeploy project. Namun sebelum itu kita akan mempublish apa saja yang sudah kita lakukan sebelum nya. Pilih Project Home kita, kemudian pilih Publish. Isi keterangan hal apa saja yang sudah kita lakukan kemudian klik Publish.



Jika sudah, klik icon seperti bundaran dibawah tulisan Oracle Business Process Composer lalu pilih Deployment > Deploy Project.

Isi Version, New Version ID serta username & password weblogic. Kemudian pilih Deploy.


Untuk mengecek apakah benar project ini sudah terdeploy atau belum , kita buka bpm workspace dan login sebagai user yang tadi mempunyai role sebagai employee, dalam kasus ini jcooper. Kita lihat pada bagian Applications disana terdapat NostraDemoProcess yang sudah kita buat dan ini menandakan kalau proses deployment nya sudah berhasil.



Kesimpulan : BPM Composer memudahkan bisnis analis ikut bagian dalam pembuatan workflow bahkan memungkinkan terjun langsung membuat sendiri seperti apa flow yang mereka inginkan. Tidak seperti versi sebelum nya, di versi 12c ini amat memudahkan dalam proses kolaborasi dengan berbagai pihak serta sudah mengadopsi Web Form yang lebih mempercantik UI dibanding dengan menggunakan ADF.

Sekian dari saya.
Semoga membantu !