All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cristalise.kernel.persistency.outcomebuilder.DimensionTableModel Maven / Gradle / Ivy

/**
 * This file is part of the CRISTAL-iSE XPath Outcome Initiator module.
 * Copyright (c) 2001-2016 The CRISTAL Consortium. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * http://www.fsf.org/licensing/licenses/lgpl.html
 */
package org.cristalise.kernel.persistency.outcomebuilder;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import org.exolab.castor.xml.schema.Annotated;
import org.exolab.castor.xml.schema.AttributeDecl;
import org.exolab.castor.xml.schema.ComplexType;
import org.exolab.castor.xml.schema.ContentModelGroup;
import org.exolab.castor.xml.schema.ElementDecl;
import org.exolab.castor.xml.schema.Group;
import org.exolab.castor.xml.schema.Order;
import org.exolab.castor.xml.schema.Particle;
import org.exolab.castor.xml.schema.SimpleType;
import org.exolab.castor.xml.schema.SimpleTypesFactory;
import org.exolab.castor.xml.schema.XMLType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DimensionTableModel {

    ElementDecl          model;
    ArrayList    columnHeadings = new ArrayList();
    ArrayList>  columnClasses  = new ArrayList>();
    ArrayList columnDecls    = new ArrayList();
    ArrayList    colHelp        = new ArrayList();

    HashMap columns = new HashMap();

    ArrayList  rows           = new ArrayList();
    ArrayList   elements       = new ArrayList();

    public DimensionTableModel(ElementDecl model) throws OutcomeBuilderException {
        XMLType modelContent = model.getType();
        this.model = model;
        // use text node for simple types
        if (modelContent.isSimpleType()) {
            SimpleType elementType = (SimpleType)modelContent;
            SimpleType baseType = elementType.getBuiltInBaseType();
            addColumn(model.getName(), baseType, baseType.getTypeCode());
        }
        else if (modelContent.isComplexType()) {  // if complex type, process child elements
            ComplexType elementType = (ComplexType)modelContent;

            // find out if a CDATA type is used for this complex type
            XMLType baseType = elementType.getBaseType();
            while (!(baseType instanceof SimpleType) && baseType != null) {
                baseType = baseType.getBaseType();
            }

            if (baseType != null) {
                int typeCode = ((SimpleType)baseType).getTypeCode();
                addColumn(model.getName(), baseType, typeCode);
            }

            // process attributes
            for (Enumeration e = elementType.getAttributeDecls(); e.hasMoreElements();) {
                AttributeDecl thisAttr = (AttributeDecl)e.nextElement();
                // HACK: if we don't resolve the reference, the type will be null
                if (thisAttr.isReference()) thisAttr = thisAttr.getReference();

                if (thisAttr.getSimpleType() == null)
                    throw new StructuralException("Attribute "+thisAttr.getName()+" in "+model.getName()+" has no type");

                addColumn(thisAttr.getName(), thisAttr, thisAttr.getSimpleType().getTypeCode());
            }

            // enumerate child elements
            enumerateElements(elementType);
        }
    }

    public synchronized void addColumn(String heading, Annotated decl, int typeCode) {
        log.debug("addColumn() - Column "+heading+" contains "+decl.getClass().getSimpleName());

        columnHeadings.add(heading);
        columnClasses.add(OutcomeStructure.getJavaClass(typeCode));
        columnDecls.add(decl);

        if (decl instanceof ElementDecl) columns.put(heading, new Field((ElementDecl)decl));

        // read help
        String helpText;
        if (decl instanceof SimpleType) helpText = OutcomeStructure.extractHelp(model);
        else                            helpText = OutcomeStructure.extractHelp(decl);

        if (helpText.length() == 0) helpText = "No help is available for this cell";

        colHelp.add(helpText);
    }


    public void enumerateElements(ContentModelGroup group) throws OutcomeBuilderException {
        for (Enumeration childElements = group.enumerate(); childElements.hasMoreElements(); ) {
            Particle thisParticle = (Particle)childElements.nextElement();
            String extraHeader = "";

            if (thisParticle instanceof Group) {
                Group thisGroup = (Group)thisParticle;
                Order order = thisGroup.getOrder();

                if (order == Order.sequence || order == Order.all)
                    enumerateElements(thisGroup);
                else // we only support sequences in data structures such as these
                    throw new StructuralException("Element "+thisGroup.getName()+". Expecting sequence or all. Got "+thisGroup.getOrder());
            }
            else if (thisParticle instanceof ElementDecl) {
                ElementDecl thisElement = (ElementDecl)thisParticle;
                int typeCode = SimpleTypesFactory.INVALID_TYPE;
                //make sure not too complex
                if (thisElement.getType() != null) {
                    if (thisElement.getType().isComplexType()) {
                        ComplexType elementType = (ComplexType)thisElement.getType();
                        if (elementType.getParticleCount() > 0 ||
                                thisElement.getMaxOccurs() > 1)
                            throw new StructuralException("Too deep for a table");
                        for (Enumeration attrs = elementType.getAttributeDecls(); attrs.hasMoreElements();) {
                            AttributeDecl thisAttr = (AttributeDecl)attrs.nextElement();
                            if (!thisAttr.isFixed())
                                throw new StructuralException("Non-fixed attributes of child elements not supported in tables.");
                            else
                                extraHeader=extraHeader+" ("+thisAttr.getName()+":"+(thisAttr.getFixedValue()!=null?thisAttr.getFixedValue():thisAttr.getDefaultValue())+")";
                        }
                        // find type
                        XMLType parentType = thisElement.getType();
                        while (!(parentType instanceof SimpleType) && parentType != null) {
                            parentType = parentType.getBaseType();
                            if (parentType != null) typeCode = ((SimpleType)parentType).getTypeCode();
                        }
                    }
                    else
                        typeCode = ((SimpleType)thisElement.getType()).getTypeCode();
                }

                //add to list
                addColumn(thisElement.getName()+extraHeader, thisElement, typeCode);
            }
            else throw new StructuralException("Particle "+thisParticle.getClass()+" not implemented");
        }
    }

    public void addInstance(Element myElement, int index) throws OutcomeBuilderException {
        if (index == -1) index = elements.size();
        Object[] newRow = new Object[columnHeadings.size()];
        for (int i=0; i getColumnClass(int columnIndex) {
        return columnClasses.get(columnIndex);
    }

    public String getColumnName(int columnIndex) {
        return columnHeadings.get(columnIndex);
    }

    public int getRowCount() {
        return rows.size();
    }

    public int getColumnCount() {
        return columnHeadings.size();
    }

    public void setValueAt(Object aValue, int rowIndex, String columnName) {
        log.debug("setValueAt() - columnName:%s", columnName);

        int idx = columnHeadings.lastIndexOf(columnName);

        if (idx == -1) throw new UnsupportedOperationException("ColumnName "+columnName+" not found in "+model.getName());

        setValueAt(aValue, rowIndex, idx);
    }

    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        Object[] thisRow = rows.get(rowIndex);
        thisRow[columnIndex]=aValue;
        Element rowElement = elements.get(rowIndex);
        // update node
        if (columnDecls.get(columnIndex) instanceof ElementDecl) { // sub element
            ElementDecl columnDecl = (ElementDecl)columnDecls.get(columnIndex);
            NodeList elements = rowElement.getElementsByTagName(columnDecl.getName());

            Element columnElement = null;

            //Create the optional element if the new value is not null
            if (elements.item(0) == null && aValue != null && !"null".equals(aValue.toString())) {
                log.debug("setValueAt() - Creating columnElement:%s", columnDecl.getName());

                columnElement = rowElement.getOwnerDocument().createElement(columnDecl.getName());
                setupDefaultElement(columnDecl, columnElement, columnClasses.get(columnIndex));
                rowElement.appendChild(columnElement);
            }
            else {
                columnElement = (Element) elements.item(0);
            }

            if (aValue != null && !"null".equals(aValue.toString())) {
                Text textNode = (Text)columnElement.getFirstChild();
                textNode.setData(aValue.toString());
            }
            else if (columnElement != null) {
                if (columnDecl.getMinOccurs() == 0) {
                    log.debug("setValueAt() - Removing columnElement:%s", columnDecl.getName());
                    rowElement.removeChild(columnElement);
                }
                else {
                    log.debug("setValueAt() - Setting columnElement:%s to default value", columnDecl.getName());
                    setupDefaultElement(columnDecl, columnElement, columnClasses.get(columnIndex));
                }
            }
        }
        else if (columnDecls.get(columnIndex) instanceof AttributeDecl) { //attribute
            AttributeDecl thisDecl = (AttributeDecl) columnDecls.get(columnIndex);

            rowElement.setAttribute(thisDecl.getName(), aValue.toString());
        }
        else { // first child node
            Text textNode = (Text)rowElement.getFirstChild();
            textNode.setData(aValue.toString());
        }
        rows.get(rowIndex)[columnIndex] = aValue;
    }

    public Element removeRow(int rowIndex) {
        Element elementToGo = elements.get(rowIndex);
        elements.remove(rowIndex);
        rows.remove(rowIndex);
        return elementToGo;
    }

    public Object setupDefaultElement(ElementDecl thisDecl, Element parent, Class type) {
        Object newValue;
        String defaultValue = thisDecl.getFixedValue();

        if (defaultValue == null) defaultValue = thisDecl.getDefaultValue();

        newValue = OutcomeStructure.getTypedValue(defaultValue, type);

        Text newNode = parent.getOwnerDocument().createTextNode(newValue.toString());
        parent.appendChild(newNode);
        // fixed attributes
        try {
            ComplexType content = (ComplexType)thisDecl.getType();
            for (Enumeration attrs = content.getAttributeDecls(); attrs.hasMoreElements();) {
                AttributeDecl thisAttr = (AttributeDecl)attrs.nextElement();
                parent.setAttribute(thisAttr.getName(), thisAttr.getFixedValue()!=null?thisAttr.getFixedValue():thisAttr.getDefaultValue());
            }
        } catch (ClassCastException ex) { } // only complex types have attributes
        return newValue;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        Object[] thisRow = rows.get(rowIndex);
        if (!(getColumnClass(columnIndex).equals(thisRow[columnIndex].getClass())))
            log.warn(thisRow[columnIndex]+" should be "+getColumnClass(columnIndex)+" is a "+thisRow[columnIndex].getClass().getName());

        return thisRow[columnIndex];
    }

    public String validateStructure() { // remove empty rows
        for (int j=0; j < rows.size(); j++) {
            Object[] elems = rows.get(j);
            boolean empty = true;
            for (int i = 0; i < elems.length && empty; i++)
                empty &= OutcomeStructure.isEmpty(elems[i]);
            if (empty)
                if (model.getMinOccurs() < rows.size())
                    removeRow(j);
                else
                    return "Too many empty rows in table "+model.getName();
        }
        return null;
    }

    public Element initNew(Document parent, int index) {
        log.info("initNew() - name:%s index:%d", model.getName(), index);

        if (index == -1) index = elements.size();
        Object[] newRow = new Object[columnHeadings.size()];
        Element myElement = parent.createElement(model.getName());

        for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy