dynamicrefactoring.domain.xml.reader.JDOMXMLRefactoringReaderImp.java Source code

Java tutorial

Introduction

Here is the source code for dynamicrefactoring.domain.xml.reader.JDOMXMLRefactoringReaderImp.java

Source

/*<Dynamic Refactoring Plugin For Eclipse 2.0 - Plugin that allows to perform refactorings 
on Java code within Eclipse, as well as to dynamically create and manage new refactorings>
    
Copyright (C) 2009  Laura Fuente De La Fuente
    
This file is part of Foobar
    
Foobar 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 3 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, see <http://www.gnu.org/licenses/>.*/

package dynamicrefactoring.domain.xml.reader;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import com.google.common.base.Throwables;

import dynamicrefactoring.RefactoringPlugin;
import dynamicrefactoring.domain.DynamicRefactoringDefinition;
import dynamicrefactoring.domain.DynamicRefactoringDefinition.Builder;
import dynamicrefactoring.domain.InputParameter;
import dynamicrefactoring.domain.RefactoringExample;
import dynamicrefactoring.domain.RefactoringMechanismInstance;
import dynamicrefactoring.domain.RefactoringMechanismType;
import dynamicrefactoring.domain.Scope;
import dynamicrefactoring.domain.metadata.interfaces.Category;

/**
 * Utiliza la implementacin basada en JDOM para leer los ficheros XML que
 * definen refactorizaciones.
 * 
 * @author <A HREF="mailto:lfd0002@alu.ubu.es">Laura Fuente de la Fuente</A>
 * @author <A HREF="mailto:alc0022@alu.ubu.es">?ngel Lpez Campo</A>
 * @author <A HREF="mailto:epf0006@alu.ubu.es">Eduardo Pea Fernndez</A>
 * @author <A HREF="mailto:sfd0009@alu.ubu.es">Sonia Fuente de la Fuente</A>
 * @author <A HREF="mailto:ehp0001@alu.ubu.es">Enrique Herrero Paredes</A>
 */
public class JDOMXMLRefactoringReaderImp implements XMLRefactoringReaderImp {

    /**
     * Lee cada uno de los componentes de la refactorizacin a partir de la
     * definicin contenida en el fichero.
     * 
     * @param in
     *            stream al fichero con la definicin de la refactorizacin.
     * @return refactorizacin leida desde el fichero
     * 
     * @throws XMLRefactoringReaderException
     *             si se produce un error al cargar la refactorizacin desde el
     *             fichero XML.
     */
    private DynamicRefactoringDefinition readFile(InputStream in) throws XMLRefactoringReaderException {

        final Element root;
        try {
            SAXBuilder builder = new SAXBuilder(true);
            builder.setIgnoringElementContentWhitespace(true);
            // El atributo SYSTEM del DOCTYPE de la definicin XML de la
            // refactorizacin es solo la parte relativa de la ruta del fichero
            // DTD. Se le antepone la ruta del directorio del plugin que
            // contiene los ficheros de refactorizaciones dinmicas.
            Document doc = builder.build(in, RefactoringPlugin.getNonEditableDynamicRefactoringsDir());
            root = doc.getRootElement();
            in.close();
        } catch (JDOMException jdomexception) {
            throw new XMLRefactoringReaderException(jdomexception);
        } catch (IOException ioexception) {
            throw new XMLRefactoringReaderException(ioexception);
        }
        Builder builder = readInformationRefactoring(root);
        builder = readInputsRefactoring(root, builder);
        builder = readMechanismRefactoring(root, builder);
        builder = readExamplesRefactoring(root, builder);
        return builder.build();
    }

