/******************************************************************************* * Copyright (c) 2005 - 2009 itemis AG (http://www.itemis.eu) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package org.eclipse.xtend.typesystem.xsd; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import javax.xml.namespace.QName; import org.apache.commons.logging.Log; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.ETypedElement; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.FeatureMap; import org.eclipse.emf.ecore.xmi.XMIResource; import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; import org.eclipse.internal.xtend.util.Cache; import org.eclipse.xtend.type.impl.java.JavaTypeImpl; import org.eclipse.xtend.typesystem.Type; import org.eclipse.xtend.typesystem.emf.EClassType; import org.eclipse.xtend.typesystem.emf.EcoreUtil2; import org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel; import org.eclipse.xtend.typesystem.xsd.builder.OawXSDResourceSet; import org.eclipse.xtend.typesystem.xsd.builder.XSDManager; import org.eclipse.xtend.typesystem.xsd.type.EFeatureMapEntryTypeImpl; import org.eclipse.xtend.typesystem.xsd.type.EFeatureMapTypeImpl; import org.eclipse.xtend.typesystem.xsd.type.EFeatureType; import org.eclipse.xtend.typesystem.xsd.type.EMapEntryType; import org.eclipse.xtend.typesystem.xsd.type.EMapType; import org.eclipse.xtend.typesystem.xsd.type.QNameType; import org.eclipse.xtend.typesystem.xsd.type.XMLEClassType; import org.eclipse.xtend.typesystem.xsd.type.XMLFeatureMapTypeImpl; import org.eclipse.xtend.typesystem.xsd.util.Msg; import org.eclipse.xtend.typesystem.xsd.util.XSDLog; /** * @author Moritz Eysholdt - Initial contribution and API */ public class XSDMetaModel extends EmfRegistryMetaModel { public final static String EFEATURE = "EFeature"; private final static String EFEATURE_MAP = "XMLFeatureMap"; public static final String EFEATURE_MAP_ENTRY = "EFeatureMapEntry"; private final static String EMAP = "EMap"; private final static String EMAP_ENTRY = "EMapEntry"; private Cache<EClassifier, EMapType> eMapCache = new Cache<EClassifier, EMapType>() { @Override protected EMapType createNew(EClassifier c) { return new EMapType(XSDMetaModel.this, EMAP, c); } }; private Cache<EClass, XMLFeatureMapTypeImpl> featueMapCache = new Cache<EClass, XMLFeatureMapTypeImpl>() { @Override protected XMLFeatureMapTypeImpl createNew(EClass c) { return new XMLFeatureMapTypeImpl(XSDMetaModel.this, EFEATURE_MAP, c); } }; private EFeatureMapEntryTypeImpl featureMapEntry; private EFeatureType featureType; private boolean registerPackagesGlobally = false; protected Log log = XSDLog.getLog(getClass()); protected String id; private Cache<EClassifier, EMapEntryType> mapEntryCache = new Cache<EClassifier, EMapEntryType>() { @Override protected EMapEntryType createNew(EClassifier arg0) { return new EMapEntryType(getTypeSystem(), EMAP_ENTRY, arg0); } }; private QNameType qnameType; private Cache<EClassType, XMLEClassType> xmlClassCache = new Cache<EClassType, XMLEClassType>() { @Override protected XMLEClassType createNew(EClassType arg0) { try { // this is due to a lack of accessibility of the // EmfRegistryMetaModel Field f = arg0.getClass().getDeclaredField("eClass"); f.setAccessible(true); EClass cls = (EClass) f.get(arg0); return new XMLEClassType(XSDMetaModel.this, arg0.getName(), cls); } catch (Exception e) { throw new RuntimeException(e); // e.printStackTrace(); } } }; private XSDManager xsdManager; protected Set<EPackage> savedPackages = new HashSet<EPackage>(); protected String savePackagesPath = null; public XSDMetaModel() { super(); xsdManager = new OawXSDResourceSet(); } // this clones an XSDMetaModel and thereby empties all type-caches. public XSDMetaModel(XSDManager manager) { super(); xsdManager = manager; } public void addSchemaFile(String uri) { log.info(Msg.create("Loading XSDSchema from ").uri(uri)); xsdManager.loadAndGenerate(EcoreUtil2.getURI(uri)); registerNewPackages(); saveNewPackages(); } @Override public EPackage[] allPackages() { Collection<EPackage> pkgs = new ArrayList<EPackage>(xsdManager .getPackages()); for (Object o : EPackage.Registry.INSTANCE.values()) if (o instanceof EPackage) pkgs.add((EPackage) o); return pkgs.toArray(new EPackage[pkgs.size()]); } public EFeatureMapEntryTypeImpl getEFeatureMapEntryType() { if (featureMapEntry == null) featureMapEntry = new EFeatureMapEntryTypeImpl(this, EFEATURE_MAP_ENTRY); return featureMapEntry; } public XMLFeatureMapTypeImpl getEFeatureMapType(EClass aClass) { return featueMapCache.get(aClass); } public EFeatureType getEFeatureType() { if (featureType == null) featureType = new EFeatureType(getTypeSystem(), EFEATURE); return featureType; } public EMapEntryType getEMapEntryType(EClassifier innerType) { return mapEntryCache.get(innerType); } public EMapType getEMapType(EClassifier innerType) { return eMapCache.get(innerType); } @Override public Set<Type> getKnownTypes() { Set<Type> r = super.getKnownTypes(); // log.info("getKnownTypes() -> " + r); return r; } public QNameType getQNameType() { // TODO: resolve the package name dynamically if (qnameType == null) qnameType = new QNameType(getTypeSystem(), "type::QName"); return qnameType; } @Override public Type getType(Object obj) { Type r = null; if (obj instanceof FeatureMap) { FeatureMap m = (FeatureMap) obj; EClass c = ((Setting) m).getEObject().eClass(); r = getEFeatureMapType(c); } else if (obj instanceof FeatureMap.Entry) { r = getEFeatureMapEntryType(); } else if (obj instanceof EStructuralFeature) { r = getEFeatureType(); } else if (EMapType.isEMapObject(obj)) { EClassifier c = ((Setting) obj).getEStructuralFeature().getEType(); r = getEMapType(c); } else if (EMapEntryType.isEMapEntryObject(obj)) { EClassifier i = (obj instanceof EObject) ? ((EObject) obj).eClass() : null; r = getEMapEntryType(i); } else if (obj instanceof QName) { r = getQNameType(); } else r = super.getType(obj); // log.info("getType(" + obj.getClass() + ") -> " + r); return r; } @Override public Type getTypeForEClassifier(EClassifier element) { Type r = super.getTypeForEClassifier(element); if (r == null || r instanceof JavaTypeImpl) r = XMLTypeMapper.instance().get(this, element, getTypeSystem()); else if (r instanceof EClassType) r = xmlClassCache.get((EClassType) r); // log.info("getTypeForEClassifier(" + element.getName() + ") -> " + r); return r; } @Override public Type getTypeForETypedElement(final ETypedElement typedElement) { EClassifier c = typedElement.getEType(); if (c == null) return getTypeSystem().getVoidType(); if (EFeatureMapTypeImpl.isFeatureMap(typedElement)) return getEFeatureMapType((EClass) typedElement.eContainer()); if (EMapType.isEMap(typedElement)) return getEMapType(typedElement.getEType()); if (EMapEntryType.isEMapEntry(typedElement)) return getEMapEntryType(typedElement.getEType()); // TODO: Handle EGenericTypes, like EmfRegistryMetaModel does. Type t = getTypeForEClassifier(typedElement.getEType()); if (typedElement.isMany()) { // TODO: use EmfListType return getTypeSystem().getListType(t); } else { return t; } } @Override public Type getTypeForName(String typeName) { // TODO: make sure type-package is loaded instead of checking manually Type r; if (getQNameType().getName().equals(typeName) /* || "QName".equals(typeName) */) r = getQNameType(); else if (EMAP_ENTRY.equals(typeName)) r = getEMapEntryType(null); else if (EFEATURE_MAP.equals(typeName)) r = getEFeatureMapType(null); else if (EFEATURE_MAP_ENTRY.equals(typeName)) r = getEFeatureMapEntryType(); else if (EFEATURE.equals(typeName)) r = getEFeatureType(); else { r = super.getTypeForName(typeName); if (r instanceof EClassType) r = xmlClassCache.get((EClassType) r); } // log.info("getTypeForName(" + typeName + ") -> " + r); return r; } public XSDManager getXsdManager() { return xsdManager; } public boolean isRegisterPackagesGlobally() { return registerPackagesGlobally; } public boolean isSaveEPackages() { return savePackagesPath != null; } protected void registerNewPackages() { if (!isRegisterPackagesGlobally()) return; EPackage.Registry reg = EPackage.Registry.INSTANCE; for (EPackage pkg : xsdManager.getPackages()) if (!reg.containsKey(pkg.getNsURI())) { log.info(Msg.create("Registering ").pkg(pkg).txt(" globally.")); reg.put(pkg.getNsURI(), pkg); } } protected void saveNewPackages() { if (!isSaveEPackages()) return; for (EPackage pkg : xsdManager.getPackages()) if (!savedPackages.contains(pkg)) { savedPackages.add(pkg); URI u = URI.createURI(savePackagesPath + "/" + pkg.getName() + ".ecore"); log.info(Msg.create("Saving ").pkg(pkg).txt(" to ").uri(u)); XMIResource r = new XMIResourceImpl(u); r.getContents().add(EcoreUtil.copy(pkg)); try { r.save(new HashMap<String, String>()); } catch (IOException e) { log.error(Msg.create("Error saving ").uri(u), e); } } } public void setId(String id) { this.id = id; } public String getID() { return id; } // public void loadFromStream(InputStream stream, URI uri) throws // IOException { // if (uri == null) // log.info("URI is null"); // OawXSDResource res = xsdResources.getXsdResource(uri, false); // if (res == null) // res = xsdResources.createXsdResource(uri); // // if (res.isLoaded() // // && (tsMap.get(res) == null || tsMap.get(res) < // // modificationTimestamp)) { // // log.info("unloading: " + uri); // // res.unload(); // // } // if (!res.isLoaded()) { // res.load(stream, Collections.EMPTY_MAP); // // tsMap.put(res, modificationTimestamp); // } // // for (EObject obj : res.getContents()) // // if (obj instanceof XSDSchema) // // builder.generate((XSDSchema) obj); // res.generateECore(); // } // private void logUnresolvedSchemaReferences(XSDSchema schema) { // for (XSDSchemaContent content : schema.getContents()) { // if (content instanceof XSDSchemaDirective) { // XSDSchemaDirective directive = (XSDSchemaDirective) content; // if (directive.getResolvedSchema() == null) { // String loc = directive.getSchemaLocation(); // if (directive instanceof XSDImport) { // XSDImport imp = (XSDImport) directive; // log.warn(Msg // .create("Unresolved import-schemaLocation ") // .uri(loc).txt(" (").ns(imp.getNamespace()).txt( // ") in ").schema(schema)); // } else if (directive instanceof XSDInclude) { // log.warn(Msg.create( // "Unresolved include-schemaLocation ").uri(loc) // .txt(" in ").schema(schema)); // } else if (directive instanceof XSDRedefine) { // log.warn(Msg.create( // "Unresolved redefine-schemaLocation ").uri(loc) // .txt(" in ").schema(schema)); // } // } // } // } // } public void setRegisterPackagesGlobally(boolean registerPackagesGlobally) { this.registerPackagesGlobally = registerPackagesGlobally; registerNewPackages(); } public void setSavePackagesPath(String path) { savePackagesPath = path; saveNewPackages(); } @Override public String toString() { return getClass().getSimpleName() + "-" + xsdManager; } }