Tuesday, March 15, 2016

Scala : Class dan Object

Setelah sebelumnya mengenal basic tentang scala. sekarang kita akan mencoba melangkah ke bagian selanjutnya yakni tetang OOP (object oriented). Selain sebagai functional programming scala juga memiliki bagian OOP nya. Sama seperti java, di scala oop juga dibentuk dengan adanya Class.
Pada dasarnya class adalah sebuah blueprint. Sebuah class dapat membuat sebuah object (dengan menggunkan keyword `new`). Misal class Mobil bisa membuat Object sedan, pickup, dll. Konsep class di scala sama seperti dipemrograman lain.
Create sebuah class.
Class bisa ada atau tanpa constructor. membuat constructor harus di definisi class nya tidak perlu menbuat method yg sama dengan nama classnya seperti di Java.

 class Person (val pName : String, val pAge : Int) {  
   var name : String = pName  
   var age : Int = pAge;  
   // setter getter  
   def setName(name : String) = {  
    this.name = name  
   }  
   def getName() : String = this.name  
   def setAge(age : Int) = {  
    this.age = age  
   }  
   def getAge() : Int = this.age  
 }  

Inisialisasi class menggunakan keywordnya.  tapi ingat harus definisi variabel di scala harus menggunakan var / val.
contoh : val mperson : Person = new Person ("budi", 99)

Extending Class
class bisa juga diturunkan dengan cara diextend.
perlu didefinisikan juga varible parent yg harus dioverride di cosntructornya.

 class Student(override val pName: String, override val pAge: Int,  
        val pAddress :String) extends Person(pName, pAge){  
  var address : String = pAddress;  
  def setAddress(address : String) = {  
   this.address = address  
  }  
  def getAddress() : String = this.getAddress()  
 }  

Singleton Object.
Scala tidak menyediakan static variable / member seperti di java. Maka jika kita membutuhkan variable yg sifatnya static dan hanya sekali dicreate kita bisa menggunakan singleton object. Kalau di java seperti kita membuat static blok.

 static {  
  // codes and variables  
 }  

Contoh singleton object

 object Person {  
  var p : Person = new Person("budi", 10)  
  def displayPerson() = {  
   println("name "+ p.getName() + " age "+ p.getAge())  
  }  
 }  

Jadi di dalam object Person akan ada varible 'p' yang isinya selalu sama.
Untuk memanggil method di singleton object cukup lewat nama objectnya,
Person.displayPerson()

Companion object
Jika class dan object mempunyai nama sama dan berada di satu source file. hanya berbeda keyword 'class' dan 'object'. Dalam satu companion object bisa saling mengakses variable membernya masing-masing.

 class Person (val pName : String, val pAge : Int) {  
   var name : String = pName  
   var age : Int = pAge;  
   // setter getter  
   def setName(name : String) = {  
    this.name = name  
   }  
   def getName() : String = this.name  
   def setAge(age : Int) = {  
    this.age = age  
   }  
   def getAge() : Int = this.age  
 }  
 object Person {  
  var p : Person = new Person("budi", 10)  
  def displayPerson() = {  
   println("name "+ p.getName() + " age "+ p.getAge())  
  }  
 }  

Kapan mengunakan companion object?.  varible yg sifatnya bisa berubah atau reuseable sebaiknya ditaruh di Class. sedangkan varible atau method yang sifatnya static / singleton / bisa dipake berkali kali sebaiknya ditaruh di Object.

Sekian dulu pembahasan tentang class dan object di scala dan selamat mencoba.

bersambung di materi scala selanjutnya

referensi :
http://docs.scala-lang.org/tutorials/tour/classes
http://docs.scala-lang.org/tutorials/tour/singleton-objects.html



Implementasi microservice dengan Java EE pada KumuluzEE

Melanjutkan blog sebelumnya, kali ini kita akan membuat REST API menggunakan standar Java EE pada framework KumuluzEE.

  1. Tambahkan modul jax-rs untuk membuat REST
  2. <dependency>
        <groupId>com.kumuluz.ee</groupId>
        <artifactId>kumuluzee-jax-rs</artifactId>
        <version>${kumuluzee.version}</version>
    </dependency>
  3. Tambahkan modul cdi untuk context dependency injection
  4. <dependency>
        <groupId>com.kumuluz.ee</groupId>
        <artifactId>kumuluzee-cdi</artifactId>
        <version>${kumuluzee.version}</version>
    </dependency>
  5. Tambahkan modul jpa untuk ORM ke database
  6. <dependency>
        <groupId>com.kumuluz.ee</groupId>
        <artifactId>kumuluzee-jpa</artifactId>
        <version>${kumuluzee.version}</version>
    </dependency>
  7. Tambahkan library HSQLDB untuk database
  8. <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <version>2.3.2</version>
    </dependency>
  9. Tambahkan library Lombok
  10. <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.6</version>
    </dependency>
  11. Tambahkan directory META-INF pada directory resources, dan buat file persistence.xml
  12. <?xml version="1.0" encoding="UTF-8" ?>
    
    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
                 version="2.1">
    
        <persistence-unit name="schools" transaction-type="RESOURCE_LOCAL">
    
            <class>org.nostra.kumuluz.models.Students</class>
    
            <properties>
                <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
                <property name="javax.persistence.jdbc.url"
                          value="jdbc:hsqldb:mem:unit-testing-jpa:9001:blog" />
                <property name="javax.persistence.jdbc.user" value="sa" />
                <property name="javax.persistence.jdbc.password" value="" />
    
                <property name="javax.persistence.schema-generation.database.action" value="create"/>
                <property name="javax.persistence.schema-generation.create-source" value="metadata"/>
                <property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
            </properties>
    
        </persistence-unit>
    </persistence>
  13. Buat domain model Students
  14. @Data
    @Entity
    @NamedQuery(name="Students.findAll", query="SELECT s FROM Students s")
    public class Students {
    
        @Id
        private String id;
    
        private String firstName;
    
        private String lastName;
    
        private Date dob;
    
        @PrePersist
        public void prePersist(){
            id = UUID.randomUUID().toString();
        }
    }
    
  15. Ubah main class App menjadi seperti dibawah ini
  16. @ApplicationPath("/v1/")
    public class App extends javax.ws.rs.core.Application {
    }
    
  17. Buat resource (REST) API untuk Students
  18. @Path("/students")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @RequestScoped
    public class StudentsResource {
    
        @PersistenceContext(unitName = "schools")
        private EntityManager em;
    
        @GET
        public Response getStudents() {
    
            TypedQuery query = em.createNamedQuery("Students.findAll", Students.class);
    
            List studentses = query.getResultList();
    
            return Response.ok(studentses).build();
        }
    
        @GET
        @Path("/{id}")
        public Response getStudents(@PathParam("id") String id) {
    
            Students b = em.find(Students.class, id);
    
            return Response.ok(b).build();
        }
    
        @POST
        public Response createStudents(Students b) {
    
            b.setId(null);
    
            em.getTransaction().begin();
    
            em.persist(b);
    
            em.getTransaction().commit();
    
            return Response.status(Response.Status.CREATED).entity(b).build();
        }
    }
    
  19. Buat file beans.xml pada directory META-INF untuk mengaktifkan context dependency injection
  20. <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
      http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/beans_1_2.xsd"
           bean-discovery-mode="annotated">
    
    </beans>
  21. Kemudian build menggunakan perintah Maven
  22. mvn clean package
  23. Jalankan aplikasi dengan perintah :
  24. java -cp target/classes:target/dependency/* com.kumuluz.ee.EeApplication

Test REST API dengan cara :
  1. Call Http POST method ke http://localhost:8080/v1/students untuk insert data ke database
  2. curl -X POST 'http://localhost:8080/v1/students' \
    -H 'Content-Type:application/json' \
    -d '{"firstName":"agus","lastName":"winarno","dob":"1984-08-17"}'
    
    {
    "id":"c8fe9c5f-3004-419d-b457-706f2ff02ac9",
    "firstName":"agus",
    "lastName":"winarno",
    "dob":461548800000
    }
  3. Call Http GET method atau Buka browser dengan url http://localhost:8080/v1/students
  4. Call Http GET method atau Buka browser dengan url http://localhost:8080/v1/students/{id}
Sekarang kita sudah dapat membuat microservice dengan Java EE API, semoga bermanfaat :)
Bitbucket link :
Referensi :

Starting AngularJS Development with Yeoman, Grunt and Bower Part 2

Sebelumnya pada part 1 kita sudah mengenerate project menggunakan angular generator dan sudah menambahkan library angular-bootstrap. Maka pada kesempatan kali ini kita akan menambahkan beberapa perubahan.
Mari kita tambahkan library AngularUI Boostrap yang sudah kita include di part 1. Dikarenakan Bower hanya package manager, dia tidak bertanggung jawab untuk menambahkan file ke index.html. Kita harus menambahkan itu sendiri.
Jadi buka app/index.htmldan tambahkan line code berikut.
 <script src="bower_components/angular-bootstrap/ui-bootstrap.js"></script>  
Setelah itu kita harus menambahkan ui-boostrap dependency ke Angular module kita. Buka app/scripts/app.js dan tambahkan ui.bootstrap module sebagai dependency.
/app/scripts/app.js
 'use strict';  
 /**  
  * @ngdoc overview  
  * @name simpleAngularApp  
  * @description  
  * # simpleAngularApp  
  *  
  * Main module of the application.  
  */  
 angular  
  .module('simpleAngularApp', [  
   'ngAnimate',  
   'ngAria',  
   'ngCookies',  
   'ngResource',  
   'ngRoute',  
   'ngSanitize',  
   'ui.bootstrap'  
  ])  
  .config(function ($routeProvider) {  
   $routeProvider  
    .when('/', {  
     templateUrl: 'views/main.html',  
     controller: 'MainCtrl'  
    })  
    .otherwise({  
     redirectTo: '/'  
    });  
  });  
Kita harus melakukan beberapa perubahan pada view kita.
View: app/views/main.html
 <div class="hero-unit">  
   <h1>'Allo, 'Allo!</h1>  
   <p>You now have</p> <!-- kita memindahkan ng-repeat kedalam directive   
   modal yang dibawa oleh angular bootstrap-->  
   <button type="button" class="btn btn-default" ng-click="open()">Open me!</button>  
   <!--ng-click sejenis event onClick dia akan melakukan sesuatu,   
   pada kasus ini ketika di klik angular akan membuka method open-->  
   </div>  
   <p>installed.</p>  
   <h3>Enjoy coding! - Yeoman</h3>  
   <!-- script disini digunakan untuk mengenerate template modal -->  
   <script type="text/ng-template" id="myModalContent.html">  
     <div class="modal-header">  
       <h3 class="modal-title">I'm a modal!</h3>  
     </div>  
     <div class="modal-body">  
       <ul>  
     <!-- ng-repeat dipindahkan kedalam sini -->  
         <li ng-repeat="item in items">  
           <a href="#" ng-click="$event.preventDefault(); selected.item = item">{{ item }}</a>  
         </li>  
       </ul>  
       Selected: <b>{{ selected.item }}</b>  
     </div>  
     <div class="modal-footer">  
       <button class="btn btn-primary" type="button" ng-click="ok()">OK</button>  
       <button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>  
     </div>  
   </script>  
  </div>  
Controller : app/script/controller/main.js
 'use strict';  
 /**  
  * @ngdoc function  
  * @name simpleAngularApp.controller:MainCtrl  
  * @description  
  * # MainCtrl  
  * Controller of the simpleAngularApp  
  */  
 angular.module('simpleAngularApp')  
  .controller('MainCtrl', ['$scope','$uibModal','$log',function ($scope,$uibModal,$log) {  
  $scope.items = [  
     'HTML5 Boilerplate',  
     'AngularJS',  
     'Karma',  
     'SitePoint'  
    ];  
   $scope.animationsEnabled = true;  
  $scope.open = function (size) {  
   var modalInstance = $uibModal.open({  
    animation: $scope.animationsEnabled,  
    templateUrl: 'myModalContent.html',  
    controller: 'ModalInstanceCtrl',  
    size: size,  
    resolve: {  
     items: function () {  
      return $scope.items;  
     }  
    }  
   });  
   modalInstance.result.then(function (selectedItem) {  
    $scope.selected = selectedItem;  
   }, function () {  
    $log.info('Modal dismissed at: ' + new Date());  
   });  
  };  
  $scope.toggleAnimation = function () {  
   $scope.animationsEnabled = !$scope.animationsEnabled;  
  };  
 }]);  
 angular.module('simpleAngularApp').controller('ModalInstanceCtrl',['$scope','$uibModalInstance','items', function ($scope, $uibModalInstance, items) {  
  $scope.items = items;  
  $scope.selected = {  
   item: $scope.items[0]  
  };  
  $scope.ok = function () {  
   $uibModalInstance.close($scope.selected.item);  
  };  
  $scope.cancel = function () {  
   $uibModalInstance.dismiss('cancel');  
  };  
 }  
  ]);  
Kita sudah menggunakan beberapa bootstrap css class, membuat modal dialog menggunakan bawaan dari angular-bootstrap dan memindahkan ng-repeat ke dalam modal dialog.
Setelah ini jalankan code dibawah untuk menjalankan angular apps. Jangan lupa jalankan ini pada root folder project kalian dimana terdapat Gruntfile.js dll
 grunt serve  
Berikut tampilan nya jika dijalankan.
Sedangkan jika kita akan meminified nya jalankan code dibawah, hasilnya akan berada di dalam folder dist dan jalankan kode ini pada root folder project kalian dimana terdapat Gruntfile.js dll
 grunt clean build  
Sekian dahulu dari saya.
Semoga Bermanfaat !

Starting AngularJS Development with Yeoman, Grunt and Bower Part 1

Pada blog ini saya akan membahas tentang AngularJS. Salah satunya adalah membuat skeleton struktur AngularJS app dengan menggunakan Yeoman, kemudian menggunakan Grunt untuk mempercepat proses development.
Pertama-tama yang harus kita lakukan adalah menginstall Yeoman, Grunt dan Bower. Untuk mempermudah kita akan memakai Node Package Manager untuk melakukan nya sekaligus. Jalankan code berikut di dalam terminal.
 npm install -g yo grunt-cli bower  
Sambil menunggu instalasi, saya akan menjelaskan sedikit apa saja yang akan kita pakai. Yeoman digunakan untuk mengenerate skeleton app. Yeoman akan membuat basic folder, files, dan konfigurasi untuk mempermudah pekerjaan kita. Salah satu fitur terbaik dari Yeoman adalah kemampuan untuk menggunakan custom generator. Salah satu generator yang akan dipakai adalah AngularJS generator.
Jika proses instalasi di atas sudah selesai. Jalankan code berikut untuk menginstall AngularJS generator.
 npm install -g generator-angular  
Jika sudah, kita sudah bisa mengenerate AngularJS Application. Untuk mengenerate jalankan code berikut.
 yo angular  
Pada saat menjalankan generator, generator tersebut akan menanyakan beberapa pertanyaan tentang apa saja yang akan di include pada aplikasi Angular yang akan di generate.

Pada gambar di atas saya membuat aplikasi angular pada folder SimpleAngular. Setelah menjawab beberapa pertanyaan tersebut, Yeoman akan mengenerate semua file dan konfigurasi yang kita butuhkan. 
Berikut adalah yang digenerate oleh Yeoman.

app/directory
app directory berisi angular app. Di dalam nya terdapat html, css dan javascript. Disinilah kalian akan menghabiskan banyak waktu saat proses development.

package.json
File package.json membantu npm untuk mengindentifikasi project kita dan juga menghandle semua dependencies nya.

node_modules
Di folder ini terdapat semua node module yang kalian butuhkan oleh angular.

Gruntfile.js
File ini merupakan file javascript untuk menkonfigurasi project yang dilakukan oleh task apapun atau plugin apapun yang dibutuhkan di dalam project. Di file inilah kita akan mengkonfig spesifik direktori ketika akan membuild.

component.json
File ini digunakan untuk memberitahu dependencies kepada Bower package manager.
File ini dipakai untuk mendistribusi config options ke bower.

Karma files
Karma adalah sebuah framework untuk testing. Kita akan menggunakannya untuk menjalankan test pada Angular app.
Bower - Package Manager untuk Web
Sebelum kita menggunakan bower, ada sedikit configurasi yang harus kita tambahkan sendiri. Buka file .bowerrc


Pada gambar di atas adalah isi dari file .bowerrc yang belum di edit. Tambahkan code berikut.

 ,"json":"bower.json"  
Sehingga isi file tersebut menjadi :

Yang dilakukan pada code tersebut adalah memberitahu Bower untuk menggunakan package bower.json bagaimana menginstall package itu. Jika sudah jalankan code berikut untuk meng-fetch dependencies.
 npm install  
 bower install  
Bower  adalah package manager. Bower akan membantu kita untuk menemukan dan menginstall favorite CSS Frameworks, javascript libraries dan plugins hanya dengan menggunakan beberapa command yang mudah.
Sekarang kita akan menginstall Angular Boostrap. Jalankan code berikut untuk menambahkan library angular boostrap menggunakan Bower.
 bower install angular-bootstrap --save
--save berarti memberitahu bower untuk menambahkan angular-bootstrap ke file bower.json sebagai dependency.
Content pada app/directory

index.html
Ini merupakan core HTML page dari app kalian.

scripts/ directory
Disini adalah tempat javascript apps kalian berada.

styles/ directory
Disini adalah tempat css/sass kalian berada.

Views
Disini adalah tempat halaman template kalian berada.

Modul: /app/scripts/app.js
'use strict';

/**
* @ngdoc overview
* @name simpleAngularApp
* @description
* Main module of the application.
* # simpleAngularApp
**/

//Disini kita mengeset angular module
angular.module('simpleAngularApp', [
    'ngAnimate',
    'ngAria',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize'
  ])
  .config(function ($routeProvider) {

//Disini kita mengconfig routerProvider
//route provider dipakai untuk meng-config app routes kita.
//views/main.html template menggunakan MainCtrl sebagai controllernya.
//config dibawah simpelnya jika kita membuka '/' itu akan membuka
//Method lain yang tidak terdaftar akan teridirect ke home.

    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  }); 
Controller: /app/scripts/controllers/main.js
 'use strict';

/**
 * @ngdoc function
 * @name simpleAngularApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the simpleAngularApp
 */

angular.module('simpleAngularApp') //ini cara memasukkan controller ke dalam module
//Kita menginject $scope ke dalam dependency Angular

.controller('MainCtrl', ['$scope',function ($scope) {
//Pada kasus ini kita menambahkan collection awesomeThings untuk di display di view.
//Apapun yang kita masukkan ke dalam scope akan bisa ditampilkan di view.

 $scope.items = [
        'HTML5 Boilerplate',
        'AngularJS',
        'Karma',
        'SitePoint'
      ];
}]);
View: app/views/main.html
  <div class="hero-unit">  
   <h1>'Allo, 'Allo!</h1>  
   <p>You now have</p>  
   <ul>  
     <!-- Disini kita menggunakan AngularJS Directive  
     untuk menghitung jumlah item yang di declare di items   
     dan menampilkan mereka sebagai list item menggunakan tag {{}} -->  
     <li ng-repeat="thing in items">{{thing}}</li>  
   </ul>  
   <p>installed.</p>  
   <h3>Enjoy coding! - Yeoman</h3>  
  </div>  
View: app/index.html
 [html] <!doctype html>  
  <html>  
   <head>...</head>  
   <!-- ng-app directive memberitahu angular module mana yang kita pakai.  
   Pada kasus ini yang kita define di scripts/app.js -->  
   <body ng-app="simpleAngularApp">   
    <!-- ng-view directive menspesifik template view yang akan di load di div ini-->  
    <div class="container" ng-view></div>  
    <!-- Disini kita load AngularJS dan AngularJS resource komponen -->  
     <script src="bower_components/jquery/dist/jquery.js"></script>  
     <script src="bower_components/angular/angular.js"></script>  
     <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>  
     <script src="bower_components/angular-animate/angular-animate.js"></script>  
     <script src="bower_components/angular-aria/angular-aria.js"></script>  
     <script src="bower_components/angular-cookies/angular-cookies.js"></script>  
     <script src="bower_components/angular-resource/angular-resource.js"></script>  
     <script src="bower_components/angular-route/angular-route.js"></script>  
     <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>  
     <script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>   
    <!-- Disini kita memasukan script yang kita gunakan -->  
    <!-- build:js scripts/scripts.js -->  
    <script src="scripts/app.js"></script>  
    <script src="scripts/controllers/main.js"></script>  
    <!-- endbuild -->  
   </body>  
  </html>  

Sampai disini kita sudah membuat Angular App dan sudah sedikit tahu tentang komponen komponen yang di generate. Berikut tampilan nya jika dijalankan.

Pada kesempatan berikut nya kita akan sedikit mengedit dari apa yang sudah di generate. Bersambung ke part 2...

KumuluzEE

KumuluzEE merupakan framework pertama yang menggunakan standar Java API untuk membangun aplikasi berarsitektur microservice yang dibangun oleh sebuah software house bernama Kumuluz dari Slovenia.

KumuluzEE termasuk salah satu dari pemenang Duke’s Choice Award 2015 di San Fransisco.

Keuntungan dari framework ini untuk Java developer ialah tidak perlu mempelajari hal-hal / cara kerja baru seperti pada umumnya framework Java misalnya Spring, karena KumuluzEE menggunakan standar Java EE specification.

Komponen

Saat ini KumuluzEE sudah memiliki support untuk :
  • Servlet 3.1
  • JSP 2.3
  • EL 3.0
  • CDI 1.2
  • JPA 2.1
  • JAX-RS 2.0
  • Bean Validation 1.1
  • JSON-P 1.0
Dan pada release berikutnya akan mensupport :
  • Websocket 1.1
  • JSF 2.2
  • JAX-WS 2.2

Quick Start

Nah, sekarang kita coba membuat microservice menggunakan KumuluzEE :
  1. Gunakan Maven untuk men-generate project
  2. mvn -B archetype:generate \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DgroupId=org.nostra.kumuluz \
    -DartifactId=blog
  3. Edit file pom.xml, tambahkan properties untuk KumuluzEE
  4. <properties>
        <kumuluzee.version>1.0.0</kumuluzee.version>
    </properties>
  5. Tambahkan modul core dari KumuluzEE
  6. <dependency>
        <groupId>com.kumuluz.ee</groupId>
        <artifactId>kumuluzee-core</artifactId>
        <version>${kumuluzee.version}</version>
    </dependency>
    Modul core ini belum cukup untuk menjalankan aplikasi. Untuk itu perlu ditambahkan server seperti Jetty/Tomcat untuk menerima request dan diteruskan ke komponen Java EE untuk diproses.
  7. Tambahkan modul servlet jetty dari KumuluzEE
  8. <dependency>
        <groupId>com.kumuluz.ee</groupId>
        <artifactId>kumuluzee-servlet-jetty</artifactId>
        <version>${kumuluzee.version}</version>
    </dependency>
    Dua modul tersebut merupakan syarat minimum untuk dapat menjalankan microservice dengan standar Servlet dan file statis.
  9. Tambahkan directory webapp pada directory resources, dan buat file index.html
  10. <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <title>Kumuluz</title>
    </head>
    <body>
    <p>Hello from KumuluzEE</p>
    </body>
    </html>
  11. Tambahkan juga plugin maven untuk meng-copy library jar (dependency) ke directory target
  12. <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.10</version>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
  13. Kemudian build menggunakan perintah Maven
  14. mvn package
  15. Jalankan aplikasi dengan perintah :
  16. java -cp target/classes:target/dependency/* com.kumuluz.ee.EeApplication
Buka browser dengan url : http://localhost:8080, maka akan tampil file index.html.

Sekian, kita lanjut di blog KumuluzEE berikutnya :)

JSch - Java Secure Channel

JSch adalah library java yang pernah saya gunakan untuk membangun koneksi ke SFTP Server. JSch dirilis oleh jcraft dengan BSD License. JSch adalah pengimplementasi murni dari SSH2, jadi sangat simple tanpa penambahan fitur-fitur diluar fitur yang dimiliki oleh SSH2. Tersedia beberapa fitur authentikasi yang bisa digunakan juga, yang bisa lebih jelas dilihat pada penjelasan di http://www.jcraft.com/jsch/

Pada contoh yang akan saya berikan adalah contoh penggunaan authentikasi dengan password atau Public Private Key. Jadi bisa di remark saja salah satu baris untuk jenis authentikasi yang tidak digunakan.

Put File
 
public boolean uploadFile(String srcFileInLocal, String dstFileInServer){
    Session session = null;
    ChannelSftp channelSftp = null;
    FileInputStream localFileStream = null;
    boolean result= false;
    try{
        JSch jsch= new JSch();
        
        // untuk penggunaan file PPK sebagai authentikasi
        File ppkFile= new File("C:\key.ppk");
        jsch.addIdentity(ppkFile.getAbsolutePath()); 
        
        // username, server, dan port
        session = jsch.getSession("root", "localhost", 22 );
        
        // untuk penggunaan password sebagai authentikasi
        session.setPassword("password"); 
        
        session.setConfig("StrictHostKeyChecking", "no");
        session.setTimeout(15000);
        session.connect();
        
        channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();
        
        File localFile = new File (srcFileInLocal);
        if (localFile.exists()){
            localFileStream = new FileInputStream(localFile);
            
            channelSftp.put(localFileStream, dstFileInServer);
            localFileStream.close();
            result=true;
        }else{
            logger.warn("Local file not found " + localFile.getAbsolutePath());
        }
        
    }catch (Exception ex) {
        logger.error(ex.getMessage(), ex);
        result = false;
    }finally{
        if(channelSftp != null){
            channelSftp.disconnect();
        }
        if(session != null){
            session.disconnect();
        }
    }
    return result;
}

 


Download File
 
public boolean downloadFile(String srcFileInServer, String dstFileInLocal){
    Session session = null; 
    ChannelSftp channelSftp = null; 
    boolean result = false;
    try{ 
        JSch jsch = new JSch(); 
       
        // untuk penggunaan file PPK sebagai authentikasi
        File ppkFile = new File("C:\key.ppk");
        jsch.addIdentity(ppkFile.getAbsolutePath()); 
        
        // username, server, dan port
        session = jsch.getSession("root", "localhost", 22 );
        
        // untuk penggunaan password sebagai authentikasi
        session.setPassword("password"); 
        
        session.setConfig("StrictHostKeyChecking", "no");
        session.setTimeout(15000);
        session.connect();
        
        channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();
        
        byte[] buffer = new byte[1024]; 
        BufferedInputStream bis = new BufferedInputStream(channelSftp.get(srcFileInServer)); 
        File newFile = new File(dstFileInLocal); 
        FileOutputStream fos = new FileOutputStream(newFile); 
        BufferedOutputStream bos = new BufferedOutputStream(fos); 
        int readCount; 
        
        while( (readCount = bis.read(buffer)) > 0) { 
            System.out.println("Writing: " ); 
            bos.write(buffer, 0, readCount); 
        } 
        bis.close(); 
        bos.close();
        result=true;            
        
    }catch(Exception ex){ 
        logger.error(ex.getMessage(), ex);
        result= false;
    }finally{
        if(channelSftp != null){
            channelSftp.disconnect();
        }
        if(session != null){
            session.disconnect();
        }
    }
    
    return result;
}

 


Delete File
 
public boolean deleteRemoteFile(String fielPathInServer){
    Session session = null; 
    ChannelSftp channelSftp = null; 
    boolean result= false;
    try{ 
        JSch jsch = new JSch();
        
        // untuk penggunaan file PPK sebagai authentikasi
        File ppkFile= new File("C:\key.ppk");
        jsch.addIdentity(ppkFile.getAbsolutePath()); 
        
        // username, server, dan port
        session = jsch.getSession(username, urlHost, Integer.parseInt(portHost) );
        
        // untuk penggunaan password sebagai authentikasi
        session.setPassword("password"); 
        
        session.setConfig("StrictHostKeyChecking", "no");
        session.setTimeout(15000);
        session.connect();
        
        channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();
        
        channelSftp.rm(fielPathInServer);
        result= true;
        
    }catch(Exception ex){ 
        logger.error(ex.getMessage(), ex); 
        result = false;
    }finally{
        if(channelSftp != null){
            channelSftp.disconnect();
        }
        if(session != null){
            session.disconnect();
        }
    }
    
    return result;
}

 

Get List File
 
public List<String> getSFTPListFile(String remoteDir){
    List<String> listFiles = null;
    Session session = null;
    ChannelSftp channelSftp = null;
    
    try{
        JSch jsch= new JSch();
        
        // untuk penggunaan file PPK sebagai authentikasi
        File ppkFile= new File("C:\key.ppk");
        jsch.addIdentity(ppkFile.getAbsolutePath());
        
        // username, server, dan port
        session = jsch.getSession(username, urlHost, Integer.parseInt(portHost) );
        
        // untuk penggunaan password sebagai authentikasi
        session.setPassword("password"); 
        
        session.setConfig("StrictHostKeyChecking", "no");
        session.setTimeout(15000);
        session.connect();
        
        channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();
        
        Vector<LsEntry> listEntry= channelSftp.ls(remoteDir);
        listFiles= new ArrayList<String>();
        
        for(LsEntry lsEntry : listEntry){
            if(!lsEntry.getAttrs().isDir()){
                listFiles.add(lsEntry.getFilename());
            }
        }
        
    }catch (Exception e) {
        logger.error(e.getMessage(), e);
    }finally{
        if(channelSftp != null){
            channelSftp.disconnect();
        }
        if(session != null){
            session.disconnect();
        }
    }
    
    return listFiles;
}

 




How to Transfer Objects Between UIViewController

Dalam pengembangan aplikasi iOS, seringkali kita membutuhkan untuk mentransfer data dari satu view ke view lainnya. Misalnya pada kasus ketika kita ingin menampilkan informasi detil sebuah user profile hasil dari pencarian user. Bagaimana cara kita melakukan hal tersebut pada iOS? Kesempatan kali ini saya ingin berbagi cara sederhana untuk melakukannya dengan menggunakan bahasa pemrograman Swift dan storyboard.

Pada pengembangan aplikasi iOS menggunakan Xcode, alur dari view aplikasi dapat didisain dengan menggunakan fitur storyboard. Storyboard merupakan fitur yang sangat bermanfaat karena pengembang aplikasi dapat merancang bentuk dan alur dari aplikasi secara independen tidak tergantung dengan kode logika dari aplikasi. Kode logika aplikasi dapat disambungkan dan dilepaskan dengan storyboard dengan usaha yang relatif minimal (cukup Ctrl+Drag). Saya sempat memiliki pengalaman ketika project files saya corrupt sehingga saya harus mendisain ulang storyboard beserta view-nya dari awal. Ketika sudah selesai, storyboard dan kode logika aplikasi dapat disambungkan kembali. Agak banyak, namun setidaknya tidak harus mengkodekan ulang. :)

Gambar di atas menunjukkan storyboard yang saya gunakan pada artikel kali ini. Storyboard aplikasi ini cukup sederhana di mana hanya terdapat 2 view. Pada view pertama hanya terdapat sebuah tombol yang ketika ditekan akan menginisiasi perpindahan view ke view pada sebelah kanan melalui show segue (panah). Perpindahan data di sini hanya akan memindahkan nilai yang dimasukkan pada textfield sehingga label "Nilai" pada view sebelah kanan akan berubah menjadi nilai apapun yang dimasukkan di textfield view pertama. Berilah nama pada show segue tersebut dengan nama yang identik dalam scope 1 project. Pada contoh ini saya beri nama "transferDataSegue". Buat 2 subclass dari UIViewController dan asosiasikan dengan masing-masing view pada storyboard. Saya mengasosiasikan view pertama dengan StartViewController dan view kedua dengan FinishViewController.


Bind textfield di view pertama ke IBOutlet pada StartViewController. Kemudian bind pula label di view kedua ke IBOutlet pada FinishViewController. Buat sebuah variable pada FinishViewController untuk meletakkan nilai yang dipindahkan dari StartViewController. Kunci dari transfer data antarview pada iOS adalah pada fungsi prepareForSegue dari UIViewController. Override fungsi tersebut kemudian isi agar sesuai seperti gambar berikut:

Fungsi prepareForSegue ini akan selalu dipanggil setiap kali terdeteksi adanya transisi dari sebuah view ke view yang lain. Jika segue yang dihubungkan lebih dari 1, maka transisi dapat terjadi beberapa kemungkinan. Oleh karena itu kita membutuhkan identifier unik untuk segue yang dibahas sebelumnya. Pada fungsi ini langkah pertama kita harus menentukan segue mana yang akan dieksekusi, dengan cara memeriksa identifier-nya. Variabel identifier pada object segue berisikan informasi identifier yang sedang dijalankan.

Setelah kita sudah memperoleh object segue yang sedang dieksekusi, kita pastikan terlebih dahulu apakah object segue tersebut memiliki kaitain dengan UIViewController tujuan. UIViewController tujuan memiliki relasi dengan sebuah segue object yaitu pada variabel destinationViewController yang merupakan FinishViewController. Jika sudah tervalidasi, maka proses transfer data antarview cukup dilakukan semudah assignment variabel biasa. Pada FinishViewController, load nilai yang telah diterima dengan meng-assign-nya ke IBOutlet textfield pada fungsi viewDidLoad.

Silahkan coba dijalankan. Sangat mudah bukan? ;)




Mengecek nilai atribut dalam List of object di dalam List dengan lambda expression

Seringkali kita mengalami kasus dimana harus memvalidasi input value dari atribut List of object di dalam sebuah List yang masuk sebelum di proses.
Sebagai contoh terdapat 3 object yang saling berkaitan :
RateRequestVO
public class RateRequestVO extends BaseVO { 
   private String email;  
   private List<OrderRateVO> orders; 
//getter setter
}
OrderRateVO :
public class OrderRateVO {
   private String orderId;
   private List<RateVO> rates;

//getter setter
}
RateVO :
public class RateVO {
   private String param;
   private Double rate;

//getter setter
}
Case :
Input adalah OrderRequestVO
Setiap request yang masuk harus mengecek nilai rate (di RateVO) tidak boleh negatif.
DI java sebelum nya kita harus melakukan loop berulang dan mengecek setiap objectnya, namun di Java 8, dengan lamda expression, permasalahan-permasalahan seperti ini bisa diselesaikan hanya dalam 1 baris.
Berikut merupakan contoh code nya :
boolean containNullNegative = vo.getOrders().stream().allMatch(
       a -> a.getRates().stream().anyMatch(rate -> rate.getRate() <= 0)
);

selamat mencoba, happy coding ^^v

Query di MongoDB : aggregation

Dikutip dari situsnya mongodb :
Aggregations operations process data records and return computed results. Aggregation operations group values from multiple documents together, and can perform a variety of operations on the grouped data to return a single result.
Singkatnya, proses agregasi dalam mongodb adalah memproses data (record) untuk dikumpulkan menjadi satu atau dipisah-pisah. 
Sebagai contoh terdapat data harga barang (nama, harga, kategori). Ingin mendapatkan harga rata-rata untuk tiap kategori barang, proses ini dinamakan agregasi.
Dalam tulisan kali ini saya akan langsung memberikan contoh kasus :
MongoDB menyinpan data dalam format JSON, dalam kasus kali ini data disimpan dengan format mempunyai format seperti dibawah ini. Data rating untuk masing-masing email (email == unique) dimana 1 email mempunyai child order, dan masing-masing order mempunyai child parameter dan nilai rating di setiap order.
/* 1 */
{
    "_id" : ObjectId("56d7c3d23004aa334327e109"),
    "_class" : "com.rating.SellerRate",
    "email" : "bibin@me.co",
    "orders" : [ 
        {
            "orderId" : "O1GT34QWKI",
            "rates" : [ 
                {
                    "param" : "QUALITY",
                    "rate" : 2.7999999523162842
                }, 
                {
                    "param" : "SERVICE",
                    "rate" : 1.0000000000000000
                }
            ]
        }, 
        {
            "orderId" : "OGHYJUKL",
            "rates" : [ 
                {
                    "param" : "QUALITY",
                    "rate" : 1.7000000476837158
                }, 
                {
                    "param" : "SERVICE",
                    "rate" : 3.2000000476837158
                }
            ]
        }
    ],
    "date" : "20160303",
    "createdBy" : "cs@nana.co",
    "modifiedBy" : "cs@nana.co",
    "creationTime" : NumberLong(1456980946865),
    "modificationTime" : NumberLong(1457326319159)
}

