FileDocCategorySizeDatePackage
AttributeFiller.javaAPI DocExample18460Thu Feb 17 20:00:42 GMT 2000com.togethersoft.modules.genidl

AttributeFiller.java

/*----------------------------------------------------------------------------
Copyright (c)2000 TogetherSoft LLC. Patents pending. All rights reserved.
----------------------------------------------------------------------------*/

package com.togethersoft.modules.genidl;

import java.util.Vector;
import com.togethersoft.openapi.scriptapi.UML.UMLClassifier;
import com.togethersoft.openapi.scriptapi.UML.UMLAssociation;
import com.togethersoft.openapi.scriptapi.UML.UMLAttribute;
import com.togethersoft.openapi.scriptapi.UML.UMLInterface;
import com.togethersoft.openapi.scriptapi.UML.UMLLink;
import com.togethersoft.openapi.scriptapi.UML.enums.UMLAttributeEnumeration;
import com.togethersoft.openapi.scriptapi.UML.enums.UMLLinkEnumeration;
import com.togethersoft.modules.genidl.idl.ProcessTags;

/** Attribute processor for IDL interfaces. */
class AttributeFiller {

    /**
     * Constructor.
     *  @see ScopeProcessor
     *  @see idl.ProcessTags
     *  @see IdlTypeConverter
     *  @see Complainer
     */
    public AttributeFiller(ScopeProcessor scopeProcessor, ProcessTags tagsProcessor, ConfigLoader configLoader,
        IdlTypeConverter typeConverter, Complainer complainer) {
            myScopeProcessor = scopeProcessor;
            myTagsProcessor = tagsProcessor;
            myConfigLoader = configLoader;
            myComplainer = complainer;
            myTypeConverter = typeConverter;
            localTypedefsBuffer = new StringBuffer();
    }

    public void setClassifier(UMLClassifier classifier) {
        myClassifier = classifier;
    }

    /**
     * Set which pass is going on.
     *  @param isFirstPass true if this is a first pass, gathering information
     */
    public void setPass(boolean isFirstPass) {
        this.isFirst = isFirstPass;
    }

    /**
     * Set structure fill mode. Structure fill mode is used for filling attributes in unions, structs and exceptions.
     *  @param isStructElement true if struct type entity is being generated
     */
    public void setStruct(boolean isStructElement) {
        this.isStruct = isStructElement;
    }

    /**
     * Sets the label generator for unions.
     *  @see CaseLabelGenerator
     */
    public void setLabelGenerator(CaseLabelGenerator labelGenerator) {
        myLabelGenerator = labelGenerator;
    }

    /** Sets the buffer to put generated declarations into */
    public void setBuffer(StringBuffer buffer) {
        myBuffer = buffer;
    }

    /** Sets the buffer to hold module-level typedefs */
    public void setModuleBuffer(StringBuffer moduleBuffer) {
        myModuleBuffer = moduleBuffer;
    }

    /**
     * Sets base indent level
     *  @param indent String of spaces which is prepended to all generated code.
     */
    public void setIndent(String indent) {
        myIndent = indent;
    }

    /**
     * Get locally generated typedef declarations.
     *  @return StringBuffer containing newly generated typedefs
     */
    public StringBuffer getLocalTypedefs() {
        return localTypedefsBuffer;
    }

    /** Do-it-all. */
    public void process() {
        StringBuffer typeAddition;
        namesInScope = new Vector();
        UMLAttribute umlAttribute;
        myScopeProcessor.getModel().setIncludeLinkAttribute(false);
        UMLAttributeEnumeration attributes = new AllAttributesEnumerator(myClassifier, myConfigLoader.isProcessAttributes(),
            myConfigLoader.isProcessLinks());
        if (!isFirst && attributes.hasMoreElements() && !isStruct) {
            myBuffer.append("//------------------------------------------" + "\n");
            myBuffer.append("//             attributes " + "\n");
            myBuffer.append("//------------------------------------------" + "\n");
        }
        while (attributes.hasMoreElements()) {
            umlAttribute = attributes.getNextUMLAttribute();
            typeAddition = new StringBuffer();
            if ((myConfigLoader.isProcessPublicMembersOnly() && !umlAttribute.isPublic()) ||
                (!(myClassifier instanceof UMLInterface) && umlAttribute.isStatic())) {
                    continue;
            }
            if (!myScopeProcessor.isDuplicatedAtt(myClassifier, umlAttribute.getName()) &&
                !myScopeProcessor.isExistsInTheCache(isFirst, myClassifier.getName(), umlAttribute.getName())) {
                    if (isFirst) {
                        myTagsProcessor.processProperties(umlAttribute, true, true);
                    }
                    else {
                        processAttributeDeclaration(umlAttribute, typeAddition);
                    }
            }
        }
        if (myConfigLoader.isProcessLinks()) {

            /* make something with pure links */

            UMLLinkEnumeration pureLinks = myClassifier.getOutgoingLinks();
            while (pureLinks.hasMoreElements()) {
                typeAddition = new StringBuffer();
                UMLLink umlLink = pureLinks.getNextUMLLink();
                if (umlLink instanceof UMLAssociation) {
                    UMLAssociation assoc = (UMLAssociation)umlLink;
                    if (assoc.getAttribute() == null) {
                        // gotcha, pure link!
                        processPureLink(assoc, typeAddition);
                    }
                }
            }
        }
    }

    public String createAttributeDeclaration(String readonly, String attrType, String attrName, boolean isStructObject) {
        String value = readonly;
        if (value.equals("")) {
            value = (isStructObject ? "" : "attribute ") + attrType + " " + attrName + ";";
        }
        else {
            value += (isStructObject ? " " : " attribute ") + attrType + " " + attrName + ";";
        }
        return value;
    }

    public String createConstDecl(String attrType, String attrName, String constValue) {
        return "const " + attrType + " " + attrName + " = " + constValue + ";";
    }

    /** Process attrbute's cardinality tag. */
    public String processCardinalityDeclaration(String anAttrType, String attrName, String cardinalityValue) {
        String attrType = StringUtility.cutAsterisksAndAmpersands(anAttrType);
        if (cardinalityValue.indexOf(".") != -1) { // 1..5, 1..*, 1..n
            int point = cardinalityValue.lastIndexOf("..");
            String lastItemOfDecl = cardinalityValue.trim().substring(point + 2, cardinalityValue.trim().length());
            if (lastItemOfDecl.trim().equals("*") || lastItemOfDecl.trim().equals("n")) {
                myScopeProcessor.addTypedefBeforeMember("sequence< " + attrType + " > " + attrName + "_type");
            }
            else {
                myScopeProcessor.addTypedefBeforeMember("sequence< " + attrType + ", " + lastItemOfDecl +
                    " > " + attrName + "_type");
            }
        }
        else {
            if (cardinalityValue.trim().equals("*") || cardinalityValue.trim().equals("n")) {
                myScopeProcessor.addTypedefBeforeMember("sequence< " + attrType + " > " + attrName + "_type");
            }
            else {
                myScopeProcessor.addTypedefBeforeMember(attrType + " " + attrName + "_type" + "[" +
                    cardinalityValue.trim() + "]");
            }
        }
        return attrName + "_type";
    }

    /** Process array declaration or sequence declaration. */
    public String processArrayDeclaration(String attrType, String attrName, String sequenceValue, boolean isSequence,
        String initialValue, boolean isStructObject) {
            ComplexArrayDefinition arrayDecl = new ComplexArrayDefinition(myScopeProcessor);
            if (isStructObject) {
                arrayDecl.setTypedefsBuffer(localTypedefsBuffer);
            }
            String decl = arrayDecl.getIdlDefinitionString(attrType, attrName, sequenceValue, isSequence, initialValue);
            return decl;
    }

    private void processPureLink(UMLAssociation assoc, StringBuffer typeAddition) {
        String attrName = assoc.getName();
        String attrType = myScopeProcessor.getReferencedType(myClassifier, assoc, null);
        if (!isFirst) {
            myBuffer.append(myIndent + createAttributeDeclaration("", attrType, attrName, false) + "\n");
        }
    }

