/** * */ package ecologylab.bigsemantics.metadata; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import ecologylab.bigsemantics.gui.EditValueEvent; import ecologylab.bigsemantics.gui.EditValueListener; import ecologylab.bigsemantics.gui.EditValueNotifier; import ecologylab.bigsemantics.metadata.scalar.MetadataScalarBase; import ecologylab.bigsemantics.metadata.scalar.types.MetadataScalarType; import ecologylab.bigsemantics.metametadata.MetaMetadataCollectionField; import ecologylab.bigsemantics.metametadata.MetaMetadataField; import ecologylab.bigsemantics.metametadata.MetaMetadataNestedField; import ecologylab.bigsemantics.metametadata.MmdCompilerService; import ecologylab.bigsemantics.metametadata.MmdGenericTypeVar; import ecologylab.bigsemantics.metametadata.declarations.MetaMetadataFieldDeclaration; import ecologylab.serialization.ClassDescriptor; import ecologylab.serialization.FieldDescriptor; import ecologylab.serialization.FieldType; import ecologylab.serialization.ScalarUnmarshallingContext; import ecologylab.serialization.XMLTools; import ecologylab.serialization.annotations.Hint; import ecologylab.serialization.annotations.simpl_scalar; import ecologylab.serialization.types.CollectionType; import ecologylab.serialization.types.ScalarType; import ecologylab.serialization.types.scalar.CompositeAsScalarType; /** * * @author andruid * */ public class MetadataFieldDescriptor<M extends Metadata> extends FieldDescriptor implements EditValueNotifier { static { MetadataScalarType.init(); } final private boolean isMixin; Method hwSetMethod; Method getter; /** * The name in the MetaMetadataComposite field whose declaration resulted in the generation of * this. */ @simpl_scalar private String mmName; private ArrayList<EditValueListener> editValueListeners = new ArrayList<EditValueListener>(); private MetaMetadataField definingMmdField; private boolean startedTraversalForPolymorphism = false; public MetadataFieldDescriptor(ClassDescriptor declaringClassDescriptor, Field field, FieldType annotationType) // String nameSpacePrefix { super(declaringClassDescriptor, field, annotationType); if (field != null) { isMixin = field.isAnnotationPresent(semantics_mixin.class); //TODO -- for future expansion??? andruid 4/14/09 // hwSetMethod = ReflectionTools.getMethod(thatClass, "hwSet", SET_METHOD_ARG); } else { isMixin = false; } this.mmName = deriveMmName(); checkScalarType(); } public MetadataFieldDescriptor(ClassDescriptor baseClassDescriptor, FieldDescriptor wrappedFD, String wrapperTag) { super(baseClassDescriptor, wrappedFD, wrapperTag); isMixin = false; checkScalarType(); } public MetadataFieldDescriptor(MetaMetadataField definingMmdField, String tagName, String comment, FieldType type, ClassDescriptor elementClassDescriptor, ClassDescriptor declaringClassDescriptor, String fieldName, ScalarType scalarType, Hint xmlHint, String fieldType) { super(tagName, comment, type, elementClassDescriptor, declaringClassDescriptor, fieldName, scalarType, xmlHint, fieldType); this.isMixin = false; this.definingMmdField = definingMmdField; if (definingMmdField.getOtherTags() != null) { String[] otherTags = definingMmdField.getOtherTags().split(","); for (String otherTag : otherTags) this.otherTags().add(otherTag.trim()); } // child tag for collections if (definingMmdField instanceof MetaMetadataCollectionField) { String childTag = ((MetaMetadataCollectionField) definingMmdField).getChildTag(); this.setCollectionOrMapTagName(childTag); } // simpl_scope for inherently polymorphic fields if (definingMmdField instanceof MetaMetadataNestedField) { MetaMetadataNestedField nested = (MetaMetadataNestedField) definingMmdField; String scopeName = nested.getPolymorphicScope(); this.setUnresolvedScopeAnnotation(scopeName); } checkScalarType(); } public MetadataFieldDescriptor() { isMixin = false; // empty constructor to satisfy S.IM.PL } private void checkScalarType() { if (this.field != null && MetadataScalarBase.class.isAssignableFrom(this.field.getType()) && this.getScalarType() != null && this.getScalarType() instanceof CompositeAsScalarType) { warning("A CompositeAsScalarType Field!"); warning("Please check if metadata scalar types registered before MetadataFieldDescriptors formed!"); } } @Override public boolean isMixin() { return isMixin; } @Override public void addEditValueListener(EditValueListener listener) { editValueListeners.add(listener); } /** * Edit the value of a scalar. * * @return True if the value of the field is set; otherwise, false. */ @Override public boolean fireEditValue(Metadata metadata, String fieldValueString) { boolean result = false; if (isScalar()) { result = this.set(metadata, fieldValueString); if(result) // uses reflection to call a set method or access the field directly if there is not one. { metadata.rebuildCompositeTermVector(); // makes this as if an hwSet(). //Call the listeners only after the field is properly set. EditValueEvent event = new EditValueEvent(this, metadata); for(EditValueListener listener : editValueListeners) { listener.editValue(event); } } } return result; } @Override public void removeEditValueListener(EditValueListener listener) { editValueListeners.remove(listener); } public MetadataBase getNestedMetadata(MetadataBase context) { return isScalar() ? null : (MetadataBase) getNested(context); } @Override public void setFieldToScalar(Object context, String value, ScalarUnmarshallingContext scalarUnmarshallingContext) { super.setFieldToScalar(context, value, scalarUnmarshallingContext); } private String deriveMmName() { String result = null; Field thatField = this.field; final mm_name mmNameAnnotation = thatField.getAnnotation(mm_name.class); if (mmNameAnnotation != null) { result = mmNameAnnotation.value(); } if (result == null) { result = XMLTools.getXmlTagName(thatField.getName(), null); if (!this.isScalar() && !thatField.isAnnotationPresent(mm_no.class)) error("Missing @mm_name annotation for " + thatField + "\tusing " + result); } return result; } /** * @return the mmName */ public String getMmName() { return mmName; } /** * get the (defining) meta-metadata field object. currently, only used by the compiler. * * @return */ public MetaMetadataField getDefiningMmdField() { return definingMmdField; } public void setDefiningMmdField(MetaMetadataField mmdField) { this.definingMmdField = mmdField; } private String fixNull(String s) { return s == null ? "NULL" : s; } @Override public String toString() { String name = getName(); if (name == null) { name = "NO_NAME"; } Class describedClass = declaringClassDescriptor.getDescribedClass(); String describedClassName = describedClass == null ? null : describedClass.getName(); if (describedClassName == null) { describedClassName = "NO_CLASS"; } FieldType fieldType = getType(); String fieldTypeName = fieldType == null ? null : fieldType.name(); if (fieldTypeName == null) { fieldTypeName = "NO_TYPE"; } return getClassSimpleName() + "[" + name + " < " + describedClassName + ": " + fieldTypeName + "]"; } @Override public void setWrapped(boolean wrapped) { super.setWrapped(wrapped); } public void setWrappedFD(MetadataFieldDescriptor wrappedFD) { super.setWrappedFD(wrappedFD); } @Override public void setTagName(String tagName) { super.setTagName(tagName); } @Override public void setCollectionOrMapTagName(String collectionOrMapTagName) { super.setCollectionOrMapTagName(collectionOrMapTagName); } @Override public MetadataFieldDescriptor clone() { return (MetadataFieldDescriptor) super.clone(); } public void setGeneric(String genericParametersString) { this.isGeneric = true; this.genericParametersString = genericParametersString; } private MmdCompilerService compilerService; public void setCompilerService(MmdCompilerService compilerService) { this.compilerService = compilerService; } private String cachedJavaType; @Override public String getJavaType() { if (cachedJavaType != null) return cachedJavaType; CollectionType collectionType = this.getCollectionType(); String javaType = super.getJavaType(); if (compilerService != null && collectionType != null && definingMmdField instanceof MetaMetadataNestedField) { MetaMetadataNestedField nested = (MetaMetadataNestedField) definingMmdField; Collection<MmdGenericTypeVar> genericTypeVars = nested.getGenericTypeVarsList(); if (genericTypeVars != null && genericTypeVars.size() > 0) { StringBuilder sb = new StringBuilder(); sb.append(javaType.substring(0, javaType.indexOf('<'))); sb.append("<"); sb.append(this.getElementClassDescriptor().getDescribedClassSimpleName()); try { compilerService.appendGenericTypeVarParameterizations(sb, nested.getGenericTypeVarsList(), nested.getRepository()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } sb.append(">"); return sb.toString(); } } if (getType() == FieldType.COMPOSITE_ELEMENT) { // FIXME this part needs to be debugged!!!! MetaMetadataNestedField nested = (MetaMetadataNestedField) definingMmdField; Collection<MmdGenericTypeVar> genericTypeVars = nested.getGenericTypeVarsList(); for (MmdGenericTypeVar mmdGenericTypeVar : genericTypeVars) { if (mmdGenericTypeVar.getNestedGenericTypeVarScope() == null || mmdGenericTypeVar.getNestedGenericTypeVars().size() == 0) { javaType = mmdGenericTypeVar.getName(); break; } } } cachedJavaType = javaType; return javaType; } private String cachedCSharpType; @Override public String getCSharpType() { if (cachedCSharpType != null) return cachedCSharpType; CollectionType collectionType = this.getCollectionType(); String csType = super.getCSharpType(); String typeName = csType; if (csType.indexOf("<") > 0) { typeName = csType.substring(csType.indexOf("<") + 1, csType.indexOf(">")); } if (compilerService != null && definingMmdField instanceof MetaMetadataNestedField) { MetaMetadataNestedField nested = (MetaMetadataNestedField) definingMmdField; Collection<MmdGenericTypeVar> genericTypeVars = nested.getGenericTypeVarsList(); Collection<MmdGenericTypeVar> superMmdGenericTypeVars = null; if (nested.getTypeMmd() != null) { superMmdGenericTypeVars = nested.getTypeMmd().getGenericTypeVarsList(); } if (collectionType != null && genericTypeVars != null && genericTypeVars.size() > 0) { StringBuilder sb = new StringBuilder(); sb.append(csType.substring(0, csType.indexOf('<'))); sb.append("<"); sb.append(this.getElementClassDescriptor().getDescribedClassSimpleName()); try { compilerService.appendGenericTypeVarParameterizations(sb, nested.getGenericTypeVarsList(), nested.getRepository()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } sb.append(">"); return sb.toString(); } else if (nested.getTypeMmd() != null && superMmdGenericTypeVars != null && superMmdGenericTypeVars.size() > 0) { StringBuilder sb = new StringBuilder(); String collType = collectionType == null ? null : csType.substring(0, csType.indexOf("<")); String elemType = collectionType == null ? csType : csType.substring(csType.indexOf("<") + 1, csType.lastIndexOf(">")); if (nested.isCovariant()) { elemType = "I" + elemType; } if (collectionType != null) { sb.append(collType).append("<"); } sb.append(elemType); try { compilerService.appendGenericTypeVarExtends(sb, superMmdGenericTypeVars, nested.getRepository()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (collectionType != null) { sb.append(">"); } return sb.toString(); } } if (getType() == FieldType.COMPOSITE_ELEMENT) { MetaMetadataNestedField nested = (MetaMetadataNestedField) definingMmdField; for (MmdGenericTypeVar mmdGenericTypeVar : nested.getGenericTypeVarsList()) { if (mmdGenericTypeVar.getNestedGenericTypeVarScope() == null || mmdGenericTypeVar.getNestedGenericTypeVars().size() == 0) { csType = mmdGenericTypeVar.getName(); break; } } } cachedCSharpType = csType; return csType; } }