-
Notifications
You must be signed in to change notification settings - Fork 7
/
AspectCopier.xtend
201 lines (173 loc) · 7.74 KB
/
AspectCopier.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
package fr.inria.diverse.melange.utils
import fr.inria.diverse.commons.asm.shade.DirectoryShader
import fr.inria.diverse.commons.asm.shade.ShadeRequest
import fr.inria.diverse.commons.asm.shade.relocation.Relocator
import fr.inria.diverse.commons.asm.shade.relocation.SimpleRelocator
import fr.inria.diverse.commons.asm.shade.resource.K3AspectPropertiesTransformer
import fr.inria.diverse.commons.asm.shade.resource.ResourceTransformer
import fr.inria.diverse.melange.ast.MetamodelExtensions
import fr.inria.diverse.melange.ast.ModelingElementExtensions
import fr.inria.diverse.melange.ast.NamingHelper
import fr.inria.diverse.melange.eclipse.EclipseProjectHelper
import fr.inria.diverse.melange.metamodel.melange.Aspect
import fr.inria.diverse.melange.metamodel.melange.Metamodel
import java.io.File
import java.io.IOException
import java.util.ArrayList
import javax.inject.Inject
import org.apache.log4j.Logger
import org.eclipse.core.resources.IFile
import org.eclipse.core.resources.IResource
import org.eclipse.core.resources.IResourceVisitor
import org.eclipse.core.runtime.CoreException
import org.eclipse.emf.common.util.URI
import org.eclipse.xtext.naming.IQualifiedNameConverter
import org.eclipse.xtext.naming.QualifiedName
import org.eclipse.xtext.util.internal.Stopwatches
import static fr.inria.diverse.melange.utils.AspectCopier.*
import fr.inria.diverse.commons.asm.shade.filter.Filter
/**
* Baaah, full of sh*t
*/
class AspectCopier
{
@Inject extension ModelingElementExtensions
@Inject extension MetamodelExtensions
@Inject extension IQualifiedNameConverter
@Inject extension NamingHelper
@Inject extension EclipseProjectHelper
@Inject ErrorHelper errorHelper
static Logger log = Logger.getLogger(AspectCopier)
// FIXME: We should first check that aspects are importable (i.e. defined
// on a type group this metamodel is a subtype of)
def String copyAspectTo(Aspect asp, Metamodel mm) {
val task = Stopwatches.forTask("copying aspects in new type group")
task.start
val project = mm.eResource.project
if (project === null)
return null
val ws = project.workspace.root
val shader = new DirectoryShader
val request = new ShadeRequest
val relocators = new ArrayList<Relocator>
val sourceEmfNamespace = asp.targetedNamespace
val targetEmfNamespace = mm.packageFqn.toQualifiedName.skipLast(1)
val sourceAspectNamespace = asp.aspectTypeRef.identifier.toQualifiedName.skipLast(1)
if(sourceEmfNamespace.equals(sourceAspectNamespace)){
errorHelper.addError(asp, "Melange cannot correctly handle aspect classes if they use the same package name as the aspectized emf classes, please move the aspect classes in a dedicated package", null)
}
val targetAspectNamespace = getAspectTargetNamespace(sourceAspectNamespace,mm)
val projectPathTmp = new StringBuilder
val projectNameTmp = new StringBuilder
ws.accept(new IResourceVisitor {
override visit(IResource resource) throws CoreException {
if (resource instanceof IFile) {
val resourcePath = resource.locationURI.path
val toBeMatched = asp.aspectTypeRef.identifier.replace(".", "/") + ".java"
if (resourcePath.endsWith(toBeMatched)) {
val projectPath = resource.project.locationURI.path
if (projectPathTmp.length == 0)
projectPathTmp.append(projectPath)
if (projectNameTmp.length == 0)
projectNameTmp.append(resource.project.name)
}
return false
}
return true
}
})
val sourceAspectFolder = projectPathTmp.toString + "/xtend-gen/"
//val targetAspectFolder = projectPathTmp.toString + "/../" + targetAspectNamespace + "/src-gen/"
val sourceFolderFile = new File(sourceAspectFolder)
val sourceProject = ws.getProject(projectNameTmp.toString)
val findTargetProject = ws.getProject(mm.name+"_Gen")
// FIXME: Just to have a first call of the EPackageProvider
// in order to set the ecoreUri when inherited
val x = mm.pkgs
val ecoreUri = URI::createURI(mm.ecoreUri)
val emfRuntimeProject = ecoreUri.segment(1)
val targetProject =
if (findTargetProject.exists)
findTargetProject
else
EclipseProjectHelper::createAspectsRuntimeProject(
sourceProject,
mm.name+"_Gen",
targetAspectNamespace.toString,
emfRuntimeProject
)
//ws.getProject(targetAspectNamespace.toString).rawLocation
val targetAspectFolder = findTargetProject.locationURI.path + "/src-gen/"
val targetFolderFile = new File(targetAspectFolder)
// val filenameToBeFound = '''/src-gen/«targetAspectNamespace.toString.replace(".", "/")»/«asp.aspectTypeRef.simpleName».java'''
// val fileToBeFound = targetProject.getFile(filenameToBeFound)
if(project.name != targetProject.name){
EclipseProjectHelper::addDependencies(project, #[targetProject.name])
}
relocators += new SimpleRelocator(sourceAspectNamespace.toString, targetAspectNamespace.toString, null, #[])
relocators += new SimpleRelocator(sourceEmfNamespace.toString, targetEmfNamespace.toString, null, #[])
val className = asp.aspectAnnotationValue
//Filter files not related to targeted aspect
val filter = new Filter(){
String targetClass = className
override canFilter(File jar) {
true
}
override finished() {}
override isFiltered(String classFile) {
return !(classFile.endsWith(targetClass+"Aspect.java") ||
classFile.endsWith(targetClass+"Aspect"+targetClass+"AspectContext.java") ||
classFile.endsWith(targetClass+"Aspect"+targetClass+"AspectProperties.java"))
}
}
request.inputFolders = #{sourceFolderFile}
request.outputFolder = targetFolderFile
request.filters = #[filter]
request.resourceTransformers = #[]
request.relocators = relocators
try {
log.debug('''Copying aspect «asp.aspectTypeRef.identifier» to «mm.name»:''')
log.debug(''' sourceEmfNamespace = «sourceEmfNamespace»''')
log.debug(''' targetEmfNamespace = «targetEmfNamespace»''')
log.debug(''' sourceAspectNamespace = «sourceAspectNamespace»''')
log.debug(''' targetAspectNamespace = «targetAspectNamespace»''')
log.debug(''' sourceAspectFolder = «sourceAspectFolder»''')
log.debug(''' targetAspectFolder = «targetAspectFolder»''')
// if (!fileToBeFound.exists) {
shader.shade(request)
log.debug('''Copying META-INF aspect_properties «asp.aspectTypeRef.identifier» to «mm.name»:''')
val sourceMetaInfFolder = projectPathTmp.toString + "/META-INF/"
val sourceMetaInfFile = new File(sourceMetaInfFolder)
val targetMetaInfFile = new File(findTargetProject.locationURI.path + "/META-INF/")
request.inputFolders = #{sourceMetaInfFile}
request.outputFolder = targetMetaInfFile
request.resourceTransformers = #[new K3AspectPropertiesTransformer(targetAspectNamespace.toString) as ResourceTransformer]
shader.shade(request)
targetProject.refreshLocal(IResource.DEPTH_INFINITE, null)
// }
return '''«targetAspectNamespace».«asp.aspectTypeRef.simpleName»'''
} catch (IOException e) {
log.debug("Copy failed", e)
return null
} catch (CoreException e) {
log.debug("Refresh failed", e)
return null
} catch (Exception e) {
log.error("Unexpected error", e)
return null
} finally {
task.stop
}
}
def protected QualifiedName getAspectTargetNamespace(QualifiedName sourceAspectNamespace , Metamodel mm){
val postfix = if(sourceAspectNamespace.segmentCount > 1 &&(sourceAspectNamespace.lastSegment.equals("aspect")
|| sourceAspectNamespace.lastSegment.equals("aspects")
|| sourceAspectNamespace.lastSegment.equals("k3dsa")
)){ sourceAspectNamespace.lastSegment } else{"aspect"}
if(sourceAspectNamespace.segmentCount > 2){
return sourceAspectNamespace.skipLast(2).append(mm.name.toLowerCase).append(postfix)
} else {
return sourceAspectNamespace.skipLast(1).append(mm.name.toLowerCase).append(postfix)
}
}
}