    /**
     * Lee el nombre, la descripcin y la motivacin de la refactorizacin a
     * partir de la definicin contenida en el fichero.
     * 
     * @param root
     *            el elemento raz del rbol XML que define la refactorizacin.
     * @return constructor de la refactorizacin
     */
    private DynamicRefactoringDefinition.Builder readInformationRefactoring(Element root) {

        // Se obtiene el nombre de la refactorizacin.
        final DynamicRefactoringDefinition.Builder builder = new DynamicRefactoringDefinition.Builder(
                root.getAttributeValue(NAME_ATTRIBUTE));

        Element information = root.getChild(INFORMATION_ELEMENT);

        // Se obtiene la descripcion de la refactorizacin.
        builder.description(information.getChildTextTrim(DESCRIPTION_ELEMENT));

        // Se obtiene la imagen que describe la refactorizacin.
        Element imageElement = information.getChild(IMAGE_ELEMENT);

        if (imageElement != null)
            builder.image(imageElement.getAttributeValue(SRC_IMAGE_ATTRIBUTE));

        // Se obtiene la categorizacion de la refactorizacin.
        Element categoryElement = information.getChild(CATEGORIZATION_ELEMENT);

        builder.categories(readCategoriesElements(categoryElement.getChildren(CLASSIFICATION_ELEMENT)));

        // Se obtienen las palabras claves que describe la refactorizacin.
        Element keywordElement = information.getChild(KEYWORDS_ELEMENT);

        if (keywordElement != null) {
            builder.keywords(readKeywordElements(keywordElement.getChildren(KEYWORD_ELEMENT)));
        }

        // Se obtiene la motivacion de la refactorizacin.
        builder.motivation(information.getChildTextTrim(MOTIVATION_ELEMENT));
        return builder;
    }

    /**
     * Obtiene una lista de las palabras claves definidas en el fichero xml para
     * la refactorizacin.
     * 
     * @param children
     *            lista de elementos "keyword" en el fichero xml
     * @return conjunto de palabras clave
     */
    private Set<String> readKeywordElements(List<Element> children) {
        Set<String> keywords = new HashSet<String>();
        for (Element keywordElement : children) {
            keywords.add(keywordElement.getTextTrim());
        }
        return keywords;
    }

    /**
     * Crea la lista de categorias a las que la refactorizacin pertenece.
     * 
     * @param children
     *            lista de elementos de tipo category
     * @return conjunto de categorias a las que la refactorizacin pertenece
     */
    private Set<Category> readCategoriesElements(List<Element> children) {
        Set<Category> categorias = new HashSet<Category>();
        for (Element classification : children) {
            String classificationName = classification.getAttributeValue(CLASSIFICATION_NAME_ATTRIBUTE);
            List<Element> categoryList = classification.getChildren(CATEGORY_ELEMENT);
            for (Element category : categoryList) {
                categorias.add(new Category(classificationName, category.getTextTrim()));
            }
        }

        return categorias;
    }

    /**
     * Lee la lista de entradas que debe proporcionar el usuario a la
     * refactorizacin, a partir de la definicin contenida en el fichero.
     * 
     * @param root
     *            el elemento raz del rbol XML que define la refactorizacin.
     * @param builder
     *            constructor actual de la refactorizacin
     * @return constructor modificacin
     */
    @SuppressWarnings({ "unchecked" }) //$NON-NLS-1$
    private Builder readInputsRefactoring(Element root, Builder builder) {

        Element inputsElement = root.getChild(INPUTS_ELEMENT);

        // Se obtienen las entradas de la refactorizacin.
        List<Element> in = inputsElement.getChildren(INPUT_ELEMENT);
        return builder.inputs(readInputsElements(in));
    }

    /**
     * Obtiene el tipo, el nombre, el origen, el mtodo y el carcter de entrada
     * principal o no de cada uno de los parmetros de una lista de entradas de
     * tipo <i>input</i>.
     * 
     * @param in
     *            la lista de entradas de tipo <i>input</i>.
     * 
     * @return un <code>ArrayList</code> de cadenas con el tipo de la entrada,
     *         su nombre, la clase de origen del parmetro, el mtodo mediante
     *         el que se puede obtener y si se trata de la entrada principal de
     *         la refactorizacin, en ese orden.
     */
    private ArrayList<InputParameter> readInputsElements(List<Element> in) {

        ArrayList<InputParameter> inputs = new ArrayList<InputParameter>();

        for (Element input : in) {
            inputs.add(new InputParameter.Builder(input.getAttributeValue(TYPE_INPUT_ATTRIBUTE))
                    .name(input.getAttributeValue(NAME_INPUT_ATTRIBUTE))
                    .from(input.getAttributeValue(FROM_INPUT_ATTRIBUTE))
                    .method(input.getAttributeValue(METHOD_INPUT_ATTRIBUTE))
                    .main(Boolean.valueOf(input.getAttributeValue(ROOT_INPUT_ATTRIBUTE))).build());
        }
        return inputs;
    }

    /**
     * Lee las precondiciones, acciones y postcondiciones de la refactorizacin
     * a partir de la definicin contenida en el fichero.
     * 
     * @param root
     *            elemento xml raz del fichero
     * @param builder
     *            constructor de la refactorizacin
     * 
     * @return constructor de la refactorizacin modificado con los mecanismos
     *         asignados
     */
    @SuppressWarnings({ "unchecked" }) //$NON-NLS-1$
    private Builder readMechanismRefactoring(Element root, Builder builder) {

        Element mechanism = root.getChild(MECHANISM_ELEMENT);

        // Se obtienen las precondiciones de la refactorizacin.
        Element preconditionsElement = mechanism.getChild(PRECONDITIONS_ELEMENT);
        List<Element> pre = preconditionsElement.getChildren(PRECONDITION_ELEMENT);

        builder.preconditions(
                readMechanismElementsAsRefactoringMechanismInstance(pre, RefactoringMechanismType.PRECONDITION));

        // Se obtienen las acciones de la refactorizacin.
        Element actionsElement = mechanism.getChild(ACTIONS_ELEMENT);
        List<Element> ac = actionsElement.getChildren(ACTION_ELEMENT);
        builder.actions(readMechanismElementsAsRefactoringMechanismInstance(ac, RefactoringMechanismType.ACTION));

        // Se obtienen las postcondiciones de la refactorizacin.
        Element postconditionsElement = mechanism.getChild(POSTCONDITIONS_ELEMENT);
        List<Element> post = postconditionsElement.getChildren(POSTCONDITION_ELEMENT);

        builder.postconditions(
                readMechanismElementsAsRefactoringMechanismInstance(post, RefactoringMechanismType.POSTCONDITION));

        return builder;
    }

    /**
     * Lee un tipo de mecanismos de la refactorizacin del fichero XML.
     * 
     * @param elements
     *            conjunto de elementos xml
     * @param type
     *            tipo de mecanismo a leer
     * @return conjunto de mecanismos leido de los elementos xml
     */
    private List<RefactoringMechanismInstance> readMechanismElementsAsRefactoringMechanismInstance(
            List<Element> elements, RefactoringMechanismType type) {

        ArrayList<RefactoringMechanismInstance> elementNames = new ArrayList<RefactoringMechanismInstance>();

        for (Element element : elements) {
            String elementName = element.getAttributeValue(NAME_ATTRIBUTE);
            elementNames.add(new RefactoringMechanismInstance(
                    dynamicrefactoring.util.PluginStringUtils.getClassName(elementName),
                    getParametersOfMechanism(element.getChildren(PARAM_ELEMENT)), type));
        }
        return elementNames;
    }

    /**
     * Lee la lista de parametros ambiguos asociados a un elemento, que puede
     * ser una precondicion, una accion o una postcondicion.
     * 
     * @param params
     *            elemento xml con la lista de parametros del mecanismo.
     * @return lista de los nombres de los parametros del mecanismo
     */
    private List<String> getParametersOfMechanism(List<Element> params) {

        List<String> parametersList = new ArrayList<String>();

        for (Element param : params) {
            parametersList.add(param.getAttributeValue(NAME_ATTRIBUTE));
        }
        return parametersList;
    }

    /**
     * Lee los ejemplos de la refactorizacin a partir de la definicin
     * contenida en el fichero y modifica el constructor de la refactorizacin
     * actual.
     * 
     * @param root
     *            el elemento raz del rbol XML que define la refactorizacin.
     * @param builder
     *            constructor actual
     * @return constructor modificado
     */
    @SuppressWarnings({ "unchecked" }) //$NON-NLS-1$
    private Builder readExamplesRefactoring(Element root, Builder builder) {

        // Se obtienen los ejemplos de la refactorizacin.
        Element examplesElement = root.getChild(EXAMPLES_ELEMENT);
        if (examplesElement != null) {
            List<Element> ex = examplesElement.getChildren(EXAMPLE_ELEMENT);
            builder.examples(readExamplesElements(ex));
        }
        return builder;
    }

    /**
     * Lee los atributos de los ejemplos de una lista de ejemplos a partir de la
     * definicin contenida en el fichero.
     * 
     * @param examples
     *            lista de ejemplos.
     * 
     * @return lista de arrays de cadenas que contienen para cada ejemplo sus
     *         atributos.
     */
    private List<RefactoringExample> readExamplesElements(List<Element> examples) {

        ArrayList<RefactoringExample> completed = new ArrayList<RefactoringExample>();

        for (Element example : examples) {
            completed.add(new RefactoringExample(example.getAttributeValue(BEFORE_EXAMPLE_ATTRIBUTE),
                    example.getAttributeValue(AFTER_EXAMPLE_ATTRIBUTE)));
        }
        return completed;
    }

    /**
     * Devuelve la definicin de la refactorizacin.
     * 
     * @return la definicin de la refactorizacin.
     */
    @Override
    public DynamicRefactoringDefinition getDynamicRefactoringDefinition(File file) {
        try {
            return readFile(FileUtils.openInputStream(file));
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
    }

    /**
     * Devuelve la definicin de la refactorizacin a partir de un stream de
     * entrada.
     * 
     * @param in
     *            stream de entrada
     * 
     * @return la definicin de la refactorizacin.
     */
    public DynamicRefactoringDefinition getDynamicRefactoringDefinition(InputStream in) {
        try {
            return readFile(in);
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
    }

    /**
     * Obtiene del fichero temporal que guarda las refactorizaciones
     * disponibles, aquellas que son ejecutables con el parmetro de entrada del
     * tipo sealado por el parmetro scope.
     * 
     * @param scopeClass
     *            tipo de la entrada principal de la refactorizacin.
     * @param path_file
     *            ruta del fichero xml en donde estan descritas las
     *            refactorizaciones disponibles.
     * @return <code>HashMap</code> cuyas claves son el nombre de las
     *         refactorizaciones y los valores la ruta del fichero que contiene
     *         la definicin de la refactorizacin en caso de ser dinmica o la
     *         cadena vacia en caso de ser esttica.
     * @throws XMLRefactoringReaderException
     *             lanzado en caso de que no se pueda leer el fichero xml.
     */
    public static Map<String, String> readAvailableRefactorings(Scope scopeClass, String path_file)
            throws XMLRefactoringReaderException {
        try {
            SAXBuilder builder = new SAXBuilder(true);
            builder.setIgnoringElementContentWhitespace(true);
            Document doc = builder.build(new File(path_file).toURI().toString());
            Element rootElement = doc.getRootElement();
            return readRefactoringData(rootElement, scopeClass);
        } catch (JDOMException jdomexception) {
            throw new XMLRefactoringReaderException(jdomexception);
        } catch (IOException ioexception) {
            throw new XMLRefactoringReaderException(ioexception);
        }

    }

    /**
     * Devuelve la informacion (nombre, ruta) del conjunto de refactorizaciones
     * cuyo ambito es el pasado.
     * 
     * @param root
     *            elemento raz del fichero xml
     * 
     * @param scope
     *            ambito que filtra las refactorizaciones a obtener
     * @return mapa cuyas claves son los nombres y los valores son las rutas de
     *         los ficheros con las definiciones de las refactorizaciones
     */
    private static Map<String, String> readRefactoringData(Element root, Scope scope) {
        HashMap<String, String> refactorings = new HashMap<String, String>();
        Element classdef = root.getChild(scope.getXmlTag());
        for (int i = 0; i < classdef.getChildren().size(); i++) {
            Element refactor = (Element) classdef.getChildren().get(i);
            String name = refactor.getAttribute("name").getValue();
            String path = refactor.getAttribute("path").getValue();
            refactorings.put(name, path);
        }
        return refactorings;
    }

}