/* 2 */
{
    "_id" : ObjectId("56e6e6ecb5f1fbfb92892d20"),
     "_class" : "com.rating.SellerRate",
    "email" : "mimi@me.co",
    "orders" : [ 
        {
            "orderId" : "O1C45HWKI",
            "rates" : [ 
                {
                    "param" : "QUALITY",
                    "rate" : 2.7999999999999998
                }, 
                {
                    "param" : "SERVICE",
                    "rate" : 1.0000000000000000
                }
            ]
        }, 
        {
            "orderId" : "OF46JKJUKL",
            "rates" : [ 
                {
                    "param" : "QUALITY",
                    "rate" : 3.3999999999999999
                }, 
                {
                    "param" : "SERVICE",
                    "rate" : 4.2999999999999998
                }
            ]
        }
    ],
    "date" : "20160303",
    "createdBy" : "cs@nana.co",
    "modifiedBy" : "cs@nana.co",
    "creationTime" : NumberLong(1456980946865),
    "modificationTime" : NumberLong(1457326319159)
}
Expected Result :
[
   {
      "email":"bibin@me.co",
      "rates":[
         {
            "param":"SERVICE",
            "rate":2.100000023841858
         },
         {
            "param":"QUALITY",
            "rate":2.25
         }
      ]
   },
   {
      "email":"mimi@me.co",
      "rates":[
         {
            "param":"SERVICE",
            "rate":2.7
         },
         {
            "param":"QUALITY",
            "rate":1.5
         }
      ]
   }
]
Berikut, kurang lebih Query yang harus dijalankan agar mendapat hasil seperti yang di inginkan.
db.seller_rates.aggregate([
    {
        $unwind : "$orders"
    },
    {
        $unwind : "$orders.rates"
    },
    {
        $project : {
            email : "$email",
            param : "$orders.rates.param",
            rate : "$orders.rates.rate"
        }
    },
    {
        $group : {
            _id : {
                email : "$email", param : "$param"
            },
            rate : {
                $avg : "$rate"
            }
        }
    },
    {
        $project : {
            email : "$_id.email",
            param : "$_id.param",
            rate : "$rate"
        }
    },
    {
        $group : {
            _id : "$email",
            rates : { $push : "$$ROOT" }
        }
    }

])

$unwind

