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.