/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.core; import java.io.File; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EFactory; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xsd.XSDAnnotation; import org.eclipse.xsd.XSDAttributeDeclaration; import org.eclipse.xsd.XSDAttributeGroupDefinition; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDFacet; import org.eclipse.xsd.XSDFactory; import org.eclipse.xsd.XSDIdentityConstraintDefinition; import org.eclipse.xsd.XSDModelGroup; import org.eclipse.xsd.XSDModelGroupDefinition; import org.eclipse.xsd.XSDNotationDeclaration; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDTypeDefinition; import org.eclipse.xsd.XSDWildcard; import org.eclipse.xsd.util.XSDResourceImpl; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.metamodels.core.extension.XAttribute; import org.teiid.designer.metamodels.core.extension.XClass; import org.teiid.designer.metamodels.core.extension.XPackage; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** * mmDefect_12555 - Created XsdObjectExtension to specialize the behavior of getting and setting extension properties for XSD * resource entities. * * @since 8.0 */ public class XsdObjectExtension extends ObjectExtension { public static final String EXTENSION_PACKAGE = "extensionPackage"; //$NON-NLS-1$ // ================================================================================== // C O N S T R U C T O R S // ================================================================================== /** * @since 4.2 */ public XsdObjectExtension() { super(); } /** * @param extendedObject * @param xclass * @param editor * @since 4.2 */ public XsdObjectExtension( EObject extendedObject, XClass xclass, ModelEditor editor ) { super(extendedObject, xclass, editor); } // ================================================================================== // O V E R R I D D E N M E T H O D S // ================================================================================== /** * @see org.teiid.designer.core.ObjectExtension#doDynamicSet(org.eclipse.emf.ecore.EStructuralFeature, * java.lang.Object) * @since 4.2 */ @Override protected void doDynamicSet( EStructuralFeature eFeature, Object newValue ) { final EObject eObject = super.getExtendedObject(); if (eObject != null && eObject instanceof XSDConcreteComponent) { final XSDConcreteComponent comp = (XSDConcreteComponent)eObject; if (XsdObjectExtension.canAnnotate(comp)) { // Get the stringified form of the value for this feature final EDataType dt = (EDataType)eFeature.getEType(); final EPackage ePackage = dt.getEPackage(); final EFactory fac = ePackage.getEFactoryInstance(); String newStringValue = null; // Multivalued feature so create space delimited string if (eFeature.isMany()) { final List values = (List)newValue; final Iterator iter = values.iterator(); while (iter.hasNext()) { final Object value = iter.next(); if (newStringValue == null) { newStringValue = fac.convertToString(dt, value); } else { newStringValue = newStringValue + " " + fac.convertToString(dt, value); //$NON-NLS-1$ } } } // Single valued feature else { newStringValue = fac.convertToString(dt, newValue); } // Add/reset the appInfo attribute for the new value final String name = eFeature.getName(); XsdObjectExtension.addAppInfoAttribute(comp, name, newStringValue); // Set and reset the XSD schema target namespace value so that the resource // gets marked as requiring save this.setAndResetTargetNamespace(comp.getSchema()); } } } /** * Perform some get/set trickery on the xsd schema so that it the resource gets marked as requiring save * * @param schema * @since 4.2 */ private void setAndResetTargetNamespace( final XSDSchema schema ) { if (schema != null) { Resource xsdResource = schema.eResource(); if (xsdResource != null) { schema.eResource().setModified(true); } final EStructuralFeature feature = schema.eClass().getEStructuralFeature("targetNamespace"); //$NON-NLS-1$ if (feature != null) { Object origValue = schema.eGet(feature); schema.eSet(feature, null); schema.eSet(feature, origValue); } } } /** * @see org.teiid.designer.core.ObjectExtension#doDynamicGet(org.eclipse.emf.ecore.EStructuralFeature, * java.lang.Object) * @since 4.2 */ @Override protected Object doDynamicGet( EStructuralFeature eFeature, Object result ) { final EObject eObject = super.getExtendedObject(); if (eObject != null && eObject instanceof XSDConcreteComponent) { final XSDConcreteComponent comp = (XSDConcreteComponent)eObject; if (XsdObjectExtension.canAnnotate(comp)) { final String name = eFeature.getName(); final EDataType dt = (EDataType)eFeature.getEType(); final EPackage ePackage = dt.getEPackage(); final EFactory fac = ePackage.getEFactoryInstance(); String value = XsdObjectExtension.getAppInfoAttributeValue(comp, name); // if the value is null, get default value, if that is null get the type default value if (value == null || CoreStringUtil.Constants.EMPTY_STRING.equals(value)) { Object defaultValue = eFeature.getDefaultValue(); if (defaultValue != null && !CoreStringUtil.Constants.EMPTY_STRING.equals(defaultValue)) { value = defaultValue.toString(); } else { Object typeDefault = dt.getDefaultValue(); value = typeDefault != null ? typeDefault.toString() : null; } } if (eFeature.isMany()) { final List values = new BasicEList(); result = values; final StringTokenizer stringTokenizer = new StringTokenizer(value, " "); //$NON-NLS-1$ while (stringTokenizer.hasMoreTokens()) { String token = stringTokenizer.nextToken(); values.add(fac.createFromString(dt, token)); } } else { result = fac.createFromString(dt, value); } } } return result; } /** * @see org.teiid.designer.core.ObjectExtension#doDynamicIsSet(org.eclipse.emf.ecore.EStructuralFeature) * @since 4.2 */ @Override protected boolean doDynamicIsSet( EStructuralFeature eFeature ) { final EObject eObject = super.getExtendedObject(); if (eObject != null && eObject instanceof XSDConcreteComponent) { final XSDConcreteComponent comp = (XSDConcreteComponent)eObject; if (XsdObjectExtension.canAnnotate(comp)) { final String name = eFeature.getName(); final String value = XsdObjectExtension.getAppInfoAttributeValue(comp, name); return value != null; } } return super.eDynamicIsSet(eFeature); } /** * @see org.teiid.designer.core.ObjectExtension#doDynamicUnset(org.eclipse.emf.ecore.EStructuralFeature) * @since 4.2 */ @Override protected void doDynamicUnset( EStructuralFeature eFeature ) { final EObject eObject = super.getExtendedObject(); if (eObject != null && eObject instanceof XSDConcreteComponent) { final XSDConcreteComponent comp = (XSDConcreteComponent)eObject; if (XsdObjectExtension.canAnnotate(comp)) { final String name = eFeature.getName(); XsdObjectExtension.removeAppInfoAttribute(comp, name); } } } // ================================================================================== // P U B L I C M E T H O D S // ================================================================================== public static boolean isWritable( final XSDConcreteComponent component ) { if (component == null) { return false; } final XSDResourceImpl rsrc = (XSDResourceImpl)component.eResource(); return isWritable(rsrc); } public static boolean isWritable( final XSDResourceImpl rsrc ) { if (rsrc == null) { return false; } URI uri = rsrc.getURI(); if (uri != null && uri.toFileString() != null) { final File file = new File(uri.toFileString()); if (file.exists()) { return file.canWrite(); } } return true; } /** * Return true if the specified XSDConcreteComponent is an entity that can be contain an XSDAnnotation, otherwise return * false. */ public static boolean canAnnotate( final XSDConcreteComponent comp ) { CoreArgCheck.isNotNull(comp); final boolean writable = XsdObjectExtension.isWritable(comp); if (!writable) { return false; } if (comp instanceof XSDSchema || comp instanceof XSDAttributeDeclaration || comp instanceof XSDAttributeGroupDefinition || comp instanceof XSDElementDeclaration || comp instanceof XSDNotationDeclaration || comp instanceof XSDModelGroup || comp instanceof XSDModelGroupDefinition || comp instanceof XSDIdentityConstraintDefinition || comp instanceof XSDTypeDefinition || comp instanceof XSDWildcard || comp instanceof XSDFacet) { return true; } return false; } /** * Return the XSDAnnotation instance associated with the XSDConcreteComponent or null if the component has no annotation. */ public static XSDAnnotation getAnnotation( final XSDConcreteComponent comp ) { CoreArgCheck.isNotNull(comp); XSDAnnotation annotation = null; if (comp instanceof XSDSchema) { List annotations = ((XSDSchema)comp).getAnnotations(); if (annotations != null) { for (Iterator iter = annotations.iterator(); iter.hasNext();) { annotation = (XSDAnnotation)iter.next(); // Stop iterating if we find an annotation containing application info // if (annotation != null && !annotation.getApplicationInformation().isEmpty()) { if (annotation != null) { break; } } } } else if (comp instanceof XSDAttributeDeclaration) { annotation = ((XSDAttributeDeclaration)comp).getAnnotation(); } else if (comp instanceof XSDAttributeGroupDefinition) { annotation = ((XSDAttributeGroupDefinition)comp).getAnnotation(); } else if (comp instanceof XSDElementDeclaration) { annotation = ((XSDElementDeclaration)comp).getAnnotation(); } else if (comp instanceof XSDNotationDeclaration) { annotation = ((XSDNotationDeclaration)comp).getAnnotation(); } else if (comp instanceof XSDModelGroup) { annotation = ((XSDModelGroup)comp).getAnnotation(); } else if (comp instanceof XSDModelGroupDefinition) { annotation = ((XSDModelGroupDefinition)comp).getAnnotation(); } else if (comp instanceof XSDIdentityConstraintDefinition) { annotation = ((XSDIdentityConstraintDefinition)comp).getAnnotation(); } else if (comp instanceof XSDTypeDefinition) { annotation = ((XSDTypeDefinition)comp).getAnnotation(); } else if (comp instanceof XSDWildcard) { annotation = ((XSDWildcard)comp).getAnnotation(); } else if (comp instanceof XSDFacet) { annotation = ((XSDFacet)comp).getAnnotation(); } return annotation; } /** * Set the XSDAnnotation instance on the XSDConcreteComponent if the component can contain annotations otherwise do nothing. */ public static void setAnnotation( final XSDConcreteComponent comp, final XSDAnnotation annotation ) { CoreArgCheck.isNotNull(comp); if (annotation == null) { return; } if (comp instanceof XSDSchema) { List annotations = ((XSDSchema)comp).getAnnotations(); if (annotations != null) { annotations.add(annotations); } } else if (comp instanceof XSDAttributeDeclaration) { ((XSDAttributeDeclaration)comp).setAnnotation(annotation); } else if (comp instanceof XSDAttributeGroupDefinition) { ((XSDAttributeGroupDefinition)comp).setAnnotation(annotation); } else if (comp instanceof XSDElementDeclaration) { ((XSDElementDeclaration)comp).setAnnotation(annotation); } else if (comp instanceof XSDNotationDeclaration) { ((XSDNotationDeclaration)comp).setAnnotation(annotation); } else if (comp instanceof XSDModelGroup) { ((XSDModelGroup)comp).setAnnotation(annotation); } else if (comp instanceof XSDModelGroupDefinition) { ((XSDModelGroupDefinition)comp).setAnnotation(annotation); } else if (comp instanceof XSDIdentityConstraintDefinition) { ((XSDIdentityConstraintDefinition)comp).setAnnotation(annotation); } else if (comp instanceof XSDTypeDefinition) { ((XSDTypeDefinition)comp).setAnnotation(annotation); } else if (comp instanceof XSDWildcard) { ((XSDWildcard)comp).setAnnotation(annotation); } else if (comp instanceof XSDFacet) { ((XSDFacet)comp).setAnnotation(annotation); } } /** * Add an attribute with the specified name and value to the appInfo documentation of the XSDConcreteComponent. If the * XSDConcreteComponent cannot contain annotations then do nothing. */ public static void addAppInfoAttribute( final XSDConcreteComponent comp, final String name, final String value ) { CoreArgCheck.isNotNull(comp); // If the XSDConcreteComponent is not a type that can be annotated then return immediately if (!canAnnotate(comp)) { return; } // Get or create the annotation for the specified component XSDAnnotation annotation = XsdObjectExtension.getAnnotation(comp); if (annotation == null) { annotation = XSDFactory.eINSTANCE.createXSDAnnotation(); setAnnotation(comp, annotation); } // Add the attribute to the appInfo addAppInfoAttribute(annotation, name, value); } /** * Add an attribute with the specified name and value to the appInfo documentation of the XSDAnnotation. */ public static void addAppInfoAttribute( final XSDAnnotation annotation, final String name, final String value ) { CoreArgCheck.isNotNull(annotation); CoreArgCheck.isNotZeroLength(name); // Check if an attribute by this name already exists in the specified annotation List appInfos = annotation.getApplicationInformation(); for (final Iterator iter = appInfos.iterator(); iter.hasNext();) { final Element appInfo = (Element)iter.next(); // If one is found then reset the value and return if (appInfo != null && appInfo.getAttribute(name) != null) { if (value == null || CoreStringUtil.Constants.EMPTY_STRING.equals(value)) { appInfo.removeAttribute(name); } else { appInfo.setAttribute(name, value); } return; } } // Get or create the appInfo instance for the specified annotation Element appInfo = null; if (annotation.getApplicationInformation().isEmpty()) { appInfo = annotation.createApplicationInformation(null); annotation.getElement().appendChild(appInfo); } else { appInfo = annotation.getApplicationInformation().iterator().next(); } // Get or create the attribute for the appInfo appInfo.setAttribute(name, value); } /** * Remove the appInfo attribute with the specified name, if it exists. */ public static void removeAppInfoAttribute( final XSDConcreteComponent comp, final String name ) { CoreArgCheck.isNotNull(comp); CoreArgCheck.isNotZeroLength(name); // If the XSDConcreteComponent is not a type that can be annotated then return immediately if (!canAnnotate(comp)) { return; } // Get the annotation, if it exists, for the specified component XSDAnnotation annotation = XsdObjectExtension.getAnnotation(comp); if (annotation == null) { return; } // Return the value for any appInfo attribute with the specified name List appInfos = annotation.getApplicationInformation(); for (final Iterator iter = appInfos.iterator(); iter.hasNext();) { final Element appInfo = (Element)iter.next(); // If one is found then return the value if (appInfo != null && appInfo.getAttribute(name) != null) { appInfo.removeAttribute(name); } } } /** * Return the value for the appInfo attribute with the specified name, if it exists, otherwise null is returned. */ public static String getAppInfoAttributeValue( final XSDConcreteComponent comp, final String name ) { CoreArgCheck.isNotNull(comp); CoreArgCheck.isNotZeroLength(name); return (String)getAppInfoAttributeMap(comp).get(name); } /** * Return a unmodifiable Map of the appInfo attribute names and values. */ public static Map getAppInfoAttributeMap( final XSDConcreteComponent comp ) { CoreArgCheck.isNotNull(comp); // If the XSDConcreteComponent is not a type that can be annotated then return immediately if (!canAnnotate(comp)) { return Collections.EMPTY_MAP; } // Get the annotation for the specified component if it exists final XSDAnnotation annotation = XsdObjectExtension.getAnnotation(comp); if (annotation == null) { return Collections.EMPTY_MAP; } // Check if an attribute by this name already exists in the specified annotation final Map result = new HashMap(); List appInfos = annotation.getApplicationInformation(); for (final Iterator iter = appInfos.iterator(); iter.hasNext();) { final Element appInfo = (Element)iter.next(); if (appInfo != null) { final NamedNodeMap map = appInfo.getAttributes(); final int length = map.getLength(); if (length > 0) { for (int i = 0; i < length; i++) { final Node mapNode = map.item(i); if (mapNode != null) { result.put(mapNode.getNodeName(), mapNode.getNodeValue()); } } } } } return Collections.unmodifiableMap(result); } public static XPackage getExtensionPackage( final XSDResourceImpl xsdResource ) throws ModelerCoreException { CoreArgCheck.isNotNull(xsdResource); final XSDSchema schema = xsdResource.getSchema(); if (schema != null) { return XsdObjectExtension.getExtensionPackage(schema); } return null; } public static XPackage getExtensionPackage( final XSDSchema schema ) throws ModelerCoreException { CoreArgCheck.isNotNull(schema); final Map extMap = XsdObjectExtension.getAppInfoAttributeMap(schema); final String extPkgLocation = (String)extMap.get(XsdObjectExtension.EXTENSION_PACKAGE); if (extPkgLocation != null && extPkgLocation.length() > 0) { XPackage extPackage = null; try { URI extPkgURI = URI.createURI(extPkgLocation); // Take the URI relative to the XSD resource location and make it absolute extPkgURI = extPkgURI.resolve(schema.eResource().getURI()); // Lookup the XPackage in the Modeler's resource set ... extPackage = (XPackage)ModelerCore.getModelContainer().getEObject(extPkgURI, true); // If not found then try looking it up in the schema's resource set ... if (extPackage == null) { extPackage = (XPackage)schema.eResource().getResourceSet().getEObject(extPkgURI, true); } } catch (CoreException err) { final String msg = ModelerCore.Util.getString("XsdObjectExtension.getExtension_1"); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, err, msg); } // If found then return the XPackage otherwise throw an exception // because an XPackage with this URI could be found if (extPackage != null) { return extPackage; } final String msg = ModelerCore.Util.getString("XsdObjectExtension.getExtension_0"); //$NON-NLS-1$ throw new ModelerCoreException(msg); } return null; } public static void removeExtensionPackage( final XSDResourceImpl xsdResource ) throws ModelerCoreException { CoreArgCheck.isNotNull(xsdResource); XPackage extPackage = XsdObjectExtension.getExtensionPackage(xsdResource); XSDSchema schema = xsdResource.getSchema(); if (extPackage != null && schema != null) { // Set the incremental update state of the XSD resource to false to // improve performance while modifying the schema components final boolean incrementalUpdate = schema.isIncrementalUpdate(); schema.setIncrementalUpdate(false); // For every XSDConcreteComponent in the resource check if remove any // appInfo attributes associated with the extension for (final Iterator iter = xsdResource.getAllContents(); iter.hasNext();) { final Object obj = iter.next(); if (obj instanceof XSDConcreteComponent) { final XSDConcreteComponent comp = (XSDConcreteComponent)obj; final EClass eClass = comp.eClass(); final XClass xClass = extPackage.findXClass(eClass); if (xClass != null) { for (Iterator iter2 = xClass.eAllContents(); iter2.hasNext();) { EObject eObj = (EObject)iter2.next(); if (eObj instanceof XAttribute) { XsdObjectExtension.removeAppInfoAttribute(comp, ((XAttribute)eObj).getName()); } } } } } // Reset the incremental update state of the XSD resource to its original state schema.setIncrementalUpdate(incrementalUpdate); } if (schema != null) { XsdObjectExtension.removeAppInfoAttribute(schema, EXTENSION_PACKAGE); } } public static void setExtensionPackage( final XSDResourceImpl xsdResource, final XPackage extPackage ) { CoreArgCheck.isNotNull(xsdResource); XsdObjectExtension.setExtensionPackage(xsdResource.getSchema(), extPackage); } public static void setExtensionPackage( final XSDSchema schema, final XPackage extPackage ) { CoreArgCheck.isNotNull(schema); CoreArgCheck.isNotNull(extPackage); final Resource xsdResource = schema.eResource(); final Resource extResource = extPackage.eResource(); if (xsdResource != null && extResource != null) { URI xsdURI = xsdResource.getURI(); URI extURI = extResource.getURI(); extURI = extURI.appendFragment(extResource.getURIFragment(extPackage)); // Make the URI relative to the XSD resource location URI relativeURI = extURI.deresolve(xsdURI); if (relativeURI != null) { XsdObjectExtension.addAppInfoAttribute(schema, EXTENSION_PACKAGE, relativeURI.toString()); } } else { final String msg = ModelerCore.Util.getString("XsdObjectExtension.setExtension_2"); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, msg); } } }