/** * * C O P Y R I G H T N O T I C E * Copyright (c) 2001 by: * * The MicroArray Gene Expression Database group (MGED) * * Rosetta Inpharmatics * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * @author $Author: rhubley $ * @version $Revision: 1.6 $ * */ package org.biomage.tools.generate_dtd; import java.io.FileWriter; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.Vector; import org.biomage.tools.generate_classes.CreateFile; import org.biomage.tools.generate_classes.CreateClassFile; import org.biomage.tools.helpers.StringOutputHelpers; import org.biomage.tools.generate_classes.XMIParseHelpers; import org.w3c.dom.*; /** * Description: * Class that is resposible for generating the DTD entities, if * base class, and element and attribute if not abstract for the * CreateClassFile passed into the c'tor. * */ public class WriteDTDClassElement extends WriteDTDElement { final static protected String NEWLINE = StringOutputHelpers.NEWLINE; /** * Description: * The documentation for this class. */ String comment = null; /** * Description: * If this is a base class, will contain the string to use for the entity. */ String entities = null; /** * Description: * The element and Attlist declarations. Includes the container elements based on * role names for this class. */ String elements = null; /** * Description: * Constructor for classes for the DTD file generator. * *
* @param createFile: the class to write to the DTD. *
*/ protected WriteDTDClassElement( CreateFile createFile ) throws Exception { super(createFile); entityPrefix = "Description: * Creates the different entities, elements and attlists * for the class. * *
* @param packageOrdering: the XML configuration element for package ordering information. * Not used by this subclass. *
*/ protected void createXMLStrings() throws Exception { comment = createComment(); entities = createEntities(); elements = createElementAndAttlists(); } /** * Description: * String to use as prefix for the entities for this class. */ final protected String entityPrefix; /** * Description: * Creates the documentation for the class. * *
* @return the completed string with the appropriate attributes and association * documentation. *
*/ protected String createComment() throws Exception { StringBuffer commentsBuffer = new StringBuffer(createFile.getClassDoc() + NEWLINE + NEWLINE); addAttributeComments(createFile.getAssociationInfo(), commentsBuffer, "associations"); addAttributeComments(createFile.getAttrInfo(), commentsBuffer, "attributes"); return commentsBuffer.toString(); } /** * Description: * Adds the documentation for the attributes passed in. * *
* @param attrInfos: the vector of attributes to add documentation. * @param commentsBuffer: buffer to fill with the comments * for the attributes of this class. * @param typeAttr: will be either "attributes" or "associations". *
*/ protected void addAttributeComments( Vector attrInfos, StringBuffer commentsBuffer, String typeAttr ) throws Exception { if ( null == createFile.getBaseClassID() && (null == attrInfos || 0 == attrInfos.size()) ) { // nothing to do return; } // The content entity commentsBuffer.append(StringOutputHelpers.initialCap(typeAttr) + NEWLINE); if (null != createFile.getBaseClassID()) { commentsBuffer.append(" Inherites " + typeAttr + " from base class " + createFile.getBaseClassFileName() + "."); } // Add the attributes for this class if (null != attrInfos) { for (int i = 0; i < attrInfos.size(); i++) { CreateFile.AttrInformation attrInfo = (CreateFile.AttrInformation) attrInfos.get(i); if (0 < i || null != createFile.getBaseClassID()) { commentsBuffer.append(NEWLINE + NEWLINE); } commentsBuffer.append(" " + attrInfo.getName() + ": " + attrInfo.getComment() ); } } commentsBuffer.append(NEWLINE + NEWLINE); } /** * Description: * Creates the different entities for the class. * *
* @return the completed string with the appropriate entity declarations * for this class. *
*/ protected String createEntities() throws Exception { StringBuffer entitiesBuffer = new StringBuffer(); if (createFile.isBaseClass()) { if ( WriteDTDFile.isReferencedClass(createFile) ) { createClassesEntity(entitiesBuffer); } createContentEntity(entitiesBuffer); createAttrsEntity(entitiesBuffer); entitiesBuffer.append(NEWLINE); } return entitiesBuffer.toString(); } /** * Description: * Creates the classes entity and, if not owned, the ref entity. * *
* @param entitiesBuffer: buffer to fill with the appropriate * entities for this class. *
*/ protected void createClassesEntity( StringBuffer entitiesBuffer ) throws Exception { createClassesOrRefEntity(entitiesBuffer, "_classes"); if (XMIParseHelpers.COMPOSITE != createFile.typeOwned()) { createClassesOrRefEntity(entitiesBuffer, "_ref"); } } /** * Description: * Creates either classes entity or the ref entity, depending on * adornment parameter. *
* @param entitiesBuffer: buffer to fill with the appropriate * entities for this class. * @param adornment: suffix for the entity, either "_classes" or * "_ref". *
*/ protected void createClassesOrRefEntity( StringBuffer entitiesBuffer, String adornment ) throws Exception { Vector classNames = createFile.getConcreteSubClassNames(); // The classes or ref entity entitiesBuffer.append(entityPrefix + adornment + " \""); if (!adornment.equals("_ref")) { adornment = ""; } if (!createFile.isAbstract() && !classNames.contains(createFile.getClassFileName())) { // only add concrete classes to the class list classNames.add(0, createFile.getClassFileName()); } for (int i = 0; i < classNames.size(); i++) { entitiesBuffer.append(classNames.get(i).toString() + adornment); if (i < classNames.size() - 1) { entitiesBuffer.append(" |" + NEWLINE + "\t\t"); } } entitiesBuffer.append("\" >" + NEWLINE); } /** * Description: * Creates the content entity for the class. * *
* @param entitiesBuffer: buffer to fill with the content * entity for this class. *
*/ protected void createContentEntity( StringBuffer entitiesBuffer ) throws Exception { // The content entity entitiesBuffer.append(entityPrefix + "_content \""); createContent(entitiesBuffer); entitiesBuffer.append("\" >" + NEWLINE); } /** * Description: * Creates the attribute entity for the class. * *
* @param entitiesBuffer: buffer to fill with the attrs * entity for this class. *
*/ protected void createAttrsEntity( StringBuffer entitiesBuffer ) throws Exception { entitiesBuffer.append(entityPrefix + "_attrs \""); createAttrs(entitiesBuffer); entitiesBuffer.append("\" >" + NEWLINE); } /** * Description: * Creates the different element and attlist declarations for the class. * *
* @return the completed string with the appropriate declarations. *
*/ protected String createElementAndAttlists() throws Exception { StringBuffer elementBuffer = new StringBuffer(); createRoleDeclarations(elementBuffer); if (!createFile.isAbstract()) { createElementAndAttlist(elementBuffer); } else if (createFile.isBaseClass()) { createReference(elementBuffer); } if (0 < elementBuffer.length()) { elementBuffer.append(NEWLINE); } return elementBuffer.toString(); } /** * Description: * Creates the element and attlist declarations for the role names of the class. * *
* @return the completed string with the appropriate declarations. *
*/ protected void createRoleDeclarations( StringBuffer elementBuffer ) throws Exception { if ( WriteDTDFile.isReferencedClass(createFile) ) { Map roles = createFile.getRoleNames(); // If not a composite, can be on package list so write out the element for that if ( XMIParseHelpers.COMPOSITE != createFile.typeOwned() ) { String name = null; if (createFile.isBaseClass()) { name = "(%" + createFile.getClassFileName() + "_classes;)"; } else { name = createFile.getClassFileName(); } elementBuffer.append("" + NEWLINE + NEWLINE); } Object roleNames[] = createFile.getRoleNames().entrySet().toArray(); boolean debug = false; for (int i = 0; i < roleNames.length; i++) { Map.Entry entry = (Map.Entry) roleNames[i]; CreateFile.RoleInformation roleInfo = (CreateFile.RoleInformation) entry.getValue(); elementBuffer.append("" + NEWLINE); } elementBuffer.append(NEWLINE); } } /** * Description: * If not owned, creates the *_ref element and attlist then * creates the element and attlist declarations for the class. * *
* @param elementBuffer: buffer to use to create the declarations. *
*/ protected void createReference( StringBuffer elementBuffer ) throws Exception { if (createFile.isReferenced()) { elementBuffer.append("" + NEWLINE); elementBuffer.append("" + NEWLINE + NEWLINE); } } /** * Description: * If not owned, creates the *_ref element and attlist then * creates the element and attlist declarations for the class. * *
* @param elementBuffer: buffer to use to create the declarations. *
*/ protected void createElementAndAttlist( StringBuffer elementBuffer ) throws Exception { createReference(elementBuffer); if ( (null == createFile.getAssociationInfo() || 0 == createFile.getAssociationInfo().size()) && (!createFile.isBaseClass() && null == createFile.getBaseClassID()) ) { // Special syntax for the classes with no associations or entities elementBuffer.append("" + NEWLINE); } else { elementBuffer.append("" + NEWLINE); } if ( !((null == createFile.getAttrInfo() || 0 == createFile.getAttrInfo().size()) && (!createFile.isBaseClass() && null == createFile.getBaseClassID())) ) { elementBuffer.append("" + NEWLINE); } } /** * Description: * Creates the content entity for the class. * *
* @param buffer: buffer to fill with the content * for this class. *
*/ protected void createContent( StringBuffer buffer ) throws Exception { // BUGBUG: Need to add return type container for methods that return a class // The content entity if (null != createFile.getBaseClassID()) { buffer.append("(%" + createFile.getBaseClassFileName() + "_content;)"); } // Add the associations for this class Vector assnInfos = createFile.getAssociationInfo(); if (null == assnInfos) { // nothing more to do return; } // Order the vector by rank of each association Vector rank2assns = new Vector(); Integer prevRank = new Integer(-1); for (int i = 0; i < assnInfos.size(); i++) { // NOTE: two associations can have the same rank, they will // form a choice group in the content CreateFile.AssociationAttrInformation assnInfo = (CreateFile.AssociationAttrInformation) assnInfos.get(i); if (assnInfo.isOwner()) { // avoid putting a ref to the container continue; } Integer rank = assnInfo.getRank(); if ( rank.equals(prevRank) ) { ((Vector) rank2assns.get(rank2assns.size() - 1)).add(assnInfo); } else { Vector newRank = new Vector(); newRank.add(assnInfo); rank2assns.add(newRank); prevRank = rank; } } for (int i = 0; i < rank2assns.size(); i++) { if ( 0 < i || null != createFile.getBaseClassID() ) { buffer.append("," + NEWLINE + "\t\t"); } Vector assns = (Vector) rank2assns.get(i); if (1 < assns.size()) { // Enclose the choice group in parens buffer.append("("); } for (int j = 0; j < assns.size(); j++) { CreateFile.AssociationAttrInformation assnInfo = (CreateFile.AssociationAttrInformation) assns.get(j); // add the choice symbol if (0 < j) { buffer.append(" | "); } // Based on the attributes, set the suffix adornment for the // the container class name buffer.append(createContainer(assnInfo)); } if (1 < assns.size()) { // Enclose the choice group in parens buffer.append(")"); } } } /** * Description: * Creates all the possibilities of ordering the vector of choices. * * Special case has been removed so this code isn't called. Left * here in case it is needed in the future. * *
* @param buffer: buffer to fill with the choices from the Vector. * @param choices: names of the differenct choices. *
*/ protected void createChoices( StringBuffer buffer, Vector choices, String offset ) throws Exception { // check the stop condition if (1 == choices.size()) { CreateFile.AssociationAttrInformation first = (CreateFile.AssociationAttrInformation) choices.get(0); buffer.append(offset + createContainer(first)); return; } buffer.append(offset + "("); for (int i = 0; i < choices.size(); i++) { CreateFile.AssociationAttrInformation first = (CreateFile.AssociationAttrInformation) choices.remove(0); buffer.append("(" + createContainer(first) + "," + NEWLINE); createChoices(buffer, choices, offset + '\t'); buffer.append(")"); choices.add(first); if (choices.size() - 1 > i) { buffer.append(" |" + NEWLINE + offset); } } buffer.append(")"); } /** * Description: * Creates the name of the container for the association passed in. * *
* @param assnInfo: the association to create the container name for. *
*/ protected String createContainer( CreateFile.AssociationAttrInformation assnInfo ) throws Exception { String name = StringOutputHelpers.initialCap(assnInfo.getName()); if ("#PCDATA".equals(name)) { if ( 0 == assnInfo.getMinCard() ) { if ( 1 < assnInfo.getMaxCard() ) { name += "*"; } else { name += "?"; } } else if ( 1 < assnInfo.getMaxCard() || -1 == assnInfo.getMaxCard() ) { name += "+"; } } else { name += "_assn"; if ( XMIParseHelpers.COMPOSITE != assnInfo.getTypeAggregated() ) { name += "ref"; } if ( 1 < assnInfo.getMaxCard() || -1 == assnInfo.getMaxCard() ) { name += "list"; } // add cardinality if ( 0 == assnInfo.getMinCard() ) { name += "?"; } } return name; } /** * Description: * Creates the attribute entity for the class. * *
* @param buffer: buffer to fill with the attrs * for this class. *
*/ protected void createAttrs( StringBuffer buffer ) throws Exception { if (null != createFile.getBaseClassID()) { buffer.append("%" + createFile.getBaseClassFileName() + "_attrs;"); } // Add the attributes for this class Vector attrInfos = createFile.getAttrInfo(); if (null != attrInfos) { for (int i = 0; i < attrInfos.size(); i++) { if (0 < i || null != createFile.getBaseClassID()) { buffer.append(NEWLINE + "\t\t"); } CreateClassFile.DataTypeAttrInformation attrInfo = (CreateClassFile.DataTypeAttrInformation) attrInfos.get(i); String name = attrInfo.getName(); int index = -1; while ( -1 != (index = name.indexOf('/')) ) { // replace the illegal '/' with _per_ name = name.substring(0, index) + "_per_" + name.substring(index+1); } if ( attrInfo.isEnum() ) { buffer.append(name + " ("); Vector enums = attrInfo.getEnumValues(); for (int j = 0; j < enums.size(); j++) { name = (String) enums.get(j); while ( -1 != (index = name.indexOf('/')) ) { // replace the illegal '/' with _per_ name = name.substring(0, index) + "_per_" + name.substring(index+1); } buffer.append(name); if (j < enums.size() - 1) { buffer.append('|' + NEWLINE + "\t\t\t"); } } buffer.append(") "); } else { buffer.append(name + " CDATA " ); } // Add required, implied or default if ( null != attrInfo.getInitialValue() && 0 != attrInfo.getInitialValue().length() ) { buffer.append("\"" + attrInfo.getInitialValue() + "\""); } else if (attrInfo.isRequired()) { buffer.append("#REQUIRED"); } else { buffer.append("#IMPLIED"); } } } } /** * Description: * Method to write out entities. * *
* @param write: the writer to use. *
*/ protected void writeEntities( FileWriter writer ) throws Exception { if (0 != entities.length()) { StringOutputHelpers.writeOutput("\t" + createFile.getClassFileName(), 3); String entityComment = "Entities for " + createFile.getClassFileName() + NEWLINE + NEWLINE + comment; StringOutputHelpers.writeDTDComment(writer, entityComment, null, true, true); writer.write(entities); } } /** * Description: * Method to write out entities. * *
* @param write: the writer to use. *
*/ protected void writeBody( FileWriter writer ) throws Exception { if (0 != elements.length()) { StringOutputHelpers.writeOutput("\t" + createFile.getClassFileName(), 3); String elementComment = "Element and Attlist declarations for " + createFile.getClassFileName() + NEWLINE + NEWLINE + comment; StringOutputHelpers.writeDTDComment(writer, elementComment, null, true, true); writer.write(elements); } } }