Apa itu Eclipse Tycho?

Ini adalah pertanyaan yang muncul saat saya sedang membaca panduan untuk men-build Cloud Foundry Integration For Eclipse, plugin resmi untuk Eclipse yang mempermudah deploy aplikasi yang dibuat di Eclipse ke Cloud Foundry.  Ini pertama kalinya saya mendengar nama Tycho disebut.  Apa sebenarnya benda itu?

Secara garis besar, Tycho adalah sebuah plugin Maven yang memungkinkan pembuat plugin di Eclipse memakai Maven.  Selama ini, saat membuat plugin Eclipse, semua informasi seperti dependencies diletakkan di file MANIFEST.MF dan plugin.xml.  Bila saya memakai Maven, berarti saya harus menduplikasikan informasi tersebut ke file khas Maven, yaitu pom.xml.  Tentu saja ini akan merepotkan!  Dan itulah alasan Tycho terlahir.

Agar proyek plugin memakai Maven, maka saya men-klik kanan nama proyek, memilih menu Configure, Convert to Maven Project.

Pada proyek yang memakai Tycho, saya akan menemukan baris seperti berikut ini di pom.xml:

<plugin>
  <groupId>org.eclipse.tycho</groupId>
  <artifactId>tycho-p2-plugin</artifactId>
  <version>${tycho-version}</version> <!-- versi Tycho yang dipakai -->
  ...
</plugin>

Baris di atas menunjukkan bahwa Maven perlu men-download dan memakai Tycho.  Saya juga akan menemukan baris seperti ini di pom.xml:

<packaging>eclipse-plugin</packaging>

Ini menunjukkan apa hasil akhir yang akan dibuat oleh Maven.  Nilai lain yang bisa dipakai adalah eclipse-feature.

Setelah melakukan konversi menjadi proyek Maven, bila ini pertama kali, saya akan menemukan banyak pesan kesalahan di pom.xml.  Untuk itu saya men-klik kanan nama proyek, memilih Maven, Update Project…  Lalu, saya memilih semua proyek yang ada dengan men-klik tombol Select All.  Saya juga memberi tanda centang pada Force Update of Snapshots/Releases.  Setelah itu saya men-klik tombol OK.  Saya memastikan komputer terhubung ke internet karena Maven perlu men-download  file-file yang dibutuhkan.  Selain itu, juga tersedia Lifecycle Mappings m2e pada proyek yang memakai Tycho, yaitu  Tycho Configurator, yang dapat di-install melalui m2e Marketplace.

Tapi saya menemukan bahwa tidak semuanya bisa diproses dari m2e.  Misalnya, di proyek Cloud Foundry Integration For Eclipse, saya harus membuka command prompt untuk memberikan perintah Maven secara manual untuk pom.xml yang berada di direktori paling luar (bukan dari bagian proyek manapun).  Ini adalah parent POM yang direferensikan oleh POM di masing-masing proyek.

Untuk menghasilkan output pada proyek open source Cloud Foundry Integration For Eclipse, saya memberikan perintah seperti berikut ini:

C:>mvn -Dmaven.test.skip=true -Pe36 package
...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] org.cloudfoundry.ide.eclipse.server.parent ........ SUCCESS [2.746s]
[INFO] org.cloudfoundry.ide.eclipse.server.core .......... SUCCESS [10.062s]
[INFO] org.cloudfoundry.ide.eclipse.server.rse ........... SUCCESS [0.998s]
[INFO] org.cloudfoundry.ide.eclipse.server.ui ............ SUCCESS [9.438s]
[INFO] org.cloudfoundry.ide.eclipse.server.branding ...... SUCCESS [0.515s]
[INFO] org.cloudfoundry.ide.eclipse.server ............... SUCCESS [1.030s]
[INFO] org.cloudfoundry.ide.eclipse.server.tests ......... SUCCESS [2.870s]
[INFO] org.cloudfoundry.ide.eclipse.server.source ........ SUCCESS [0.343s]
[INFO] org.cloudfoundry.ide.eclipse.server.sdk ........... SUCCESS [0.468s]
[INFO] Cloud Foundry Integration for Eclipse ............. SUCCESS [6.365s]
[INFO] org.cloudfoundry.ide.eclipse.server.target ........ SUCCESS [0.952s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0:0.761s
[INFO] Finished at: Fri Dec 28 13:35:45 ICT 2012
[INFO] Final Memory: 77M/1024M
[INFO] ------------------------------------------------------------------------

Parameter -D yang memberi nilai maven.test.skip dengan true menyebabkan unit test tidak dikerjakan.  Sementara itu, parameter -P akan memilih profil yang aktif, yaitu e36.  Profil ini didefinisikan di pom.xml Cloud Foundry Integeration For Eclipse.  Btw, pada saat pertama kali dijalankan, perintah ini membutuhkan waktu lama karena ia akan men-download file yang dibutuhkan ke dalam repository lokal Maven.

Hasil akhirnya adalah sebuah folder dengan nama org.cloudfoundry.ide.eclipse.server.site, dimana folder ini adalah folder site yang sudah berisi hasil build plugin dan siap dipakai oleh pengguna bila diletakkan di web server.  Selain itu, juga ada versi ZIP untuk distribusi manual.

Semua proses build ini berlangsung dengan 1 perintah Maven di command line.  Tycho memungkinkan Maven untuk melakukan ini.  Sebagai perbandingan, tanpa Maven dan Tycho, saya harus men-klik tampilan dashboard plugin di Eclipse RCP.  Sebenarnya tidak beda repot.  Tapi lain halnya bila dibutuhkan nightly snapshot (rilis harian) dan continuous integration (pengujian secara periodik dan otomatis) dimana operasi mouse di GUI tidak bisa dijadwalkan untuk dikerjakan secara otomatis.

Tugas Tycho hanya sampai disini!  Bila misalnya ada masalah dependency di IDE Eclipse RCP, saya tetap harus menyelesaikannya.  Misalnya seluruh dependencies telah di-download oleh Maven, tapi Eclipse RCP mungkin tidak tahu harus mencari dimana.  Bila terjadi hasil seperti ini, saya perlu memilih menu Window, Preferences, Plug-in Development.  Lalu pada Target Platform, saya bisa meng-edit target yang aktif untuk menambahkan direktori baru yang berisi plugin yang dibutuhkan.

Men-setup Querydsl Di Eclipse

Untuk membuat kode program dengan memakai Querydsl, saya harus membuat class khusus berdasarkan domain class yang ada.  Misalnya, untuk class User, harus dibuat class QUser.  Untungnya, saya tidak perlu melakukan ini secara manual karena Querydsl akan memakai APT (Annotation Processing Tool) untuk menghasilkan class tersebut otomatis.

Bicara soal menghasilkan kode program secara otomatis, saya teringat seorang teman yang sedang membuat tesis dengan memakai framework PHP Symfony.  Ia mengetikkan sebuah perintah di command line untuk menghasilkan presentation layer secara otomatis berdasarkan domain object model.  Agar mudah mencari perintah yang dibutuhkan suatu saat nanti, ia mencatat semua command line yang dibutuhkan dalam notepad.  Jika domain object model-nya berubah suatu saat nanti, ia akan memberikan perintah update.  Ia tidak ingin melakukan otomatisasi dan mencari IDE yang mendukung Symfony.  Sebagai perbandingan, di Java, Apache Maven adalah sebuah “tool” serupa (membuat struktur proyek, menghapus folder output, menjalankan proyek, dsb)  yang didukung oleh kebanyakan IDE populer seperti Eclipse dan NetBeans.

Querydsl APT akan mencari annotation @Entity untuk setiap class yang ada, dan bila menemukannya, akan membuat class metada untuk query nanti.  Berbeda dengan teman saya, saya menginginkan sebuah kenyamanan penuh.   Saya ingin semuanya dilakukan secara otomatis setiap kali domain class saya berubah.  Dan saya ingin bisa langsung memakai class yang dihasilkan pada saat itu juga.  Bagaimana caranya?

Saya akan memakai STS 3.1.0 yang berbasiskan Eclipse 4.2.1.  Langkah pertama yang saya lakukan adalah memastikan bahwa Eclipse dijalankan oleh JDK bukan JRE.  Untuk itu, saya mengubah file STS.ini di folder instalasi STS.  Bila memakai Eclipse biasa, maka nama file konfigurasinya adalah Eclipse.ini.  Saya  menambahkan  baris berikut ini pada file konfigurasi tersebut:

-vm
C:\Progra~1\Java\jdk1.7.0_09\bin\javaw.exe

Saya perlu menyesuaikan lokasi direktori di atas dengan lokasi instalasi JDK yang ada di komputer.  Setelah melakukan perubahan file konfigurasi Eclipse, saya segera menjalankan Eclipse.

Langkah berikutnya adalah men-install connector m2e-apt untuk m2e (m2e adalah plugin Eclipse yang berinteraksi dengan Apache Maven).  Caranya adalah memilih Window, Preferences.  Kemudian saya memilih Maven, Discovery.  Klik pada tombol Open Catalog.  Saya memastikan bahwa saya sedang terkoneksi ke internet karena Eclipse akan men-download catalog URL. Pada daftar catalog yang muncul, beri tanda centang pada m2e-apt dan klik tombol Finish seperti yang terlihat pada gambar berikut ini:

Menambahkan m2e-apt di Eclipse

Menambahkan m2e-apt di Eclipse

Lanjutkan proses instalasi dengan mengikuti wizard yang ada.  Setelah selesai, restart Eclipse.  Bila muncul pesan kesalahan seperti berikut ini:

You need to run build with JDK or have tools.jar on the classpath.  If this occures during eclipse build make sure you run eclipse under JDK as well (com.mysema.maven:apt-maven-plugin:1.0.6:process:default:generate-sources)

Pastikan bahwa Eclipse telah dijalankan melalui JDK bukan JRE.

m2e-apt akan memungkinkan Eclipse untuk mengenali kode program yang dihasilkan secara dinamis.  Untuk mengaktifkannya, saya kembali memilih menu Window, Preferences.   Pada menu Maven, kini terdapat submenu baru yaitu Annotation Processing.   Saya akan memilih Experimental: Delegate Annotation Processing to maven plugins (for maven-processor-plugin only) dan men-klik tombol OK, seperti pada gambar berikut ini:

Mengaktifkan m2e-apt

Mengaktifkan m2e-apt

Sekarang, saya akan menyertakan dependency Querydsl pada Maven di proyek saya.  Caranya adalah dengan mendouble klik file pom.xml, kemudian memilih tab Dependencies.  Lalu klik tombol Add, untuk menambahkan dependency berikut ini:

  1. group-id: com.mysema.querydsl;  artifact-id: querydsl-apt;  version:  2.8.1; classifier: jpa; scope: provided
  2. group-id: com.mysema.querydsl;  artifact-id: querydsl-jpa;  version: 2.8.1
  3. group-id: org.slf4j;  artifact-id: slf4j-api; version: 1.6.6

Yang akan melakukan annotation processing adalah artifact querydsl-apt.  Karena saya memakai JPA sebagai persistence layer, maka saya memastikan bahwa classifier yang dipakai adalah jpa.  Artifact versi generik (tanpa classifier) tidak akan bekerja sama dengan apt-m2e.

Langkah berikutnya adalah saya perlu memberi tahu Maven, tepatnya apt2-me2, untuk mengerjakan querydsl-apt setiap kali proyek saya di-compile.  Untuk itu, saya akan membuka tab pom.xml sehingga saya dapat mengedit file pom.xml secara langsung. Saya menambahkan bagian berikut ini:

<build>
  <plugins>
    <plugin>
      <groupId>org.bsc.maven</groupId>
      <artifactId>maven-processor-plugin</artifactId>
      <version>2.0.5</version>
      <executions>
        <execution>
          <goals>
            <goal>process</goal>
          </goals>
          <configuration>
            <outputDirectory>target/generated-sources/java</outputDirectory>
            <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
          </configuration>
        </execution>
      </executions>
      <dependencies>
        <dependency>
          <groupId>com.mysema.maven</groupId>
          <artifactId>apt-maven-plugin</artifactId>
          <version>1.0.6</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

Yang saya lakukan di atas adalah mendefinisikan plugin maven-processor-plugin yang akan mengerjakan apt-maven-plugin (lihat di bagian <execution> dan <dependency>).   m2e-apt akan mengetahui apa saja yang generated source yang harus disertakan sebagai bagian dari proyek berdasarkan definisi di atas.

Setelah itu, saya men-klik kanan nama proyek, memilih Maven, Update Project… untuk memperbaharui Maven.  Saya tidak lupa memastikan komputer sedang terkoneksi ke internet karena Maven mungkin perlu men-download beberapa file yang dibutuhkan.

Setelah proses update selesai, akan ada sebuah folder baru yang berisi source Java, yaitu target/generated-sources/java.  Folder ini berisi file yang dihasilkan oleh Querydsl APT berdasarkan domain class yang ada.  Setiap kali saya melakukan perubahan pada domain class, isi dari folder ini juga akan diperbaharui secara otomatis.   Gambar berikut ini memperlihatkan struktur proyek Eclipse saya:

Struktur proyek setelah m2e-apt aktif

Struktur proyek setelah m2e-apt aktif

Membuat Proyek Maven “Lokal” Untuk Disertakan Dalam Proyek Lain

Untuk menyertakan proyek lain (seperti framework atau helper library), biasanya saya tinggal menambahkan file JAR.  Akan tetapi, bila proyek dari awal sudah menggunakan Maven, alangkah baiknya bila proyek lain disertakan melalui dependency Maven di file pom.xml.  Sebagai contoh, saya perlu meng-edit DbUnit karena ada beberapa “kejanggalan” yang belum diperbaiki pembuatnya, tetapi karena tidak yakin semua orang butuh perbaikan ini, maka saya ingin DbUnit yang sudah dirubah ini hanya dipakai untuk keperluan internal.  Bagaimana caranya?

Saya mulai dengan memilih menu File, New, Project di Eclipse. Lalu saya memilih MavenMaven Project dan men-klik tombol Next.  Pada dialog yang muncul, saya memberi tanda centang di bagian Create a simple project (skip archetype selection).  Lalu saya men-klik tombol Next.  Pada dialog berikutnya, saya mengisi informasi untuk proyek Maven yang akan dibuat seperti pada gambar berikut ini:

Mengisi informasi artifact Maven

Mengisi informasi artifact Maven

Lalu, saya men-klik tombol Finish.

Eclipse akan membuat sebuah proyek baru dengan nama dbunit.  Berikutnya, saya perlu men-copy kode program original DbUnit di package org.dbunit ke folder src/main/java.  Struktur proyek akan terlihat seperti gambar berikut ini:

Struktur Proyek

Struktur Proyek

Berikutnya, saya men-double click pada file pom.xml.  File pom.xml adalah file milik Apache Maven yang berisi seluruh informasi tentang proyek tersebut.  Karena DbUnit  membutuhkan dependency lain, saya harus menyertakan dependency tersebut.  Saya men-klik tab Dependencies.  Kemudian saya menambahkan dependency baru dengan men-klik tombol Add, mengisi Group Id, Artifact Id dan Version yang dibutuhkan oleh DbUnit.  Berikut ini adalah daftar dependency yang dibutuhkan untuk men-build DbUnit:

  1. Group Id:  org.slf4j;  Artifact Id: slf4j-api; Version: 1.6.6
  2. Group Id: commons-collections;  Artifact Id: commons-collections; Version: 3.2.1
  3. Group Id: junit;  Artifact Id: junit; Version: 3.8.2; Scope: test
  4. Group Id: ant;  Articact Id: ant;  Version: 1.7.0;  Scope: provided
  5. Group Id: org.apache.poi;  Artifact Id: poi;  Version: 3.2-FINAL;  Scope: provided

Karena saya sedang terkoneksi ke Internet, begitu selesai mengisi dependency yang ada dan men-save file pom.xml, Eclipse akan secara otomatis men-download file artifact yang dibutuhkan.

Sampai disini, saya tinggal melakukan perubahan kode program sesuai kebutuhan dan tujuan.

Setelah perubahan kode program selesai dilakukan, saya tidak bisa langsung memakai hasil perubahan di proyek lain.  Saya terlebih dahulu harus men-install proyek ke repository lokal.  Caranya adalah dengan men-klik kanan nama proyek dbunit, memilih Run As, Maven install seperti yang terlihat pada gambar berikut ini:

Men-install Proyek Pada Repository Lokal

Men-install Proyek Pada Repository Lokal

Bila ini pertama kalinya saya men-install proyek Maven, maka saya harus memastikan saya sedang terkoneksi ke internet.  Hal ini karena Maven akan men-download beberapa plugin yang dibutuhkan untuk men-install proyek secara otomatis.

Untuk memastikan bahwa proyek sudah ter-install di repository lokal, saya akan memeriksa isi repository lokal.  Lokasi default-nya adalah di C:\Users\[nama_user]\.m2.  Sebagai contoh, saya menemukan dbunit versi lokal saya di folder berikut ini:

Memeriksa Isi Repository Lokal

Memeriksa Isi Repository Lokal

Setelah ini, saya bisa memakai artifact di atas di proyek lain secara mudah.  Caranya cukup dengan menambahkan dependency Maven baru pada proyek yang akan DbUnit hasil modifikasi ini.  Di dialog Select Dependency, bila saya mengetikkan dbunit untuk pencarian, artifact di repository lokal juga akan ikut muncul, seperti yang terlihat pada gambar berikut ini:

Menambah Dependency Dari Proyek Lain

Menambah Dependency Dari Proyek Lain

Memakai Jetty sebagai embedded web server

Jetty adalah sebuah web server yang unik.  Hal ini karena Jetty dapat dipakai sebagai embedded web server.  Apa maksudnya?  Biasanya pada aplikasi web, program yang telah kita buat perlu di-‘copy‘ ke sebuah container (web server).  Tapi embedded web server adalah kebalikannya.   Aplikasi kita didalamnya telah mengandung web server, sehingga kita tidak perlu memindahkan kode program ke web server lagi.  Lalu apa gunanya? Embedded web server dapat dipakai pada pengujian aplikasi dimana aplikasi akan dijalankan  pada embedded web  server yang tidak membutuhkan banyak setup serta tidak ‘berat.

Sebagai contoh, saya akan menggunakan Jetty untuk front-end testing secara otomatis.  Proyek saya berjalan pada Cloud Foundry yang memakai Tomcat 6.  Dengan demikian, versi Jetty yang paling mendekati adalah Jetty 7 yang masih memakai spesifikasi Servlet 2.5 sama seperti Tomcat 6.  Sebagai informasi, Jetty sudah mencapai versi 9 yang mendukung spesifikasi Servlet 3.0 seperti Tomcat 7.

Karena memakai Apache Maven, saya dapat menambahkan dependency ke Jetty secara mudah.  Agar mudah, saya menambahkan seluruh JAR yang dibutuhkan (versi aggregate), dengan informasi seperti berikut ini:

Group Id:  org.eclipse.jetty.aggregate
Artifact Id: jetty-all
Version: 7.6.7.v20120910
Scope: test

Disini saya memakai scope test,  yang menunjukkan bahwa artifact JAR Jetty hanya dibutuhkan untuk pengujian saja, bukan untuk menjalankan aplikasi saya.

Saya juga memastikan bahwa servlet-api dan jsp-api sudah ada di dependency Maven:

Group Id: javax.servlet
Artifact Id: servlet-api
Version: 2.5
Scope: provided

Group Id: javax.servlet.jsp
Artifact Id: jsp-api
Version: 2.1
Scope: provided

Saya memakai scope provided, yang menunjukkan bahwa kedua artifact tersebut dibutuhkan untuk melakukan kompilasi kode program, tetapi tidak perlu disertakan sebagai bagian dari proyek karena mereka telah disediakan oleh server.

Dan terakhir, karena implementasi JSP yang saya pakai adalah Jasper,  saya perlu menambahkan artifact Juli (untuk logging di Tomcat) pada dependency Maven:

Group Id: org.apache.tomcat
Artifact Id: juli
Version: 6.0.36
Scope: test

Setelah memastikan  Maven telah men-download semua artifact JAR yang dibutuhkan, saya bisa membuat kode program.  Sebagai contoh, berikut ini adalah penggalan kode program yang menjalankan Jetty sebagai embedded web server:

...
Server server = new Server (8080);
WebAppContext context = new WebAppContext();
context.setDescriptor("../FolderProyek/src/main/webapp/WEB-INF/web.xml");
context.setResourceBase("../FolderProyek/src/main/webapp");
context.setContextPath("/proyek");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
...

Semua proyek web Java selalu memiliki file web.xml.  Yang saya lakukan adalah memberitahu lokasi web.xml yang akan dijalankan pada Jetty.  Selain itu, saya juga memberi tahu lokasi folder yang berisi file HTML, JSP, dan sebagainya (resource base).  Dengan setContextPath(“/proyek”) maka Jetty dapat dipanggil dengan URL seperti http://localhost:8080/proyek.

Sekarang, bila kode program di atas selesai dikerjakan, saya dapat langsung membuka http://localhost:8080/proyek tanpa perlu meng-install  server seperti Tomcat atau GlassFish.

Proyek lain yang cukup menarik adalah Cargo (informasi ada di http://cargo.codehaus.org).  Dengan Cargo, saya bisa memberikan deskripsi server yang akan saya pakai  (misalnya Tomcat, Jetty, GlassFish, dan sebagainya) di kode program.  Nantinya, Cargo yang akan men-download dan men-install server yang dibutuhkan bila belum ada di komputer dimana program saya berjalan, kemudian Cargo akan memindahkan hasil build program secara otomatis.  Jadi bila saya ingin beralih dari Tomcat ke GlassFish, saya hanya perlu mengubah deskripsi server yang saya pakai.  Contoh kegunaan Cargo adalah pada server Continous Integration (CI).  Server CI akan men-checkout hasil kerja masing-masing programmer yang telah digabungkan, lalu menjalankan function testing secara otomatis.  Server CI bekerja secara periodik dan otomatis sehingga bila ditemui kesalahan, developer akan secepat mungkin mendapat notifikasi.