Oppdaterings-API til Matrikkelen

Innholdsfortegnelse

1 Overordnet om matrikkeltjeneren

2 Innsyn og oppdatering via oppdateringsapi

3 Prinsipper for domenemodellen

4 Håndtering av mer komplekse matrikkeldata

5 Dokumentasjon

6 Nedlastning

7 Kort innføring i JNBProxy

1 Overordnet om matrikkeltjeneren

Matrikkelsystemet er basert på Java/J2EE teknologi og en sentral applikasjonstjener tilbyr et tjeneste-orientert grensesnitt for all aksess til systemet. Denne arkitekturen baserer seg på en tre-lags arkitektur der tjeneren håndterer forretningslogikk og innkapsler all kommunikasjon med databasene.

Oversikt over systemet

1.1 Tjeneste-orientert arkitektur

Matrikkeltjeneren tilbyr et tjeneste-orientert grensesnitt som alle klienter kan benytte for kommunikasjon med systemet. I begrepet tjeneste-orientert ligger følgende:

Tjenestene er hovedsaklig gruppert etter en inndeling i funksjonelle områder. Eksempel på tjenester er:

Alle tjenestene er implementert som Enterprise JavaBeans av typen Stateless Session Beans.

1.2 Domenemodell

Domenemodellen er en objekt-orientert modell av datene i matrikkelen. Domenemodellen er én felles modell som benyttes av alle tjenester. Det vil si at alle tjenester hovedsaklig benytter domenemodellen for parametre og returverdier.

Eksempler på domeneobjekter i matrikkelsystemet er:

1.3 Feilhåndtering

Alle feil som oppstår under prosessering på matrikkeltjeneren vil meldes til klienten som unntak (exception). Det finnes to hovedgrupper unntak:

1.4 Autentisering

For å få adgang til matrikkeltjeneren må klienten autentisere seg med en gyldig bruker i form av brukernavn og passord. Dette skjer i forbindelse med at man

1.5 Lastbalansering og høy tilgjengelighet

Matrikkeltjeneren vil kjøre på en plattform med lastbalansering og høy tilgjengelighet. Dette innebærer blant annet at det vil være en klynge av matrikkeltjenere som utad fungerer som en logisk tjener.

2 Innsyn og oppdatering via oppdateringsapi

Dette kapittelet beskriver hovedprinsippene for oppkobling og bruk av tjenester i oppdateringsapi’et. Dette api’et gir tilgang til uthenting og oppdatering av alle data i Matrikkelen. Således kan det også benyttes som et innsynsapi for klienter som vil hente all informasjon om objekter i matrikkelen. Tilgang til oppdateringsfunksjoner vs. uthentingsfunksjoner vil styres av rettighetene til brukeren som er pålogget.

2.1 Klientkode for oppdatering

Distribusjon av klientkode inneholder:

Klientsidekoden inneholder klientsidefunksjonalitet for å håndtere slike ting som login og caching av id’er.

Klientsidekoden vår er ment som et tilbud til leverandører som skal implementere klienter til matrikkelen. Den bakenforliggende teknologien i oppdateringsAPIet er EJB'er (RMI over IIOP). Dette er kjent teknologi som leverandørene godt kan aksessere direkte hvis de heller skulle ønske det enn å benytte klientsidebiblioteket vårt.

Klientsidekoden er implementert i Java. Leverandører kan velge å enten benytte Java selv, eller bruke en såkalt .Net-Java bro for å kunne implementere i .Net. Kartverket har benyttet JNBridgePro 3.0 i sin integrasjonstesting, men andre bro-produkter skal også kunne fungere, f.eks. JIntegra Espresso eller JuggerNET.

2.2 Oppkobling og bruk av tjeneste

OppdateringsAPI’et består av flere tjenester. Disse kan deles opp i hovedfunksjonalitet og støttetjenester, støttetjenester i kursiv brukes kun indirekte.

Hovedfunksjonalitet:

Støttetjenester/Infrastrukturtjenester:

Noen ting å merke seg angående tjenestene er:

2.2.1 Tjenester for lesing av data

Alle hovedtjenestene benyttes både ved lesing og skriving av data, men man må forholde seg forskjellig til StoreService.

