/* * 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.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EMap; import org.eclipse.emf.ecore.EAttribute; 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.impl.EObjectImpl; import org.eclipse.emf.ecore.resource.Resource; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.core.workspace.ModelUtil; import org.teiid.designer.metamodels.core.Annotation; import org.teiid.designer.metamodels.core.AnnotationContainer; import org.teiid.designer.metamodels.core.CoreFactory; import org.teiid.designer.metamodels.core.extension.XClass; /** * ObjectExtension * * @since 8.0 */ public class ObjectExtension extends EObjectImpl { private static final String DELIM = " "; //$NON-NLS-1$ private EObject extendedObject; private Annotation annotation; private ModelEditor editor; /** * Construct an instance of ObjectExtension. * */ public ObjectExtension() { super(); } public ObjectExtension(final EObject extendedObject, final XClass xclass, final ModelEditor editor) { this.editor = editor; this.extendedObject = extendedObject; if ( this.extendedObject != null && xclass != null ) { super.eSetClass(xclass); } } public ObjectExtension(final EObject extendedObject, final XClass xclass) { this(extendedObject, xclass, null); } // ================================================================================== // P U B L I C M E T H O D S // ================================================================================== /** * @return */ public EObject getExtendedObject() { return extendedObject; } /** * @param annotation */ public void setExtendedObject(EObject extendedObject) { this.extendedObject = extendedObject; } /** * @see org.eclipse.emf.ecore.impl.EObjectImpl#eDynamicSet(org.eclipse.emf.ecore.EStructuralFeature, java.lang.Object) * @generated NOT */ @Override public void eDynamicSet(EStructuralFeature eFeature, Object newValue) { super.eDynamicSet(eFeature, newValue); if ( this.extendedObject != null ) { if ( eFeature.isTransient() || !eFeature.isChangeable() ) { return; } doDynamicSet(eFeature, newValue); } } /** * @see org.eclipse.emf.ecore.impl.EObjectImpl#eDynamicSet(int, org.eclipse.emf.ecore.EStructuralFeature, java.lang.Object) * @generated NOT */ @Override public void eDynamicSet(int dynamicFeatureID, EStructuralFeature eFeature, Object newValue) { super.eDynamicSet(dynamicFeatureID, eFeature, newValue); if ( this.extendedObject != null ) { if ( eFeature.isTransient() || !eFeature.isChangeable() ) { return; } doDynamicSet(eFeature, newValue); } } /** * @see org.eclipse.emf.ecore.impl.EObjectImpl#eDynamicUnset(org.eclipse.emf.ecore.EStructuralFeature) * @generated NOT */ @Override public void eDynamicUnset(EStructuralFeature eFeature) { super.eDynamicUnset(eFeature); doDynamicUnset(eFeature); } /** * * @see org.eclipse.emf.ecore.impl.BasicEObjectImpl#eGet(org.eclipse.emf.ecore.EStructuralFeature, boolean) * @generated NOT */ @Override public Object eGet(EStructuralFeature feature, boolean resolve) { // TODO Auto-generated method stub return this.eDynamicGet(feature, resolve); } /** * @see org.eclipse.emf.ecore.impl.EObjectImpl#eDynamicGet(org.eclipse.emf.ecore.EStructuralFeature, boolean) * @generated NOT */ @Override public Object eDynamicGet(EStructuralFeature eFeature, boolean resolve) { Object result = null; if ( this.extendedObject != null ) { result = doDynamicGet(eFeature, result); } if ( result == null ) { result = super.eDynamicGet(eFeature, resolve); } return result; } /** * @see org.eclipse.emf.ecore.impl.EObjectImpl#eDynamicGet(int, org.eclipse.emf.ecore.EStructuralFeature, boolean) * @generated NOT */ @Override public Object eDynamicGet(int featureID, boolean resolve, boolean coreType) { Object result = null; if ( this.extendedObject != null ) { EStructuralFeature eFeature = eClass().getEStructuralFeature(featureID); result = doDynamicGet(eFeature, result); } if ( result == null ) { result = super.eDynamicGet(featureID, resolve, coreType); } return result; } /** * @see org.eclipse.emf.ecore.impl.EObjectImpl#eDynamicIsSet(org.eclipse.emf.ecore.EStructuralFeature) */ @Override public boolean eDynamicIsSet(EStructuralFeature eFeature) { return doDynamicIsSet(eFeature); } // ================================================================================== // P R O T E C T E D M E T H O D S // ================================================================================== public static AnnotationContainer getAnnotationContainer(final Resource eResource) { for (final Iterator iter = eResource.getContents().iterator(); iter.hasNext();) { final EObject root = (EObject)iter.next(); if (root instanceof AnnotationContainer) { return (AnnotationContainer)root; } } return null; } protected Annotation getAnnotation( final boolean createIfRequired ) { if ( this.annotation == null ) { if ( this.extendedObject != null ) { if(this.editor == null) { final Resource resource = extendedObject.eResource(); AnnotationContainer cntr = getAnnotationContainer(resource); if (cntr == null) { if(createIfRequired && !ModelUtil.isXsdFile(resource) ) { cntr = CoreFactory.eINSTANCE.createAnnotationContainer(); resource.getContents().add(cntr); }else { //In non- ModelEditor mode, can't support XSD return null; } } final Annotation existing = cntr.findAnnotation(extendedObject); if ( existing != null) { return existing; } if(createIfRequired) { final Annotation ann = CoreFactory.eINSTANCE.createAnnotation(); ann.setAnnotatedObject(extendedObject); cntr.getAnnotations().add(ann); return ann; } return null; } try { final ModelEditor ed = getModelEditor(); this.annotation = ed.getAnnotation(this.extendedObject,createIfRequired); } catch (ModelerCoreException e) { ModelerCore.Util.log(e); } } } return this.annotation; } protected ModelEditor getModelEditor() { if ( this.editor == null ) { this.editor = ModelerCore.getModelEditor(); } return this.editor; } /** * @param eFeature * @param newValue * @since 4.2 */ protected void doDynamicSet(EStructuralFeature eFeature, Object newValue) { final Annotation annotation = getAnnotation(true); if ( annotation != null ) { final EMap tags = annotation.getTags(); final Object key = eFeature.getName(); if ( newValue == null || CoreStringUtil.Constants.EMPTY_STRING.equals(newValue)) { tags.removeKey(key); } else { final EDataType dt = (EDataType)eFeature.getEType(); final EPackage ePackage = dt.getEPackage(); final EFactory fac = ePackage.getEFactoryInstance(); String newStringValue = null; 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 + DELIM + fac.convertToString(dt, value); } } } else { newStringValue = fac.convertToString(dt, newValue); } tags.put(key,newStringValue); } } } /** * @param eFeature * @since 4.2 */ protected void doDynamicUnset(EStructuralFeature eFeature) { if ( this.extendedObject != null ) { final Annotation annotation = getAnnotation(false); if ( annotation != null ) { final EMap tags = annotation.getTags(); final Object key = eFeature.getName(); tags.removeKey(key); } } } /** * @param eFeature * @param result * @return * @since 4.2 */ protected Object doDynamicGet(EStructuralFeature eFeature, Object result) { final Annotation annotation = getAnnotation(true); if ( annotation != null ) { final EMap tags = annotation.getTags(); final Object key = eFeature.getName(); final EDataType dt = (EDataType)eFeature.getEType(); final EPackage ePackage = dt.getEPackage(); final EFactory fac = ePackage.getEFactoryInstance(); String value = (String)tags.get(key); // 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, DELIM); if (stringTokenizer.hasMoreTokens()) { while( stringTokenizer.hasMoreTokens() ) { String token = stringTokenizer.nextToken(); try { values.add(fac.createFromString(dt, token)); } catch (RuntimeException theException) { // since we currently don't support multi-valued ObjectExtensions // I couldn't test this code. Not sure what should be done. Wanted // to keep all values even if they weren't valid. Validation rules // will indicate if values are invalid. I chose to return the bad // values in the return list but have their type be String // instead of the correct EDataType. This could obviously break // something at some point in the future when multi-values are supported. (Dan F) values.add(token); } } } } else { try { result = fac.createFromString(dt, value); } catch (RuntimeException theException) { // just return the string representation. result = value; } } } return result; } /** * @param eFeature * @return * @since 4.2 */ protected boolean doDynamicIsSet(EStructuralFeature eFeature) { if ( this.extendedObject != null ) { final Annotation annotation = getAnnotation(false); if ( annotation != null ) { final EMap tags = annotation.getTags(); final Object key = eFeature.getName(); final String value = (String)tags.get(key); return value != null; } } return super.eDynamicIsSet(eFeature); } /** * Indicates if the specified extension property has a valid default value. * @param theExtensionPropertyId the identifier of the property being checked * @return <code>true</code>if valid; <code>false</code> otherwise. * @since 4.2 */ public boolean isValid(Object theExtensionPropertyId) { boolean result = true; Annotation annotation = this.getAnnotation(false); if (annotation == null) { // should not happen. log if it does. final IPath path = ModelerCore.getModelEditor().getModelRelativePath(this); final String msg = ModelerCore.Util.getString("ObjectExtension.NullAnnotation", //$NON-NLS-1$ path); ModelerCore.Util.log(IStatus.ERROR, msg); } else { final EMap tags = annotation.getTags(); if ((tags != null) && tags.containsKey(theExtensionPropertyId)) { final EClass xclass = eProperties.getEClass(); final List attributes = xclass.getEAllAttributes(); // loop through all attributes checking to see if the string representation of it's value // is compatible with it's type if ((attributes != null) && !attributes.isEmpty()) { for (int size = attributes.size(), i = 0; i < size; ++i) { final EAttribute attribute = (EAttribute)attributes.get(i); if (attribute.getName().equals(theExtensionPropertyId)) { final EDataType type = (EDataType)attribute.getEType(); final EPackage ePackage = type.getEPackage(); final EFactory factory = ePackage.getEFactoryInstance(); final String value = (String)tags.get(theExtensionPropertyId); if (value != null) { // could have many values or just one final StringTokenizer stringTokenizer = new StringTokenizer(value, DELIM); if (stringTokenizer.hasMoreTokens()) { while (stringTokenizer.hasMoreTokens()) { String token = stringTokenizer.nextToken(); try { factory.createFromString(type, token); } catch (RuntimeException theException) { result = false; break; } } } } break; } } } } else { // either no tags or extension property not found final IPath path = ModelerCore.getModelEditor().getModelRelativePath(annotation); final Object[] params = new Object[] {theExtensionPropertyId, path}; final String msg = ModelerCore.Util.getString("ObjectExtension.ExtendedPropertyNotFound", //$NON-NLS-1$ params); ModelerCore.Util.log(IStatus.ERROR, msg); } } return result; } }