/
MelangeResourceImpl.xtend
213 lines (175 loc) · 6.24 KB
/
MelangeResourceImpl.xtend
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package fr.inria.diverse.melange.resource
import fr.inria.diverse.melange.adapters.EObjectAdapter
import fr.inria.diverse.melange.resource.loader.DozerLoader
import org.eclipse.emf.common.util.AbstractTreeIterator
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.EPackage
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl
import org.eclipse.xtend.lib.annotations.Delegate
import fr.inria.diverse.melange.resource.MelangeRegistry.LanguageDescriptor
import org.eclipse.emf.common.notify.Notification
import fr.inria.diverse.melange.resource.loader.ModelCopier
/**
* This class wraps a resource and shift the types of the contained
* EObjects to get instances of a ModelType's classes
*/
class MelangeResourceImpl implements MelangeResource
{
@Delegate Resource.Internal wrappedResource
String expectedMt
String expectedLang
URI melangeUri
// DozerLoader loader = new DozerLoader
Resource contentResource
new(URI uri) {
// FIXME: Retrieve the currently-used one
val rs = new ResourceSetImpl
val query = uri.query
val SEPARATOR = "&|;"
val pairs = query?.split(SEPARATOR)
expectedMt = pairs?.findFirst[startsWith("mt=")]?.substring(3)
expectedLang = pairs?.findFirst[startsWith("lang=")]?.substring(5)
melangeUri = uri
wrappedResource = rs.getResource(MelangeResourceUtils.melangeToFallbackURI(uri), true) as Resource.Internal
}
override Resource getWrappedResource() {
return wrappedResource
}
/**
* Return the content of the wrapped resource.
* If expectedMt and/or expectedLang are set, the EObjects are contained in an internal resource.
*/
override getContents() throws RuntimeException {
if(contentResource === null)
doAdapt()
return contentResource.contents
}
override getAllContents() {
return
new AbstractTreeIterator<EObject>(this, false) {
override getChildren(Object object) {
return
if (object instanceof Resource)
object.contents.iterator
else if (object instanceof EObject)
object.eContents.iterator
}
}
}
override getEObject(String uriFragment) {
return contentResource.getEObject(uriFragment)
}
override getURIFragment(EObject o) {
return
if (o instanceof EObjectAdapter<?>)
wrappedResource.getURIFragment(o.adaptee)
else null
}
override getURI() {
return melangeUri
}
/**
* Return a ResourceAdapter exposing {@link modelType} interfaces and
* delegating to {@link adaptedResource}
*/
private def Resource adaptResourceToMT(Resource adaptedResource, String modelType){
val actualLanguage = adaptedResource.language
val adapterCls = actualLanguage.getAdapterFor(modelType)
if (adapterCls !== null) {
try {
return adapterCls.newInstance => [
adaptee = adaptedResource
parent = this
URI = org.eclipse.emf.common.util.URI.createURI("modelAsAdapted")
]
} catch (InstantiationException e) {
throw new MelangeResourceException('''Cannot instantiate adapter type «adapterCls»''', e)
} catch (IllegalAccessException e) {
throw new MelangeResourceException('''Cannot access adapter type «adapterCls»''', e)
}
}
throw new MelangeResourceException('''No adapter class registered for <«actualLanguage.identifier», «modelType»>''')
}
/**
* Return a resource in the namespace of {@link language}
*/
private def Resource adaptResourceToLang(Resource adaptedResource, String language){
val actualLanguage = adaptedResource.language
val expectedLanguage = MelangeRegistry.INSTANCE.getLanguageByIdentifier(language)
if (expectedLanguage === null)
throw new MelangeResourceException("Cannot find a registered language with URI " + language)
val actualMt = MelangeRegistry.INSTANCE.getModelTypeByIdentifier(actualLanguage.exactType)
val expectedMt = MelangeRegistry.INSTANCE.getModelTypeByIdentifier(expectedLanguage.exactType)
if (actualMt.identifier == expectedMt.identifier) {
// Nothing to do
return adaptedResource
}
else if (actualMt.superTypes.contains(expectedMt.identifier)) {
// Upcast
return adaptedResource
}
else if (expectedMt.superTypes.contains(actualMt.identifier)) {
// Downcast
val actualPkg = EPackage.Registry.INSTANCE.getEPackage(actualLanguage.uri)
val expectedPkg = EPackage.Registry.INSTANCE.getEPackage(expectedLanguage.uri)
val copier = new ModelCopier(#[actualPkg].toSet,#[expectedPkg].toSet)
return copier.clone(adaptedResource)
// loader.initialize(actualPkg, expectedPkg)
// return loader.loadBaseAsExtended(adaptedResource, expectedPkg)
}
else
// No typing hierarchy found
throw new MelangeResourceException('''«actualMt.identifier» cannot be transtyped to «expectedMt.identifier»''')
}
private def LanguageDescriptor getLanguage(Resource resource){
val objs = resource.getContents()
val actualPkgUri = objs.head.eClass.EPackage.nsURI
val actualLanguage = MelangeRegistry.INSTANCE.getLanguageByUri(actualPkgUri)
if (actualLanguage === null)
throw new MelangeResourceException("Cannot find a registered language with URI " + actualPkgUri)
return actualLanguage
}
/**
* Create a ResourceAdapter for expectedMt or/and copy the wrapped resource for expectedLang
*/
private def void doAdapt() {
contentResource = wrappedResource
if (!wrappedResource.getContents().empty && !(expectedMt == null && expectedLang == null)) {
// 1 - Convert Language to Language
if (expectedLang !== null) {
contentResource = contentResource.adaptResourceToLang(expectedLang)
}
// 2 - Adapt Language to ModelType
if (expectedMt !== null) {
contentResource = contentResource.adaptResourceToMT(expectedMt)
}
}
this.resourceSet.resources.add(contentResource)
}
override void upcast(String modelTypeID) {
expectedMt = modelTypeID
doAdapt()
}
override void extendAs(String languageID) {
expectedLang = languageID
doAdapt()
}
override String getModelType() {
return expectedMt
}
override String getLanguage() {
return expectedLang
}
override eAdapters() {
if(contentResource === null)
doAdapt()
return contentResource.eAdapters
}
override eNotify(Notification notification) {
if(contentResource === null)
doAdapt()
contentResource.eNotify(notification)
}
}