Bruken av Tjenestene ved lesing av data følger denne strukturen:

  1. Login, dette vil validere brukernavn og passord mot JNDI tjeneren til Weblogic. Brukernavn og passord vil så lagres og brukes hver gang dere gjør et remote-kall.
  2. Søkemetoder brukes for å gjøre komplekse søk eller for å returnere flere enn ett objekt.
  3. Hvis man skal hente ut en bestemt domeneboble, som man har id’en til, så kan man gjøre det med StoreService, bruk Lock.NONE.
  4. Alle referanser fra en domeneboble til en annen vil være myke, dvs. at de inneholder id’en til en annen domeneboble, som man så må hente ut f.eks. vha. StoreService.

Her er to enkle eksempler som leser data i hhv. Java og C#:

Eksempel#1 - Java:

   public void testFindVegadresse_Success() {
   LoginService.Accessor.get().login("test1", "matrikkel");

   Kommune nittedal = KommuneService.Accessor.get().findKommune("0233");

   Vegadresse vadresse = AdresseService.Accessor.get().findVegadresse(nittedal.getId(), 4200, 13, "B");

   assertNotNull(gadresse);
   assertEquals("Feil husnr", 13, gadresse.getHusnr());
   assertEquals("Feil bokstav", "B", gadresse.getBokstav());
   }
Eksempel#2 - C#:

   public void testFindVeg() {
   LoginService.Accessor.get().login("test1", "matrikkel");
   AdresseService adresseService = AdresseService.Accessor.get();

   Kommune nittedal = KommuneService.Accessor.get().findKommune("0233");
   Veg veg = adresseService.findVeg(nittedal.getId(), 4200);

   Assert.Equals("Gamle Trondheimsvei".ToUpper(), veg.getAdressenavn().ToUpper(), "Feil adressenavn");
   Assert.Equals(4200, veg.getAdressekode(), "Feil adressekode");
   }

2.2.2 Tjenester for oppdatering av matrikkeldata

Oppdatering (update, delete) fungerer noe annerledes enn lesing.

Bruken av Tjenestene ved oppdatering følger denne strukturen:

  1. Login, dette vil validere brukernavn og passord mot JNDI tjeneren til Weblogic. Brukernavn og passord vil så lagres og brukes hver gang dere gjør et remote-kall.
  2. Søkemetoder brukes for å gjøre komplekse søk eller for å returnere flere enn ett objekt.
  3. Hvis man skal oppdatere domenebobler, så må disse hentes ut låst fra StoreService, bruk Lock.WRITE. Dette må vanligvis gjøres etter at man har søkt de frem med en av metodene i AdresseService.
  4. Hvis man skal hente ut en bestemt domeneboble, som man har id’en til, så kan man gjøre det med StoreService.
  5. Alle referanser fra en domeneboble til en annen vil være myke, dvs. at de inneholder id’en til en annen domeneboble, som man så må hente ut vha. StoreService.

Bruken av tjenester for oppdatering av matrikkeldata er tilsvarende som for uthenting av data. Men det er noen viktige aspekter rundt oppdatering:

Her er to eksempler som oppdaterer data i hhv. Java og C#:

Eksempel#3 - Java:

   public void testUpdateVegadresse() {
   LoginService.Accessor.get().login("test1", "matrikkel");
   Kommune nittedal = KommuneService.Accessor.get().findKommune("0233");

   Vegadresse vegadresse1 = AdresseService.Accessor.get().findVegadresse(nittedal.getId(), 4200, 13, "B");

   vegadresse1 = (Vegadresse) StoreService.Accessor.get().get(vegadresse1.getId(), Lock.WRITE);
   vegadresse1.setHusNr(15);
   vegadresse1.setBokstav(””);

   AdresseService.Accessor.get().updateVegadresse(vegadresse1);


   Vegadresse vegadresse2 = (Vegadresse) StoreService.Accessor.get().get(vegadresse1.getId(), Lock.NONE);

   assertNotNull(vegadresse2);
   assertEquals("Feil husnr", 15, vegadresse2.getHusnr());
   assertEquals("Feil bokstav", "", vegadresse2.getBokstav());
   }
Eksempel#4 - C#:

   public void testUpdateVegadresse(){
   AdresseService adresseService = AdresseService.Accessor.get();
   StoreService storeService = StoreService.Accessor.get();

   Kommune nittedal = KommuneService.Accessor.get().findKommune("0233");
   Vegadresse vegadresse1 = adresseService.findVegadresse(nittedal.getId(), 4200, 13, "B");

   vegadresse1 = (Vegadresse) storeService.get(vegadresse1.getId(), Lock.WRITE);
   vegadresse1.setHusnr(15);
   vegadresse1.setBokstav("");

   adresseService.updateVeg(veg);

   vegadresse2 = (Vegadresse) storeService.get(vegadresse1.getId(), Lock.NONE);

   Assert.Equals(15, vegadresse2.getHusNr(), "Feil husnr");
   Assert.Equals("", vegadresse2.getBokstav(), "Feil bokstav");
   }

2.2.3 Lagring av nye matrikkelobjekter

Tjenester som lagrer nye matrikkelobjekter forutsetter at domenebobler på forhånd er tildelt en unik id. Det er kun matrikkeltjeneren som kan tildele nye unike id’er, dette gjøres gjennom en egen service (IdService).

Objekter som ligger inne i domenebobler og som dermed ikke er en subklasse av MatrikkelBubbleObject skal ikke tildeles id’er før lagring, dette gjøres automatisk av tjeneren.

Se kap. 3.2 for en nærmere forklaring på forskjellen mellom domenebobler og komponenter.

Bruken av Tjenestene må derfor følge denne strukturen:

  1. Login, dette vil validere brukernavn og passord mot JNDI tjeneren til Weblogic. Brukernavn og passord vil så lagres og brukes hver gang dere gjør et remote-kall.
  2. Søkemetoder brukes for å gjøre komplekse søk eller for å returnere flere enn ett objekt.
  3. Hvis man skal oppdatere domenebobler, så må disse hentes ut låst fra StoreService, bruk Lock.WRITE. Dette må vanligvis gjøres etter at man har søkt de frem med en av metodene i AdresseOppdateringsService.
  4. Hvis man skal hente ut en bestemt domeneboble, som man har id’en til, så kan man gjøre det med StoreService.
  5. All referanser fra en domeneboble til en annen vil være myke, dvs. at de inneholder id’en til en annen domeneboble, som man så må hente ut vha. StoreService.
  6. Hvis dere skal opprette nye objekter så må dere benytte IdService for å generere nye objektId’er først. Matrikkelen forventer at nye objekter er utstyrt med id’er.

Her er et eksempel som legger inn et nytt objekt:

Eksempel#5 - Java:

   public void testInsertVegadresse () {

   LoginService loginService = LoginService.Accessor.get();
   KommuneService kommuneService = KommuneService.Accessor.get();
   AdresseService adresseService = AdresseService.Accessor.get();

   loginService.login("test1", "matrikkel");

   Kommune nittedal = kommuneService.findKommune("0233");
   List veger = adresseService.findVegerMedNavn(nittedal.getId(),0, "sollia");
   VegId vegId = ((Veg)veger.get(0)).getId();

   List adresser = adresseService.findAdresserForVeg(vegId);

   int gammeltAntallVeger = adresser.size();

   Vegadresse nyVegadresse = new Vegadresse();

   idService.assignId(nyVegadresse);

   nyVegadresse.setHusnr(14);
   nyVegadresse.setVegId(vegId);

   Representasjonspunkt rep = new Representasjonspunkt(CoordinateSystem.EUREF_SONE33, 6656515.30, 273344.60, 0.00);
   nyVegadresse.setRepresentasjonspunkt(rep);

   adresseService.insertVegadresse(nyVegadresse);

   adresser = adresseService.findAdresserForVeg(vegId);


   assertEquals("Vegen skulle fått lagt inn en vegadresse til", (gammeltAntallVeger + 1), adresser.size());
   }

2.2.3 Litt om låsing

Når man skal gjøre oppdateringer i systemet så må man som vist over låse objektene som skal oppdateres først. Systemet fungerer slik at for hver transaksjonell update tjeneste som fullfører med suksess så låses alle låsene til den brukeren opp. Dette innebærer at hvis man ønsker å gjøre flere oppdateringer rett etter hverandre så må man låse de nødvendige objektene på nytt mellom hver oppdatering.

Det er også slik at systemet kun låser opp objekter ved en vellykket opdpatering. Hvis en feil oppstår under et update-kall så vil låsene som brukeren hadde før update-kallet begynte fremdeles være låst etter at kallet har feilet. Hvis brukeren avbryter operasjonen eller et kall feiler så er det opp til klientprogrammet å håndtere dette korrekt. Det vil f.eks. være opp til programmet å sørge for å kalle StoreService.unlock() for å låse opp de låste objektene.

3 Prinsipper for domenemodellen

Domenemodellen inneholder representasjon av alle dataene i matrikkelsystemet. Matrikkelsystemet baserer seg på en objekt-orientert modell der data og forretninglogikk er innkapslet. Domenemodellen kan beskrives fra to forskjellige synsvinkler:

3.1 Designmodell

Dersom analysemodellen ble direkte overført til en designmodell ville dette gitt en domenemodell der mer eller mindre hele domenemodellen hang sammen med harde referanser (pekere). Dette gir en del utfordringer i forhold til kommunikasjon mellom klient og tjener:

Den ene tjenesten skal f.eks. bare skal oppdatere en adresse, mens en annen skal oppdatere både adresser og dens tilhørende bruksenheter/bygninger. En tjeneste skal oppdatere adresser på en matrikkelenhet, mens en annen skal oppdatere matrikkelenheten og dens teiger.

Et enkelt objekt kan være referert til fra mange andre objekter. Eksempelvis kan en vegadresse være referert til fra både en veg, en bruksenhet og en matrikkelenhet. På klienten ønsker vi ikke multiple instanser av delte objekter. Spesielt vil dette lett kunne forekomme ved uthenting av data gjennom en serie av kall til matrikkeltjeneren.

Skal kun matrikkelenhet låses dersom teiggrensene skal justeres? Hva med delte grenser mellom eiendommer? Må også adresser tilknyttet matrikkelenheten låses?

Matrikkelsystemet løser disse utfordringene med en designmodell som deler analysemodellen opp i veldefinerte domenebobler. En domeneboble består av en samling assosierte domeneobjekter som behandles som en enhet med hensyn til uthenting og oppdatering. Alle objektene inni en domeneboble refererer til hverandre ved hjelp av harde referanser (pekere et programmeringsspråk).

Alle objektene i domeneboblen eies av et rot-objekt. Dette har en id som er en global id for hele boblen. Objekter utenfor domeneboblen kan bare refereres gjennom rot-objektet til dens domeneboble. Referanser til objekter utenfor domeneboblen implementeres da som myke referanser (referansen er da id’en for rot-objektet i den andre domeneboblen).

Regler for domenebobler

En del regler gjelder for bruk av domenebobler:

Domenebobler tilsvarer Eric Evans begrep Aggregate [Evans].

Eksempler på domenebobler

I designmodellen vil for eksempel Matrikkelenhet være rot-objekt for en domeneboble. Referanser til andre domeneobjekter gjøres ved at objekter i boblen har referanser til id'en til rot-entiteten i de respektive bobler. Dette ser vi i eksempelet under ved at relasjonen til kommune gjøres ved referanse til KommuneId.

Domeneboble for Matrikkelenhet:

Domeneboble for Matrikkelenhet


Domeneboble for Adresse:

Domeneboble for Adresse


Domeneboble for Bygg:

Domeneboble for Bygg

Hvilke domenebobler som finnes kan sees i analysemodellen.

4 Håndtering av mer komplekse matrikkeldata

For enkelte deler av domenemodellen vil det være naturlig at tjenestene arbeider med mange domenebobler. For eksempel gjelder dette matrikkelenheter og geometri for disse. I slike tilfeller kan det være nødvendig med oversendelse av en større mengde domenebobler til/fra en tjeneste.

4.1 Oppdatering med UnitOfWorkTransfer

En tjeneste for å lagre en matrikkelenhet med oppdatert geometri trenger både bobler av typen Matrikkelenhet, Teig, Teiggrense og CurveSegment. For å håndtere slike tilfeller brukes en UnitOfWorkTransfer. Dette er et objekt brukt for overføring av data over nettverket. Egne UnitOfWorkTransfer defineres for de enkelte tjenester. Egenskapene til en UnitOfWorkTransfer er:

4.2 Uthenting med BubbleTransfer

Tjenester for uthenting vil også kunne defines til å returnere flere domenebobler. For eksempel av ytelseshensyn (færre runder over nettverket) eller for å sikre konsistent låsing. Siden en tjeneste bare kan ha en returverdi må dette gjøres gjennom et eget objekt som holder på alle boblene. Til dette bruk har man en BubbleTransfer, egenskapene til denne er:

5 Dokumentasjon

For dokumentasjon av domeneboblene i oppdateringsmodellen så har vi lagt inn en referanse til kjernemodell dokumentasjonen. Dvs. at for alle klasser som er med i en domeneboble vil det bare være en referanse videre til dokumentasjonen av denne klassen i kjernen.

For tjenestene så vil alle metodene være dokumentert. Hvilke klasser som kan/skal være med i et transfer-objekt (UnitOfWorkTransfer eller BubbleTransfer) er beskrevet under den enkelte metode med referanser til klassene i kjernemodellen.

Online JavaDoc for APIet.

Det er ikke egne UML diagrammer for oppdateringsapi, da datamodellen er basert på den underliggende domenemodellen for matrikkelen.
UML diagrammer for domenemodellen finnes her, og detaljert tekstlig dokumentasjon finnes her.

6 Nedlastning

Her kan dere laste ned nødvendig programvare:

Zip fil som inneholder .jar-filer som trengs for å bygge .dll vha JNBridgePro og Visual Studio 2005 prosjekt med eksempel-kode

Zip-filen inneholder alle nødvendige filer både for en ren Java oppkobling og for en .NET til Java oppkobling via JNBridgePro (v. 3.2). For .NET må det manuelt genereres en Proxy.dll for mapping av .NET til Java via JNBridgePro, og man må ha en korrekt oppsatt App.config for prosjektet for at classpath som JNBridgePro bruker skal bli riktig. Endelig må man ha installert JNBridgePro med gyldig lisens, se JNBridgePro. Zip-filen inneholder 2 nødvendige filer fra JNBridgePro v. 3.2: JNBSharedMem.dll, JNBShared.dll. Dersom en annen versjon av JNBridge benyttes bør disse erstattes med tilsvarende versjoner i henhold til JNBridgePro dokumentasjonen.

7 Kort innføring i JNBProxy fra JNBridgePro

JNBProxy brukes for å generere en .Net dll fra jar-filene som følger med Zip-filen over. Det er to fremgangsmåter for å generere en dll fil med proxyer:

7.1a Generer proxyer med GUI verktøyet til JNBridge

7.1b Generer proxyer med ProxyGen.bat

7.2 Redigering av .Net-prosjekt

Når du bruker den genererte dll-en i et .Net-prosjekt må du sette opp konfigurasjon for JNBProxy i en applikasjonskonfigurasjonsfil (app.config), som beskrevet i JNBridgePro users guide i kapittelet Configuring the .NET side:

   <dotNetToJavaConfig scheme=”sharedmem”
                       jvm=”full path to jvm.dll in JDK or JRE”
                       jnbcore=”full path to jnbcore.jar”
                       bcel=”full path to bcel-5.1-jnbridge.jar”
                       classpath=”semicolon-separated Java classpath”/>
classpath må her inneholde alle jar-filene i klient-zip-filen, samt rotkatalogen der du har pakket ut innholdet. Rotkatalogen er nødvendig fordi denne inneholder en weblogic lisensfil som er nødvendig for ssl kommunikasjon. Man kan enten angi absolutte stinavn eller relative stinavn. Relative stinavn må være i forhold til hvor applikasjonsnavn.exe og applikasjonsnavn.exe.config ligger og ikke i forhold til App.config. Se innholdet av medfølgende App.config for nødvendige jar filer.

7.3 Bruk av backupserver med JNBridge og Visual Studio

For å kunne koble opp mot en backupserver så må filen matrikkel_klient.properties endres til å inneholde korrekt ip-nummer og port. Dette kan gjøres ved å legge inn en egen matrikkel_klient.properties fil i classpathen til JNBridge. Man kan enten oppdatere filen som ligger i oppdateringapi_v3-client-<versjon>.jar eller legge en ny fil i f.eks rotkatalogen som er inneholdt i classpathen. Det er da viktig at denne katalogen står først i classpathen. Det er også mulig å sette oppkoblingsserver og port programmatisk. Se src.test\SimpleTestClient.cs for eksempel på hvordan dette gjøres.

Fotnoter

[1] JNBridgePro Users’ Guide, Version 3.2, s. 11:
Note: While shared memory is faster than binary/TCP, it has not been chosen as the default setting due to certain limitations in the Java Native Interface (JNI), which require that JNBProxy be exited and restarted whenever JNBProxy’s classpath is changed. If this is not an issue, using shared memory with JNBProxy is recommended.