Programmering

Udvik let konfigurerbare softwareapplikationer

Udvikling af let konfigurerbar software er af største vigtighed i nutidens forretningsmiljø. Softwareapplikationer bedømmes ikke længere blot efter mængden af ​​forretningslogik, de indkapsler; de bedømmes også af, hvor lette de er at vedligeholde. Evnen til at ændre softwareadfærd via konfiguration udgør et vigtigt aspekt af denne vedligeholdelsescyklus.

Mens Java-sproget indeholder en række funktioner, såsom ejendomsfiler og ressourcegrupper, for at hjælpe med konfigurationen, mangler disse de funktioner, der kræves til nutidens dynamiske forretningsmiljøer. Mange Java-standarder, værktøjer og containere bruger allerede mere avancerede og tilpassede XML-konfigurationsformater.

Obix Framework er en open source-ramme, der giver de almindelige midler og formater til lagring af konfigurationsdata i XML og for adgang til disse data via enkle Java-objekter. Det muliggør modularisering af konfigurationsdata ved at lade konfigurationsfiler importeres og inkluderes i hinanden og ved at organisere konfigurationsoplysninger i "moduler".

Derudover understøtter den "hot" -konfigurationsændringer - gennem automatisk detektion og automatisk genindlæsning af ændringer til konfigurationsdata - og yder også support til Java Naming and Directory Interface API (JNDI). Desuden kan den integreres i Java-applikationer på adskillige måder, herunder gennem Java Management Extensions (JMX) og Java Platform, Enterprise Edition-lyttere, der ikke kræver kodning, samt almindelige Java-klasser, der kan påberåbes direkte. Endelig giver rammen en brugervenlig plug-in API, der lader udviklere udvide den til at udføre initialiseringsrelaterede opgaver. Denne API er blevet brugt af Obix-teamet til at levere initialiseringsværktøjer til andre open source-rammer såsom Apache's log4j, Hibernate og Commons DBCP (databaseforbindelsespuljer).

I denne vejledning beskriver jeg et hypotetisk scenario, der kræver konfigurerbar software, og som vi opretter skeletapplikationer til ved hjælp af Obix. Det første eksempel giver den nærmeste ting til et "Hello World" -koncept-bevis, mens det andet og tredje udvider denne applikation til at fremvise mindre trivielle aspekter ved konfiguration.

Bemærk, at alle kodeeksemplerne i denne artikel er pakket som et arkiv, som kan downloades via det link, der findes i Resources.

Problem scenarie

Værdiansættelse af finansielle aktiver såsom aktier eller optioner indebærer undertiden at simulere aktivets pris tusindvis af gange og tage gennemsnittet af disse værdier - i den tro, at gennemsnittet giver det bedste gæt om aktivets "sande" fremtidige værdi. Sådanne simuleringer kræver typisk statistisk input i form af den aktuelle pris på aktivet / aktiverne, gennemsnitsprisen over et givet tidsrum samt afvigelsen fra gennemsnittet.

Lad os antage, at vi opretter en ansøgning til vurdering af sådanne instrumenter. Som sådan skal denne applikation downloade de statistiske input via en webtjeneste, og detaljerne - såsom URL- og godkendelsesoplysninger - til oprettelse af forbindelse til denne service er gemt i et konfigurationsdokument. Det er tilstrækkeligt at sige, at antallet af simuleringer, der skal udføres for en given anmodning om værdiansættelse, også skal være fleksibelt og som sådan vil blive specificeret via konfiguration.

Eksempel 1: En grundlæggende konfigurationsfil

I dette eksempel opretter vi en grundlæggende konfigurationsfil, eksempel1-config.xml, til vores applikation, som indeholder detaljerne til oprettelse af forbindelse til den webtjeneste, der leverer de statistiske input til værdiansættelsesprocessen. Denne konfigurationsfil gemmer også antallet af simuleringer, der skal udføres for enhver anmodning om værdiansættelse. Denne fil (såvel som konfigurationsfilerne til de andre eksempler) er i konfigurationsmappen i det downloadede arkiv, der er knyttet til denne vejledning. Indholdet af konfigurationsfilen er angivet som følger:

//www.some-exchange.com/marketdata

trading_app_dbo

nopassword

10000

Hvis vi undersøger filen mere detaljeret, skal du bemærke, at den starter med rodnoden ; dette markerer starten på et Obix-konfigurationsdokument. Der er fire noder, der hver indkapsler en konfigurationsindgang. De første tre har URL, bruger-id og adgangskode til at oprette forbindelse til indgangstjenesten; den sidste post indeholder antallet af simuleringer, der skal udføres for hver værdiansættelsesanmodning. Bemærk, at hver post har en unik nøgle som specificeret af entryKey attribut, og at værdien i hver post er indkapslet af en knude.

Dernæst opretter vi skelettet til vores værdiansættelsesapplikation, og vigtigere, vi demonstrerer, hvordan konfigurationsdokumentet læses ved kørsel. Klassen af ​​interesse kaldes Eksempel 1. java og kan findes i src-mappen i det downloadede arkiv, der er knyttet til denne vejledning. Klassedefinitionen er som følger:

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

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

ConfigurationAdapter adapter = adapterFactory.create (null);

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

privat statisk ugyldigt printMarketDataInfo () {Configuration globalConfig = Configuration.getConfiguration ();

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

System.out.println ("Bruger-ID for datatjeneste: \ t \ t" + globalConfig.getValue ("market.data.service.uid"));

System.out.println ("Adgangskode for datatjeneste: \ t \ t" + globalConfig.getValue ("market.data.service.password"));

System.out.println ("Antallet af simulationer: \ t \ t" + globalConfig.getValue ("antal.af.valuering.simuleringer")); }}

For at køre dette og efterfølgende eksempler skal du downloade binære filer fra Obix Framework til et sted, der er tilgængeligt via din klassesti. Din klassesti skal referere til Obix-biblioteket, obix-framework.jar, som kan findes i lib-mappen i rammens rodmappe. Du skal også bruge følgende open source-biblioteker fra tredjepart: dom.jar, jaxen-full.jar, sax.jar, saxpath.jarog xercesImpl.jar, som kan findes i mappen lib / thirdParty i rammens rodmappe.

Udførelse af denne klasse skal give følgende resultat:

URL til datatjeneste: //www.some-exchange.com/marketdata Data Service Bruger-ID: trading_app_dbo Datatjenesteadgangskode: nopassword Simulation Count: 10000 

For at dissekere denne klasse starter vi med hovedmetoden. Den første linje i denne metode opretter en forekomst af klassen org.obix.configuration.ConfigurationAdapterFactory, som er ansvarlig for oprettelse af en konfigurationsadapter (en forekomst af klasse org.obix.configuration.ConfigurationAdapter). Adapteren er til gengæld ansvarlig for faktisk at læse et konfigurationsdokument fra en given placering (angivet som en filsti eller URL).

Følgende kodeekstrakt læser indholdet af vores konfigurationsfil i den globale / statiske konfigurationsinstans ved at påkalde adaptermetoden adaptConfiguration (), og ved at videresende en henvisning til den globale instans - som det fremgår af opkaldet Configuration.getConfiguration ()—Og stien til vores konfigurationsfil config / example1-config.xml:

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

Bemærk, at det er muligt at oprette en ny konfigurationsforekomst til at gemme vores konfigurationsdata i stedet for at bruge den statiske (globale) forekomst, men for enkelheds skyld (og kortfattethed) bruger vi den statiske forekomst til dette eksempel.

Dernæst undersøger vi metoden kort printMarketDataInfo (), som simpelthen læser konfigurationsposterne (dvs. XML-noder) og udskriver deres værdier (dvs. deres barneknuder). Bemærk, at hver indgangs værdi opnås ved at kalde metoden getValue (...) på den tilknyttede Konfiguration eksempel ved at videregive postens navn / nøgle - som angivet for indtastningsknudepunktet entryKey attribut. Som en sidebemærkning skal du bemærke, at en post kan have flere værdier, hvilket vil blive vist senere i denne vejledning.

