Sidt opdateret: 23. juni 2005
Dette dokument indeholder en grundlæggende oversigt over EMF's valideringsstruktur og nogle kodeeksempler, der kan lette implementeringen. En mere omfattende beskrivelse af alle funktionerne i EMF kan du finde i EMF: Eclipse Modeling Framework, Second Edition (Addison-Wesley Professional, 2008) eller i Javadoc vedrørende selve strukturens klasser.
Vil du være sikker på, at din models data overholder de begrænsninger, der er fastlagt for dataene? Denne oversigt giver med tre hurtige trin en ide om, hvordan du kan opnå det ved hjælp af EMF's valideringsstruktur.
Invariant - implementeres som klassemetode, defineret på modellen. Betragtes som et vægtigere udsagn om validitet end en betingelse. Eksempel: hasUSState() |
![]() |
![]() |
![]() |
Navngivet betingelse - implementeres som metode på en ekstern validatorklasse, ikke på selve modellen. Betragtes som et mindre vægtigt udsagn om validitet end en Invariant. Eksempel: NonNegativeQuantity, ValidShipDate |
![]() |
![]() |
![]() |
Skemabaseret betingelse - som navngivet betingelse, men defineret i et skema. Eksempel: 'quantity skal være en int mellem 0 og 100'. Eftersom disse typer betingelser har kendte funktionsmåder, kræves ikke yderligere arbejde for at implementere dem. Alle betingelser med en simpel type implementeres automatisk af kodegeneratoren. <xsd:element name="quantity"> <xsd:simpleType> <xsd:restriction base="xsd:int"> <xsd:minInclusive value="0"/> <xsd:maxInclusive value="100"/> </xsd:restriction> </xsd:simpleType> </xsd:element> |
Trin 1: | Opret betingelser i modellen |
Trin 2: | Definér betingelser |
Trin 3: | Generér og udfør |
Appendiks: | Udvidede emner |
Som for al EMF-udvikling kan du starte fra annoteret Java, et XML-skema eller en Rose-model. Metoden til definition af betingelser afhænger af kilden til modellen.
For Rose repræsenterer stereotypen <<inv>> for en funktion en Invariant. Du finder et eksempel på det i Figur 1 ovenfor.
Hvis du vil tilføje en betingelse i Rose 98, skal du åbne modellen og derefter vælge en klasse (f.eks. "Item" i det eksempel, der vises her). Højreklik, og vælg "Open Specification" (eller dobbeltklik på "Item"). Vælg derefter skillebladet "Ecore", og klik på feltet constraints for at tilføje betingelser som i Figur 2 ovenfor.
For et skema kan du definere en<xsd:restriction/>-betingelse (som ovenfor) eller en navngivet betingelse:
<xsd:complexType name="Item"> <xsd:annotation> <xsd:appinfo source="http://www.eclipse.org/emf/2002/Ecore" ecore:key="constraints"> NonNegativeQuantity ValidShipDate </xsd:appinfo> </xsd:annotation> ... </xsd:complexType>
For annoteret Java kan du definere Invariant-forekomster og betingelser på denne måde:
Invariant /** * @model */ public interface USAddress { ... /** * @model */ boolean hasUSState( DiagnosticChain diagnostics, Map context); ... } |
![]() |
![]() |
![]() |
Betingelse /** * @model annotation="http://www.eclipse.org/emf/2002/Ecore constraints='NonNegativeQuantity ValidShipDate'" */ public interface Item { ... } |
Importér din model i EMF, og generér derefter kode som i trin 2-3 i øveprogrammet Generér en EMF-model.
Den genererede kode vil se omtrent sådan ud:
Invariant, com.example.ppo.impl.USAddressImpl public boolean hasUSState( DiagnosticChain diagnostics, Map context) { // TODO: implement this method // -> specify the condition that violates // the invariant // -> verify the details of the diagnostic, // including severity and message // Ensure that you remove @generated or // mark it @generated NOT if (false) { if (diagnostics != null) { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, PPOValidator.DIAGNOSTIC_SOURCE, PPOValidator.US_ADDRESS__HAS_US_STATE, EcorePlugin.INSTANCE.getString( "_UI_GenericInvariant_diagnostic", new Object[] { "hasUSState", EObjectValidator.getObjectLabel(this, context)}), new Object [] { this })); } return false; } return true; } |
![]() |
![]() |
![]() |
Betingelse, com.example.ppo.util.PPOValidator public boolean validateItem_ValidShipDate( Item item, DiagnosticChain diagnostics, Map context) { // TODO implement the constraint // -> specify the condition that violates // the constraint // -> verify the diagnostic details, // including severity, code, and message // Ensure that you remove @generated or // mark it @generated NOT if (false) { if (diagnostics != null) { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, DIAGNOSTIC_SOURCE, 0, EcorePlugin.INSTANCE.getString( "_UI_GenericConstraint_diagnostic", new Object[] { "ValidShipDate", getObjectLabel(item, context) }), new Object[] { item })); } return false; } return true; } |
Der genereres også kode i validatoren, f.eks. i com.example.ppo.util.PPOValidator, for hver defineret Invariant, men disse metoder delegerer blot til Invariant-metoderne på selve objekterne, f.eks.:
public boolean validateUSAddress_hasUSState(USAddress usAddress, DiagnosticChain diagnostics, Map context) { return usAddress.hasUSState(diagnostics, context); }
I begge tilfælde skal den genererede kode ændres manuelt for at beskrive over for EMF, hvordan Invariant'en eller betingelsen skal implementeres. I det første tilfælde skal du ændre første linje fra:
if (false)
til
if ("US".equals(getCountry()) && getState() == null).
Når du er færdig med at definere betingelser, skal du starte et nyt arbejdsområde. Der er flere oplysninger i trin 4 i øveprogrammet Generér en EMF-model.
Din model har nu punktet Validér på editormenuen.
Figur 3. Start validering fra brugergrænsefladen
Hvis modellen indeholder ugyldige data, opstår problemer under valideringen, og der vises en dialogboks som den i figur 4.
Figur 4. Dialogboksen Valideringsproblemer
Hvis du vælger en af fejlfindingsmeddelelserne i dialogboksen, før du klikker på knappen OK, vælges det objekt i editoren, som er årsag til meddelelsen. Der vises også markeringer af disse fejlfindingsmeddelelser i oversigten Problemer i Eclipse.
Du kan implementere validering på en anden måde, f.eks. når en fil skal gemmes eller åbnes, ved at gøre noget i stil med dette:
public static boolean validateObject(EObject eObject) { Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObject); return diagnostic.getSeverity() == Diagnostic.OK; }
Når der bruges en Diagnostician, beregnes resultatet af evalueringen på grundlag af en Diagnostic-forekomst, ikke blot en returneret boolesk værdi. Det sætter dig i stand til at afgøre, hvilket niveau der udgør en fejl, og vise oplysninger om de betingelser og Invariant-forekomster, der ikke er overholdt. Hvis du f.eks. kun er interesseret i fejl og advarsler, kan du opnå det sådan her:
public static boolean validateObject(EObject eObject) { Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObject); if (diagnostic.getSeverity() == Diagnostic.ERROR || diagnostic.getSeverity() == Diagnostic.WARNING) { System.err.println(diagnostic.getMessage()); for (Iterator i=diagnostic.getChildren().iterator(); i.hasNext();) { Diagnostic childDiagnostic = (Diagnostic)i.next(); switch (childDiagnostic.getSeverity()) { case Diagnostic.ERROR: case Diagnostic.WARNING: System.err.println("\t" + childDiagnostic.getMessage()); } } return false; } return true; }
Bemærk, at når Diagnostician.INSTANCE.validate() bruges, får du foræret noget indbygget Ecore-betingelsesvalidering takket være EObjectValidator, basis for alle genererede pakkevalidatorklasser. Det drejer sig om: