]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.xml.sax/src/org/simantics/xml/sax/SchemaConverter.java
XML data based schema and ontology generation
[simantics/interop.git] / org.simantics.xml.sax / src / org / simantics / xml / sax / SchemaConverter.java
1 package org.simantics.xml.sax;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.FileNotFoundException;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.util.ArrayList;
9 import java.util.Date;
10 import java.util.HashSet;
11 import java.util.LinkedHashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.regex.Matcher;
16
17 import javax.xml.bind.JAXBContext;
18 import javax.xml.bind.JAXBElement;
19 import javax.xml.bind.JAXBException;
20 import javax.xml.bind.Unmarshaller;
21
22 import org.simantics.utils.datastructures.MapList;
23 import org.simantics.xml.sax.configuration.Configuration;
24 import org.w3._2001.xmlschema.Annotation;
25 import org.w3._2001.xmlschema.Import;
26 import org.w3._2001.xmlschema.Include;
27 import org.w3._2001.xmlschema.OpenAttrs;
28 import org.w3._2001.xmlschema.Schema;
29
30 /**
31  * This file is developed for XMpLant / Proteus schema conversion is not able to handle all XML Schema definitions.
32  * 
33  * @author mlmarko
34  *
35  */
36 public class SchemaConverter {
37         
38         protected File outputPlugin;
39         protected File schemaFile;
40         protected File conversionFile;
41         protected File ontologyFile;
42         protected File parserDir;
43         protected Schema schema;
44         protected Configuration configuration;
45         
46         protected String pluginName;
47         
48         private String[] header;
49         
50         boolean createPGraph = true;
51         boolean createImporter = true;
52         boolean createExporter = true;
53         
54         private List<SchemaConverter> parent = new ArrayList<>();
55         private List<SchemaConverter> subConverters = new ArrayList<>();
56         private Map<String,SchemaConverter> fileMap;
57         private MapList<String,SchemaConverter> schemaNSMap;
58         private MapList<String,SchemaConverter> shortNameMap;
59         
60         protected String schemaNs;
61         protected String ontologyUri;
62         protected String className;
63         protected String name;
64         protected String shortName;
65         
66         protected SchemaConversionBase base;
67         
68         private ManualSchemaFileImport fileImport;
69         
70         public SchemaConverter(File schemaFile, File conversionFile, File outputPlugin) throws IOException {
71                 this(null,schemaFile,conversionFile,outputPlugin);
72         }
73         
74         public SchemaConverter(SchemaConverter parent,File schemaFile, File conversionFile, File outputPlugin) throws IOException {
75                 if (schemaFile == null || outputPlugin == null)
76                         throw new IllegalArgumentException();
77                 this.outputPlugin = outputPlugin;
78                 this.schemaFile = schemaFile;
79                 this.conversionFile = conversionFile;
80                 
81                 pluginName = outputPlugin.getName();
82                 String packageParts[] = pluginName.split("\\.");
83                 String outputLoc = outputPlugin.getAbsolutePath();
84                 outputLoc += "/src";
85                 for (String s : packageParts)
86                         outputLoc += "/"+s;
87                 String outputGraph = outputPlugin.getAbsolutePath();
88                 outputGraph += "/graph";
89                 outputGraph += "/" + schemaFile.getName().substring(0, schemaFile.getName().length()-4) +".pgraph";
90                 
91                 
92                 this.ontologyFile = new File(outputGraph);
93                 this.parserDir = new File(outputLoc);
94                 
95                 if (parent != null) {
96                         this.parent.add(parent);
97                         parent.subConverters.add(this);
98                 } else {
99                         fileMap = new LinkedHashMap<>();
100                         schemaNSMap = new MapList<>();
101                         shortNameMap = new MapList<>();
102                 }
103                 getRoot().fileMap.put(schemaFile.getAbsolutePath(), this);
104         }
105         
106         public List<SchemaConverter> getConverter(String schemaNS) {
107                 return getRoot().schemaNSMap.getValues(schemaNS);
108         }
109         
110         public void setFileImport(ManualSchemaFileImport fileImport) {
111                 this.fileImport = fileImport;
112         }
113
114         
115         public void setCreateExporter(boolean createExporter) {
116                 this.createExporter = createExporter;
117         }
118         
119         public void setCreateImporter(boolean createImporter) {
120                 this.createImporter = createImporter;
121         }
122         
123         public void setCreatePGraph(boolean createPGraph) {
124                 this.createPGraph = createPGraph;
125         }
126         
127         protected SchemaConverter createSubConverter(String location, String ns) throws JAXBException, IOException {
128                 File directory = schemaFile.getParentFile();
129                 File schemaFile = new File(directory.getAbsolutePath()+File.separator+location);
130                 if (!schemaFile.exists()) {
131                         if (getRoot().fileImport != null) {
132                                 schemaFile = getRoot().fileImport.getFileForLocation(location);
133                         }
134                         if (!schemaFile.exists())
135                                 throw new FileNotFoundException(schemaFile.getAbsolutePath());
136                 }
137                 SchemaConverter subConverter = getRoot().fileMap.get((schemaFile.getAbsolutePath()));
138                 if (subConverter == null) {
139                         subConverter = constructSubConverter(this, schemaFile, conversionFile, outputPlugin, ns);
140                         subConverter.createPGraph = this.createPGraph;
141                         subConverter.createImporter = this.createImporter;
142                         subConverter.createExporter = this.createExporter;
143                 } else {
144                         subConverter.parent.add(this);
145                         subConverters.add(subConverter);
146                 }
147                 return subConverter;
148         }
149         
150         protected SchemaConverter constructSubConverter(SchemaConverter parent, File schemaFile, File conversionFile, File outputPlugin, String ns) throws IOException {
151                 return new SchemaConverter(parent,schemaFile, conversionFile, outputPlugin);
152         }
153         
154         protected SchemaConverter getRoot() {
155                 if (this.fileMap != null)
156                         return this;
157                 Set<SchemaConverter> processed = new HashSet<>();
158                 return _getRoot(processed);
159         }
160         
161         protected SchemaConverter _getRoot(Set<SchemaConverter> processed) {
162                 if (processed.contains(this))
163                         return null;
164                 if (this.fileMap != null)
165                         return this;
166                 processed.add(this);
167                 
168                 for (SchemaConverter sc : this.parent) {
169                         if (sc.fileMap != null)
170                                 return sc;
171                 }
172                 for (SchemaConverter sc : this.parent) {
173                         SchemaConverter root = sc._getRoot(processed);
174                         if (root != null)
175                                 return root;
176                 }
177                 return null;
178         }
179         
180         public void convert() throws JAXBException, IOException {
181                 
182                 init();
183                 for (SchemaConverter sc : getRoot().fileMap.values()) {
184                         sc.doConvert();
185                 }
186         }
187         
188         boolean init = false;
189         
190         protected void assignShortName() {
191                 shortName = name.substring(0, 3).toUpperCase();
192                 SchemaConverter root = getRoot();
193                 if (!root.shortNameMap.containsKey(shortName)) {
194                         root.shortNameMap.add(shortName, this);
195                         return;
196                 } else {
197                         SchemaConverter sc = root.shortNameMap.getValues(shortName).get(0);
198                         if (sc.schemaNs.equals(schemaNs)) {
199                                 root.shortNameMap.add(shortName, this);
200                                 return;
201                         }
202                 }
203                 int i = 1;
204                 while (true) {
205                         String n = shortName+i;
206                         if (!root.shortNameMap.containsKey(n)) {
207                                 shortName = n;
208                                 root.shortNameMap.add(shortName, this);
209                                 return;
210                         } else {
211                                 SchemaConverter sc = root.shortNameMap.getValues(n).get(0);
212                                 if (sc.schemaNs.equals(schemaNs)) {
213                                         shortName = n;
214                                         root.shortNameMap.add(shortName, this);
215                                         return;
216                                 }
217                         }
218                         i++;
219                 }
220         }
221         
222         protected Schema createSchema() throws JAXBException, FileNotFoundException {
223                 JAXBContext jc = JAXBContext.newInstance("org.w3._2001.xmlschema");
224                 Unmarshaller u = jc.createUnmarshaller();
225                 //u.setSchema(schema);
226         InputStream fileStream = new FileInputStream(schemaFile);
227                 return (Schema)u.unmarshal(fileStream);
228         }
229         
230         protected void init() throws IOException, JAXBException {
231                 if (init)
232                         return;
233                 init = true;
234                 
235                 schema = createSchema();
236                 
237                 if (conversionFile != null) {
238                         JAXBContext jc = JAXBContext.newInstance("org.simantics.xml.sax.configuration");
239                         Unmarshaller u = jc.createUnmarshaller();
240                         InputStream fileStream = new FileInputStream(conversionFile);
241                         configuration = (Configuration)((JAXBElement<?>)u.unmarshal(fileStream)).getValue();
242                 } else {
243                         configuration = new Configuration();
244                 }
245                 
246                 header = new String[4];
247                 header[0] = "Generated with org.simantics.xml.sax XML schema converter";
248                 header[1] = "";
249                 header[2] = "File " + schemaFile.getAbsolutePath().replaceAll(Matcher.quoteReplacement("\\"), "/");
250                 header[3] = "Date " + new Date().toString();
251                 
252                 schemaNs = schema.getTargetNamespace();
253                 
254                 ontologyUri = schemaNs;
255                 if (ontologyUri == null) {
256                         ontologyUri = getSchemaFile().getName();
257                         
258                         int index = ontologyUri.lastIndexOf(".");
259                         if (index > 0)
260                                 ontologyUri = ontologyUri.substring(0, index);
261                         schemaNs = "";
262                 } else {
263                         // Special case for XAML
264                         if (ontologyUri.startsWith("clr-namespace:")) {
265                                 ontologyUri = ontologyUri.substring("clr-namespace:".length());
266                                 int i = ontologyUri.indexOf(";assembly");
267                                 if (i > 0)
268                                         ontologyUri = ontologyUri.substring(0, i);
269                         }
270                 }
271                 ontologyUri = ontologyUri.replaceAll(" ", "_");
272                 ontologyUri = ontologyUri.replaceAll(":", "_");
273                 ontologyUri = ontologyUri.replaceAll(";", "_");
274                 String parts[] = ontologyUri.split("/");
275                 for (int i = parts.length-1; i >= 0; i--) {
276                         name = parts[i];
277                         if (!Character.isDigit(name.charAt(0)))
278                                 break;
279                 }
280                 if (name == null) {
281                         throw new JAXBException("Could not resolve proper name for schema " + ontologyUri);
282                 }
283                 
284                 
285                 name = name.replaceAll("\\.", "_");
286                 if (!ontologyUri.startsWith("http://"))
287                         ontologyUri = "http://" + ontologyUri.replaceAll("/", "_");
288                 else
289                         ontologyUri = "http://" + ontologyUri.substring("http://".length()).replaceAll("/", "_");
290                 
291                 String version = schema.getVersion();
292                 if (version == null)
293                         version = "1.0";
294                 ontologyUri +="-"+ version;
295
296                 
297                 className = getPluginName() + "." + name + "Ontology";
298                 assignShortName();
299                 if (schemaNs != null)
300                         getRoot().schemaNSMap.add(schemaNs, this);
301                 
302                 base = new SchemaConversionBase(this,ontologyUri,className);
303                 base.init(schema);
304                 
305                 for (OpenAttrs attrs : schema.getIncludeOrImportOrRedefine()) {
306                         if (attrs instanceof Import) {
307                                 Import imp = (Import)attrs;
308                                 String location = imp.getSchemaLocation();
309                                 SchemaConverter sc = createSubConverter(location, imp.getNamespace());
310                                 sc.init();
311                         } else if (attrs instanceof Include) {
312                                 Include inc = (Include)attrs;
313                                 String location = inc.getSchemaLocation();
314                                 SchemaConverter sc = createSubConverter(location, null);
315                                 sc.init();
316                         } else if (attrs instanceof Annotation) {
317                                 
318                         } else {
319                                 throw new IOException("Cannot handle schema file " + schemaFile.getName() + ", the schema uses redefine elements.");
320                         }
321                 }
322         }
323
324         private boolean converting = false;
325         
326         protected void doConvert() throws IOException, JAXBException {
327                 if (converting)
328                         return;
329                 converting = true;
330                 if (!ontologyFile.exists()) {
331                         ontologyFile.getParentFile().mkdirs();
332                         ontologyFile.createNewFile();
333                 }
334                 if (!parserDir.exists())
335                         parserDir.mkdirs();
336                 
337                 if (createPGraph) {
338                         OntologyGenerator ontologyGenerator = new OntologyGenerator(this,base);
339                         ontologyGenerator.createOntology();
340                 }
341                 if (createImporter) {
342                         ImporterGenerator importerGenerator = new ImporterGenerator(this,base);
343                         importerGenerator.createParser();
344                 }
345                 if (createExporter) {
346                         ExporterGenerator exporterGenerator = new ExporterGenerator(this,base);
347                         exporterGenerator.createParser();
348                 }
349                 base.component = null;
350         }
351         
352         public File getOntologyFile() {
353                 return ontologyFile;
354         }
355         public File getParserDir() {
356                 return parserDir;
357         }
358         
359         public Schema getSchema() {
360                 return schema;
361         }
362         
363         public File getSchemaFile() {
364                 return schemaFile;
365         }
366         
367         public String getPluginName() {
368                 return pluginName;
369         }
370         
371         public String[] getHeader() {
372                 return header;
373         }
374         
375         public Configuration getConfiguration() {
376                 return configuration;
377         }
378         
379         public List<SchemaConverter> getParent() {
380                 return parent;
381         }
382         
383         public List<SchemaConverter> getSubConverters() {
384                 return subConverters;
385         }
386         
387         public boolean isPrimary() {
388                 return true;
389 //              if (getRoot() == this)
390 //                      return true;
391 //              List<SchemaConverter> conv = new ArrayList<>(getRoot().fileMap.values());
392 //              int current = conv.indexOf(this);
393                 
394         }
395
396         public String getShortName(String namespaceURI) {
397                 List<SchemaConverter> converters = getRoot().getConverter(namespaceURI);
398                 for (SchemaConverter conv : converters) {
399                         if (conv.shortName != null)
400                                 return conv.shortName;
401                 }
402                 return null;
403         }
404         
405         public String getOntologyClassName(String namespaceURI) {
406                 List<SchemaConverter> converters = getRoot().getConverter(namespaceURI);
407                 for (SchemaConverter conv : converters) {
408                         if (conv.className != null)
409                                 return conv.className;
410                 }
411                 return null;
412         }
413
414
415 }