    /** @return false if this attribute is being skipped */
    private boolean processAttributeDeclaration(UMLAttribute attribute, StringBuffer typeAddition) {
        String attrType, attrName, idlNative, readonly, supplierCardinality, idlStringCapacity, idlSequence, idlCaseLabel;
        boolean isConst, isIgnored, typeChanged;
        String idlCode = myTagsProcessor.getPropertyValue(attribute, IdlTags.IDLCODE);
        if (!idlCode.equals("")) {
            myBuffer.append(myIndent + myTagsProcessor.processingTag_idlCode(idlCode, true) + "\n");
        }
        typeChanged = false;
        isConst = false;
        isIgnored = false;
        attrName = "";
        attrType = "";
        idlNative = "";
        readonly = "";
        idlSequence = "";
        idlCaseLabel = "";
        idlStringCapacity = "";
        supplierCardinality = "";
        // typeAddition = new StringBuffer();
        myScopeProcessor.resetMemberTypedefs();

        /* check for the stereotype first */

        String stereotype = myTagsProcessor.getPropertyValue(attribute, IdlTags.STEREOTYPE);
        if (stereotype.equals(IdlTags.NESTED)) {
            return false;
        }

        /** svo: we should detect if attribute type is class */
        attrType = myScopeProcessor.getReferencedType(myClassifier, attribute, null);
        // * check for inherited methods
        // * we must process tags before process parameters;
        myTagsProcessor.processProperties(attribute, isFirst, true);
        attrName = attribute.getName();
        if (IdlKeywords.isKeyword(attrName)) {
            attrName += "_";
        }
        // * process idlType or idlNative or idlFixed to change type value
        String tempType = myTagsProcessor.getPropertyValue(attribute, IdlTags.IDLTYPE);
        if (!tempType.equals("")) {
            tempType = myTagsProcessor.processingTag_idlType(tempType, false);
        }
        if (!tempType.equals("")) {
            attrType = tempType;
        }
        if (myConfigLoader.isProcessCardinality()) {
            if (attribute.hasProperty(IdlTags.SUPPLIER_CARDINALITY)) {
                if (!myConfigLoader.isProcessLinks()) // check for option value
                        isIgnored = true;
                else {
                    String value = myTagsProcessor.getPropertyValue(attribute, IdlTags.SUPPLIER_CARDINALITY);
                    if (value.trim().equals("0")) {
                        isIgnored = true;
                    }
                    else {
                        attrType = processCardinalityDeclaration(attrType, attrName, value);
                    }
                }
            }
        }
        // process arrays' type
        boolean hasSequence = attribute.hasProperty(IdlTags.IDLSEQUENCE);
        boolean isPointer = false;
        if (attrType.trim().endsWith("*")) {
            isPointer = true;
        }
        if (hasSequence) {
            idlSequence = myTagsProcessor.getPropertyValue(attribute, IdlTags.IDLSEQUENCE);
        }
        if (!isIgnored && (attrType.lastIndexOf("[") != -1 || hasSequence || isPointer)) {
            attrType = processArrayDeclaration(attrType, attrName, idlSequence, hasSequence,
                attribute.getInitialValue(), isStruct);
            typeChanged = true;
        }
        if (!myScopeProcessor.getMemberTypedefsBuffer().equals("")) {
            if (isStruct) {
                localTypedefsBuffer.append(myScopeProcessor.getMemberTypedefsBuffer());
            }
            else {
                myBuffer.append(myScopeProcessor.getMemberTypedefsBuffer());
            }
        }
        String fooType = myScopeProcessor.checkTypeAndConvert(false, myScopeProcessor.getCurrentScope(), attrType);
        if ((fooType.equals(IdlType.STRING) || fooType.equals(IdlType.WSTRING))) {
            if (!myTagsProcessor.getPropertyValue(attribute, IdlTags.IDLSTRINGCAPACITY).equals("")) {
                typeAddition.append("<");
                typeAddition.append(myTagsProcessor.getPropertyValue(attribute, IdlTags.IDLSTRINGCAPACITY));
                typeAddition.append(">");
            }
        }
        isConst = processConst(attribute, attrName, attrType, myBuffer);
        if (attribute.hasProperty("idlReadonly") || attribute.isConst()) {
            if (isStruct) {
                myComplainer.error(myClassifier.getQualifiedName() + ": struct methods can't be readonly");
            }
            else {
                readonly = "readonly";
            }
        }
        if (!isConst && !isIgnored) // FIXME, should here be the brace?
                if (attrType.equals("native")) {
                    myBuffer.append(myIndent + attrType + " " + attrName + ";" + "\n");
            }
            else { // if !idlNative
                if (!typeChanged) {
                    attrType = myScopeProcessor.checkTypeAndConvert(false, myScopeProcessor.getCurrentScope(), attrType);
                }
                attrType += typeAddition.toString();
                if (myLabelGenerator == null) {
                    myBuffer.append(myIndent + createAttributeDeclaration(readonly, attrType, attrName, isStruct) + "\n");
                }
                else {
                    // filling union
                    String nextCaseLabel = "";
                    if (!attribute.hasProperty("idlCaseLabel")) {
                        nextCaseLabel = myLabelGenerator.nextCaseLabel();
                        if (nextCaseLabel == null) {
                            myComplainer.error("Union " + myClassifier.getQualifiedName() +
                                " exceeds maximum number of cases for given selector type");
                            return false;
                        }
                        myBuffer.append(myIndent + "case  " + nextCaseLabel + ":");
                    }
                    else { // has property
                        nextCaseLabel = myTagsProcessor.getPropertyValue(attribute, "idlCaseLabel").trim();
                        if (myLabelGenerator.isUsedLabel(nextCaseLabel)) {
                            myComplainer.error("Union " + myClassifier.getQualifiedName() + " already has case " +
                                nextCaseLabel + ", label ignored");
                            return false;
                        }
                        myBuffer.append(myIndent + (nextCaseLabel.equals("default") ? nextCaseLabel :
                            "case " + nextCaseLabel) + ":");
                    }
                    myBuffer.append(" " + createAttributeDeclaration(readonly, attrType, attrName, true) + "\n");
                }
            }
        return true;
    }

    private boolean processConst(UMLAttribute umlAttribute, String attrName, String attrType, StringBuffer buffer) {
        boolean isConst = false;
        String constValue = myTagsProcessor.getPropertyValue(umlAttribute, IdlTags.IDLCONST);
        String scope = "interface";
        if (umlAttribute.hasProperty(IdlTags.IDLCONST)) {
            if (constValue.trim().startsWith("module")) {
                scope = "module";
            }
            else if (constValue.trim().startsWith("global")) {
                scope = "global";
            }
            constValue = myTagsProcessor.processingTag_idlConst(constValue, umlAttribute.getInitialValue()).trim();
            System.err.println("for const: " + attrName + ", constValue = " + constValue);
            boolean valueCreated = false;
            if (constValue.equals("")) {
                constValue = StringUtility.createDefaultConstValue(myTypeConverter.getConvertedType(attrType));
                valueCreated = true;
            }
            if (myTypeConverter.getConvertedType(attrType) == null) {
                myComplainer.error(umlAttribute.getQualifiedName() + " has unknown type and was not generated.");
                return false;
            }
            if (constValue.equals("")) { // we have initial value
                myComplainer.error("Cannot initialize constant: " + attrName + ", skipped");
            }
            else {
                myComplainer.error("Default value " + constValue + " generated for const " + umlAttribute.getQualifiedName());
                //convert type for const  declaration
                if (scope.equals("global")) {
                    myScopeProcessor.addGlobalConstDeclaration(
                        createConstDecl(myTypeConverter.getConvertedType(attrType), attrName, constValue) + "\n");
                }
                if (scope.equals("interface")) {
                    buffer.insert(0, myIndent + createConstDecl(myTypeConverter.getConvertedType(attrType), attrName,
                        constValue) + "\n");
                }
                else if (scope.equals("module")) {
                    String shift = myTagsProcessor.getPosition();
                    myModuleBuffer.insert(0, shift + createConstDecl(myTypeConverter.getConvertedType(attrType), attrName,
                        constValue) + "\n");
                }
            } // else
            // add const to buffer
            isConst = true;
        }
        return isConst;
    }

    private Vector namesInScope;
    private UMLClassifier myClassifier;
    private boolean isFirst = true;
    private boolean isStruct = false;
    private String myIndent = "";
    private CaseLabelGenerator myLabelGenerator;
    private StringBuffer myBuffer;
    private StringBuffer myModuleBuffer;
    private ScopeProcessor myScopeProcessor;
    private ProcessTags myTagsProcessor;
    private ConfigLoader myConfigLoader;
    private Complainer myComplainer;
    private IdlTypeConverter myTypeConverter;
    private StringBuffer localTypedefsBuffer;
}