Přehled ověření EMF

Poslední aktualizace: 23. června 2005

Tento dokument přináší základní přehled rámce ověření EMF a nabízí několik ukázek kódu k usnadnění implementace. Podrobnější popis všech funkcí EMF naleznete v publikaci EMF: Eclipse Modeling Framework, Second Edition (Addison-Wesley Professional, 2008), případně v dokumentaci Javadoc, kde jsou popsány přímo jednotlivé třídy struktury.

Úvod

Chcete zajistit, aby data vašeho modelu odpovídala omezením, která pro ně platí? Tento přehled vám ve třech rychlých krocích nabídne představu o tom, jak toho můžete dosáhnout pomocí rámce ověření EMF.


Definice

Invariant - Implementuje se jako metoda třídy definovaná na modelu. Považuje se za "silnější" výrok platnosti než omezení. Např. hasUSState()

Model Rose - Invariant
Obrázek 1. Model Rose - Invariant

Pojmenované omezení - Implementuje se jako metoda na externí třídě validátoru, nikoli na modelu samotném. Považuje se za "slabší" výrok platnosti než invariant. Např. NonNegativeQuantity, ValidShipDate

Model Rose - Omezení
Obrázek 2. Model Rose - Omezení

Omezení na základě schématu - Stejné jako u pojmenovaného omezení, definuje se však v rámci schématu. Např. 'množství musí být hodnota typu int v rozmezí 0 až 100'. Protože je chování těchto typů omezení známé, nevyžaduje jejich implementace žádnou další práci: všechna omezení jednoduchého typu budou automaticky implementována generátorem kódu.

  <xsd:element name="množství">
    <xsd:simpleType>
      <xsd:restriction base="xsd:int">
        <xsd:minInclusive value="0"/>
        <xsd:maxInclusive value="100"/>
      </xsd:restriction>
    </xsd:simpleType>
  </xsd:element>

Obsah 

Krok 1: Vytvořit omezení v modelu
Krok 2: Definovat omezení
Krok 3: Vygenerovat a spustit
Příloha: Rozšířená témata

 obsah

Krok 1: Vytvořit omezení v modelu

Stejně jako u všech ostatních případů vývoje EMF můžete začít od anotovaného prostředí Java, schématu XML nebo modelů Rose. Metoda definování omezení závisí na zdroji modelu.

V případě modelu Rose stereotyp <<inv>> na operaci představuje invariant. Příklad viz Obrázek 1 výše.

Chcete-li přidat omezení pomocí produktu Rose 98, otevřete model a poté vyberte třídu (např. "Položka" ve zde uvedeném příkladu). Klepněte na ni pravým tlačítkem myši a vyberte volbu "Otevřít specifikaci" (nebo na "Položku" poklepejte). Poté vyberte kartu "Ecore", klepněte na pole omezení a přidejte omezení jako na Obrázku 2 výše.

Pro schéma můžete definovat omezení <xsd:restriction/> (viz výše) nebo pojmenované omezení:

  <xsd:complexType name="Položka">
    <xsd:annotation>
       <xsd:appinfo source="http://www.eclipse.org/emf/2002/Ecore"
       ecore:key="constraints">
         NonNegativeQuantity ValidShipDate
       </xsd:appinfo>
    </xsd:annotation>
  ... </xsd:complexType>

Pro anotované prostředí Java můžete definovat invarianty a omezení takto:

Invariant

  /**
    * @model
    */
    public interface USAddress
    {
      ...     /**
       * @model
       */
      boolean hasUSState(
        DiagnosticChain diagnostics, 
        Map context);
      ...   }

Omezení

  /**
   * @model 
  annotation="http://www.eclipse.org/emf/2002/Ecore 
  constraints='NonNegativeQuantity ValidShipDate'"
   */
    public interface Item
    {
       ...   }

 obsah

Krok 2: Definovat omezení

Naimportujte model do EMF, poté vygenerujte kód jako v Kroku 2 - 3 výukového programu Generování modelu EMF

Vygenerovaný kód bude vypadat asi takto:

Invariant, com.example.ppo.impl.USAddressImpl

  public boolean hasUSState(
    DiagnosticChain diagnostics,
    Map context)
  {
    // TODO: implementace této metody
    // -> určete podmínku, která poruší
    //    invariant
    // -> ověřte podrobnosti diagnostiky
    //    včetně závažnosti a zprávy
    // Nezapomeňte odebrat značku @generated nebo
    // ji označit jako @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;
  }

Omezení, com.example.ppo.util.PPOValidator

  public boolean validateItem_ValidShipDate(
    Item item, DiagnosticChain diagnostics,
    Map context)
  {
    // TODO implementace omezení
    // -> určete podmínku, která poruší
    //    omezení
    // -> ověřte podrobnosti diagnostiky
    //    včetně závažnosti, kódu a zprávy
    // Nezapomeňte odebrat značku @generated nebo
    // ji označit jako @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;
  }

Kód se také generuje ve validátoru, např. v com.example.ppo.util.PPOValidator, pro každý definovaný invariant, tyto metody však pouze delegují na metody invariantu na objektech samotných, např.:

  public boolean validateUSAddress_hasUSState(USAddress usAddress, 
    DiagnosticChain diagnostics, Map context)
  {
    return usAddress.hasUSState(diagnostics, context);
  }

V obou případech je třeba vygenerovaný kód ručně upravit a vysvětlit EMF, jak se má invariant nebo omezení implementovat. V prvním případě změňte řádek z:

    if (false)

na

    if ("US".equals(getCountry()) && getState() == null).


 obsah

Krok 3: Vygenerovat a spustit

Po dokončení definování omezení spusťte nový pracovní prostor. Podrobnosti viz Krok 4 výukového programu Generování modelu EMF.

Váš model nyní bude mít v nabídce svého editoru položku 'Ověřit'.

Spuštění ověření platnosti z uživatelského rozhraní
Obrázek 3. Spuštění ověření platnosti z uživatelského rozhraní

Pokud model obsahuje neplatná data, ověření platnosti se nezdaří a zobrazí se dialogové okno podobné jako na obrázku 4.

Dialogové okno Problémy s ověřením platnosti
Obrázek 4. Dialogové okno Problémy s ověřením platnosti

Při výběru jedné z diagnostik v dialogovém okně před klepnutím na tlačítko OK bude v editoru vybrán objekt, který způsobil porušení. Značkovače pro tyto diagnostiky budou zobrazeny rovněž v pohledu Problémy platformy Eclipse.


 obsah

Rozšířená témata

Chcete-li implementovat ověření platnosti jiným způsobem, například při uložení nebo otevření souboru, stačí, když provedete například toto:

  public static boolean validateObject(EObject eObject)
  {
    Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObject);
    return diagnostic.getSeverity() == Diagnostic.OK;
  }

Při použití volby Diagnostician se výsledek vyhodnocení počítá na základě Diagnostic, nikoli pouze logického návratu. To vám umožňuje rozhodnout, která závažnost představuje selhání, a odkrýt informace o omezením a invariantech, které nebyly splněny. Pokud by vás například zajímaly pouze chyby a varování, mohli byste postupovat zhruba takto:

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

Pamatujte, že při použití Diagnostician.INSTANCE.validate() skrytě získáte vnitřní ověření platnosti omezení Ecore díky validátoru EObjectValidator, který je základem pro všechny třídy validátorů generovaných balíků. To zahrnuje například: