1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.sequencer.teiid;
25
26 import java.io.FileWriter;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.List;
31 import org.modeshape.common.collection.Problems;
32 import org.modeshape.common.collection.SimpleProblems;
33 import org.modeshape.common.i18n.I18n;
34 import org.modeshape.graph.ExecutionContext;
35 import org.modeshape.graph.Graph;
36 import org.modeshape.graph.Location;
37 import org.modeshape.graph.Subgraph;
38 import org.modeshape.graph.SubgraphNode;
39 import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource;
40 import org.modeshape.graph.property.Name;
41 import org.modeshape.graph.property.NamespaceRegistry;
42 import org.modeshape.graph.property.NamespaceRegistry.Namespace;
43 import org.modeshape.graph.property.basic.LocalNamespaceRegistry;
44 import com.beust.jcommander.JCommander;
45 import com.beust.jcommander.Parameter;
46 import com.google.common.collect.ArrayListMultimap;
47 import com.google.common.collect.Multimap;
48
49
50
51
52 public class CndFromEcore {
53
54 public static void main( String[] args ) {
55 CndFromEcore converter = new CndFromEcore();
56 JCommander commander = new JCommander(converter, args);
57 if (!converter.isValid()) {
58 commander.usage();
59 } else {
60 converter.execute();
61 if (converter.getProblems().hasProblems()) {
62 System.out.println(converter.getProblems());
63 }
64 }
65 }
66
67 private static final char NEWLINE = '\n';
68
69 @Parameter( description = "Comma-separated list of Ecore input file paths or URLs" )
70 private List<String> ecoreFileNames = new ArrayList<String>();
71 @Parameter( names = {"-o", "-out"}, description = "Name of the CND output file" )
72 private String cndFileName;
73 @Parameter( names = "-debug", description = "Debug mode" )
74 private boolean debug = false;
75 @Parameter( names = "-mixin", description = "EClasses are converted to node types" )
76 private boolean mixins = false;
77 @Parameter( names = "-shortNames", description = "Generate shorter names where possible" )
78 private boolean shortNames = false;
79
80 private Problems problems = new SimpleProblems();
81
82
83
84
85
86
87 public List<String> getEcoreFileNames() {
88 return ecoreFileNames;
89 }
90
91
92
93
94 public void setEcoreFileNames( List<String> ecoreFileNames ) {
95 this.ecoreFileNames = ecoreFileNames;
96 }
97
98
99
100
101 public void setEcoreFileNames( String... ecoreFileNames ) {
102 this.ecoreFileNames = new ArrayList<String>(Arrays.asList(ecoreFileNames));
103 }
104
105
106
107
108 public String getCndFileName() {
109 return cndFileName;
110 }
111
112
113
114
115 public void setCndFileName( String cndFileName ) {
116 this.cndFileName = cndFileName;
117 }
118
119
120
121
122 public boolean isDebug() {
123 return debug;
124 }
125
126
127
128
129 public void setDebug( boolean debug ) {
130 this.debug = debug;
131 }
132
133
134
135
136 public boolean generatesMixins() {
137 return mixins;
138 }
139
140
141
142
143 public void setGeneratesMixins( boolean mixins ) {
144 this.mixins = mixins;
145 }
146
147
148
149
150 public boolean generateShortNames() {
151 return shortNames;
152 }
153
154
155
156
157 public void setGeneratesShortNames( boolean shortNames ) {
158 this.shortNames = shortNames;
159 }
160
161 public boolean isValid() {
162 if (ecoreFileNames.isEmpty()) return false;
163 return true;
164 }
165
166
167
168
169 public Problems getProblems() {
170 return problems;
171 }
172
173 public void execute() {
174 ExecutionContext context = new ExecutionContext();
175 NamespaceRegistry registry = context.getNamespaceRegistry();
176
177
178 LocalNamespaceRegistry localRegistry = new LocalNamespaceRegistry(registry);
179 context = context.with(localRegistry);
180
181
182 List<String> ecoreFileContributions = new ArrayList<String>();
183 for (String ecoreFileName : getEcoreFileNames()) {
184 String ecoreName = ecoreFileName.replace("\\.ecore", "");
185 debug(TeiidI18n.readingEcoreFile, ecoreFileName);
186 StringBuilder sb = new StringBuilder();
187 try {
188 InMemoryRepositorySource source = new InMemoryRepositorySource();
189 source.setName(ecoreName);
190 Graph graph = Graph.create(source, context);
191 graph.importXmlFrom(ecoreFileName).into("/");
192 Subgraph subgraph = graph.getSubgraphOfDepth(20).at("/ecore:EPackage");
193 CndGraphReader reader = new CndGraphReader(subgraph, generatesMixins(), generateShortNames());
194 reader.writeTo(sb);
195
196 ecoreFileContributions.add(sb.toString());
197 } catch (Throwable t) {
198 problems.addError(TeiidI18n.errorReadingEcoreFile, ecoreFileName, t.getLocalizedMessage());
199 }
200 }
201
202
203 StringBuilder output = new StringBuilder();
204
205 output.append(getHeader());
206
207
208 for (Namespace namespace : localRegistry.getLocalNamespaces()) {
209 write(output, namespace);
210 }
211 output.append(NEWLINE);
212
213
214 for (String contribution : ecoreFileContributions) {
215 output.append(contribution);
216 output.append(NEWLINE);
217 }
218
219
220 if (cndFileName != null && cndFileName.trim().length() != 0) {
221 try {
222 FileWriter writer = new FileWriter(cndFileName);
223 try {
224 } finally {
225 writer.close();
226 }
227 } catch (Throwable t) {
228 problems.addError(TeiidI18n.errorWritingCndFile, cndFileName, t.getLocalizedMessage());
229 }
230 } else {
231 System.out.println(output);
232 }
233 }
234
235 protected void write( StringBuilder writer,
236 Namespace namespace ) {
237 writer.append("<")
238 .append(namespace.getPrefix())
239 .append("='")
240 .append(namespace.getNamespaceUri())
241 .append("'>")
242 .append(NEWLINE);
243 }
244
245 protected String getHeader() {
246 StringBuilder sb = new StringBuilder();
247 sb.append("/*").append(NEWLINE);
248 sb.append(" * Generated using the ").append(getClass().getCanonicalName()).append(" program.").append(NEWLINE);
249 sb.append(" *").append(NEWLINE);
250 sb.append(" */").append(NEWLINE);
251 return sb.toString();
252 }
253
254 protected void debug( I18n msg,
255 Object... params ) {
256 if (isDebug()) {
257 System.out.println(msg.text(params));
258 }
259 }
260
261 protected static class CndGraphReader extends XmiGraphReader {
262 private final boolean generateMixins;
263
264 protected CndGraphReader( Subgraph subgraph,
265 boolean generateMixins,
266 boolean generateShortNames ) {
267 super(subgraph, generateShortNames);
268 this.generateMixins = generateMixins;
269 }
270
271 protected void writeTo( StringBuilder sb ) {
272 SubgraphNode pkg = subgraph.getRoot();
273 String pkgName = inflector.titleCase(firstValue(pkg, "name"));
274 String uri = firstValue(pkg, "nsURI");
275 String prefix = namespacePrefix(firstValue(pkg, "nsPrefix"));
276
277
278 sb.append("// -------------------------------------------").append(NEWLINE);
279 sb.append("// ").append(pkgName).append(NEWLINE);
280 sb.append("// -------------------------------------------").append(NEWLINE);
281
282
283 namespaces.register(prefix, uri);
284 setCurrentNamespaceUri(uri);
285
286
287 Multimap<Name, String> literalsByEnumName = ArrayListMultimap.create();
288 for (Location child : pkg.getChildren()) {
289 SubgraphNode classifier = pkg.getNode(child.getPath().getLastSegment());
290 String type = firstValue(classifier, "xsi:type");
291 if ("ecore:EEnum".equals(type)) {
292 Name enumName = nameFrom(firstValue(classifier, "name"));
293 for (Location feature : classifier.getChildren()) {
294 SubgraphNode literal = classifier.getNode(feature.getPath().getLastSegment());
295 String literalValue = firstValue(literal, "name");
296 literalsByEnumName.put(enumName, literalValue);
297 }
298 }
299 }
300
301 for (Location child : pkg.getChildren()) {
302
303 SubgraphNode classifier = pkg.getNode(child.getPath().getLastSegment());
304 String type = firstValue(classifier, "xsi:type");
305 if ("ecore:EEnum".equals(type)) continue;
306
307 Name nodeTypeName = nameFrom(firstValue(classifier, "name"));
308 boolean isAbstract = firstValue(classifier, "abstract", false);
309 List<Name> supertypes = names(classifier, "eSuperTypes", "\\s");
310
311
312 sb.append("[").append(stringFrom(nodeTypeName)).append("] ");
313
314
315 if (!supertypes.isEmpty()) {
316 sb.append("> ");
317 boolean first = true;
318 for (Name supertype : supertypes) {
319 if (first) first = false;
320 else sb.append(",");
321 sb.append(stringFrom(supertype)).append(" ");
322 }
323 }
324 if (isAbstract) sb.append("abstract ");
325 if (generateMixins) sb.append("mixin ");
326
327
328 for (Location feature : classifier.getChildren()) {
329 SubgraphNode structuralFeature = classifier.getNode(feature.getPath().getLastSegment());
330 String featureType = firstValue(structuralFeature, "xsi:type");
331 Name featureName = nameFrom(firstValue(structuralFeature, "name"));
332 long upperBound = firstValue(structuralFeature, "upperBound", 1L);
333 long lowerBound = firstValue(structuralFeature, "lowerBound", 0L);
334 boolean isSingle = upperBound == 1;
335 boolean isRequired = lowerBound > 0;
336 boolean isReference = "ecore:EReference".equals(featureType);
337 boolean isTransient = firstValue(structuralFeature, "transient", false);
338 boolean isContainment = firstValue(structuralFeature, "containment", false);
339 boolean isUnsettable = firstValue(structuralFeature, "unsettable", false);
340 boolean isVolatile = firstValue(structuralFeature, "volatile", false);
341 boolean isChangeble = firstValue(structuralFeature, "changeable", true);
342 Name dataType = nameFrom(firstValue(structuralFeature, "eType"));
343 String defaultValue = firstValue(structuralFeature, "defaultValueLiteral");
344
345
346 String jcrType = jcrTypeNameFor(dataType);
347 Collection<String> constraints = literalsByEnumName.get(dataType);
348 if (!constraints.isEmpty()) {
349
350 jcrType = "STRING";
351 }
352
353 if (isContainment) {
354
355 int x = 0;
356 } else {
357
358 String propDefnName = stringFrom(featureName);
359 sb.append(NEWLINE);
360 sb.append(" - ").append(propDefnName).append(" (").append(jcrType).append(") ");
361 if (defaultValue != null) sb.append("= '").append(defaultValue).append("' ");
362 if (isRequired) sb.append("mandatory ");
363 if (!isSingle) sb.append("multiple ");
364 if (!isChangeble) sb.append("protected autocreated");
365 if (!constraints.isEmpty()) {
366 sb.append(NEWLINE);
367 sb.append(" < ");
368 boolean first = true;
369 for (String constraint : constraints) {
370 if (first) first = false;
371 else sb.append(", ");
372 sb.append("'").append(constraint).append("'");
373 }
374 }
375 }
376 }
377 sb.append(NEWLINE);
378 sb.append(NEWLINE);
379 }
380 }
381 }
382 }