2015-03-31 3 views
2

Пожалуйста, рассмотрите эту минимальную грамматику Xtext.Перекрестная ссылка XText на ресурс, не относящийся к DSL

Model: 
    "As a" stackeholder=Stakeholder "I want" want=Want; 

Stakeholder: 
    'client' | 'developer' | 'manager'; 

Want: 
    'everything' | 'cookies' | 'fame'; 

Теперь то, что мне нужно сделать, чтобы переместить определение заинтересованных сторон (давайте забудем о want) в НЕКОТОРЫХ внешнего источника данных. Этот «внешний источник данных» может быть CSV-файлом, может быть БД или, возможно, веб-службой. Но мне вряд ли будет какой-то Xtext-файл или прийти с EMF-моделью. Но все же я хочу перекрестно ссылаться на него так же, как вы можете перекрестно ссылаться на типы Java в вашей DSL.

Вопросы, такие как ручной синтаксический анализ и кеширование (ради выполнения) в стороне: это даже выполнимо?

Я немного вникнул в тему областей и поставщиков ресурсов, но все, что я нашел, требует, чтобы внешний источник был частью хотя бы другого DSL.

Я был бы очень доволен тем, что нужно было сделать.

+0

вы в основном адаптировать мировой поставщик области действия и создать eobjects для внешнего материала там. проблема синтаксического анализа и кеширования вручную не может быть отвечена для общей usacase, она очень специфична для каждой usecase (db vs file vs whatever) и того, как и когда эти ресурсы меняются и как их изменения могут быть обнаружены –

+0

Thx Christian. Да, я специально упустил «конкретную» часть. Я попробую ваши предложения завтра. Все еще не уверен, как подключить EObjects к моему файлу xtext, но по крайней мере теперь я знаю, где копать глубже ... – agschaid

ответ

1

Извините, мне потребовалось столько времени, чтобы ответить. Я попробовал христианское предложение, был не очень доволен, а приоритеты сдвинулись. Теперь у меня будет другая проблема, и для того, чтобы документировать для других (и очистить голову), я напишу, что я сделал до сих пор, так как это было не так просто и требовало достаточного количества экспериментов.

Я не буду публиковать полные классы, но только соответствующие части. Не стесняйтесь спрашивать больше, если вам это нужно.

My Синтаксис-Definition теперь выглядит следующим образом:

Model: 
    stakeholders+=StakeholderDecl* 
    requirements+=Requirement*; 

Requirement: 
    'As a' stakeholder=[Stakeholder] 'I want' want=('everything' | 'cookies' | 'results') 
; 

StakeholderDecl returns Stakeholder : 
    'Stakeholder' Stakeholder 
; 

Stakeholder: 
    name=ID 
; 

Пусть это будет отметить, что все, что ниже необходимо сделать в .ui пакете.

Сначала я создал StakeholdersProvider.xtend:

class StakeholdersProvider extends AbstractResourceDescription { 

    // this is the dummy for an "external source". Just raw data. 
    val nameList = newArrayList("buddy", "boss") 

    val cache = nameList.map[it.toDescription] 

    private val uri = org.eclipse.emf.common.util.URI.createPlatformResourceURI("neverland", true) 

    def public List<IEObjectDescription> loadAdditionalStakeholders() { 
     cache 
    } 

    def private IEObjectDescription toDescription(String name) { 

    ExternalFactoryImpl.init() 
    val ExternalFactory factory = new ExternalFactoryImpl() 

    val Stakeholder obj = factory.createStakeholder as StakeholderImpl 
    obj.setName(name) 


    new StakeholderDescription(name, obj, uri) 
    } 

. . . 

    override getURI() { 
    uri 
    } 

    def public boolean isProvided(EObject object) { 
    if(object.eClass.classifierID != ExternalPackageImpl.STAKEHOLDER) { 
     false 
    } 
    else { 
     val stakeholder = object as Stakeholder 
     nameList.exists[it == stakeholder.name] 
    } 
    } 

} 

к сведению, что провайдер также является resourceDescription и его УИР конечно нонсенс.

С этим провайдером я написал ScopeWrapper.xtend:

class ScopeWrapper implements IScope { 

    private var IScope scope; 
    private var StakeholdersProvider provider 

    new(IScope scopeParam, StakeholdersProvider providerParam) { 
    scope=scopeParam 
    provider = providerParam 
    } 

    override getAllElements() { 
    val elements = scope.allElements.toList 

    val ret = provider.loadAdditionalStakeholders() 
    ret.addAll(elements) 

    ret 
    } 

    override getSingleElement(QualifiedName name) { 
     allElements.filter[it.name == name].head 
    } 

. . . 

} 

и ResourceDescriptionWrapper.xtend

class ResourceDescriptionsWrapper implements IResourceDescriptions { 

    private StakeholdersProvider provider; 
    private IResourceDescriptions descriptions; 

    new(IResourceDescriptions descriptionsParam, StakeholdersProvider providerParam) { 
    descriptions = descriptionsParam 
    provider = providerParam 
    } 

    override getAllResourceDescriptions() { 
    val resources = descriptions.allResourceDescriptions.toList 
    resources.add(provider) 
    resources 
    } 

    override getResourceDescription(URI uri) { 
    if(uri == provider.URI) provider 
    else descriptions.getResourceDescription(uri) 
    } 
    override getExportedObjects() { 
    val descriptions = descriptions.exportedObjects.toList 

    descriptions.addAll(provider.exportedObjects) 

    descriptions 

    } 

    . . . some overrides for getExportedObjects-functions 

} 

все это соединены вместе MyGlobalScopeProvider.xtend

class MyGlobalScopeProvider extends TypesAwareDefaultGlobalScopeProvider { 

    val provider = new StakeholdersProvider() 

    override getScope(Resource context, EReference reference, Predicate<IEObjectDescription> filter) { 
    val scope = super.getScope(context, reference, filter) 
    return new ScopeWrapper(scope, provider) 
    } 

    override public IResourceDescriptions getResourceDescriptions(Resource resource) { 
    val superDescr = super.getResourceDescriptions(resource) 
    return new ResourceDescriptionsWrapper(superDescr, provider) 
    } 

} 

, который зарегистрирован в MyDslUiModule.java

public Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() { 
    return MyGlobalScopeProvider.class; 
} 

Пока все хорошо. Теперь я получаю boss и buddy, предлагаемые в качестве заинтересованных сторон. Однако, когда я использую один из этих двух, я получаю сообщение об ошибке в редакторе, жалующемся на оборванную ссылку и сообщение об ошибке на консоли, которое заинтересовало cannot be exported as the target is not contained in a resource.Выяснение этих 2 мощи связаны я попытался исправить протоколирование ошибок, созданного MyresourceDescriptionStrategy.xtend

class MyResourcesDescriptionStrategy extends DefaultResourceDescriptionStrategy { 

    val provider = new StakeholdersProvider() 

    override isResolvedAndExternal(EObject from, EObject to) { 
    if (provider.isProvided(to)) { 
     // The object is a stakeholder that was originally provided by 
     // our StakeholdersProvider. So we mark it as resolved. 
     true 
    } else { 
     super.isResolvedAndExternal(from, to) 
    } 
    } 
} 

, а также подключить его в UiModule:

public Class<? extends IDefaultResourceDescriptionStrategy> bindDefaultResourceDescriptionStrategy() { 
    return MyResourcesDescriptionStrategy.class; 
} 

Это исправляет ошибку протоколирования, но проблема «оборванная ссылка» остается. Я искал решения для этого, и most prominent result предполагает, что определение IResourceServiceProvider было бы лучшим способом решить мою проблему в первую очередь. Я потрачу немного больше времени на текущий подход и попробую его с ResourceProvider.

EDIT: У меня исправлена ​​проблема «оборванных ссылок». loadAdditionalStakeholders() функция StakeholdersProvider.xtend теперь выглядит следующим образом:

override loadAdditionalStakeholders() { 

    val injector = Guice.createInjector(new ExternalRuntimeModule()); 
    val rs = injector.getInstance(ResourceSet) 
    val resource = rs.createResource(uri) 
    nameList.map[it.toDescription(resource)] 
} 

def private IEObjectDescription toDescription(String name, Resource resource) { 

    ExternalFactoryImpl.init() 
    val ExternalFactory factory = new ExternalFactoryImpl() 

    val Stakeholder obj = factory.createStakeholder as StakeholderImpl 

    obj.setName(name) 
    // not sure why or how but when adding the obj to the resource, the 
    // the resource will be set in obj . . . thus no more dangling ref 
    resource.contents += obj 


    new StakeholderDescription(name, obj, uri) 
} 
+0

, если вы сказали, что внешний материал, если на основе emf я бы рекомендовал вам написать resourceerviceprovider в первую очередь. но вы сказали, что это csv или db и, следовательно, вряд ли будет базироваться на emf. - загрузка и добавление их в ресурс лица (один раз) в глобальном провайдере возможностей также выполнили бы работу в вашем решении. –

+0

Я только в процессе чтения «книги» и только снял документацию. Поэтому я все еще не совсем уверен, что на самом деле означает EMF. Извините, если предоставлена ​​вводящая в заблуждение информация. – agschaid

+0

Я в процессе чтения «книги» и только снял документацию. Поэтому я все еще не совсем уверен, что на самом деле означает EMF. Когда я написал начальный пост, я понял, что это означало бы наличие сущностей в файле, который придерживается определенного синтаксиса. Извините, если предоставлена ​​вводящая в заблуждение информация. Но на самом деле я все еще говорю о некоторой исходной информации, полученной из db или файла. У меня есть список имен в 'StakeholdersProvider.xtend'. Да, это жестко запрограммировано. Но на моей стадии эксперимента он представляет собой макет для внешнего источника данных. Это что-то меняет? – agschaid

Смежные вопросы