$unwind merupakan perintah untuk mengeluarkan child menjadi row. Dalam kasus ini 1 email mempunyai 2 orders, maka jika operasi { "$unwind" : "$orders"} gambaran singkatnya kurang lebih digambarkan dibawah ini, data awal :
{
   "email":"bibin@me.co",
   "orders":[
      {
         "orderId":"O1GT34QWKI",
         "rates":[
            {
               "param":"QUALITY",
               "rate":2.7999999523162842
            },
            {
               "param":"SERVICE",
               "rate":1.0000000000000000
            }
         ]
      },
      {
         "orderId":"OGHYJUKL",
         "rates":[
            {
               "param":"QUALITY",
               "rate":1.7000000476837158
            },
            {
               "param":"SERVICE",
               "rate":3.2000000476837158
            }
         ]
      }
   ]
}
Hasil $unwind :
{
   "result":[
      {
         "email":"bibin@me.co",
         "orders":{
            "orderId":"O1GTLAQWKI",
            "rates":[
               {
                  "param":"QUALITY",
                  "rate":2.7999999523162842
               },
               {
                  "param":"SERVICE",
                  "rate":1.0000000000000000
               }
            ]
         }
      },
      {
         "email":"bibin@me.co",
         "orders":{
            "orderId":"OGHYJUKL",
            "rates":[
               {
                  "param":"QUALITY",
                  "rate":1.7000000476837158
               },
               {
                  "param":"SERVICE",
                  "rate":3.2000000476837158
               }
            ]
         }
      }
   ]
}

$project

Operasi $project memungkinkan kita hanya memilih spesifik field yang akan ditampilkan. Contoh jika Query nya demikian (dengan menggunakan data existing).
db.seller_rates.aggregate([
    {
        $unwind : "$orders"
    },
    {
        $unwind : "$orders.rates"
    },
    {
        $project : {
            email : "$email",
            param : "$orders.rates.param",
            rate : "$orders.rates.rate"
        }
    }
])
Hasil $project :
/* 1 */
{
    "result" : [ 
        {
            "_id" : ObjectId("56d7c3d23004aa334327e109"),
            "email" : "bibin@me.co",
            "param" : "QUALITY",
            "rate" : 2.7999999523162842
        }, 
        {
            "_id" : ObjectId("56d7c3d23004aa334327e109"),
            "email" : "bibin@me.co",
            "param" : "SERVICE",
            "rate" : 1.0000000000000000
        }, 
        {
            "_id" : ObjectId("56d7c3d23004aa334327e109"),
            "email" : "bibin@me.co",
            "param" : "QUALITY",
            "rate" : 1.7000000476837158
        }, 
        {
            "_id" : ObjectId("56d7c3d23004aa334327e109"),
            "email" : "bibin@me.co",
            "param" : "SERVICE",
            "rate" : 3.2000000476837158
        }, 
        {
            "_id" : ObjectId("56e6e6ecb5f1fbfb92892d20"),
            "email" : "mimi@me.co",
            "param" : "QUALITY",
            "rate" : 2.7999999999999998
        }, 
        {
            "_id" : ObjectId("56e6e6ecb5f1fbfb92892d20"),
            "email" : "mimi@me.co",
            "param" : "SERVICE",
            "rate" : 1.0000000000000000
        }, 
        {
            "_id" : ObjectId("56e6e6ecb5f1fbfb92892d20"),
            "email" : "mimi@me.co",
            "param" : "QUALITY",
            "rate" : 3.3999999999999999
        }, 
        {
            "_id" : ObjectId("56e6e6ecb5f1fbfb92892d20"),
            "email" : "mimi@me.co",
            "param" : "SERVICE",
            "rate" : 4.2999999999999998
        }
    ],
    "ok" : 1.0000000000000000

}


$group

Jika dianalogikan dengan MySQL $group sama dengan operasi GROUP BY. Dalam kasus kita kali ini, bahwa ingin menghitung rata-rata rating berdasarkan email dan parameter. Berikut merupakan contoh query nya :
db.seller_rates.aggregate([
    {
        $unwind : "$orders"
    },
    {
        $unwind : "$orders.rates"
    },
    {
        $project : {
            email : "$email",
            param : "$orders.rates.param",
            rate : "$orders.rates.rate"
        }
    },
    {
        $group : {
            _id : {
                email : "$email", param : "$param"
            },
            rate : {
                $avg : "$rate"
            }
        }
    }

])
Hasil $group :
/* 1 */
{
    "result" : [ 
        {
            "_id" : {
                "email" : "mimi@me.co",
                "param" : "SERVICE"
            },
            "rate" : 2.6499999999999999
        }, 
        {
            "_id" : {
                "email" : "bibin@me.co",
                "param" : "SERVICE"
            },
            "rate" : 2.1000000238418579
        }, 
        {
            "_id" : {
                "email" : "mimi@me.co",
                "param" : "QUALITY"
            },
            "rate" : 3.0999999999999996
        }, 
        {
            "_id" : {
                "email" : "bibin@me.co",
                "param" : "QUALITY"
            },
            "rate" : 2.2500000000000000
        }
    ],
    "ok" : 1.0000000000000000
}
Pada hasil Query di atas, terlihat bahwa ada attribute “_id” selalu muncul, atibut ini yang digunakan sebagai key dalam operasi GROUP BY dan field “_id” merupakan mandatory ketika melakukan operasi GROUP BY. 

$push

$push merupakan operasi di dalam $group, satu level dengan $avg, $max, $sum, dll. Operasi $push akan mengembalikan array dari semua value dengan key yang sama.
Dari contoh query di bawah ini, dari hasil query sebelum nya, bahwa email dijadikan sebagai key, dan di push sebagai root dan attribut yang lain otomatis sebagai child (list of array).
db.seller_rates.aggregate([
    {
        $unwind : "$orders"
    },
    {
        $unwind : "$orders.rates"
    },
    {
        $project : {
            email : "$email",
            param : "$orders.rates.param",
            rate : "$orders.rates.rate"
        }
    },
    {
        $group : {
            _id : {
                email : "$email", param : "$param"
            },
            rate : {
                $avg : "$rate"
            }
        }
    },
    {
        $project : {
            email : "$_id.email",
            param : "$_id.param",
            rate : "$rate"
        }
    },
    {
        $group : {
            _id : "$email",
            rates : { $push : "$$ROOT" }
        }
    }
])
Hasil akhir :
/* 1 */
{
    "result" : [ 
        {
            "_id" : "bibin@me.co",
            "rates" : [ 
                {
                    "_id" : {
                        "email" : "bibin@me.co",
                        "param" : "SERVICE"
                    },
                    "rate" : 2.1000000238418579,
                    "email" : "bibin@me.co",
                    "param" : "SERVICE"
                }, 
                {
                    "_id" : {
                        "email" : "bibin@me.co",
                        "param" : "QUALITY"
                    },
                    "rate" : 2.2500000000000000,
                    "email" : "bibin@me.co",
                    "param" : "QUALITY"
                }
            ]
        }, 
        {
            "_id" : "mimi@me.co",
            "rates" : [ 
                {
                    "_id" : {
                        "email" : "mimi@me.co",
                        "param" : "SERVICE"
                    },
                    "rate" : 2.6499999999999999,
                    "email" : "mimi@me.co",
                    "param" : "SERVICE"
                }, 
                {
                    "_id" : {
                        "email" : "mimi@me.co",
                        "param" : "QUALITY"
                    },
                    "rate" : 3.0999999999999996,
                    "email" : "mimi@me.co",
                    "param" : "QUALITY"
                }
            ]
        }
    ],
    "ok" : 1.0000000000000000
}
selamat mencoba ^^v

Referensi :
[ 1 ] https://docs.mongodb.org/manual/aggregation/
[ 2 ] https://docs.mongodb.org/manual/reference/operator/aggregation/group/
[ 3 ] https://docs.mongodb.org/manual/reference/operator/aggregation/project/
[ 4 ] https://docs.mongodb.org/manual/reference/operator/aggregation/unwind/
[ 5 ] https://docs.mongodb.org/manual/reference/operator/aggregation/push/#grp._S_push

Materialize VS Bootstrap

Pada kesempatan sebelumnya kita telah berkenalan dengan materialize. Pada kesempatan kali ini saya akan melihat sedikit beberapa atribut yang dimiliki baik oleh materialize maupun Bootstrap.

Sebelumnya kita bahas sedikit mengenai Bootstrap. Seperti halnya Materialize, Bootstrap juga merupakan sebuah framework atau lebih tepatnya html,css,js framework. Bootstrap mempermudah developer dalam membuat tampilan yang layak dilihat. Bootstrap sendiri di buat oleh Twitter dengan tujuan untuk mempermudah pembuatan responsive website. Sedangkan Materialize seperti sudah dijelaskan sebelumnya bahwa google mengusung kembali material design dalam bentuk web.

Apabila dilihat dari spesifikasinya, maka Bootstrap dan Materialize akan memiliki data seperti ini :
Atribut Bootstrap       Materialize                       
IE 8+ 10+
Firefox      support support
Chrome support support
Opera support support
LESS support ( drop on version 4 )  not support
SASS support support


Berikutnya mari kita mencoba beberapa component dari kedua framework tersebut.

  1. Collapsible
    Yap, collapsible adalah hal yang cukup merepotkan untuk dibuat ketika kita masih tidak memiliki banyak pilihan framework. Saat ini banyak framework yang telah mempermudah kita dalam pembuatanannya termasuk Boostrap dan Materialize

    Boostrap Code :
    <div class="container">  
      <a href="#demo" class="btn btn-info" data-toggle="collapse">collapsible</a>
      <div id="demo" class="collapse">   
       Lorem ipsum dolor sit amet, consectetur adipisicing elit,    
       sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
       Ut enim ad minim veniam,    
       quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.  
      </div>
    </div>
    Result :

    video

    Materialize 
    Html :
     <ul class="collapsible popout" data-collapsible="accordion">
        <li>
          <div class="collapsible-header"><i class="material-icons">filter_drama</i>First</div>
          <div class="collapsible-body"><p>Lorem ipsum dolor sit amet.</p></div>
        </li>
        <li>
          <div class="collapsible-header"><i class="material-icons">place</i>Second</div>
          <div class="collapsible-body"><p>Lorem ipsum dolor sit amet.</p></div>
        </li>
        <li>
          <div class="collapsible-header"><i class="material-icons">whatshot</i>Third</div>
          <div class="collapsible-body"><p>Lorem ipsum dolor sit amet.</p></div>
        </li>
      </ul>
    Javascript :
     $(document).ready(function(){
        $('.collapsible').collapsible({
          accordion : false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
        });
      });
    Result  :

    video
  2.  Form
    Membuat web tentunya tidak terlepas dari form. Berikut merupakan sample pembuatan form dari kedua framework tersebut.
    BootstrapCode :
    <form role="form">
        <div class="form-group">
          <label for="email">Email:</label>
          <input type="email" class="form-control" id="email" placeholder="Enter email">
        </div>
        <div class="form-group">
          <label for="pwd">Password:</label>
          <input type="password" class="form-control" id="pwd" placeholder="Enter password">
        </div>
        <div class="checkbox">
          <label><input type="checkbox"> Remember me</label>
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
    Result :
    Default form dari boostrap tidak terlalu banyak berbeda dari form yang telah disediakan html.

    video


    Materialize
    Code :
    <div class="row">
        <form class="col s12">
          <div class="row">
            <div class="input-field col s6">
              <input id="first_name" type="text" class="validate">
              <label for="first_name">First Name</label>
            </div>
            <div class="input-field col s6">
              <input id="last_name" type="text" class="validate">
              <label for="last_name">Last Name</label>
            </div>
          </div>
          <div class="row">
            <div class="input-field col s12">
              <input id="password" type="password" class="validate">
              <label for="password">Password</label>
            </div>
          </div>
          <div class="row">
            <div class="input-field col s12">
              <input id="email" type="email" class="validate">
              <label for="email">Email</label>
            </div>
          </div>
          <div class="row">
            <div class="input-field col s12">
              <input type="checkbox" id="test6" checked="checked" />
              <label for="test6">Yellow</label>
            </div>
          </div>
          <div class="row">
            <div class="input-field col s12">
              <input type="checkbox" class="filled-in" id="filled-in-box" checked="checked" />
              <label for="filled-in-box">Red</label>
            </div>
          </div>
          <div class="row">
            <div class="input-field col s12">
              <p class="range-field">
                <input type="range" id="test5" min="0" max="100" />
              </p>
            </div>
          </div>
        </form>
      </div>
    Result :
    Default Form yang di sediakan materialize lebih berkesan casual. Dan ada tambahan input menarik berupa range yang mirip seperti slider. Dan masih ada beberapa input type lain seperti switches yang dapat dilihat pada : http://materializecss.com/forms.html
    video


    Masih banyak lagi atribut lain yang dimiliki keduanya. Dari sana kita bisa melihat perbedaan design yang diusung oleh kedua framework tersebut. Dari segi tampilan, apabila kita membandingkan antara materialize dan bootstrap maka tidak ada yang lebih baik antara satu dengan yang lainnya. Yang perlu dipikirkan adalah website seperti apa yang ingin di bangun. Dari situlah baru kita dapat menentukan framework apa yang sebaiknya kita gunakan.

    Sekian sekilas cerita dari saya. Happy eksploring~ :D