Kembangkan aplikasi perangkat lunak yang dapat dikonfigurasi dengan mudah

Mengembangkan perangkat lunak yang mudah dikonfigurasi adalah sangat penting dalam lingkungan bisnis saat ini. Aplikasi perangkat lunak tidak lagi dinilai hanya dari jumlah logika bisnis yang dirangkumnya; mereka juga dinilai dari seberapa mudahnya untuk dipelihara. Kemampuan untuk mengubah perilaku perangkat lunak, melalui konfigurasi, merupakan aspek penting dari siklus pemeliharaan ini.

Meskipun bahasa Java menyediakan sejumlah fitur, seperti file properti dan bundel sumber daya, untuk membantu konfigurasi, ini kekurangan fitur yang diperlukan untuk lingkungan bisnis yang dinamis saat ini. Banyak standar, alat, dan penampung Java sudah menggunakan format konfigurasi XML yang lebih canggih dan khusus.

Kerangka Kerja Obix adalah kerangka kerja sumber terbuka yang menyediakan cara dan format umum untuk menyimpan data konfigurasi dalam XML, dan untuk mengakses data ini melalui objek Java sederhana. Ini memungkinkan modularisasi data konfigurasi dengan mengizinkan file konfigurasi untuk diimpor dan disertakan satu sama lain, dan dengan mengatur informasi konfigurasi ke dalam "modul".

Selain itu, ia mendukung amandemen konfigurasi "panas" — melalui deteksi otomatis dan pemuatan ulang perubahan data konfigurasi secara otomatis — dan juga menyediakan dukungan untuk Java Naming and Directory Interface API (JNDI). Selain itu, dapat diintegrasikan ke dalam aplikasi Java dengan berbagai cara, termasuk melalui Java Management Extensions (JMX) dan Platform Java, pendengar Edisi Perusahaan yang tidak memerlukan pengkodean, serta kelas Java biasa yang dapat dipanggil secara langsung. Terakhir, kerangka kerja menyediakan API plugin yang mudah digunakan yang memungkinkan pengembang memperluasnya untuk melakukan tugas terkait inisialisasi. API ini telah digunakan oleh tim Obix untuk menyediakan utilitas inisialisasi untuk kerangka kerja sumber terbuka lainnya seperti Apache's log4j, Hibernate, dan Commons DBCP (kumpulan koneksi database).

Dalam tutorial ini, saya menjelaskan skenario hipotetis yang membutuhkan perangkat lunak yang dapat dikonfigurasi dan kami membuat aplikasi kerangka menggunakan Obix. Contoh pertama memberikan hal yang paling mendekati bukti konsep bergaya "Hello World", sedangkan contoh kedua dan ketiga memperluas aplikasi ini untuk menampilkan aspek konfigurasi yang tidak terlalu sepele.

Harap dicatat bahwa semua contoh kode dalam artikel ini dikemas sebagai arsip, yang dapat diunduh melalui tautan yang disediakan di Sumber.

Skenario masalah

Menilai aset keuangan seperti saham atau opsi terkadang melibatkan simulasi harga aset ribuan kali, dan mengambil rata-rata dari nilai-nilai ini — dengan keyakinan bahwa rata-rata memberikan tebakan terbaik untuk nilai aset "sebenarnya" di masa depan. Simulasi semacam itu biasanya memerlukan input statistik dalam bentuk harga aset saat ini, harga rata-rata selama rentang waktu tertentu, serta penyimpangan dari rata-rata.

Misalkan kita membuat aplikasi untuk menilai instrumen semacam itu. Karena itu, aplikasi ini perlu mengunduh input statistik melalui layanan Web, dan detailnya — seperti URL dan informasi otentikasi — untuk menghubungkan ke layanan ini disimpan dalam dokumen konfigurasi. Cukup dikatakan, jumlah simulasi yang akan dilakukan untuk permintaan penilaian tertentu juga harus fleksibel dan, dengan demikian, akan ditentukan melalui konfigurasi.

Contoh 1: File konfigurasi dasar

Dalam contoh ini, kami membuat file konfigurasi dasar, example1-config.xml, untuk aplikasi kami, yang menyimpan detail untuk menghubungkan ke layanan Web yang menyediakan input statistik untuk proses penilaian. File konfigurasi ini juga akan menyimpan jumlah simulasi yang akan dilakukan untuk setiap permintaan penilaian. File ini (serta file konfigurasi untuk contoh lainnya) ada di direktori config dari arsip yang dapat didownload yang terkait dengan tutorial ini. Isi file konfigurasi terdaftar sebagai berikut:

//www.some-exchange.com/marketdata

trading_app_dbo

nopassword

10000

Jika kita memeriksa file secara lebih rinci, perhatikan bahwa file dimulai dengan node root ; ini menandai awal dari dokumen konfigurasi Obix. Ada empat node, masing-masing merangkum entri konfigurasi. Tiga yang pertama berisi URL, ID pengguna, dan kata sandi untuk menghubungkan ke layanan input; entri terakhir menyimpan jumlah simulasi yang akan dilakukan untuk setiap permintaan penilaian. Perhatikan bahwa setiap entri memiliki kunci unik, seperti yang ditentukan oleh entryKeyatribut, dan nilai di setiap entri dienkapsulasi oleh sebuah node.

Selanjutnya, kami membuat kerangka aplikasi penilaian kami, dan, yang lebih penting, kami mendemonstrasikan bagaimana dokumen konfigurasi dibaca saat runtime. Kelas yang diminati disebut Example1.javadan dapat ditemukan di folder src dari arsip yang dapat diunduh yang terkait dengan tutorial ini. Definisi kelasnya adalah sebagai berikut:

import org.obix.configuration.Configuration; import org.obix.configuration.ConfigurationAdapter; import org.obix.configuration.ConfigurationAdapterFactory;

public class Example1 { public static void main(String[] args) { ConfigurationAdapterFactory adapterFactory = ConfigurationAdapterFactory.newAdapterFactory();

ConfigurationAdapter adapter = adapterFactory.create(null);

adapter.adaptConfiguration(Configuration.getConfiguration(), "config/example1-config.xml"); printMarketDataInfo(); }

private static void printMarketDataInfo() { Configuration globalConfig = Configuration.getConfiguration();

System.out.println("Data Service URL :\t\t" + globalConfig.getValue("market.data.service.url"));

System.out.println("Data Service User-ID :\t\t" + globalConfig.getValue("market.data.service.uid"));

System.out.println("Data Service Password :\t\t" + globalConfig.getValue("market.data.service.password"));

System.out.println("Simulation Count :\t\t" + globalConfig.getValue("number.of.valuation.simulations")); } }

Untuk menjalankan ini dan contoh berikutnya, Anda perlu mengunduh binari Obix Framework ke lokasi yang dapat diakses melalui jalur kelas Anda. Classpath Anda harus merujuk ke perpustakaan Obix, obix-framework.jar , yang dapat ditemukan di folder lib dari direktori root framework. Anda juga memerlukan pustaka sumber terbuka pihak ketiga berikut: dom.jar , jaxen-full.jar , sax.jar , saxpath.jar , dan xercesImpl.jar , yang dapat ditemukan di folder lib / thirdParty dari root framework direktori.

Pelaksana kelas ini harus menghasilkan hasil sebagai berikut:

Data Service URL : //www.some-exchange.com/marketdata Data Service User-ID : trading_app_dbo Data Service Password : nopassword Simulation Count : 10000 

Untuk membedah kelas ini, kita mulai dengan metode utama. Baris pertama dari metode ini membuat instance kelas org.obix.configuration.ConfigurationAdapterFactory, yang bertanggung jawab untuk membuat adaptor konfigurasi (instance kelas org.obix.configuration.ConfigurationAdapter). Adaptor, pada gilirannya, bertanggung jawab untuk benar-benar membaca dokumen konfigurasi dari lokasi tertentu (ditetapkan sebagai jalur file atau URL).

Ekstrak kode berikut membaca konten file konfigurasi kita ke dalam instance konfigurasi global / statis dengan menjalankan metode adaptor adaptConfiguration(), dan dengan meneruskan referensi ke instance global — seperti yang diperoleh dari panggilan tersebut Configuration.getConfiguration()— dan jalur ke file konfigurasi config / example1 kita -config.xml:

adapter.adaptConfiguration(Configuration.getConfiguration(), "config/example1-config.xml"); 

Perhatikan bahwa dimungkinkan untuk membuat instance konfigurasi baru untuk menyimpan data konfigurasi kita, daripada menggunakan instance statis (global), tetapi demi kesederhanaan (dan singkatnya), kami menggunakan instance statis untuk contoh ini.

Selanjutnya, kita secara singkat memeriksa metode printMarketDataInfo(), yang hanya membaca entri konfigurasi (yaitu, node XML) dan mencetak nilainya (yaitu, node turunannya). Perhatikan bahwa setiap nilai entri diperoleh dengan memanggil metode getValue (...)pada Configurationinstance terkait , dengan meneruskan nama / kunci entri — seperti yang ditentukan untuk entryKeyatribut node entri . Sebagai tambahan, perhatikan bahwa sebuah entri dapat memiliki banyak nilai, yang akan didemonstrasikan nanti dalam tutorial ini.

Contoh 2: Memodularisasi data konfigurasi

Applications of this nature will typically generate a report detailing a request's results in some sort of format. Our hypothetical application is no different; it is capable of producing valuation reports in a variety of formats. In addition, the reporting formats used in a given application run are dictated by a configuration entry, and all generated reports are emailed to a list of recipients within our organization—where the recipients are also specified in the configuration set.

Logically, reporting is a distinct piece of functionality—when compared to valuation—even though both are related; so it would be quite reasonable to encapsulate our "reporting" configuration data. This not only provides a cleaner separation of the configuration data, but also makes it simpler for a novice to visualize the delineation of functionality within the application.

We encapsulate the reporting configuration for this example by creating a configuration module for reporting, which is a child of our root module. We modify the configuration file from the last example by appending the node shown below to its list of nodes; the resulting file is called example2-config.xml and can be found in the config directory of the source archive.

.................... .................... ................... [email protected]

spreadsheet text-file pdf

Two things immediately stand out in this configuration file: the first, of course, is our module definition , followed by the module's second entry node . We begin with the module definition. An Obix configuration document can contain any number of submodules. Barring two elements—not discussed in this tutorial—modules support the same node set as the root module. In other words, modules have entries and can contain other modules; hence, modules can effectively be used to replicate a tree structure.

Recall that in the last example, I mentioned that a configuration entry can have multiple values. This functionality is demonstrated by the configuration entry for holding reporting formats, i.e., . As you can see, this differs from other entries in that it has three values—specifying the three formats in which reports should be generated.

We now examine the Java code for reading the entries in our reporting configuration module. We modify the Java source for the previous example by adding the following method; the modified source file (class) is renamed Example2.java, and can be found in the src folder of the archive associated with this tutorial:

private static void printReportingConfig() { Configuration globalConfig = Configuration.getConfiguration();

Configuration reportingConig = globalConfig.getModule("reporting.parameters");

System.out.println("Reports Destination :\t\t" + reportingConig.getValue("reports.destination.email"));

System.out.println("Reporting Formats :\t\t" + reportingConig.getValues("report_formats")); }

On executing this class, it should produce the output:

Data Service URL : //www.some-exchange.com/marketdata Data Service User-ID : trading_app_dbo Data Service Password : nopassword Simulation Count : 10000

Reporting Config Parameters= Reports Destination : [email protected] Reporting Formats : [spreadsheet, text-file, pdf]

Setelah memeriksa metode tambahan secara mendetail, kami melihat bahwa metode tersebut pertama kali memperoleh referensi ke Configurationcontoh global ; kemudian melanjutkan untuk memperoleh referensi ke modul konfigurasi yang menyimpan informasi konfigurasi pelaporan. Metode tersebut menyelesaikan tugas-tugas ini dengan memanggil metode getModule(...)pada modul induk, meneruskan ID modul yang akan diterima. Perhatikan bahwa sintaks ini bersifat umum dalam artian mendapatkan turunan dari modul apa pun — meskipun bukan modul root — dicapai dengan memanggil getModule(...)modul yang diberikan.