XText cross-reference to an non-DSL resource - xtext

Please consider this minimal Xtext grammar.
Model:
"As a" stackeholder=Stakeholder "I want" want=Want;
Stakeholder:
'client' | 'developer' | 'manager';
Want:
'everything' | 'cookies' | 'fame';
Now what I need to do, is to move the definition of stakeholders (let's forget about want) to SOME external data source. This "external data source" might be a CSV file, might be a DB or maybe a web service. But I it is highly unlikely to be some Xtext file or to come with an EMF model. But still I want to cross-reference it just like you can cross-reference java types in your DSL.
Issues like manual parsing and caching (for performance sake) aside: is this even doable?
I've dug a little into the topic of scopes and resource providers but everything I found required the external source to be part of at least another DSL.
I'd be very happy about a rough outline what would be needed to be done.

Sorry it took me so long to respond. I tried Christians suggestion, was not very satisfied and than priorities shifted. Now I'll have another go at the problem and in order to document for others (and to clear my head) I'll write down what I did so far since it was not all that straight forward and required a fair amount of experimentation.
I will not post full classes but only the relevant parts. Feel free to ask for more detail if you need it.
My Syntax-Definition now looks like this:
Model:
stakeholders+=StakeholderDecl*
requirements+=Requirement*;
Requirement:
'As a' stakeholder=[Stakeholder] 'I want' want=('everything' | 'cookies' | 'results')
;
StakeholderDecl returns Stakeholder :
'Stakeholder' Stakeholder
;
Stakeholder:
name=ID
;
Let it be noted that everything below needed to to be done in the .ui package.
First I created 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]
}
}
}
note that the provider is also a resourceDescription and its uri of course is nonsense.
With this provider I wrote a 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
}
. . .
}
and 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
}
all of this is wired together 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)
}
}
which is registered in MyDslUiModule.java
public Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() {
return MyGlobalScopeProvider.class;
}
So far so good. I now get boss and buddy suggested as stakeholders. However when I use one of those 2 I get an error in the editor complaining about a dangling reference and an error logging in the console that a stakeholder cannot be exported as the target is not contained in a resource. Figuring those 2 might are related I tried to fix the error logging, created 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)
}
}
}
and also wire it in the UiModule:
public Class<? extends IDefaultResourceDescriptionStrategy> bindDefaultResourceDescriptionStrategy() {
return MyResourcesDescriptionStrategy.class;
}
This fixes the logging error but the "dangling reference" problem remains. I searched for solutions for this and the most prominent result suggests that defining a IResourceServiceProvider would have been the best way to solve my problem in the first place.
I'll spend a bit more time on the current approach and than try it with a ResourceProvider.
EDIT: I got the "dangling reference" problem fixed. The loadAdditionalStakeholders() function in StakeholdersProvider.xtend now looks like this:
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)
}

Related

Why are Java lambdas treated differently from nested classes with respect to instance field initialization?

With javac 1.8.0_77 this class does not compile:
import java.util.function.*;
public class xx {
final Object obj;
final Supplier<Object> supplier1 = new Supplier<Object>() {
#Override
public Object get() {
return xx.this.obj;
}
};
final Supplier<Object> supplier2 = () -> { return this.obj; };
xx(Object obj) {
this.obj = obj;
}
}
Here's the error:
xx.java:12: error: variable obj might not have been initialized
final Supplier<Object> supplier2 = () -> { return this.obj; };
^
1 error
Questions:
Is the generation of this error correct according to the JLS?
If so, what is the reasoning behind the JLS treating a #FunctionalInterface lamba implementation (supplier2) differently from its equivalent inner class implementation (supplier1) in this respect?
EDITED TO ADD (2022/9/21)
FYI here's a simple compiler patch that fixes this. It causes lambdas to be treated like non-constructor methods with respect to field initialization (namely, ignore them) in Flow.AssignAnalyzer:
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
index 20abb281211..7e77d594143 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
## -2820,30 +2909,33 ## public class Flow {
#Override
public void visitLambda(JCLambda tree) {
final Bits prevUninits = new Bits(uninits);
final Bits prevInits = new Bits(inits);
int returnadrPrev = returnadr;
+ int firstadrPrev = firstadr;
int nextadrPrev = nextadr;
ListBuffer<PendingExit> prevPending = pendingExits;
try {
returnadr = nextadr;
+ firstadr = nextadr;
pendingExits = new ListBuffer<>();
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
inits.incl(def.sym.adr);
uninits.excl(def.sym.adr);
}
if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
scanExpr(tree.body);
} else {
scan(tree.body);
}
}
finally {
returnadr = returnadrPrev;
uninits.assign(prevUninits);
inits.assign(prevInits);
pendingExits = prevPending;
+ firstadr = firstadrPrev;
nextadr = nextadrPrev;
}
}
Browsing through the JLS changes from JSR 335, this looks like an omission to me:
Access to blank final fields is regulated by JLS Chapter 16
There is a section "Definite Assignment and Anonymous Classes" which mandates the error in the case of supplier1.
The JSR 335 spec has only one marginal change for chapter 16, never mentioning "lambda" or "method references" throughout this chapter.
In fact the only change in Chap.16 is (using bold type face for additions):
Throughout the rest of this chapter, we will, unless explicitly stated otherwise, write V to represent an in-scope (6.3) local variable or a blank final field (for rules of definite assignment) or a blank final variable (for rules of definite unassignment).
At the bottom line, compilers seem to be right in not complaining in the lambda case, but for consistency JLS should probably be amended to cover this case, too.
Edit:: OpenJDK already has a spec bug for this, changes are being proposed as we speak.

Interception Using StructureMap 3.*

I've done interception using Castle.DynamicProxy and StructureMap 2.6 API but now can't do it using StructureMap 3.0. Could anyone help me find updated documentation or even demo? Everything that I've found seems to be about old versions. e.g. StructureMap.Interceptors.TypeInterceptor interface etc.
HAHAA! I f***in did it! Here's how:
public class ServiceSingletonConvention : DefaultConventionScanner
{
public override void Process(Type type, Registry registry)
{
base.Process(type, registry);
if (type.IsInterface || !type.Name.ToLower().EndsWith("service")) return;
var pluginType = FindPluginType(type);
var delegateType = typeof(Func<,>).MakeGenericType(pluginType, pluginType);
// Create FuncInterceptor class with generic argument +
var d1 = typeof(FuncInterceptor<>);
Type[] typeArgs = { pluginType };
var interceptorType = d1.MakeGenericType(typeArgs);
// -
// Create lambda expression for passing it to the FuncInterceptor constructor +
var arg = Expression.Parameter(pluginType, "x");
var method = GetType().GetMethod("GetProxy").MakeGenericMethod(pluginType);
// Crate method calling expression
var methodCall = Expression.Call(method, arg);
// Create the lambda expression
var lambda = Expression.Lambda(delegateType, methodCall, arg);
// -
// Create instance of the FuncInterceptor
var interceptor = Activator.CreateInstance(interceptorType, lambda, "");
registry.For(pluginType).Singleton().Use(type).InterceptWith(interceptor as IInterceptor);
}
public static T GetProxy<T>(object service)
{
var proxyGeneration = new ProxyGenerator();
var result = proxyGeneration.CreateInterfaceProxyWithTarget(
typeof(T),
service,
(Castle.DynamicProxy.IInterceptor)(new MyInterceptor())
);
return (T)result;
}
}
The problem here was that SM 3.* allows interception for known types, i.e. doing something like this:
expression.For<IService>().Use<Service>().InterceptWith(new FuncInterceptor<IService>(service => GetProxyFrom(service)));
But what if you'd like to include the interception logic inside your custom scanning convention where you want to intercept all instances of type with specific signature (types having name ending on 'service', in my case)?
That's what I've accomplished using Expression API and reflection.
Also, I'm using here Castle.DinamicProxy for creating proxy objects for my services.
Hope someone else will find this helpful :)
I find the best place to go for any new versions is directly to the source.
If it's written well, then it will include test cases. Thankfully structuremap does include test cases.
You can explore the tests here
In the meantime I've written an example of an Activator Interceptor, and how to configure it.
static void Main()
{
ObjectFactory.Configure(x =>
{
x.For<Form>().Use<Form1>()
.InterceptWith(new ActivatorInterceptor<Form1>(y => Form1Interceptor(y), "Test"));
});
Application.Run(ObjectFactory.GetInstance<Form>());
}
public static void Form1Interceptor(Form f)
{
//Sets the title of the form window to "Testing"
f.Text = "Testing";
}
EDIT:
How to use a "global" filter using PoliciesExpression
[STAThread]
static void Main()
{
ObjectFactory.Configure(x =>
{
x.Policies.Interceptors(new InterceptorPolicy<Form>(new FuncInterceptor<Form>(y => Intercept(y))));
});
Application.Run(ObjectFactory.GetInstance<Form>());
}
private static Form Intercept(Form form)
{
//Do the interception here
form.Text = "Testing";
return form;
}

OntModel interface has no listHierarchyRootProperties method

Jena's OntModel has a method listHierarchyRootClasses that returns an iterator over the classes in this ontology model that represent the uppermost nodes of the class hierarchy. But why does OntModel have no method of the same function for the semantic properties? There is a property hierarchy as well, so why developers make a listHierarchyRootProperties?
I have solved this by using listAllOntProperties method, but it is a workaround, and does not look good. I don't understand why is it necessary. What is the reason?
Jena is an open-source project. You are more than welcome to submit a patch with the additional functionality you would like to see in the library. Please submit patches via the Jira account.
To answer your direct question: there's no particular reason why there's no equivalent for the property hierarchy. However, property inheritance isn't as widely used as as class inheritance in OWL, and in all the years since I wrote listHierarchyRootClasses, you're the first person I can remember asking about the property hierarchy.
Here is my workaround, which produces alphabetically sorted hierarchy (tree) of semantic properties. The getPropertyTreeModel() method returns a model for an ice:tree component and the parameter domContent is not important (it is for my special needs):
protected static DefaultTreeModel getPropertyTreeModel(OntModel ontModel, Document domContent) {
System.out.println("Creating property model...");
DefaultMutableTreeNode rootTreeNode = getRoot();
DefaultTreeModel treeModel = new DefaultTreeModel(rootTreeNode);
Iterator i = getAlphabeticalIterator(ontModel.listAllOntProperties().filterDrop(new Filter() {
#Override
public boolean accept(Object o) {
return !((OntProperty) o).listSuperProperties(true).toList().isEmpty();
}
}));
while (i.hasNext()) {
joinResource(rootTreeNode, (OntProperty) i.next(), new ArrayList(), OntProperty.class, domContent);
}
return treeModel;
}
private static Iterator getAlphabeticalIterator(ExtendedIterator ei) {
List l = ei.toList();
Collections.sort(l, new Comparator<OntResource>() {
#Override
public int compare(OntResource o1, OntResource o2) {
return (o1.getLocalName().compareTo(o2.getLocalName()));
}
});
return l.iterator();
}
private static DefaultMutableTreeNode getRoot() {
DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode();
ClassNodeUserObject rootObject = new ClassNodeUserObject(rootTreeNode);
rootObject.setExpanded(true);
rootTreeNode.setUserObject(rootObject);
return rootTreeNode;
}
private static void joinResource(DefaultMutableTreeNode parent, OntResource res, List occurs, Class c, Document domContent) {
DefaultMutableTreeNode branchNode = new DefaultMutableTreeNode();
SemanticNodeUserObject branchObject = (c.equals(OntClass.class))
? new ClassNodeUserObject(branchNode) : new PropertyNodeUserObject(branchNode);
branchObject.setOntResource(res);
branchObject.setExpanded(false);
branchObject.setLeaf(true);
// optimalizace: v pripade prazdneho souboru bez parsovani, aktualizace barev
if (domContent != null) {
setColorToNode(branchObject, domContent);
}
branchNode.setUserObject(branchObject);
parent.add(branchNode);
// rekurze
if (res.canAs(c) && !occurs.contains(res)) {
ExtendedIterator ei = (c.equals(OntClass.class)) ? ((OntClass) res).listSubClasses(true)
: ((OntProperty) res).listSubProperties(true);
branchObject.setLeaf(!ei.hasNext());
for (Iterator i = getAlphabeticalIterator(ei); i.hasNext();) {
OntResource sub = (OntResource) i.next();
occurs.add(res);
joinResource(branchNode, sub, occurs, c, domContent);
occurs.remove(res);
}
}
}

