it.eng.qbe.datasource.configuration.dao.fileimpl.CalculatedFieldsDAOFileImpl.java Source code

Java tutorial

Introduction

Here is the source code for it.eng.qbe.datasource.configuration.dao.fileimpl.CalculatedFieldsDAOFileImpl.java

Source

/* SpagoBI, the Open Source Business Intelligence suite
    
 * Copyright (C) 2012 Engineering Ingegneria Informatica S.p.A. - SpagoBI Competency Center
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0, without the "Incompatible With Secondary Licenses" notice. 
 * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package it.eng.qbe.datasource.configuration.dao.fileimpl;

import it.eng.qbe.datasource.configuration.dao.DAOException;
import it.eng.qbe.datasource.configuration.dao.ICalculatedFieldsDAO;
import it.eng.qbe.model.structure.ModelCalculatedField;
import it.eng.qbe.model.structure.ModelCalculatedField.Slot;
import it.eng.qbe.model.structure.ModelCalculatedField.Slot.IMappedValuesDescriptor;
import it.eng.qbe.model.structure.ModelCalculatedField.Slot.MappedValuesPunctualDescriptor;
import it.eng.qbe.model.structure.ModelCalculatedField.Slot.MappedValuesRangeDescriptor;
import it.eng.spagobi.utilities.assertion.Assert;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

/**
 * @author Andrea Gioia (andrea.gioia@eng.it)
 */
public class CalculatedFieldsDAOFileImpl implements ICalculatedFieldsDAO {

    protected File modelJarFile;

    public static final String CFIELDS_FROM_META_FILE_NAME = "cfields_meta.xml";
    public static final String CFIELDS_FROM_USER_FILE_NAME = "cfields_user.xml";

    public final static String ROOT_TAG = "CFIELDS";

    public final static String FIELD_TAG = "CFIELD";
    public final static String FIELD_TAG_ENTIY_ATTR = "entity";
    public final static String FIELD_TAG_NAME_ATTR = "name";
    public final static String FIELD_TAG_TYPE_ATTR = "type";
    public final static String FIELD_TAG_NATURE_ATTR = "nature";
    public final static String FIELD_TAG_IN_LINE_ATTR = "isInLine";

    public final static String EXPRESSION_TAG = "EXPRESSION";
    public final static String SLOTS_TAG = "SLOTS";
    public final static String SLOT_TAG = "SLOT";

    public final static String VALUESET_TAG = "VALUESET";
    public final static String FROM_TAG = "FROM";
    public final static String TO_TAG = "TO";
    public final static String VALUE_TAG = "VALUE";

    public static transient Logger logger = Logger.getLogger(CalculatedFieldsDAOFileImpl.class);

    public CalculatedFieldsDAOFileImpl(File modelJarFile) {
        this.modelJarFile = modelJarFile;
    }

    // =============================================================================
    // LOAD
    // =============================================================================

    public Map<String, List<ModelCalculatedField>> loadCalculatedFields() {
        File calculatedFieldsFile;
        Map<String, List<ModelCalculatedField>> calculatedFiledsMap;

        calculatedFiledsMap = new HashMap<String, List<ModelCalculatedField>>();

        calculatedFieldsFile = getMetaCalculatedFieldsFile();
        loadCalculatedFieldsFromFile(calculatedFieldsFile, calculatedFiledsMap);

        calculatedFieldsFile = getUserCalculatedFieldsFile();
        loadCalculatedFieldsFromFile(calculatedFieldsFile, calculatedFiledsMap);

        return calculatedFiledsMap;
    }

    private void loadCalculatedFieldsFromFile(File calculatedFieldsFile,
            Map<String, List<ModelCalculatedField>> calculatedFiledsMap) {

        FileInputStream in;
        SAXReader reader;
        Document document;
        String entity;
        String name;
        String type;
        String nature;
        Boolean inlineCalculatedField;
        String expression;
        ModelCalculatedField calculatedField;
        List calculatedFieldNodes;
        Iterator it;
        Node calculatedFieldNode;
        List<ModelCalculatedField> calculatedFileds;

        logger.debug("IN");

        in = null;

        try {

            logger.debug("Load calculated fields from file [" + calculatedFieldsFile + "]");

            if (calculatedFieldsFile != null && calculatedFieldsFile.exists()) {

                document = guardedRead(calculatedFieldsFile);
                Assert.assertNotNull(document, "Document cannot be null");

                calculatedFieldNodes = document.selectNodes("//" + ROOT_TAG + "/" + FIELD_TAG + "");
                logger.debug("Found [" + calculatedFieldNodes.size() + "] calculated field/s");

                it = calculatedFieldNodes.iterator();
                while (it.hasNext()) {
                    calculatedFieldNode = (Node) it.next();
                    entity = calculatedFieldNode.valueOf("@" + FIELD_TAG_ENTIY_ATTR);
                    name = calculatedFieldNode.valueOf("@" + FIELD_TAG_NAME_ATTR);
                    type = calculatedFieldNode.valueOf("@" + FIELD_TAG_TYPE_ATTR);
                    nature = calculatedFieldNode.valueOf("@" + FIELD_TAG_NATURE_ATTR);
                    inlineCalculatedField = new Boolean(calculatedFieldNode.valueOf("@" + FIELD_TAG_IN_LINE_ATTR));
                    expression = loadExpression(calculatedFieldNode);
                    calculatedField = new ModelCalculatedField(name, type, expression,
                            inlineCalculatedField.booleanValue());
                    calculatedField.setNature(nature);

                    // parse slots
                    List<ModelCalculatedField.Slot> slots = loadSlots(calculatedFieldNode);
                    calculatedField.addSlots(slots);
                    if (slots.size() > 0) {
                        String defaultSlotValue = loadDefaultSlotValue(calculatedFieldNode);
                        calculatedField.setDefaultSlotValue(defaultSlotValue);
                    }

                    if (!calculatedFiledsMap.containsKey(entity)) {
                        calculatedFiledsMap.put(entity, new ArrayList());
                    }
                    calculatedFileds = calculatedFiledsMap.get(entity);
                    ModelCalculatedField calculatedFieldToRemove = null;
                    for (ModelCalculatedField cf : calculatedFileds) {
                        if (cf.getName().equals(calculatedField.getName())) {
                            calculatedFieldToRemove = cf;
                            break;
                        }
                    }

                    if (calculatedFieldToRemove != null) {
                        boolean removed = calculatedFileds.remove(calculatedFieldToRemove);
                        logger.debug("Calculated field [" + calculatedFieldToRemove.getName()
                                + "] already defined. The old version will be replaced with this one");
                    }
                    calculatedFileds.add(calculatedField);

                    logger.debug("Calculated filed [" + calculatedField.getName() + "] loaded succesfully");
                }
            } else {
                logger.debug("File [" + calculatedFieldsFile
                        + "] does not exist. No calculated fields have been loaded.");
            }
        } catch (Throwable t) {
            if (t instanceof DAOException)
                throw (DAOException) t;
            throw new DAOException("An unpredicted error occurred while loading calculated fields on file ["
                    + calculatedFieldsFile + "]", t);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw new DAOException(
                            "Impossible to properly close stream to file file [" + calculatedFieldsFile + "]", e);
                }
            }
            logger.debug("OUT");
        }
    }

    private String loadExpression(Node calculatedFieldNode) {
        String expression;

        expression = null;

        Node expressionNode = calculatedFieldNode.selectSingleNode(EXPRESSION_TAG);
        if (expressionNode != null) {
            expression = expressionNode.getStringValue();
        } else { // for back compatibility
            expression = calculatedFieldNode.getStringValue();
        }

        return expression;
    }

    private List<ModelCalculatedField.Slot> loadSlots(Node calculatedFieldNode) {

        List<ModelCalculatedField.Slot> slots = new ArrayList<ModelCalculatedField.Slot>();

        Node slotBlock = calculatedFieldNode.selectSingleNode(SLOTS_TAG);
        if (slotBlock != null) {
            List<Node> slotNodes = slotBlock.selectNodes(SLOT_TAG);

            for (Node slotNode : slotNodes) {
                ModelCalculatedField.Slot slot = loadSlot(slotNode);
                slots.add(slot);
            }
        }

        return slots;
    }

    private String loadDefaultSlotValue(Node calculatedFieldNode) {

        String defaultSlotValue = null;

        Node slotBlock = calculatedFieldNode.selectSingleNode(SLOTS_TAG);
        if (slotBlock != null) {
            defaultSlotValue = slotBlock.valueOf("@defaultSlotValue");
        }

        return defaultSlotValue;
    }

    private ModelCalculatedField.Slot loadSlot(Node slotNode) {
        ModelCalculatedField.Slot slot;

        String slotValue = slotNode.valueOf("@value");
        slot = new ModelCalculatedField.Slot(slotValue);

        List<Node> mappedValues = slotNode.selectNodes(VALUESET_TAG);
        for (Node mappedValuesNode : mappedValues) {
            ModelCalculatedField.Slot.IMappedValuesDescriptor descriptor = loadDescriptor(mappedValuesNode);
            slot.addMappedValuesDescriptors(descriptor);
        }

        return slot;
    }

    private ModelCalculatedField.Slot.IMappedValuesDescriptor loadDescriptor(Node mappedValuesNode) {
        ModelCalculatedField.Slot.IMappedValuesDescriptor descriptor = null;

        String descriptorType = mappedValuesNode.valueOf("@type");
        if (descriptorType.equalsIgnoreCase("range")) {
            descriptor = loadRangeDescriptor(mappedValuesNode);
        } else if (descriptorType.equalsIgnoreCase("punctual")) {
            descriptor = loadPunctualDescriptor(mappedValuesNode);
        }

        return descriptor;
    }

    private ModelCalculatedField.Slot.MappedValuesPunctualDescriptor loadPunctualDescriptor(Node mappedValuesNode) {
        ModelCalculatedField.Slot.MappedValuesPunctualDescriptor punctualDescriptor;

        punctualDescriptor = new ModelCalculatedField.Slot.MappedValuesPunctualDescriptor();
        List<Node> punctualValueNodes = mappedValuesNode.selectNodes(VALUE_TAG);
        for (Node punctualValueNode : punctualValueNodes) {
            String punctualValue = punctualValueNode.valueOf("@value");
            punctualDescriptor.addValue(punctualValue);
        }

        return punctualDescriptor;
    }

    private ModelCalculatedField.Slot.MappedValuesRangeDescriptor loadRangeDescriptor(Node mappedValuesNode) {
        ModelCalculatedField.Slot.MappedValuesRangeDescriptor rangeDescriptor = null;

        Node fomrNode = mappedValuesNode.selectSingleNode(FROM_TAG);
        String fromValue = fomrNode.valueOf("@value");
        Node toNode = mappedValuesNode.selectSingleNode(TO_TAG);
        String toValue = toNode.valueOf("@value");
        rangeDescriptor = new ModelCalculatedField.Slot.MappedValuesRangeDescriptor(fromValue, toValue);
        String includeValue = null;
        includeValue = fomrNode.valueOf("@include");
        if (includeValue != null
                && (includeValue.equalsIgnoreCase("TRUE") || includeValue.equalsIgnoreCase("FALSE"))) {
            rangeDescriptor.setIncludeMinValue(Boolean.parseBoolean(includeValue));
        }
        includeValue = toNode.valueOf("@include");
        if (includeValue != null
                && (includeValue.equalsIgnoreCase("TRUE") || includeValue.equalsIgnoreCase("FALSE"))) {
            rangeDescriptor.setIncludeMaxValue(Boolean.parseBoolean(includeValue));
        }

        return rangeDescriptor;
    }

    // =============================================================================
    // SAVE
    // =============================================================================

    public void saveCalculatedFields(Map<String, List<ModelCalculatedField>> calculatedFields) {

        File calculatedFieldsFile;
        Iterator it;
        String entityName;
        List fields;
        Document document;
        Element root;
        ModelCalculatedField modelCalculatedField;

        logger.debug("IN");

        calculatedFieldsFile = null;

        try {
            Assert.assertNotNull(calculatedFields, "Input parameter [calculatedFields] cannot be null");

            calculatedFieldsFile = getUserCalculatedFieldsFile();
            Assert.assertNotNull(calculatedFieldsFile, "Destination file cannot be null");
            logger.debug("Calculated fields will be saved on file [" + calculatedFieldsFile + "]");

            if (!calculatedFieldsFile.getParentFile().exists()) {
                DAOException e = new DAOException(
                        "Destination file folder [" + calculatedFieldsFile.getPath() + "] does not exist");
                e.addHint("Check if [" + calculatedFieldsFile.getPath()
                        + "] folder exist on your server filesystem. If not create it.");
                throw e;
            }

            if (calculatedFieldsFile.exists()) {
                logger.warn("File [" + calculatedFieldsFile
                        + "] already exists. New settings will override the old ones.");
            }

            document = DocumentHelper.createDocument();
            root = document.addElement(ROOT_TAG);

            logger.debug("In the target model there are [" + calculatedFields.keySet()
                    + "] entity/es that contain calculated fields");
            it = calculatedFields.keySet().iterator();
            while (it.hasNext()) {
                entityName = (String) it.next();
                logger.debug("Serializing [" + calculatedFields.size() + "] calculated fields for entity ["
                        + entityName + "]");
                fields = (List) calculatedFields.get(entityName);
                for (int i = 0; i < fields.size(); i++) {
                    modelCalculatedField = (ModelCalculatedField) fields.get(i);
                    logger.debug("Serializing calculated field [" + modelCalculatedField.getName()
                            + "] for entity [" + entityName + "]");
                    Element fieldElement = root.addElement(FIELD_TAG).addAttribute(FIELD_TAG_ENTIY_ATTR, entityName)
                            .addAttribute(FIELD_TAG_NAME_ATTR, modelCalculatedField.getName())
                            .addAttribute(FIELD_TAG_TYPE_ATTR, modelCalculatedField.getType())
                            .addAttribute(FIELD_TAG_NATURE_ATTR, modelCalculatedField.getNature())
                            .addAttribute(FIELD_TAG_IN_LINE_ATTR, "" + modelCalculatedField.isInLine());

                    fieldElement.addElement(EXPRESSION_TAG).addCDATA(modelCalculatedField.getExpression());

                    List<Slot> slots = modelCalculatedField.getSlots();
                    if (slots != null && slots.size() > 0) {
                        Element slotsElement = fieldElement.addElement(SLOTS_TAG);
                        if (modelCalculatedField.getDefaultSlotValue() != null) {
                            slotsElement.addAttribute("defaultSlotValue",
                                    modelCalculatedField.getDefaultSlotValue());
                        }

                        for (Slot slot : slots) {
                            Element slotElement = slotsElement.addElement(SLOT_TAG);
                            slotElement.addAttribute("value", slot.getName());
                            saveValueSets(slot, slotElement);
                        }
                    }
                }
            }

            guardedWrite(document, calculatedFieldsFile);

        } catch (Throwable t) {
            if (t instanceof DAOException)
                throw (DAOException) t;
            throw new DAOException("An unpredicetd error occurred while saving calculated fields on file ["
                    + calculatedFieldsFile + "]");
        } finally {
            logger.debug("OUT");
        }
    }

    public void saveValueSets(Slot slot, Element slotElement) {
        List<IMappedValuesDescriptor> descriptors = slot.getMappedValuesDescriptors();
        for (IMappedValuesDescriptor descriptor : descriptors) {
            Element valuesetElement = slotElement.addElement(VALUESET_TAG);

            if (descriptor instanceof MappedValuesPunctualDescriptor) {
                MappedValuesPunctualDescriptor punctualDescriptor = (MappedValuesPunctualDescriptor) descriptor;
                valuesetElement.addAttribute("type", "punctual");
                Set<String> values = punctualDescriptor.getValues();
                for (String value : values) {
                    valuesetElement.addElement(VALUE_TAG).addAttribute("value", value);
                }
            } else if (descriptor instanceof MappedValuesRangeDescriptor) {
                MappedValuesRangeDescriptor rangeDescriptor = (MappedValuesRangeDescriptor) descriptor;
                valuesetElement.addAttribute("type", "range");
                valuesetElement.addElement(FROM_TAG).addAttribute("value", rangeDescriptor.getMinValue())
                        .addAttribute("include", "" + rangeDescriptor.isIncludeMinValue());
                valuesetElement.addElement(TO_TAG).addAttribute("value", rangeDescriptor.getMaxValue())
                        .addAttribute("include", "" + rangeDescriptor.isIncludeMaxValue());
            } else {
                throw new DAOException(
                        "An unpredicetd error occurred while saving valueset of slot [" + slot.getName() + "]");
            }

        }
    }

    private File getUserCalculatedFieldsFile() {
        File calculatedFieldsFile = null;
        calculatedFieldsFile = new File(modelJarFile.getParentFile(), CFIELDS_FROM_USER_FILE_NAME);
        return calculatedFieldsFile;
    }

    private File getMetaCalculatedFieldsFile() {
        File calculatedFieldsFile = null;
        calculatedFieldsFile = new File(modelJarFile.getParentFile(), CFIELDS_FROM_META_FILE_NAME);
        return calculatedFieldsFile;
    }

    // ------------------------------------------------------------------------------------------------------
    // Guarded actions. see -> http://java.sun.com/docs/books/tutorial/essential/concurrency/guardmeth.html
    // ------------------------------------------------------------------------------------------------------

    private boolean locked = false;

    private synchronized void getLock() {
        while (locked) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        locked = true;
    }

    private synchronized void releaseLock() {
        locked = false;
        notifyAll();
    }

    private Document guardedRead(File file) {
        FileInputStream in;
        SAXReader reader;
        Document document;

        logger.debug("IN");

        in = null;
        reader = null;

        try {

            logger.debug("acquiring lock...");
            getLock();
            logger.debug("Lock acquired");

            try {
                in = new FileInputStream(file);
            } catch (FileNotFoundException fnfe) {
                DAOException e = new DAOException(
                        "Impossible to load calculated fields from file [" + file.getName() + "]", fnfe);
                e.addHint("Check if [" + file.getPath()
                        + "] folder exist on your server filesystem. If not create it.");
                throw e;
            }
            Assert.assertNotNull(in, "Input stream cannot be null");

            reader = new SAXReader();
            try {
                document = reader.read(in);
            } catch (DocumentException de) {
                DAOException e = new DAOException("Impossible to parse file [" + file.getName() + "]", de);
                e.addHint("Check if [" + file + "] is a well formed XML file");
                throw e;
            }
            Assert.assertNotNull(document, "Document cannot be null");
        } catch (Throwable t) {
            if (t instanceof DAOException)
                throw (DAOException) t;
            throw new DAOException("An unpredicetd error occurred while writing on file [" + file + "]");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw new DAOException("Impossible to properly close stream to file [" + file + "]", e);
                }
            }
            logger.debug("releasing lock...");
            releaseLock();
            logger.debug("lock released");

            logger.debug("OUT");
        }

        return document;
    }

    private void guardedWrite(Document document, File file) {
        Writer out;
        OutputFormat format;
        XMLWriter writer;

        logger.debug("IN");

        out = null;
        writer = null;

        try {

            logger.debug("acquiring lock...");
            getLock();
            logger.debug("Lock acquired");

            out = null;
            try {
                out = new FileWriter(file);
            } catch (IOException e) {
                throw new DAOException("Impossible to open file [" + file + "]", e);
            }
            Assert.assertNotNull(out, "Output stream cannot be null");

            format = OutputFormat.createPrettyPrint();
            format.setEncoding("ISO-8859-1");
            format.setIndent("    ");
            writer = new XMLWriter(out, format);
            try {

                writer.write(document);
                writer.flush();
            } catch (IOException e) {
                throw new DAOException("Impossible to write to file [" + file + "]", e);
            }
        } catch (Throwable t) {
            if (t instanceof DAOException)
                throw (DAOException) t;
            throw new DAOException("An unpredicetd error occurred while writing on file [" + file + "]");
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    throw new DAOException("Impossible to properly close stream to file file [" + file + "]", e);
                }
            }
            logger.debug("releasing lock...");
            releaseLock();
            logger.debug("lock released");

            logger.debug("OUT");
        }

    }

}