Package pspdash

Source Code of pspdash.TemplateAutoData

// Process Dashboard - Data Automation Tool for high-maturity processes
// Copyright (C) 2003 Software Process Dashboard Initiative
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// The author(s) may be contacted at:
// OO-ALC/TISHD
// Attn: PSP Dashboard Group
// 6137 Wardleigh Road
// Hill AFB, UT 84056-5843
//
// E-Mail POC:  processdash-devel@lists.sourceforge.net


package pspdash;

import pspdash.data.DataRepository;
import pspdash.data.ListData;

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

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/** Automatically defines data for a process, based on its XML template.
*/
public class TemplateAutoData extends AutoData {


    private transient Element template;
    private String templateStr = null;
    private String templateID, usesRollupID, definesRollupID;
    private String dataFile;
    private Map definitions = null;


    TemplateAutoData(Element template, String templateID, String usesRollupID,
                     String definesRollupID, String dataFile) {
        this.template = template;
        this.templateID = templateID;
        this.usesRollupID = usesRollupID;
        this.definesRollupID = definesRollupID;
        this.dataFile = dataFile;
    }

    /** Create the default data definitions for the template
     *  represented by this AutoData object.
     */
    public Map getDefinitions(DataRepository data) {
        if (definitions == null)
            buildDefaultData(data);

        return definitions;
    }

    private void buildDefaultData(DataRepository data) {
        //System.out.println("buildDefaultData for " + templateID);
        Map dataDefinitions = new HashMap();
        StringBuffer globalDataHeader = new StringBuffer(1024);
        globalDataHeader.append("#define TEMPLATE_ID ")
            .append(esc(templateID)).append("\n");
        if (XMLUtils.hasValue(usesRollupID))
            globalDataHeader.append("#define USES_ROLLUP_ID ")
                .append(esc(usesRollupID)).append("\n");
        if (XMLUtils.hasValue(definesRollupID))
            globalDataHeader.append("#define DEFINE_ROLLUP_ID ")
                .append(esc(definesRollupID)).append("\n");

        // Eventually, we will look at the template and dynamically
        // determine whether or not to #define the next two tokens,
        // but for now we'll just do it.
        globalDataHeader.append("#define PROCESS_HAS_SIZE\n")
            .append("#define PROCESS_HAS_DEFECTS\n");

        // Go get the data about the phases in this process.
        PhaseLister phases = new PhaseLister();
        phases.run(template);
        phases.commit();

        // Were any phases found in this template?
        if (phases.all.size() > 0) {
            globalDataHeader.append("#define PROCESS_HAS_PHASES\n");
            dataDefinitions.put(PHASE_LIST_ELEM, phases.all);

            // Were any failure phases defined?
            if (phases.failure.size() > 0) {
                globalDataHeader.append("#define PROCESS_HAS_FAILURE\n");
                dataDefinitions.put(FAIL_LIST_ELEM, phases.failure);
                String lastFailurePhase =
                    (String) phases.failure.get(phases.failure.size()-1);
                globalDataHeader.append("#define LAST_FAILURE_PHASE ")
                    .append(esc(lastFailurePhase)).append("\n");

                // Yield is only meaningful if failure phases have been
                // defined - otherwise, it would always be 100%.
                if (phases.yield.size() > 0) {
                    globalDataHeader.append("#define PROCESS_HAS_YIELD\n");
                    dataDefinitions.put(YIELD_LIST_ELEM, phases.yield);
                }
            }

            // Were any appraisal phases defined?
            if (phases.appraisal.size() > 0) {
                globalDataHeader.append("#define PROCESS_HAS_APPRAISAL\n");
                dataDefinitions.put(APPR_LIST_ELEM, phases.appraisal);
            }

            // Were any quality phases defined?
            if (phases.quality.size() > 0) {
                globalDataHeader.append("#define PROCESS_HAS_QUALITY\n");
                dataDefinitions.put(QUAL_LIST_ELEM, phases.quality);
            }

            // Were any development phases defined?
            if (phases.development.size() > 0)
                dataDefinitions.put(DEVEL_LIST_ELEM, phases.development);

            // Were any overhead phases defined?
            if (phases.overhead.size() > 0)
                dataDefinitions.put(OVERHEAD_LIST_ELEM, phases.overhead);
        }

        buildDefaultData(template, "", data, dataDefinitions,
                         globalDataHeader.length(), globalDataHeader);

        // Fill in data for the entire process.
        StringBuffer processData = globalDataHeader;
        defineIterMacro(processData, "FOR_EACH_PHASE", phases.all);
        defineIterMacro(processData, "FOR_EACH_APPR_PHASE", phases.appraisal);
        defineIterMacro(processData, "FOR_EACH_FAIL_PHASE", phases.failure);
        defineIterMacro(processData, "FOR_EACH_YIELD_PHASE", phases.yield);
        data.putDefineDeclarations(dataFile, processData.toString());

        processData.append("\n").append(PROCESS_DATA);
        parseDefinitions(data, processData.toString(), dataDefinitions);

        definitions = dataDefinitions;
    }

    private void buildDefaultData(Element node, String path,
                                  DataRepository data, Map definitions,
                                  int globalDataLength,
                                  StringBuffer nodeDefinitions)
    {
        if (!isProcessNode(node)) return;
        if (noAutoDataNode(node)) return;

        // Check for a local redefinition of the Size metric.
        int localDataLength = globalDataLength;
        String sizeMetric = node.getAttribute(SIZE_METRIC_ATTR);
        if (XMLUtils.hasValue(sizeMetric)) {
            String localSizeDefn = "#define Size " + esc(sizeMetric) + "\n";
            nodeDefinitions.append(localSizeDefn);
            localDataLength += localSizeDefn.length();
        }

        // Iterate over the children of this element.
        NodeList children = node.getChildNodes();
        int numChildren = children.getLength();
        ListData childList = newEmptyList();
        Node c; Element child;
        for (int i=0;  i<numChildren;  i++) {
            c = children.item(i);
            if (c instanceof Element && isProcessNode((Element) c) &&
                !noAutoDataNode((Element) c)) {
                child = (Element) c;
                String childName =
                    pathConcat(path, child.getAttribute(NAME_ATTR));
                childList.add(childName);
                buildDefaultData(child, childName, data, definitions,
                                 localDataLength, nodeDefinitions);
            }
        }
        childList.setImmutable();

        // truncate the nodeDefinitions StringBuffer so it only
        // contains the global data definitions plus the local size
        // definition (probably unnecessary, but a wise and safe thing
        // to do).
        nodeDefinitions.setLength(localDataLength);

        if (XMLUtils.hasValue(path))
            nodeDefinitions.append("#define ").append(PATH_MACRO)
                .append(" ").append(esc(path)).append("\n");
        if (node.hasAttribute(PSPProperties.IMAGINARY_NODE_ATTR))
            nodeDefinitions.append("#define IS_IMAGINARY_NODE\n");

        if (childList.size() > 0) {
            definitions.put(pathConcat(path, CHILD_LIST_ELEM), childList);
            nodeDefinitions.append(NODE_DATA);
        } else {
            // This is a phase.

            // #define various symbols based on the nature of this phase.
            String phaseType = node.getAttribute(PHASE_TYPE_ATTR);
            if (XMLUtils.hasValue(phaseType)) {
                phaseType = cleanupPhaseType(phaseType);
                nodeDefinitions.append("#define IS_")
                    .append(phaseType.toUpperCase()).append("_PHASE\n");
                if (appraisalPhaseTypes.contains(phaseType))
                    nodeDefinitions.append("#define IS_APPRAISAL_PHASE\n")
                        .append("#define IS_QUALITY_PHASE\n");
                else if (failurePhaseTypes.contains(phaseType))
                    nodeDefinitions.append("#define IS_FAILURE_PHASE\n")
                        .append("#define IS_QUALITY_PHASE\n");
                else if (overheadPhaseTypes.contains(phaseType))
                    nodeDefinitions.append("#define IS_OVERHEAD_PHASE\n");
                else if (developmentPhaseTypes.contains(phaseType))
                    nodeDefinitions.append("#define IS_DEVELOPMENT_PHASE\n");
            }

            nodeDefinitions.append(LEAF_DATA);
        }

        String finalData = nodeDefinitions.toString();
        if (!XMLUtils.hasValue(path))
            finalData = StringUtils.findAndReplace
                (finalData, PATH_MACRO + "/", "");
        /*
        System.out.println("For " + templateID+"->"+path + ", data is");
        System.out.println("------------------------------------------------");
        System.out.println(finalData);
        System.out.println("------------------------------------------------");
        */

        parseDefinitions(data, finalData, definitions);

        // truncate the nodeDefinitions StringBuffer so it only
        // contains the global data definitions.
        nodeDefinitions.setLength(globalDataLength);
    }

    private static void defineIterMacro(StringBuffer buf,
                                        String macroName,
                                        ListData list) {
        buf.append("\n#define ").append(macroName).append("(macro)");
        for (int i = 0;  i < list.size();  i++)
            buf.append(" macro(").append(list.get(i)).append(")");
        if (list.size() == 0)
            buf.append("/* */");
        buf.append("\n");
    }

    private static String cleanupPhaseType(String phaseType) {
        phaseType = StringUtils.findAndReplace(phaseType, " ", "");
        phaseType = StringUtils.findAndReplace(phaseType, "\t", "");
        return phaseType;
    }

    static PhaseTypeSet appraisalPhaseTypes = new PhaseTypeSet(new String[] {
        "appraisal", "reqinsp", "hldr", "hldrinsp",
        "dldr", "dldinsp", "cr", "codeinsp" });
    static PhaseTypeSet failurePhaseTypes = new PhaseTypeSet(new String[] {
        "failure", "comp", "ut", "it", "st", "at", "pl" });
    static PhaseTypeSet overheadPhaseTypes = new PhaseTypeSet(new String[] {
        "mgmt", "strat", "plan", "pm" });
    static PhaseTypeSet developmentPhaseTypes = new PhaseTypeSet(new String[] {
        "req", "stp", "itp", "td", "hld", "dld", "code", "doc" });

    public static boolean isAppraisalPhaseType(String phaseType) {
        return appraisalPhaseTypes.contains(phaseType); }
    public static boolean isFailurePhaseType(String phaseType) {
        return failurePhaseTypes.contains(phaseType); }
    public static boolean isDevelopmentPhaseType(String phaseType) {
        return developmentPhaseTypes.contains(phaseType); }
    public static boolean isOverheadPhaseType(String phaseType) {
        return overheadPhaseTypes.contains(phaseType); }

    private static final String LEAF_DATA    = getFileContents("leafData.txt");
    private static final String NODE_DATA    = getFileContents("nodeData.txt");
    private static final String PROCESS_DATA =
        getFileContents("processData.txt");

    public static boolean isProcessNode(Element e) {
        String tagName = e.getTagName();
        return ("node".equals(tagName) ||
                "phase".equals(tagName) ||
                "template".equals(tagName));
    }
    public static boolean noAutoDataNode(Element e) {
        return "none".equals(e.getAttribute(DATA_EXTENT_ATTR));
    }


    private static final String PATH_MACRO = "PATH";
    private static final String CHILD_LIST_ELEM = "Child_List";
    private static final String YIELD_LIST_ELEM = "Yield_Phase_List";
    private static final String FAIL_LIST_ELEM  = "Failure_Phase_List";
    private static final String APPR_LIST_ELEM  = "Appraisal_Phase_List";
    private static final String OVERHEAD_LIST_ELEM  = "Overhead_Phase_List";
    private static final String DEVEL_LIST_ELEM  = "Development_Phase_List";
    private static final String QUAL_LIST_ELEM  = "Quality_Phase_List";
    private static final String PHASE_LIST_ELEM = "Phase_List";
    static final String PHASE_TYPE_ATTR = "type";



    /** Analyze an XML template to find the various phases in the process.
     */
    private class PhaseLister extends XMLDepthFirstIterator {

        ListData all, yield, appraisal, failure, quality, overhead, development, nodes;
        String lastNameSeen = null;

        public PhaseLister() {
            all = newEmptyList();
            yield = newEmptyList();
            appraisal = newEmptyList();
            failure = newEmptyList();
            quality = newEmptyList();
            overhead = newEmptyList();
            development = newEmptyList();
        }

        public void commit() {
            all.setImmutable();
            yield.setImmutable();
            appraisal.setImmutable();
            failure.setImmutable();
            quality.setImmutable();
            overhead.setImmutable();
            development.setImmutable();
        }

        public int getOrdering() { return POST; }

        public String getPathAttributeName(Element e) {
            return (isProcessNode(e) ? NAME_ATTR : null);
        }

        public void run(Node n, Stack path) {
            if (n instanceof Element && noAutoDataNode((Element) n))
                return;
            else
                super.run(n, path);
        }

        public void caseElement(Element e, List path) {
            if (isProcessNode(e)) {
                String nodeName = concatPath(path, false);
                if (nodeName.length() > 0 &&
                    (lastNameSeen == null ||
                     lastNameSeen.startsWith(nodeName+"/") == false)) {

                    // add this phase to the complete list.
                    all.add(nodeName);

                    // Determine whether this phase should be added to the
                    // appraisal, failure, and/or yield lists.
                    String phaseType =
                        e.getAttribute(PHASE_TYPE_ATTR);
                    if (failurePhaseTypes.contains(phaseType)) {
                        failure.add(nodeName);
                        quality.add(nodeName);
                    } else if (appraisalPhaseTypes.contains(phaseType)) {
                        appraisal.add(nodeName);
                        quality.add(nodeName);
                    } else if (developmentPhaseTypes.contains(phaseType)) {
                        development.add(nodeName);
                    } else if (overheadPhaseTypes.contains(phaseType)) {
                        overhead.add(nodeName);
                    }

                    if (failure.size() == 0) yield.add(nodeName);
                }
                lastNameSeen = nodeName;
            }
        }


        public String concatPath(List path, boolean includeFirst) {
            if (path.isEmpty()) return "";

            Iterator i = path.iterator();
            if (!includeFirst) i.next();

            StringBuffer buffer = new StringBuffer();
            String component;
            while (i.hasNext()) {
                component = (String) i.next();
                if (component != null && component.length() > 0)
                    buffer.append("/").append(component);
            }
            String result = buffer.toString();
            if (result.length() > 0)
                return result.substring(1);
            else
                return "";
        }
    }

    private void writeObject(java.io.ObjectOutputStream out)
        throws IOException
    {
        templateStr = XMLUtils.getAsText(template);
        out.defaultWriteObject();
    }
    private void readObject(java.io.ObjectInputStream in)
        throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        try {
            template = XMLUtils.parse(templateStr).getDocumentElement();
            templateStr = null;
        } catch (Exception e) {}
    }
}

/** A case-insensitive set containing phase types.
*/
class PhaseTypeSet {

    public final String[] phaseTypes;
    public final Set phaseTypeSet;

    /** Construct a PhaseTypeSet from the list of types in the given array.
     *  The array must contain strings which are all lower case.
     */
    public PhaseTypeSet(String [] phaseTypes) {
        this.phaseTypes = phaseTypes;
        this.phaseTypeSet = Collections.unmodifiableSet
            (new HashSet(Arrays.asList(phaseTypes)));
    }

    /** Returns true if a given phaseType is contained in this PhaseTypeSet.
     */
    public boolean contains(String phaseType) {
        return phaseTypeSet.contains(phaseType.toLowerCase());
    }
}
TOP

Related Classes of pspdash.TemplateAutoData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');