ch.epfl.codimsd.qep.QEPFactory.java Source code

Java tutorial

Introduction

Here is the source code for ch.epfl.codimsd.qep.QEPFactory.java

Source

/*
* CoDIMS version 1.0 
* Copyright (C) 2006 Othman Tajmouati
*
* 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 2.1 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; without 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
package ch.epfl.codimsd.qep;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.dom4j.Document;

import ch.epfl.codimsd.connection.CatalogManager;
import ch.epfl.codimsd.exceptions.dataSource.CatalogException;
import ch.epfl.codimsd.exceptions.initialization.QEPInitializationException;
import ch.epfl.codimsd.exceptions.initialization.RequestTypeNotFoundException;
import ch.epfl.codimsd.qeef.BlackBoard;
import ch.epfl.codimsd.qeef.DataSourceManager;
import ch.epfl.codimsd.qeef.SystemConfiguration;
import ch.epfl.codimsd.qeef.util.Constants;

/**
 * The QEPFactory is responsible for building QEP objects. It transforms what it reads from
 * formated QEP to hashtable of opNode structures.
 * 
 * @author Othman Tajmouati.
 */
public class QEPFactory {

    /**
     * Indicates if its the first time we call the factory.
     */
    private static boolean fisrtCall = false;

    /**
     * Log4j logger.
     */
    //@SuppressWarnings("unused")
    private static Logger logger = Logger.getLogger(QEPFactory.class.getName());

    /**
     * Retrieve the requested QEP path, according to its templateID and to the requestType.
     * 
     * @param requestType type of the request (@see ch.epfl.codims.qeef.util.Constants).
     * @param templateID identifier of the template (see Catalog)
     * @return the path of the query execution plan.
     * @throws RequestTypeNotFoundException
     * @throws CatalogException
     */
    public static String getQEP(int requestType, int templateID)
            throws RequestTypeNotFoundException, CatalogException {

        String qepInitialFile = null;

        // Get the CatalogManager and construct the query
        CatalogManager catalogManager = CatalogManager.getCatalogManager();
        String query = "SELECT PlanTemplate.path FROM PlanTemplate, RequestTypeTemplate WHERE "
                + "RequestTypeTemplate.idRequest = " + requestType + " AND "
                + "RequestTypeTemplate.idTemplate =  PlanTemplate.idTemplate AND " + "PlanTemplate.templateType = "
                + templateID;

        try {
            // get the qep path.
            ResultSet rset = catalogManager.executeQueryString(query);
            rset.next();
            qepInitialFile = SystemConfiguration.getSystemConfigInfo(Constants.HOME) + rset.getString(1);

        } catch (SQLException ex) {
            throw new CatalogException("SQLException while reading template from catalog : " + ex.getMessage());
        } catch (CatalogException ex) {
            throw new CatalogException("CatalogException while reading template from catalog : " + ex.getMessage());
        }
        return qepInitialFile;
    }

    /**
     * Reads a qep file in xml or string format, and build the hashtable of opNode structures
     * representing the operators.
     * 
     * If this method is called remotly, the parameter "type" should be set to Constants.qepAccessTypeRemote;
     * in order to read from a string file.
     * 
     * @param qepFile path to QEP file.
     * @param type type of access (remote mode or centralized mode).
     * @param qep this qep. It is send in order to be filled with corresponding hashtable.
     * @return hashtable containing opNode structures.
     * @throws QEPInitializationException
     */
    public static Hashtable<String, OpNode> loadQEP(String qepFile, String type, QEP qep)
            throws QEPInitializationException {

        // Initializations.
        Hashtable<String, OpNode> operatorList = null;
        Document document = null;

        try {
            // Call Sax reader in order to parse the xml document.
            SAXReader reader = new SAXReader();
            document = reader.read(qepFile);
            qep.setDocument(document);

            // Build the hashtable of opNodes.
            operatorList = buildOpNodeTable(document);

        } catch (DocumentException ex) {
            ex.printStackTrace();
            throw new QEPInitializationException(
                    "DocumentException error while loadind the XML QEP : " + ex.getMessage());
        }

        return operatorList;
    }

    /**
     * Retrieve the IRI from which the operator of type "Scan" reads from. This method is called
     * in order to compute the initial number of tuples in the DiscoveryOptimizer.
     * 
     * @param qep the query execution plan.
     * @return IRI to read from.
     */
    public static String getScanSource(QEP qep) {

        Hashtable opNodeHashtable = qep.getOperatorList();
        String IRI = "";

        for (int i = 1; i <= qep.getOperatorList().size(); i++) {

            OpNode opNode = (OpNode) opNodeHashtable.get(i + "");
            if (opNode.getType().equalsIgnoreCase("Scan")) {
                IRI = opNode.getParams()[0];
            }
        }

        return IRI;
    }

    public static void logFile(String fileName, String fileContent) {

        try {

            String qepDir = SystemConfiguration.getSystemConfigInfo(Constants.HOME) + File.separator + "logs"
                    + File.separator + "qeps";

            if (fisrtCall == false) {

                File qep = new File(qepDir);
                deleteDir(qep);
                boolean success = (new File(qepDir)).mkdir();

                if (!success)
                    //logger.debug("Cannot create qeps directory (containing generated qeps).");

                    fisrtCall = true;
            }

            String filePath = qepDir + File.separator + fileName;
            BufferedWriter out = new BufferedWriter(new FileWriter(filePath));
            out.write(fileContent);
            out.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Delete directories and subdirectories.
     * 
     * @param dir - the file to delete
     * @return true if the database is deleted, false otherwise
     */
    private static boolean deleteDir(File dir) {

        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }

        return dir.delete();
    }

    /**
     * Build a hashtable containing operator opNode structures, according to what is defined
     * in the query execution plan.
     * 
     * @param document dom4j document of the QEP.
     * @return the opnode hashtable.
     * 
     * @throws QEPInitializationException
     */
    private static Hashtable<String, OpNode> buildOpNodeTable(Document document) throws QEPInitializationException {

        Hashtable<String, OpNode> operatorList = new Hashtable<String, OpNode>();

        /*List listMod = document.selectNodes( "//qep:Module" );
        Element modElement = (Element)listMod;
        String[] stringType = modElement.attributeValue("type").split(",");
        int numberOfIterations = Integer.parseInt(modElement.attributeValue("numberOfIterations"));
        */
        List list = document.selectNodes("//op:Operator");
        Iterator itt = list.iterator();

        while (itt.hasNext()) {

            Element opElement = (Element) itt.next();

            // Get operator ID from xml QEP
            int opID = Integer.parseInt(opElement.attributeValue("id"));

            // Build producers from xml QEP
            String[] stringProducers = opElement.attributeValue("prod").split(",");
            int[] producers = new int[stringProducers.length];

            for (int i = 0; i < stringProducers.length; i++)
                producers[i] = Integer.parseInt(stringProducers[i]);

            // Get operator type
            String type = opElement.attributeValue("type");

            // Get parallelizable information
            String parallelAtt = opElement.attributeValue("parallelizable");
            boolean parallelizable = false;
            if (parallelAtt != null) {
                if (parallelAtt.equalsIgnoreCase("true"))
                    parallelizable = true;
            }

            // Get operator name from xml QEP
            Iterator opItt = opElement.elementIterator();
            Node xmlOpNode = (Node) opItt.next();
            String opName = xmlOpNode.getText();

            // Build operator parameters
            int i = 0;
            String paramString = "";
            String[] params = null;

            if (opItt.hasNext()) {

                Element parameterList = (Element) opItt.next();
                Iterator paramItt = parameterList.elementIterator();

                while (paramItt.hasNext()) {

                    Node parameter = (Node) paramItt.next();
                    paramString = paramString + parameter.getText() + ";";
                    i++;
                }

                params = new String[i];
                params = paramString.split(";");
            }

            // Build operator timeStamp
            long idTimeStamp = System.currentTimeMillis();

            // Build OpNode object for this operator
            OpNode opNode = new OpNode(opID, opName, producers, params, idTimeStamp + "", type, parallelizable);

            // Build DataSources if necessary
            if (opNode.getType() != null) {

                if (opNode.getType().equalsIgnoreCase("Scan")) {

                    // Write the number of tuples in the BlackBoard as specified in the QEP
                    // This operation is not done in remote nodes as G2N has already been called
                    String numberOfTuples = opElement.attributeValue(Constants.QEP_SCAN_NUMBER_TUPLES);

                    // In remote QEP this parameter is null, so we dont write again the field numberOfTuples
                    // used in the DiscoveryOptimizer when it calls G2N
                    if (numberOfTuples != null) {

                        if (!numberOfTuples.equalsIgnoreCase("?")) {

                            BlackBoard bl = BlackBoard.getBlackBoard();
                            bl.put(Constants.QEP_SCAN_NUMBER_TUPLES, numberOfTuples);
                        }
                    }

                    try {
                        DataSourceManager dsManager = DataSourceManager.getDataSourceManager();
                        dsManager.createDataSources(opNode);

                    } catch (Exception ex) {
                        throw new QEPInitializationException(
                                "Error creating the " + "datasource : " + ex.getMessage());
                    }
                }
            }

            // Put OpNode in the QEP
            operatorList.put(opID + "", opNode);
        }

        return operatorList;
    }

    /**
     * Add an operator template to the QEP Document.
     * 
     * @param document dom4j document.
     * @param opNode opNode structure of the operator to build.
     * @param opID identifier of the operator.
     */
    private static void createOperator(Document document, OpNode opNode, int opID) {

        Element root = document.getRootElement();
        Iterator ittRoot = root.elementIterator();
        Element qepElement = (Element) ittRoot.next();

        // create new operator xml template (attributes, name)
        Element newOp = qepElement.addElement("op:Operator").addAttribute("id", opID + "").addAttribute("prod",
                buildProducers(opNode));

        if (opNode.getType() != null)
            newOp.addAttribute("type", opNode.getType());

        Element newNameOp = newOp.addElement("Name");
        newNameOp.addText(opNode.getOpName());

        // create operator xml parameters
        if (opNode.getParams() != null) {
            if (opNode.getParams().length != 0) {
                Element newParameterList = newOp.addElement("ParameterList");
                for (int i = 0; i < opNode.getParams().length; i++) {
                    Element newParam = newParameterList.addElement("Param");
                    newParam.addText(opNode.getParams()[i]);
                }
            }
        }
    }

    /**
     * Add producers to the operator in its "producer" attribute (see xml QEP).
     * 
     * @param opNode opNode structure.
     * @return the string written to the QEP.
     */
    private static String buildProducers(OpNode opNode) {

        // Get producers from the opNode structure.
        int[] producerIDs = opNode.getProducerIDs();
        String stringProducers = "";

        for (int i = 0; i < producerIDs.length; i++) {
            stringProducers += producerIDs[i] + ",";
        }

        stringProducers = stringProducers.substring(0, stringProducers.length() - 1);

        return stringProducers;
    }

    /**
     * Creates the xml string corresponding to a QEP. This string wiil be sent
     * to remote node in order to create the remote operators.
     * 
     * @param qep the query execution plan.
     * @param type type of the Document.
     * @return the xml string.
     */
    public static String generateString(QEP qep, String type) {

        Document document = createTemplate(type);

        for (int i = 1; i <= qep.getOperatorList().size(); i++) {
            OpNode opNode = (OpNode) qep.getOperatorList().get("" + i);
            createOperator(document, opNode, i);
        }

        return document.asXML();
    }

    /**
     * Creates the xml structure where we embed the operators.
     * 
     * @param type type of the xml template.
     * @return dom4j Document.
     */
    private static Document createTemplate(String type) {

        // Create empty dom4j document.
        Document document = DocumentHelper.createDocument();

        // Add "QEPTemlate", "op", "qep",  tags.
        Element root = document.addElement("QEPTemplate", "http://giga03.lncc.br/DIP/WP4/CoDIMS-D");
        root.addNamespace("op", "http://giga03.lncc.br/DIP/WP4/CoDIMS-D/Operator");
        root.addNamespace("qep", "http://giga03.lncc.br/DIP/WP4/CoDIMS-D/QEP");
        root.addElement("qep:QEP").addAttribute("type", type);

        return document;
    }
}