Eksempel 2: Modularisering af konfigurationsdata

Anvendelser af denne art genererer typisk en rapport, der beskriver en anmodnings resultater i et eller andet format. Vores hypotetiske anvendelse er ikke anderledes; det er i stand til at producere værdiansættelsesrapporter i en række forskellige formater. Derudover dikteres rapporteringsformaterne, der anvendes i en given applikationskørsel, af en konfigurationsindgang, og alle genererede rapporter sendes til en liste over modtagere i vores organisation - hvor modtagerne også er specificeret i konfigurationssættet.

Logisk set er rapportering et særskilt stykke funktionalitet - sammenlignet med værdiansættelse - selvom begge er relateret; så det ville være ret rimeligt at indkapsle vores "rapporterings" konfigurationsdata. Dette giver ikke kun en renere adskillelse af konfigurationsdataene, men gør det også lettere for en nybegynder at visualisere afgrænsningen af ​​funktionalitet i applikationen.

Vi indkapsler rapporteringskonfigurationen for dette eksempel ved at oprette et konfigurationsmodul til rapportering, som er et barn til vores rodmodul. Vi ændrer konfigurationsfilen fra det sidste eksempel ved at føje noden vist nedenfor til dens liste over noder; den resulterende fil hedder eksempel2-config.xml og kan findes i konfigurationsmappen i kildearkivet.

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

regneark tekst-fil pdf

To ting skiller sig straks ud i denne konfigurationsfil: den første er selvfølgelig vores moduldefinition efterfulgt af modulets anden indgangsknude . Vi begynder med moduldefinitionen. Et Obix-konfigurationsdokument kan indeholde et hvilket som helst antal undermoduler. Spærring af to elementer - ikke diskuteret i denne vejledning - understøtter moduler det samme knudesæt som rodmodulet. Med andre ord, moduler har poster og kan indeholde andre moduler; derfor kan moduler effektivt bruges til at replikere en træstruktur.

Husk, at jeg i det sidste eksempel nævnte, at en konfigurationsindgang kan have flere værdier. Denne funktionalitet demonstreres af konfigurationsindgangen til at holde rapporteringsformater, dvs. . Som du kan se, adskiller dette sig fra andre poster, fordi det har tre værdier - angiver de tre formater, hvor rapporter skal genereres.

Vi undersøger nu Java-koden til at læse poster i vores rapporteringskonfigurationsmodul. Vi ændrer Java-kilden til det foregående eksempel ved at tilføje følgende metode; den ændrede kildefil (klasse) omdøbes Eksempel2.java, og kan findes i src-mappen i arkivet, der er knyttet til denne vejledning:

privat statisk ugyldig printReportingConfig () {Configuration globalConfig = Configuration.getConfiguration ();

KonfigurationsrapporteringConig = globalConfig.getModule ("rapportering.parametre");

System.out.println ("Rapporter destination: \ t \ t" + rapporteringConig.getValue ("rapporter.destination.email"));

System.out.println ("Rapporteringsformater: \ t \ t" + rapporteringConig.getValues ​​("rapportformater")); }

Ved udførelse af denne klasse skal den producere output:

URL til datatjeneste: //www.some-exchange.com/marketdata Data Service Bruger-ID: trading_app_dbo Datatjenesteadgangskode: nopassword Simulation Count: 10000

Rapporteringskonfigurationsparametre = Rapporter Destination: [email protected] Rapporteringsformater: [regneark, tekstfil, pdf]

Efter at have undersøgt den yderligere metode i detaljer bemærker vi, at den først får en henvisning til det globale Konfiguration instans; derefter fortsætter det med at erhverve en henvisning til konfigurationsmodulet, der indeholder rapporteringskonfigurationsoplysningerne. Metoden opnår disse opgaver ved at påkalde metoden getModule (...) på modermodulet og videregive ID'et til det modul, der skal modtages. Bemærk, at denne syntaks er generisk i den forstand, at det at få barnet til ethvert modul - selvom ikke rodmodulet - opnås ved at påberåbe sig getModule (...) på det givne modul.