alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.lib.jmi.xmi;

import java.io.*;
import java.util.*;

import javax.jmi.reflect.*;
import javax.jmi.model.*;

import org.netbeans.lib.jmi.util.DebugException;
import org.netbeans.lib.jmi.util.Logger;

public class XmiDtdProducer extends org.netbeans.api.mdr.DTDProducer {

    public static String TAG_ELEMENT = "!ELEMENT";
    public static String TAG_ATTLIST = "!ATTLIST";
    public static String TAG_REQUIRED = "#REQUIRED";
    public static String TAG_PCDATA = "#PCDATA";
    public static String TAG_CDATA = "CDATA";
    public static String TAG_IMPLIED = "#IMPLIED";
    public static String TAG_IDREFS = "IDREFS";
    public static String TAG_EMPTY = "EMPTY";
    public static String TAG_XMI_REFERENCE = "XMI.reference";
    public static String TAG_XMI_EXTENSION = "XMI.extension";
    public static String TAG_XMI_VALUE = "xmi.value";
    public static String TAG_XMI_FIXED_ATTRIBS = "%XMI.element.att; %XMI.link.att;";    
    
    // String used in DTD fixed file to mark end of the licence part.
    private static String END_OF_LICENCE_MARKER = "";
    // Fixed DTD file name.
    private static String FIXED_DTD_FILE = "resources/fixed.dtd";
    // treshold (number of chars) for line breaking when writing !ELEMENT
    private static int LINE_BOUND = 60;

    // output stream to which the produced DTD is written
    private PrintStream stream;
    // main package extent
    private RefPackage extent;
    // elements cache used to obtain classes' attributes, references, etc.
    private ElementsCache elementsCache;
    // stored already processed packages
    private Set trackedPackages;
    // stores mapping class -> set of all direct subtypes
    private Map classHierarchy;
    // cache for mapping class -> all subtypes (direct and non-direct)
    private Map allSubtypes_cache;
    // mapping MofPackage -> namespace name
    private Map namespaces;
    // flag indicating, if first item in !ELEMENT is to be written
    private boolean isFirstItem;
    // counter of characters in currently writen line (used when writing !ELEMENT)
    private int charsCounter;

    // init .....................................................................

    public void init () {
        elementsCache = new ElementsCache (extent);
        trackedPackages = new HashSet ();
        classHierarchy = new HashMap ();
        allSubtypes_cache = new HashMap ();
        namespaces = new HashMap ();

        elementsCache = new ElementsCache (extent);
        findNamespaces (extent);        
        trackedPackages.clear ();
    }

    // methods ..................................................................

    public void startElement (String name) {
        stream.println ();
        isFirstItem = true;        
        stream.print ("<" + TAG_ELEMENT + " ");
        stream.print (name);
        charsCounter = TAG_ELEMENT.length () + 2 + name.length ();
    }

    public void addEmptyElement () {
        stream.println (" " + TAG_EMPTY + ">");
    }
    
    public void addElementItem (String name) {
        if (!isFirstItem) {
            stream.print (" | ");
            charsCounter += 3;
        } else {
            isFirstItem = false;            
            stream.print (" (");
            charsCounter += 2;
        }
        charsCounter += name.length ();
        if (charsCounter > LINE_BOUND) {
            stream.println ();
            stream.print ("    ");
            charsCounter = 4;
        }
        stream.print (name);        
    }

    public void endElement () {
        stream.println (")* >");
    }     
    
    public void startAttlist (String text) {
        stream.print ("<" + TAG_ATTLIST + " ");
        stream.print (text);        
    }
    
    public void addAttlistItem (String text) {
        stream.println ();
        stream.print ("   " + text);        
    }
        
    public void endAttlist () {
        stream.println (">");
    }
    
    // ..........................................................................
    
