Wednesday, 10 September 2014

Import objects should link to proper source MIB definition - Part 1

MIB file "import" really means the objects are from other MIB file (MIB Definition).


RFC1213-MIB.mib
          IMPORTS
                  mgmt, NetworkAddress, IpAddress, Counter, Gauge,
                          TimeTicks
                      FROM RFC1155-SMI
                  OBJECT-TYPE
                          FROM RFC-1212;

For example, mgmt is defined in RFC1155-SMI.mib file or OBJECT-TYPE is defined in RFC-1212.mib file.


RFC1155-SMI.mib
 mgmt          OBJECT IDENTIFIER ::= { internet 2 }


RFC-1212.mib
          OBJECT-TYPE MACRO ::=
          BEGIN
              TYPE NOTATION ::=
                                          -- must conform to
                                          -- RFC1155's ObjectSyntax
                                "SYNTAX" type(ObjectSyntax)
                                "ACCESS" Access
                                "STATUS" Status
                                DescrPart
                                ReferPart
                                IndexPart
                                DefValPart
              VALUE NOTATION ::= value (VALUE ObjectName) <etc etc>


Therefore, we need to make the references link across the file.

Xtext provides this via special attributes "importedNamespace" or "importURI". Since each MIB is enclosed by Definition block and provides Import section - its more closely resemble namespace so "importedNamespace" will be my choice.

Before working directly on MIB grammar, I decided to get familiarize on Xtext import namespace concept using 15 Minutes Tutorial example.

Notice that root rule is using multiplicity - making it single instance causes "Open-Declaration" (i.e F3) feature to stop working - I take this as hint that each files data get appended into a single model container .

Domainmodel.xtext
Domainmodel:
//  (elements += AbstractElement)*
  elements = AbstractElement
;

Therefore, the Mib grammar should be modified as follow.

Mib.xtext
MibModel:
 definitions+=Definition* ;

Definition:
 name=ID 'DEFINITIONS' '::=' 'BEGIN'
 Export?
 imports=Import?
 (identifiers+=Identifier | DataType)+
 'END';

Additionally using that 15 Minutes Tutorial again, lets modify the import syntax something similar to Mib.

blog.dmodel
//  import my.company.common.HasAuthor
  import HasAuthor from my.company.common

Therefore the grammar need to be changed as follow:

Domainmodel.xtext
Import:
//  'import' importedNamespace = QualifiedNameWithWildcard
  'import' lastSegment=(ID|'*') 'from' qname=QualifiedName
;
  
//QualifiedNameWithWildcard:
//  QualifiedName '.*'?
//;

Since "importedNamespace" attribute can't be used directly, we lose the default Xtext behaviour and need manual construct of Imported Namespace. This can be done by overriding getImportedNamespace() method from ImportedNamespaceAwareLocalScopeProvider.

DomainmodelImportedNamespaceAwareLocalScopeProvider.xtend
package org.example.domainmodel.scoping

import org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider
import org.eclipse.emf.ecore.EObject
import org.example.domainmodel.domainmodel.Import

class DomainmodelImportedNamespaceAwareLocalScopeProvider extends ImportedNamespaceAwareLocalScopeProvider {

 override String getImportedNamespace(EObject object) {
  if (object instanceof Import)
   (object as Import).qname + "." + (object as Import).lastSegment
 }

}

And to bind this class, override configureIScopeProviderDelegate() as follow:

DomainmodelRuntimeModule.java
 @Override
 public void configureIScopeProviderDelegate(com.google.inject.Binder binder) {
  binder.bind(org.eclipse.xtext.scoping.IScopeProvider.class)
    .annotatedWith(
      com.google.inject.name.Names
        .named(org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider.NAMED_DELEGATE))
    .to(DomainmodelImportedNamespaceAwareLocalScopeProvider.class);
 }


Now the new import syntax should work.

TODO: Why there is another alternative ImportedNamespaceAwareLocalScopeProvider binding through Model workflow file while we can override this through above method? When or any reason at all to use this?

GenerateDomainmodel.mwe2
   fragment = scoping.ImportNamespacesScopingFragment auto-inject {}

No comments:

Post a Comment