EMF érvényesítés áttekintése

Utolsó frissítés: 2005. június 23.

A dokumentum alapszintű áttekintést nyújt az EMF érvényesítési keretrendszeréről és néhány kódpéldával szolgál megvalósítás megkönnyítése érdekében. Az EMF összes szolgáltatásának teljesebb leírását az EMF: Eclipse Modeling Framework, Második kiadás (Addison-Wesley Professional, 2008) című kiadványban vagy maguknak a keretrendszer osztályoknak a Javadoc dokumentációjában találja.

Bevezetés

Biztosítani akarja, hogy a modell adatai megfeleljenek a rájuk vonatkozó megszorításoknak? Ez az áttekintés bemutatja, hogy hogyan teheti ezt meg három gyors lépésben az EMF érvényesítési keretrendszerének használatával.


Definíciók

Állandó - Az adott modellhez meghatározott osztálymetódusként megvalósított. "Erősebb" utasítás az érvényességre vonatkozóan, mint egy megszorítás. Például: hasUSState()

Rose modell - Állandó
1. ábra: Rose modell - Állandó

Nevesített megszorítás - Metódusként megvalósított egy külső érvényesítő osztályon, nem magán a modellen. "Gyengébb" utasítás az érvényességre vonatkozóan, mint egy állandó. Például: NonNegativeQuantity, ValidShipDate

Rose modell - Megszorítás
2. ábra: Rose modell - Megszorítás

Séma alapú megszorítás - olyan, mint a nevesített megszorítás, de sémán belül meghatározva. Például: 'a quantity egy int kell legyen 0 és 100 között'. Mivel ezek a típusú megszorítások ismert viselkedésűek, nincs szükség további munkára a megvalósításukhoz: a kódelőállító automatikusan megvalósítja az összes egyszerű típus megszorítást.

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

Tartalom 

1. lépés: Megszorítások létrehozása a modellben
2. lépés: Megszorítások meghatározása
3. lépés: Előállítás és futtatás
Függelék: Haladó témakörök

 tartalom

1. lépés: Megszorítások létrehozása a modellben

Az összes EMF fejlesztéshez hasonlóan a kiindulási alap itt is lehet annotált Java, XML séma vagy Rose modell. A megszorítások meghatározásának módja a modell forrástól függ.

A Rose eszközben a műveletek <<inv>> sztereotípiája egy állandót képvisel. Példát a fenti 1. ábra tartalmaz.

Ha megszorítást akar felvenni a Rose 98 használatával, akkor nyissa meg a modellt, és válasszon ki egy osztályt (jelen példában az "Item"). Kattintson a jobb egérgombbal, majd válassza az előugró menü "Specifikáció megnyitása" menüpontját. Alternatív megoldásként kattintson duplán az "Item" elemre. Válassza az "Ecore" lapot, és kattintson a megszorítások mezőre a hozzáadásukhoz, mint ahogyan azt a fenti 2. ábra mutatja.

Sémának meghatározható <xsd:restriction/> (mint fent) vagy nevesített megszorítás:

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

Annotált Java esetén az alábbiak szerint határozhat meg állandókat és megszorításokat:

Állandó

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

Megszorítás

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

 tartalom

2. lépés: Megszorítások meghatározása

Importálja a modellt az EMF-be, majd állítson elő kódot az EMF modell előállítása ismertető 2-3. lépése szerint

Az előállított kód az alábbihoz hasonlóan néz ki:

Invariant, com.example.ppo.impl.USAddressImpl

  public boolean hasUSState(
    DiagnosticChain diagnostics,
    Map context)
  {
    // TODO: metódus megvalósítása
    // -> az állandót sértő feltétel
    //    megadása
    // -> a diagnosztika részleteinek ellenőrzése,
    //    beleértve a súlyosságot és az üzenetet
    // Vagy távolítsa el a @generated elemet,
    // vagy jelölje meg mint @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;
  }

Constraint, com.example.ppo.util.PPOValidator

  public boolean validateItem_ValidShipDate(
    Item item, DiagnosticChain diagnostics,
    Map context)
  {
    // TODO: megszorítás megvalósítása
    // -> a megszorítást sértő feltétel
    //    megadása
    // -> a diagnosztikai részletek ellenőrzése
    //    beleértve a súlyosságot, kódot és üzenetet
    // Mindenképpen távolítsa el a @generated
    // annotációt vagy jelölje meg mint @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;
  }

Az érvényesítőben (com.example.ppo.util.PPOValidator) is előállításra kerül minden egyes meghatározott állandó kódja, de ezek a metódusok egyszerűen csak megbízzák maguknak az objektumokban az állandó metódusait; például:

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

Mindkét esetben kézileg kell módosítani az előállított kódot, hogy elmagyarázza az EMF-nek az állandó vagy megszorítás megvalósításának módját. Az első esetben módosítsa az első sort erről:

    if (false)

erre:

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


 tartalom

3. lépés: Előállítás és futtatás

Amikor kész a megszorítások meghatározása, indítson egy új munkaterületet. Részleteket az EMF modell előállítása ismertető 4. lépése tartalmaz.

Most már lesz egy 'Érvényesítés' pont a modell szerkesztő menüjében.

Érvényesítés indítása a felhasználói felületről
3. ábra: Érvényesítés indítása a felhasználói felületről

Ha érvénytelen adatok vannak a modellben, akkor az érvényesítés hibát jelez a 4. ábrán látható párbeszédablakban.

Érvényesítési problémák párbeszédablak
4. ábra: Érvényesítési problémák párbeszédablak

Ha kijelöli valamelyik diagnosztikai üzenetet a párbeszédablakban, mielőtt az OK gombra kattintana, akkor a szerkesztőben ki lesz jelölve a sértést okozó objektum. A diagnosztikai üzenetek jelzői megjelennek az Eclipse Problémák nézetében is.


 tartalom

Haladó témakörök

Ha más módon akarja megvalósítani az érvényesítést, például a fájlok mentésekor vagy megnyitásakor, akkor tegye az alábbihoz hasonlót:

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

Diagnostician használatával a kiértékelés eredményét egy Diagnostic alapján számítja ki a rendszer, nem egyszerűen egy visszaadott logikai érték lesz. Így meghatározhatja, hogy milyen súlyossági szint jelent hibát, és exponálhatja a megszorítások és állandók azon információit, amelyek nem teljesültek. Ha például csak a hibák és a figyelmeztetések érdeklik, akkor tegye a következőket:

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

A Diagnostician.INSTANCE.validate() alatt valamilyen belső Ecore megszorítás-érvényesítést kap az EObjectValidator osztálynak köszönhetően, ami az összes előállított csomag érvényesítő osztály alapja. Ezek a következők: