S lakoćom razvijajte softverske programe koji se mogu konfigurirati

Razvoj lako podesivog softvera od iznimne je važnosti u današnjem poslovnom okruženju. Softverske se aplikacije više ne ocjenjuju samo po količini poslovne logike koju sadrže; ocjenjuju se i prema tome koliko ih je lako održavati. Sposobnost promjene ponašanja softvera putem konfiguracije važan je aspekt ovog ciklusa održavanja.

Iako jezik Java pruža brojne značajke, poput datoteka svojstava i snopova resursa, kao pomoć u konfiguraciji, njima nedostaju značajke potrebne za današnje dinamično poslovno okruženje. Mnogi Java standardi, alati i spremnici već koriste naprednije i prilagođene formate XML konfiguracije.

Obix Framework je okvir otvorenog koda koji pruža uobičajena sredstva i formate za pohranu podataka o konfiguraciji u XML i za pristup tim podacima putem jednostavnih Java objekata. Omogućuje modularizaciju podataka o konfiguraciji dopuštajući uvoz i uvrštavanje datoteka u konfiguraciju te organiziranje podataka o konfiguraciji u "module".

Uz to, podržava "vruće" izmjene konfiguracije - automatskim otkrivanjem i automatskim ponovnim učitavanjem promjena u podacima o konfiguraciji - a također pruža podršku za API za imenovanje Java i sučelja direktorija (JNDI). Nadalje, može se integrirati u Java programe na brojne načine, uključujući putem Java Management Extensions (JMX) i Java Platform, slušatelje Enterprise Edition koji ne zahtijevaju kodiranje, kao i obične Java klase na koje se može izravno pozvati. Konačno, okvir pruža jednostavan API za dodatak koji ga omogućuje programerima da ga prošire za obavljanje zadataka povezanih s inicijalizacijom. Ovaj API koristio je Obixov tim za pružanje uslužnih programa za inicijalizaciju za druge okvire otvorenog koda kao što su Apacheov log4j, Hibernate i Commons DBCP (spremišta baze podataka).

U ovom uputstvu opisujem hipotetski scenarij koji zahtijeva konfigurabilni softver i za koji izrađujemo skeletne aplikacije koristeći Obix. Prvi primjer pruža najbližu dokazu koncepta u stilu "Hello World", dok drugi i treći proširuju ovu aplikaciju kako bi prikazali manje trivijalne aspekte konfiguracije.

Imajte na umu da su svi uzorci koda u ovom članku zapakirani u arhivu koja se može preuzeti putem veze koja se nalazi u Resursima.

Problemski scenarij

Procjena financijske imovine poput dionica ili opcija ponekad uključuje simulaciju cijene imovine tisućama puta i uzimanje prosjeka tih vrijednosti - u uvjerenju da prosjek najbolje pogađa o "istinskoj" budućoj vrijednosti imovine. Takve simulacije obično zahtijevaju statistički unos u obliku trenutne cijene imovine, prosječne cijene tijekom određenog vremenskog raspona, kao i odstupanja od prosjeka.

Pretpostavimo da stvaramo aplikaciju za vrednovanje takvih instrumenata. Kao takva, ova će aplikacija trebati preuzeti statističke ulaze putem web usluge, a detalji - poput URL-a i podataka za provjeru autentičnosti - za povezivanje s ovom uslugom pohranjeni su u konfiguracijskom dokumentu. Dovoljno je reći, broj simulacija koje će se izvesti za zadani zahtjev za vrednovanjem također bi trebao biti fleksibilan i kao takav bit će naveden u konfiguraciji.

Primjer 1: Osnovna konfiguracijska datoteka

U ovom primjeru za našu aplikaciju izrađujemo osnovnu konfiguracijsku datoteku, example1-config.xml, koja sadrži detalje za povezivanje s web uslugom koja pruža statističke ulaze u postupak vrednovanja. Ova konfiguracijska datoteka pohranit će i broj simulacija koje će se izvesti za bilo koji zahtjev za vrednovanjem. Ova se datoteka (kao i konfiguracijske datoteke za ostale primjere) nalazi u config direktoriju preuzete arhive pridružene ovom vodiču. Sadržaj konfiguracijske datoteke naveden je na sljedeći način:

//www.some-exchange.com/marketdata

trading_app_dbo

nopassword

10000

Ako datoteku proučimo detaljnije, primijetite da počinje s korijenskim čvorom ; ovo označava početak Obixovog konfiguracijskog dokumenta. Postoje četiri čvora, svaki enkapsulira unos konfiguracije. Prva tri sadrže URL, korisnički ID i lozinku za povezivanje s uslugom unosa; konačni unos sadrži broj simulacija koje treba izvršiti za svaki zahtjev za procjenu. Primijetite da svaki unos ima jedinstveni ključ, kako je naveden u entryKeyatributu, te da vrijednost u svakom unosu enkapsulira čvor.

Dalje kreiramo kostur naše aplikacije za vrednovanje i, što je još važnije, demonstriramo kako se konfiguracijski dokument čita tijekom izvođenja. Pozvana je klasa interesa koja se Example1.javamože naći u src mapi arhive koja se može preuzeti koja je pridružena ovom vodiču. Definicija razreda je sljedeća:

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")); } }

Da biste pokrenuli ovaj i naredne primjere, morate preuzeti binarne datoteke Obix Framework na mjesto dostupno putem vaše staze. Vaša put predavanja mora se pozivati ​​na biblioteku Obix, obix-framework.jar , koja se može naći u mapi lib korijenskog direktorija okvira. Također će vam trebati sljedeće biblioteke otvorenog koda treće strane: dom.jar , jaxen-full.jar , sax.jar , saxpath.jar i xercesImpl.jar , koje se mogu naći u mapi lib / thirdParty korijena okvira okvira imenik.

Izvršenje ove klase treba rezultirati sljedećim rezultatom:

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

Da bismo secirali ovu klasu, započinjemo s glavnom metodom. Prvi redak ove metode stvara instancu klase org.obix.configuration.ConfigurationAdapterFactorykoja je odgovorna za stvaranje konfiguracijskog prilagodnika (instance klase org.obix.configuration.ConfigurationAdapter). Adapter je, pak, odgovoran za stvarno čitanje konfiguracijskog dokumenta s određenog mjesta (navedeno kao put datoteke ili URL).

Sljedeći ekstrakt koda čita sadržaj naše konfiguracijske datoteke u globalnu / statičku instancu konfiguracije pozivanjem metode adaptora adaptConfiguration()i prosljeđivanjem reference na globalnu instancu - kako je dobivena iz poziva Configuration.getConfiguration()- i putanju do naše konfiguracijske datoteke config / example1 -config.xml:

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

Imajte na umu da je moguće stvoriti novu konfiguracijsku instancu za pohranu naših podataka o konfiguraciji, umjesto da se koristi statička (globalna) instanca, ali radi jednostavnosti (i kratkoće), za ovaj primjer koristimo statičku instancu.

Dalje, ukratko ispitujemo metodu printMarketDataInfo()koja jednostavno čita unose u konfiguraciju (tj. XML čvorove) i ispisuje njihove vrijednosti (tj. Njihove podređene čvorove). Primijetite da se vrijednost svakog unosa dobiva pozivanjem metode getValue (...)na pridruženoj Configurationinstanci, unošenjem imena / ključa unosa - kako je navedeno za entryKeyatribut čvora unosa . Kao stranu, imajte na umu da unos može imati više vrijednosti, što će biti prikazano kasnije u ovom vodiču.

Primjer 2: Modulariziranje podataka o konfiguraciji

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]

Nakon detaljnog ispitivanja dodatne metode primjećujemo da prvo dobiva referencu na globalnu Configurationinstancu; zatim nastavlja s dobivanjem reference na konfiguracijski modul koji sadrži informacije o konfiguraciji izvještavanja. Metoda postiže ove zadatke pozivanjem metode getModule(...)na nadređeni modul, predavanjem ID-a modula koji će se primiti. Imajte na umu da je ova sintaksa generička u smislu da se dobivanje podređenosti bilo kojeg modula - čak i ako nije korijenski - postiže pozivanjem getModule(...)na zadani modul.