fr.lip6.move.coloane.projects.its.io.ModelHandler.java Source code

Java tutorial

Introduction

Here is the source code for fr.lip6.move.coloane.projects.its.io.ModelHandler.java

Source

/**
 * Copyright (c) 2006-2010 MoVe - Laboratoire d'Informatique de Paris 6 (LIP6).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Jean-Baptiste VORON (LIP6) - Project Head / Initial contributor
 *   Clment DMOULINS (LIP6) - Project Manager
 *   Yann THIERRY-MIEG (LIP6)
 *
 * Official contacts:
 *   coloane@lip6.fr
 *   http://coloane.lip6.fr
 */
package fr.lip6.move.coloane.projects.its.io;

import fr.lip6.move.coloane.projects.its.CompositeTypeDeclaration;
import fr.lip6.move.coloane.projects.its.Concept;
import fr.lip6.move.coloane.projects.its.ITypeDeclaration;
import fr.lip6.move.coloane.projects.its.TypeDeclaration;
import fr.lip6.move.coloane.projects.its.TypeDeclarationFactory;
import fr.lip6.move.coloane.projects.its.TypeList;
import fr.lip6.move.coloane.projects.its.checks.CheckList;
import fr.lip6.move.coloane.projects.its.expression.IEvaluationContext;
import fr.lip6.move.coloane.projects.its.expression.IVariable;
import fr.lip6.move.coloane.projects.its.expression.Variable;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.commons.lang.StringEscapeUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Classe destinee a la lecture d'un fichier XML. La lecture du fichier permet la construction d'un modele
 * @author yann based on jbvoron
 *
 */
public class ModelHandler extends DefaultHandler {
    private final Logger logger = Logger.getLogger("fr.lip6.move.coloane.its"); //$NON-NLS-1$

    private Deque<Object> stack = new ArrayDeque<Object>();

    // Correspondance entre les id du document xml et celle des nouveaux objets.
    private Map<Integer, Object> ids = new HashMap<Integer, Object>();

    // object constructed
    private TypeList types;

    private String readString;

    private URI workFile;

    public ModelHandler(URI workFile) {
        this.workFile = workFile;
    }

    /** {@inheritDoc} */
    @Override
    public final void startElement(String uri, String localName, String baliseName, Attributes attributes)
            throws SAXException {
        // Balise MODEL
        if ("model".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("types".equals(baliseName)) { //$NON-NLS-1$
            // stack a new TypeList
            stack.push(new TypeList(workFile));
        } else if ("type".equals(baliseName)) { //$NON-NLS-1$
            startType(attributes);
        } else if ("concept".equals(baliseName)) { //$NON-NLS-1$
            handleConcept(attributes);
        } else if ("concepts".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("parameter".equals(baliseName)) { //$NON-NLS-1$
            handleParameter(attributes);
        } else if ("parameters".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("checks".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("check".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("typeid".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("formula".equals(baliseName)) { //$NON-NLS-1$
            // NOP
            handleFormula(attributes);
        } else if ("formulas".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else {
            logger.warning("Unknown XML tag in source file: " + baliseName); //$NON-NLS-1$
        }
    }

    /** {@inheritDoc} */
    @Override
    public final void endElement(String uri, String localName, String baliseName) throws SAXException {
        // Balise MODEL
        if ("model".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("types".equals(baliseName)) { //$NON-NLS-1$
            // assign the constructed TypeList
            this.types = (TypeList) stack.pop();
        } else if ("type".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("concept".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("concepts".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("parameter".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("parameters".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("checks".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("check".equals(baliseName)) { //$NON-NLS-1$
            // NOP
            CheckList cl = (CheckList) stack.pop();
            types.addCheckList(cl);
        } else if ("typeid".equals(baliseName)) { //$NON-NLS-1$
            stack.push(handleCheck(readString));
        } else if ("formula".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else if ("formulas".equals(baliseName)) { //$NON-NLS-1$
            // NOP
        } else {
            logger.warning("Unknown XML tag in source file: " + baliseName); //$NON-NLS-1$
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
        readString = new String(arg0, arg1, arg2);
    }

    /**
     * Parse a check description :type declaration field.
     * @param typeid the type name
     * @throws SAXException any parse error
     */
    private CheckList handleCheck(String typeid) throws SAXException {
        // Get effective with maximum safeguards      
        int idEffective;
        try {
            idEffective = Integer.parseInt(typeid); //$NON-NLS-1$
        } catch (NumberFormatException e) {
            throw new SAXException("Corrupted XML file, effective id " + typeid
                    + " should be an integer referring to a type declaration");
        }

        TypeDeclaration effective;
        try {
            effective = (TypeDeclaration) ids.get(idEffective);
        } catch (ClassCastException e) {
            throw new SAXException(
                    "Corrupted XML file, effective id " + idEffective + " should refer to a type declaration");
        }
        return new CheckList(effective);
    }

    private void handleFormula(Attributes attributes) {
        String name = attributes.getValue("name");
        String comment = attributes.getValue("description");
        String form = StringEscapeUtils.unescapeXml(attributes.getValue("formula"));
        CheckList cl = (CheckList) stack.peek();
        cl.addCTLFormula(name, form, comment);
    }

    /**
     * Parse a concept description
     * @param attributes the attributes of the concept in XML
     * @throws SAXException any parse error
     */
    private void handleConcept(Attributes attributes) throws SAXException {
        String name = attributes.getValue("name"); //$NON-NLS-1$
        int idEffective = Integer.parseInt(attributes.getValue("effective")); //$NON-NLS-1$
        int idParent = Integer.parseInt(attributes.getValue("parent")); //$NON-NLS-1$

        if (idEffective == -1) {
            // concept is not assigned
            return;
        }

        // Get parent with maximum safeguards
        CompositeTypeDeclaration parent;
        try {
            parent = (CompositeTypeDeclaration) ids.get(idParent);
        } catch (ClassCastException e) {
            throw new SAXException(
                    "Corrupted XML file, id " + idParent + " should refer to a composite type declaration");
        }
        if (parent == null) {
            throw new SAXException(
                    "Corrupted XML file, Dangling parent type id " + idParent + " in concept " + name);
        }
        // Get effective with maximum safeguards
        ITypeDeclaration effective;
        try {
            effective = (ITypeDeclaration) ids.get(idEffective);
        } catch (ClassCastException e) {
            throw new SAXException(
                    "Corrupted XML file, effective id " + idEffective + " should refer to a type declaration");
        }
        if (effective == null) {
            throw new SAXException(
                    "Corrupted XML file, Dangling Effective type id " + idEffective + " in concept " + name);
        }
        // get the concept
        Concept concept = parent.getConcept(name);
        if (concept == null) {
            logger.warning("Concept effective definition which should belong to CompositeType " + parent
                    + " does not exist in the actual model file. Ignoring Concept setting.");
        } else {
            concept.setEffective(effective);
        }
    }

    /**
     * Parse a parameter description
     * @param attributes the attributes of the concept in XML
     * @throws SAXException any parse error
     */
    private void handleParameter(Attributes attributes) throws SAXException {
        String name = attributes.getValue("name"); //$NON-NLS-1$
        int value = Integer.parseInt(attributes.getValue("value")); //$NON-NLS-1$
        int idParent = Integer.parseInt(attributes.getValue("parent")); //$NON-NLS-1$

        // Get parent with maximum safeguards
        ITypeDeclaration parent;
        try {
            parent = (ITypeDeclaration) ids.get(idParent);
        } catch (ClassCastException e) {
            throw new SAXException("Corrupted XML file, id " + idParent + " should refer to a type declaration");
        }
        if (parent == null) {
            throw new SAXException(
                    "Corrupted XML file, Dangling parent type id " + idParent + " in parameter " + name);
        }
        // get the evaluation context
        IEvaluationContext params = parent.getParameters();
        IVariable var = new Variable(name);
        if (!params.containsVariable(var)) {
            logger.warning("Concept effective definition which should belong to CompositeType " + parent
                    + " does not exist in the actual model file. Ignoring Concept setting.");
        } else {
            params.setVariableValue(var, value);
        }
    }

    /**
     * Analyze a type declaration
     * @param attributes Les attributs attache  la balise
     * @throws SAXException if the referenced model file is bad.
     */
    private void startType(Attributes attributes) throws SAXException {
        TypeList types = (TypeList) stack.peek();

        int id = Integer.parseInt(attributes.getValue("id")); //$NON-NLS-1$

        String name = attributes.getValue("name"); //$NON-NLS-1$
        String formalism = attributes.getValue("formalism"); //$NON-NLS-1$

        String workDir = new File(workFile).getParentFile().toURI().getPath();
        String filePath = workDir + "/" + attributes.getValue("path");

        URI file = new File(filePath).toURI();

        if (file == null || !new File(filePath).canRead()) {
            throw new SAXException("Could not open referenced file " + filePath, null);
        }
        ITypeDeclaration type;
        try {
            type = TypeDeclarationFactory.create(name, file, types);
        } catch (IOException e) {
            throw new SAXException("Could not open referenced file " + filePath, null);
        }
        if (!formalism.equals(type.getTypeType())) {
            String errmsg = "Model formalism type for file " + filePath + " does not match file contents.\n "
                    + "Expected type " + formalism + " read type " + type.getTypeType();
            logger.fine(errmsg);

            throw new SAXParseException(errmsg, null);
        }
        // store type in hash
        ids.put(id, type);
        types.addTypeDeclaration(type);
    }

    /**
     * @return the type list loaded from the XML file
     */
    public final TypeList getTypes() {
        return types;
    }
}