    /** Generates DTD based on outermost package.
     *
     * @param outermost package
     */
    public void generate (OutputStream stream, RefPackage extent) {
        this.stream = new PrintStream (stream);
        this.extent = extent;
        init ();
        writeFixedContent ();
        writeNamespaces ();
        writePackageDTD (extent);
        
        try {
            stream.flush ();
            stream.close ();
        } catch (IOException e) {
            e.printStackTrace ();
        }
    }

    public void writePackageDTD (RefPackage pkg) {
        if (trackedPackages.contains (pkg)) {
            return;
        } else {
            trackedPackages.add (pkg);
        }
        Iterator iter = pkg.refAllPackages ().iterator ();
        while (iter.hasNext ()) {
            writePackageDTD ((RefPackage) iter.next ());
        }
        iter = pkg.refAllClasses ().iterator ();
        while (iter.hasNext ()) {
            writeClassDTD ((RefClass) iter.next ());
        }
        iter = pkg.refAllClasses ().iterator ();
        while (iter.hasNext ()) {
            writeStaticAttributesDTD ((RefClass) iter.next ());
        }
        iter = getFreeAssociations (pkg).iterator ();
        while (iter.hasNext ()) {
            writeAssociationDTD ((Association) iter.next ());
        }
        
        writePackageElementDef (pkg);
    }
    
    public void writeClassDTD (RefClass proxy) {
        Iterator iter;
        String text;
        StringBuffer buffer = new StringBuffer ();
        MofClass meta = (MofClass) proxy.refMetaObject ();
        String className = objectName (meta);
        List instAttrs, references;
        
        instAttrs = elementsCache.instanceAttributes (meta);
        references = elementsCache.references (meta);
        
        // attribute element definitions        
        iter = instAttrs.iterator ();
        while (iter.hasNext ()) {
            Attribute attr = (Attribute) iter.next ();
            if (attr.getContainer () == meta) {
                writeAttributeElemDef (attr);
            }
        } // while
        
        // reference element definitions
        iter = references.iterator ();
        while (iter.hasNext ()) {
            Reference ref = (Reference) iter.next ();
            if (ref.getContainer () != meta)
                continue;
            startElement (elementName (ref));            
            MofClass type = (MofClass) ref.getType ();
            Iterator it = elementsCache.getAllSubtypes ((MofClass) type).iterator ();
            while (it.hasNext ()) {
                addElementItem (objectName ((MofClass) it.next ()));
            } // while            
            endElement ();
        } // while
        
        // class element definition        
        startElement (className);
        Iterator it;
        for (it = instAttrs.iterator (); it.hasNext ();) {
            addElementItem (elementName ((Attribute) it.next ()));            
        }
        for (it = references.iterator (); it.hasNext ();) {
            addElementItem (elementName ((Reference) it.next ()));            
        }
        for (it = getComposites (meta).iterator (); it.hasNext ();) {
            addElementItem (objectName ((MofClass) it.next ()));
        }
        addElementItem (TAG_XMI_EXTENSION);
        endElement ();
                
        buffer.delete(0, buffer.length ());
        startAttlist (className);
        for (it = references.iterator (); it.hasNext ();) { //  ? [PENDING] non-composite reference, multiplicity 1 allowed ...
            buffer.append (((Reference) it.next ()).getName ());
            buffer.append (" " + TAG_IDREFS + " " + TAG_IMPLIED);
            addAttlistItem (buffer.toString ());
            buffer.delete(0, buffer.length ());
        }
        for (it = instAttrs.iterator (); it.hasNext ();) {
            Attribute attr = (Attribute) it.next ();
            buffer.append (attr.getName ());
            Classifier type = getType (attr);
            if (type instanceof EnumerationType) {
                int prefixLength = labelPrefix ((EnumerationType) type).length ();
                buffer.append (" (");
                for (Iterator it_2 = ((EnumerationType) type).getLabels ().iterator (); it_2.hasNext ();) {
                    buffer.append (((String) it_2.next ()).substring (prefixLength));
                    if (it_2.hasNext ())
                        buffer.append ("|");
                }
                buffer.append (") " + TAG_IMPLIED);
            } else if (type instanceof MofClass) {                
                buffer.append (" " + TAG_IDREFS + " " + TAG_IMPLIED);
            } else {
                buffer.append (" " + TAG_CDATA + " " + TAG_IMPLIED);
            }
            addAttlistItem (buffer.toString ());
            buffer.delete(0, buffer.length ());
        }
        addAttlistItem (TAG_XMI_FIXED_ATTRIBS);
        endAttlist ();
    }

    public void writeStaticAttributesDTD (RefClass proxy) {
        MofClass meta = (MofClass) proxy.refMetaObject ();
        for (Iterator iter = elementsCache.classAttributes (meta).iterator (); iter.hasNext ();) {
            Attribute attr = (Attribute) iter.next ();
            if (attr.getContainer () == meta)
                writeAttributeElemDef (attr);
        }
    }
    
    public void writeAssociationDTD (Association assoc) {
        String name;
        Set subtypes = new HashSet ();
        for (Iterator iter = assoc.getContents ().iterator (); iter.hasNext ();) {
            Object elem = iter.next ();
            if (elem instanceof AssociationEnd) {
                subtypes.addAll (elementsCache.getAllSubtypes ((MofClass) ((AssociationEnd) elem).getType ()));
            } // if
        } // for
        name = objectName (assoc);
        startElement (name);
        for (Iterator iter = subtypes.iterator (); iter.hasNext ();) {
            addElementItem (objectName ((MofClass) iter.next ()));
        }
        addElementItem (TAG_XMI_EXTENSION);
        endElement ();
        
        startAttlist (name);
        addAttlistItem (TAG_XMI_FIXED_ATTRIBS);
        endAttlist ();
        /*
        String name;
        String end_name [] = new String [2];
        int num = 0;
        for (Iterator iter = assoc.getContents ().iterator (); iter.hasNext ();) {
            Object elem = iter.next ();
            if (elem instanceof AssociationEnd) {
                AssociationEnd end = (AssociationEnd) elem;
                name = elementName (end);
                end_name [num++] = name;
                startElement (name);
                addEmptyElement ();
        
                startAttlist (name);
                addAttlistItem (TAG_XMI_FIXED_ATTRIBS);
                endAttlist ();
            } // if
        } // for
        name = objectName (assoc);
        startElement (name);
        addElementItem (end_name [0]);
        addElementItem (end_name [1]);
        addElementItem (TAG_XMI_EXTENSION);
        endElement ();
        
        startAttlist (name);
        addAttlistItem (TAG_XMI_FIXED_ATTRIBS);
        endAttlist ();
         */
    }
    
    public void writeAttributeElemDef (Attribute attr) {                    
        StringBuffer buffer = new StringBuffer ();
        Classifier type = getType (attr);
        boolean isEnum = type instanceof EnumerationType;
        startElement (elementName (attr));

        if (isEnum) { // AttribEnum
            addEmptyElement ();
        } else if (type instanceof MofClass) { // AttribMofClass
            Iterator it = elementsCache.getAllSubtypes ((MofClass) type).iterator ();
            addElementItem (objectName ((MofClass) it.next ()));
            while (it.hasNext ()) {
                MofClass clazz = (MofClass) it.next ();
                addElementItem (objectName (clazz));
            } // while
            endElement ();
        } else if (type instanceof StructureType) { // StructureType
            addElementItem ("XMI.field");
            endElement ();
        } else { // AttribData
            addElementItem (TAG_PCDATA);
            addElementItem (TAG_XMI_REFERENCE);
            endElement ();
        }
            
        if (isEnum) {
            int prefixLength = labelPrefix ((EnumerationType) type).length ();
            buffer = new StringBuffer ();
            startAttlist (elementName (attr));
            buffer.append (TAG_XMI_VALUE + " (");
            Iterator it = ((EnumerationType) type).getLabels ().iterator ();
            while (it.hasNext ()) {
                buffer.append (((String) it.next ()).substring (prefixLength));
                if (it.hasNext ())
                    buffer.append ("|");
            }
            buffer.append (") " + TAG_REQUIRED);
            addAttlistItem (buffer.toString ());
            endAttlist ();
        }        
    }
    
    /**
     * Writes fixed part of XMI DTD content.
     */
    public void writeFixedContent () {
        java.net.URL fixedDTD = getClass().getResource(FIXED_DTD_FILE);
        if (fixedDTD == null) {
            throw new DebugException("Resource not found: " + FIXED_DTD_FILE);
        }
        try {
            InputStream in = fixedDTD.openStream ();
            BufferedReader reader = new BufferedReader (new InputStreamReader(in));
            String line;
            // skip licence            
            do {
                line = reader.readLine ();
            } while (!line.equals (END_OF_LICENCE_MARKER));
            // copy fixed DTD elements
            line = reader.readLine ();
            while (line != null) {
                stream.println (line);
                line = reader.readLine();
            }
        } catch (IOException e) {
            Logger.getDefault().log("Unable to open " + FIXED_DTD_FILE + ": " + e.getMessage());
            throw new DebugException (e.getMessage ());
        }
    }

    public void writeNamespaces () {
        Set names = new HashSet ();
        if (namespaces.size () > 0) {
            startAttlist ("XMI");
            for (Iterator iter = namespaces.entrySet ().iterator (); iter.hasNext ();) {
                Object name = ((Map.Entry) iter.next ()).getValue ();
                if (!names.contains (name)) {
                    addAttlistItem ("xmlns:" + name + " " + TAG_CDATA + " " + TAG_IMPLIED);
                    names.add (name);
                }
            } // for
            endAttlist ();
        } // if
    }

    public void writePackageElementDef (RefPackage pkg) {
        MofPackage meta = (MofPackage) pkg.refMetaObject ();
        String packageName = packageName (meta);
        Set classes = new HashSet ();
        StringBuffer buffer = new StringBuffer ();
        for (Iterator iter = pkg.refAllClasses ().iterator (); iter.hasNext ();) {
            classes.addAll (elementsCache.getAllSubtypes ((MofClass) ((RefClass) iter.next ()).refMetaObject ()));
        }
        startElement (packageName);
        // owned classes
        for (Iterator iter = classes.iterator (); iter.hasNext ();) {
            addElementItem (objectName ((MofClass) iter.next ()));
        }
        // owned associations that are not accessible via any reference
        for (Iterator iter = getFreeAssociations (pkg).iterator (); iter.hasNext ();) {
            addElementItem (objectName ((Association) iter.next ()));
        }
        // nested packages (imported are excluded, is it correct ? [PENDING])
        for (Iterator iter = pkg.refAllPackages ().iterator (); iter.hasNext ();) {
            RefPackage refPkg = (RefPackage) iter.next ();
            MofPackage metaPkg = (MofPackage) refPkg.refMetaObject ();
            if (metaPkg.getContainer () == meta) {
                addElementItem (packageName (metaPkg));
            }
        }
        // XMI.extension
        addElementItem (TAG_XMI_EXTENSION);
        endElement ();
        
        // attributes
        startAttlist (packageName);
        addAttlistItem (TAG_XMI_FIXED_ATTRIBS);
        endAttlist ();
    }

    // helper methods ...........................................................

    /**
     * Finds and caches namespace declarations.
     */
    private void findNamespaces (RefPackage pkg) {
        String name;
        Iterator iter;

        if (trackedPackages.contains (pkg))
            return;
        else
            trackedPackages.add (pkg);

        MofPackage metaPackage = (MofPackage) pkg.refMetaObject ();
        name = WriterBase.getTagValue (metaPackage, XmiConstants.TAGID_XMI_NAMESPACE);        
        if (name != null) {
            namespaces.put (metaPackage, name);
        }

        iter =  pkg.refAllPackages ().iterator ();
        while (iter.hasNext ()) {
            findNamespaces ((RefPackage) iter.next ());
        }
    }

    public String elementName (ModelElement element) {
        ModelElement container = element.getContainer ();
        return objectName (container) + '.' + element.getName ();
    }

    public String objectName (ModelElement element) {
        String namespace = (String) namespaces.get (element.getContainer ());
        if (namespace != null) {
            return namespace + ":" + element.getName ();
        } else {
            return qualifiedName (element);
        }
    }    
    
    public String packageName (MofPackage pkg) {
        String namespace = (String) namespaces.get (pkg);
        if (namespace != null) {
            return namespace + ":" + pkg.getName ();
        } else {
            return qualifiedName (pkg);
        }
    }
    
    public String qualifiedName (ModelElement element) {
        Iterator iter = element.getQualifiedName ().iterator ();
        String name = (String) iter.next ();
        while (iter.hasNext ()) {
            name = name.concat (XmiConstants.DOT_SEPARATOR).concat ((String) iter.next ());
        }
        return name;
    }
    
    /**
     * Returns labels prefix given by "unprefix" tag attached to EnumerationType or
     * the empty String if no such tag is present.
     */
    public String labelPrefix (EnumerationType type) {        
        String prefix = WriterBase.getTagValue (type, XmiConstants.TAGID_XMI_ENUMERATION_UNPREFIX);
        if (prefix == null)
            prefix = "";
        return prefix;
    }
    
    /**
     * Returns type of the typed element. Aliases are substituted by proper types.
     */
    public Classifier getType (TypedElement elem) {
        Classifier type = elem.getType ();
        while (type instanceof AliasType)
            type = ((AliasType) type).getType ();
        return type;
    }
    
    public Set getComposites (MofClass meta) {
        return new HashSet ();
        /*
        Set set = new HashSet ();
        Iterator iter = elementsCache.instanceAttributes (meta).iterator ();
        while (iter.hasNext ()) {
            Attribute attr = (Attribute) iter.next ();
            Classifier type = attr.getType ();
            if (type instanceof MofClass)
                set.add (type);
        }
        iter = elementsCache.references (meta).iterator ();
        while (iter.hasNext ()) {
            Reference ref = (Reference) iter.next ();
            if (AggregationKindEnum.COMPOSITE.equals (ref.getReferencedEnd ().getAggregation ()))
                set.add (ref.getType ());
        }
        Set result = new HashSet ();
        iter = set.iterator ();
        while (iter.hasNext ()) {
            Set temp = elementsCache.getAllSubtypes ((MofClass) iter.next ());
            result.addAll(temp);
        }
        return result;
         */
    }
    
    /**
     * Returns associations in the package that are not accessible via any reference.
     */
    public Set getFreeAssociations (RefPackage pkg) {
        ModelPackage model = (ModelPackage) pkg.refMetaObject ().refImmediatePackage ();
        RefersTo refersTo = model.getRefersTo ();
        Set set = new HashSet ();
        for (Iterator iter = pkg.refAllAssociations ().iterator (); iter.hasNext ();) {
            Association assoc = (Association) ((RefAssociation) iter.next ()).refMetaObject ();
            boolean found = false;
            for (Iterator it = assoc.getContents ().iterator (); it.hasNext ();) {
                Object elem = it.next ();
                if (elem instanceof AssociationEnd) {
                    Collection col = refersTo.getReferent ((AssociationEnd) elem);
                    if ((col != null) && (col.size () > 0)) {
                        found = true;
                        break;
                    }
                }
            } // for
            if (!found) {
                set.add (assoc);
            }
        } // for
        return set;
    }
    
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.