Ability to add "plugin" in war-mode

I am lookin for a way to let the admin-role of my grails-app add a "feature"/"plugin"
to the running server, so that the system makes use of it instantly.
To be more concrete here is a small example:
package domains
abstract class Provider {
def protected name;
def protected activated = false;
def private valid;
def Provider( providerName ) {
if( providerName != null ) {
name = providerName;
valid = true;
else valid = false;
}
def isValid() { valid }
def getName() { name }
def isActivated() { activated }
def setActivated( bool ) { activaed = bool }
abstract List<String> search( String searchKey );
}
Some Subclass:
package googleprovider
import Provider;
class GoogleProvider extends Provider {
def GooleProvider( active ) {
super( "Google" );
activated = active;
}
#Override
List<String> search( String searchKey ) {
return ["http://www.google.com"]
}
}
Now every "plugin"/"feature" should extend from Provider and be placed as what ever file in a directory "plugins/providers/".
And the server should create an instance of this GoogleProvider on an "onAdd"-event or something leashed by that admin.
Is there any chance this could be done? Or am I totally dreaming?
If it is somehow possible and it's just that I am going a completly wrong direction,
just tell me! ;-)
Thanks for your time!
I suggest you look for plugins that registers new Artefacts, so in your startup you can lookup for this classes. You can also create a folder in grails-app to store the providers classes.
See the Grails Dao Artefacts plugin, for example. It creates the daos folder inside grails-app, and consider all classes as a DAO Artefact. You also gain the ability of use Depenceny Injection in your classes (e.g. services).
Some points to look
Install Script creates the directory
You have some classes that declare the Artefact
The plugin descriptor is responsible to register them as Spring Beans
More info in
Grails developer wiki
Blog post with example

Groovy Meta Programming

I want to override a method definition in Grails. I am trying to use Groovy metaprogramming as the class which I want to override belongs to a framework.
Below is the original class.
class SpringSocialSimpleSignInAdapter implements SignInAdapter {
private RequestCache requestCache
SpringSocialSimpleSignInAdapter(RequestCache requestCache) {
this.requestCache = requestCache;
}
String signIn(String localUserId, Connection<?> connection, NativeWebRequest request) {
SignInUtils.signin localUserId
extractOriginalUrl request
}
}
I am trying to override like below
SpringSocialSimpleSignInAdapter.metaClass.signIn = {java.lang.String str, org.springframework.social.connect.Connection conn, org.springframework.web.context.request.NativeWebRequest webreq ->
println 'coming here....' // my implementation here
return 'something'
}
But for some reason overriding is not hapening. I am not able to figure it out. Any help would be greatly appretiated.
Thanks
Yeah, seems like that bug. I don't know your whole scenario, but anyway, here's a small workaround i made:
In your class definition, you don't implement the interface
You create your object and do your metamagic
Use groovy coercion to make it act as the interface and then you can pass it around
Here is a small script i made using JIRA bug to prove it:
interface I {
def doIt()
}
class T /*implements I*/ {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
// here the coercion happens and the assertion works fine
def i = t as I
assert !i.doIt()
assert !t.doIt()
// here the polymorphism happens fine
def iOnlyAcceptInterface(I i) { assert !i.doIt() }
iOnlyAcceptInterface(i)

Resources