/*----------------------------------------------------------------------------
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;
}
|