eu.uqasar.util.UQasarUtil.java Source code

Java tutorial

Introduction

Here is the source code for eu.uqasar.util.UQasarUtil.java

Source

package eu.uqasar.util;

/*
 * #%L
 * U-QASAR
 * %%
 * Copyright (C) 2012 - 2015 U-QASAR Consortium
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.io.FileOutputStream;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.ResourceBundle;

import javax.inject.Singleton;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.wicket.model.IModel;
import org.jboss.solder.logging.Logger;
import org.topbraid.spin.arq.ARQ2SPIN;
import org.topbraid.spin.arq.ARQFactory;
import org.topbraid.spin.model.Select;
import org.topbraid.spin.system.SPINModuleRegistry;

import thewebsemantic.Bean2RDF;
import thewebsemantic.Sparql;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QuerySolutionMap;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.util.FileUtils;

import eu.uqasar.model.formula.Formula;
import eu.uqasar.model.measure.MetricSource;
import eu.uqasar.model.meta.ContinuousIntegrationTool;
import eu.uqasar.model.meta.CustomerType;
import eu.uqasar.model.meta.IssueTrackingTool;
import eu.uqasar.model.meta.MetaData;
import eu.uqasar.model.meta.ProgrammingLanguage;
import eu.uqasar.model.meta.ProjectType;
import eu.uqasar.model.meta.QModelTagData;
import eu.uqasar.model.meta.SoftwareDevelopmentMethodology;
import eu.uqasar.model.meta.SoftwareLicense;
import eu.uqasar.model.meta.SoftwareType;
import eu.uqasar.model.meta.SourceCodeManagementTool;
import eu.uqasar.model.meta.StaticAnalysisTool;
import eu.uqasar.model.meta.TestManagementTool;
import eu.uqasar.model.meta.Topic;
import eu.uqasar.model.notification.INotification;
import eu.uqasar.model.tree.Metric;
import eu.uqasar.model.tree.Project;
import eu.uqasar.model.tree.QualityIndicator;
import eu.uqasar.model.tree.QualityObjective;
import eu.uqasar.model.tree.QualityStatus;
import eu.uqasar.model.tree.TreeNode;
import eu.uqasar.model.user.User;
import eu.uqasar.service.dataadapter.AdapterDataService;
import eu.uqasar.service.meta.ContinuousIntegrationToolService;
import eu.uqasar.service.meta.CustomerTypeService;
import eu.uqasar.service.meta.IssueTrackingToolService;
import eu.uqasar.service.meta.ProgrammingLanguageService;
import eu.uqasar.service.meta.ProjectTypeService;
import eu.uqasar.service.meta.QModelTagDataService;
import eu.uqasar.service.meta.SoftwareDevelopmentMethodologyService;
import eu.uqasar.service.meta.SoftwareLicenseService;
import eu.uqasar.service.meta.SoftwareTypeService;
import eu.uqasar.service.meta.SourceCodeManagementToolService;
import eu.uqasar.service.meta.StaticAnalysisToolService;
import eu.uqasar.service.meta.TestManagementToolService;
import eu.uqasar.service.meta.TopicService;
import eu.uqasar.service.similarity.ProjectSimilarityService;
import eu.uqasar.service.similarity.QualityObjectiveSimilarityService;
import eu.uqasar.service.tree.TreeNodeService;
import eu.uqasar.service.user.UserService;
import eu.uqasar.util.resources.ResourceBundleLocator;

/**
 * Various utilities used on the platform 
 *
 */
@Setter
@Getter
@Singleton
public class UQasarUtil {

    final static String SEPARATOR = java.nio.file.FileSystems.getDefault().getSeparator();
    final static String ONTOLOGYFILE = "uq-ontology-model.rdf";

    protected static ResourceBundle res = null;
    private static Logger logger = Logger.getLogger(UQasarUtil.class);

    // List containing the notifications triggered by the rules' engine
    @Setter
    @Getter
    private static List<INotification> notifications = new ArrayList<>();

    @Setter
    @Getter
    private static Date latestTreeUpdateDate = new Date();

    @Setter
    @Getter
    private static Model uqModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);

    // Enumeration for the various suggestion types
    public enum SuggestionType {

        NO_SUGGESTION("no_suggestion"), QO_REMOVE("qo.remove"), QO_REPLACE("qo.replace"), METRIC_REMOVE(
                "metric.remove"),

        ;

        private final String labelKey;

        SuggestionType(final String labelKey) {
            this.labelKey = labelKey;
        }

        @Override
        public String toString() {
            return getLabelModel().getObject();
        }

        public IModel<String> getLabelModel() {
            return ResourceBundleLocator.getLabelModel(UQasarUtil.class, "suggestion." + labelKey);
        }

        public static List<SuggestionType> getAllSuggestionTypes() {
            return Arrays.asList(values());
        }
    }

    /**
     * Get the temp directory to be used; in case JBoss is used, use 
     * its temp dir, otherwise the user temp.
     * @return
     */
    public static String getTempDirPath() {
        String tempDirectory = null;

        Properties systemProp = System.getProperties();
        // In case JBoss is used, use the JBoss temp dir
        if (systemProp.containsKey("jboss.server.temp.dir")) {
            tempDirectory = systemProp.getProperty("jboss.server.temp.dir");
            if (!tempDirectory.endsWith(SEPARATOR)) {
                tempDirectory += SEPARATOR;
            }
        }
        // Otherwise use a temp directory
        else {
            tempDirectory = System.getProperty("java.io.tmpdir");
            if (!tempDirectory.endsWith(SEPARATOR)) {
                tempDirectory += SEPARATOR;
            }
        }

        return tempDirectory;
    }

    /**
     * Get the data dir to be used; in case JBoss is used, use its data dir, 
     * otherwise the user temp.
     * @return
     */
    public static String getDataDirPath() {
        String dataDirectory = null;
        Properties systemProp = System.getProperties();
        // In case JBoss is used
        if (systemProp.containsKey("jboss.server.data.dir")) {
            dataDirectory = systemProp.getProperty("jboss.server.data.dir");
            if (!dataDirectory.endsWith(SEPARATOR)) {
                dataDirectory += SEPARATOR;
            }
        }
        // Otherwise use a temp directory
        else {
            dataDirectory = System.getProperty("java.io.tmpdir");
            if (!dataDirectory.endsWith(SEPARATOR)) {
                dataDirectory += SEPARATOR;
            }
        }

        return dataDirectory;
    }

    /**
     * Construct a formula string to be evaluated.
     * @param varsAndOpers
     * @return
     */
    public static String constructFormula(List<Object> varsAndOpers) {
        String formula = "";

        for (Object object : varsAndOpers) {
            formula += object;
        }

        logger.info("Constructed formula to be evaluated: " + formula);
        return formula;
    }

    /**
     * Get properties resource
     * @return
     */
    public static ResourceBundle getProperties() {
        if (res == null) {
            loadProperties();
        }
        return res;
    }

    /**
     * Load properties file
     */
    private static void loadProperties() {
        res = ResourceBundle.getBundle("uqasar");
    }

    /**
     * Round double to two decimals
     * @param number
     * @return
     */
    public static Double round(double number) {
        DecimalFormat df = new DecimalFormat("#,##");
        df.setRoundingMode(RoundingMode.DOWN);
        String s = df.format(number);
        return Double.valueOf(s);
    }

    /**
     * Replace whitespace chars with the defined separator and escape the 
     * String  
     * @param name
     */
    public static String sanitizeName(String name) {
        final String SEPARATOR = "_";
        if (name.contains(" ")) {
            String processed = name.replaceAll(" ", SEPARATOR).concat(SEPARATOR);
            return StringEscapeUtils.escapeJavaScript(processed);
        }
        // Otherwise return the actual string
        return name;
    }

    /**
     * Replace the separator with whitespaces and unescape the String
     * @param name
     * @return
     */
    public static String unSanitizeName(String name) {
        final String SEPARATOR = "_";
        if (name.contains(SEPARATOR)) {
            return StringEscapeUtils.unescapeJavaScript(name).replaceAll(SEPARATOR, " ").trim();
        }
        return StringEscapeUtils.unescapeJavaScript(name).trim();
    }

    /**
     * Get the pwd used for encrypting and decrypting adapter passwords
     * TODO: Where could this be saved securely 
     * @return
     */
    public static String getEncDecPwd() {
        return "jvnqeiPIqX_6cpdOYfDc7sHk7nEIv4zRn5984JwIHnq4AX7XQt";
    }

    /**
     * Get the Jira metric names
     * TODO: Fetch the list of metrics from uQasarMetric
     * @return
     */
    public static List<String> getJiraMetricNames() {
        String metrics[] = { "PROJECTS_PER_SYSTEM_INSTANCE", "ISSUES_PER_PROJECTS_PER_SYSTEM_INSTANCE",
                "FIXED_ISSUES_PER_PROJECT", "UNRESOLVED_ISSUES_PER_PROJECT", "UNRESOLVED_BUG_ISSUES_PER_PROJECT",
                "UNRESOLVED_TASK_ISSUES_PER_PROJECT" };

        return Arrays.asList(metrics);
    }

    public static List<String> getJiraMetricNamesAbbreviated() {
        String metrics[] = { "Projects", "Issues", "Fixed issues", "Unresolved issues" };

        return Arrays.asList(metrics);
    }

    /**
     * TODO: Fetch the list of metrics from uQasarMetric
     * Get the Sonar metric names
     * @return
     */
    public static List<String> getSonarMetricNames() {

        String metrics[] = { "NCLOC", // lines of code (NC=non comment)
                "LINES", // lines (i.e. all lines)
                "COMMENT_LINES", // number of comment lines
                "STATEMENTS", // number of statements
                "CLASSES", // number of classes
                "FILES", // number of files
                "DIRECTORIES", // number of directories
                "FUNCTIONS", // number of functions
                "COMMENT_LINES_DENSITY", // the density of comment lines (number in [0..100])

                "DUPLICATED_LINES", // number of duplicated lines
                "DUPLICATED_LINES_DENSITY", // the density of duplicated lines (number in [0..100])
                "COMPLEXITY", // cyclomatic complexity of the project
                "FUNCTION_COMPLEXITY", // the average cyclomatic complexity of a function
                "FILE_COMPLEXITY", // the average cyclomatic complexity of a source code file
                "CLASS_COMPLEXITY", // the average cyclomatic complexity of a class
                "UT_COVERAGE", // code coverage by unit tests
                "AT_COVERAGE", // code coverage by acceptance tests
                "OVERALL_COVERAGE", // code coverage by both, unit and acceptance tests
                "PACKAGE_TANGLES", // Number of file dependencies to cut in order to remove all cycles between directories.
                "PACKAGE_TANGLE_INDEX", // Level of directory interdependency. Best value (0%) means that there is no cycle and worst value (100%) means that directories are really tangled.
                "TEST_SUCCESS_DENSITY", // ratio of successfully executed tests to the overall number of te
                "TEST_FAILURES", // number of failed tests (failure = test could be run and is failed)
                "TEST_ERRORS", // number of errored tests (error = test could not be run)
                "TESTS", // number of tests

                // Sonar, available metrics that can be used if they are implemented on the adapter

                //               /* core statistics */
                //            "LINES",
                //            "NCLOC",
                //            "CLASSES",
                //            "FILES",
                //            "DIRECTORIES",
                //            "PACKAGES",
                //            "FUNCTIONS",
                //            "ACCESSORS",
                //            "STATEMENTS",
                //            "PUBLIC_API",
                //               
                //               /* complexity */
                //            "COMPLEXITY",
                //            "CLASS_COMPLEXITY",
                //            "FUNCTION_COMPLEXITY",
                //            "FILE_COMPLEXITY", 
                //            "CLASS_COMPLEXITY_DISTRIBUTION",
                //            "FUNCTION_COMPLEXITY_DISTRIBUTION",
                //               
                //               /* comments */
                //            "COMMENT_LINES",
                //            "COMMENT_LINES_DENSITY",
                //            "PUBLIC_DOCUMENTED_API_DENSITY",
                //            "PUBLIC_UNDOCUMENTED_API",
                //            "COMMENTED_OUT_CODE_LINES",
                //               
                //               /* unit tests */
                //            "TESTS",
                //            "TEST_EXECUTION_TIME",
                //            "TEST_ERRORS",
                //            "SKIPPED_TESTS",
                //            "TEST_FAILURES",
                //            "TEST_SUCCESS_DENSITY",
                //            "TEST_DATA",
                //               
                //               /* code coverage by unit tests */
                //            "COVERAGE",
                //            "LINES_TO_COVER",
                //            "UNCOVERED_LINES",
                //            "LINE_COVERAGE",
                //            "COVERAGE_LINE_HITS_DATA",
                //               
                //            "CONDITIONS_TO_COVER",
                //            "UNCOVERED_CONDITIONS",
                //            "BRANCH_COVERAGE",
                //            "BRANCH_COVERAGE_HITS_DATA",
                //               
                //            "UNCOVERED_COMPLEXITY_BY_TESTS",
                //               
                //               /* duplicated lines */
                //            "DUPLICATED_LINES", 
                //            "DUPLICATED_BLOCKS",
                //            "DUPLICATED_FILES",
                //            "DUPLICATED_LINES_DENSITY",
                //            "DUPLICATIONS_DATA",
                //               
                //               /* coding rules */
                //            "USABILITY",
                //            "RELIABILITY",
                //            "EFFICIENCY",
                //            "PORTABILITY",
                //            "MAINTAINABILITY",
                //               
                //            "WEIGHTED_VIOLATIONS",
                //            "VIOLATIONS_DENSITY",
                //            "VIOLATIONS",
                //            "BLOCKER_VIOLATIONS",
                //            "CRITICAL_VIOLATIONS",
                //            "MAJOR_VIOLATIONS",
                //            "MINOR_VIOLATIONS",
                //            "INFO_VIOLATIONS",
        };

        return Arrays.asList(metrics);
    }

    /**
     * TODO: Fetch the list of metrics from uQasarMetric
     * Get the TestLink metric names
     * @return 
     */
    public static List<String> getTestLinkMetricNames() {
        String metrics[] = { "TEST_P", "TEST_F", "TEST_B", "TEST_N", "TEST_TOTAL" };

        return Arrays.asList(metrics);
    }

    /**
     * TODO: Fetch the list of metrics from uQasarMetric
     * Get the Cubes direct Metric names
     * @return Cubes metric Names
     */
    public static List<String> getCubesMetricNames() {
        String metrics[] = { "cube/jira/aggregate?cut=Status:Done", "cube/jira/aggregate?cut=Type:Bug",
                "cube/jira/aggregate?cut=Status:To%20Do", "cube/jira/aggregate?cut=Priority:Blocker",
                "cube/jira/aggregate?cut=Priority:Critical", "cube/jira/aggregate?cut=Priority:Major",
                "cube/jira/aggregate?cut=Priority:Minor", "cube/jira/aggregate?cut=Status:Open&cut=Priority:Major",
                //            "cube/jira/fact/UQ-1", 
                //            "cube/jira/model",
                //            "cube/jira/cell",
                //            "cube/jira/members/Status",
                //            "cube/jira/facts",
                //            "cubes"
        };

        return Arrays.asList(metrics);
    }

    public static List<String> getGitlabMetricNames() {

        String metrics[] = { "GIT_COMMITS", "GIT_PROJECTS" };

        return Arrays.asList(metrics);
    }

    /**
     * Convert minutes to ms
     * @param minutes
     * @return
     */
    public static int minsToMs(int minutes) {
        final int SEC = 60;
        final int MS = 1000;
        return minutes * SEC * MS;
    }

    /**
     * Compare two dates returning true if equal and false if not. This comparison omits milliseconds
     * @param dateOne
     * @param dateTwo
     * @return
     */
    public static boolean isDateEqual(Date dateOne, Date dateTwo) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String date1 = sdf.format(dateOne);
        String date2 = sdf.format(dateTwo);

        if (date1.equals(date2)) {
            return true;
        }

        return false;
    }

    /**
     * Takes care of computing the tree values (update metrics and 
     * compute QO/QI values based on that) starting from the root node.
     * @param projectRoot Node
     */
    public static void updateTree(TreeNode projectRoot) {
        // Create a timestamp at the start of the tree update so that 
        // all the updated entities have the same value for the date. 
        setLatestTreeUpdateDate(new Date());
        logger.info("Updating the QA Project tree...");
        postorder(projectRoot);
    }

    /**
     * Traverse the tree in postorder and update tree values
     * @param node
     */
    private static void postorder(TreeNode node) {

        if (node == null) {
            return;
        }

        logger.debug("------------postorder: " + node.getName() + "---------------");

        // Iterate the node children
        for (Object o : node.getChildren()) {
            TreeNode nodeChild = (TreeNode) o;
            UQasarUtil.postorder(nodeChild);
        }
        logger.debug("Traversing project tree in postorder..." + node.toString());
        // Update the value
        try {
            InitialContext ic = new InitialContext();
            AdapterDataService adapterDataService = new AdapterDataService();
            TreeNodeService treeNodeService = (TreeNodeService) ic.lookup("java:module/TreeNodeService");

            if (node instanceof Metric) {
                Metric metric = (Metric) node;
                logger.debug("Recomputing the value of the Metric " + node);
                Float value = null;
                if (metric.getMetricSource() == MetricSource.Manual) {
                    metric.updateQualityStatus();
                } else {
                    value = adapterDataService.getMetricValue(metric.getMetricSource(), metric.getMetricType(),
                            metric.getProject());
                    metric.setValue(value);
                }
                metric.setLastUpdated(getLatestTreeUpdateDate());
                metric.addHistoricValue();
                // End Metric node treatment 
            } else if (node instanceof QualityIndicator) {
                logger.info("Recomputing the value of the Quality Indicator " + node);
                QualityIndicator qi = (QualityIndicator) node;
                if (qi.getUseFormula()) {
                    String formulaToEval = Formula.parseFormula(qi.getViewFormula());
                    if (formulaToEval != null && !formulaToEval.isEmpty()) {

                        Float computedValue = Formula.evalFormula(formulaToEval);
                        if (computedValue != null && !computedValue.isNaN()) {
                            qi.setValue(computedValue);
                            qi.setLastUpdated(getLatestTreeUpdateDate());
                            treeNodeService.update(qi);
                        }

                    }
                } else {
                    float achieved = 0;
                    float denominator = 0;
                    for (final TreeNode me : qi.getChildren()) {
                        float weight = ((Metric) me).getWeight();
                        if (me.getQualityStatus() == QualityStatus.Green) {
                            achieved += weight;
                        }
                        denominator += weight;
                    }
                    if (denominator == 0)
                        qi.getChildren().size();
                    qi.setValue(achieved * 100 / denominator);
                }
                qi.setLastUpdated(getLatestTreeUpdateDate());
                qi.addHistoricValue();
                // End Q.Indicator node treatment 
            } else if (node instanceof QualityObjective) {
                logger.info("Recomputing the value of the Quality Objective " + node);
                QualityObjective qo = (QualityObjective) node;
                if (qo.getUseFormula()) {
                    String formulaToEval = Formula.parseFormula(qo.getViewFormula());
                    if (formulaToEval != null && !formulaToEval.isEmpty()) {

                        Float computedValue = Formula.evalFormula(formulaToEval);
                        if (computedValue != null && !computedValue.isNaN()) {
                            qo.setValue(computedValue);
                            qo.setLastUpdated(getLatestTreeUpdateDate());
                        }

                    }
                } else {
                    float denominator = 0;
                    float achieved = 0;
                    for (final TreeNode qi : qo.getChildren()) {
                        float weight = ((QualityIndicator) qi).getWeight();
                        if (qi.getQualityStatus() == QualityStatus.Green) {
                            achieved += weight;
                        }
                        denominator += weight;
                    }
                    qo.setValue(achieved * 100 / denominator);
                }
                qo.setLastUpdated(getLatestTreeUpdateDate());
                qo.addHistoricValue();
                // End Quality Objective node treatment 
            } else if (node instanceof Project) {
                logger.info("Recomputing the value of the Project " + node);
                Project prj = (Project) node;
                double qoValueSum = 0;
                double denominator = 0;
                for (Object o : node.getChildren()) {
                    QualityObjective qo = (QualityObjective) o;
                    if (qo.getWeight() == 0) {
                        continue;
                    }
                    qoValueSum += qo.getValue() * (prj.isFormulaAverage() ? qo.getWeight() : 1);
                    denominator += prj.isFormulaAverage() ? qo.getWeight() : 1;
                }

                // bad idea to divide something under 0
                if (denominator == 0) {
                    denominator = 1;
                }

                Double computedValue = qoValueSum / denominator;

                if (computedValue != null && !computedValue.isNaN() && !computedValue.isInfinite()) {
                    prj.setValue(computedValue);
                }

                prj.setLastUpdated(getLatestTreeUpdateDate());
                prj.addHistoricValue();
                logger.debug(" [" + qoValueSum + "] denominator [" + denominator + "] " + computedValue);
                // End Project node treatment 
            }

            // Get a (possible) suggestion for the tree node
            Multimap<?, ?> suggestions = getSuggestionForNode(node);
            //TODO: take all the suggestions into account
            Object[] types = suggestions.keys().toArray();
            Object[] suggestionsValues = suggestions.values().toArray();
            if (types.length > 0) {
                // for now use the first item as suggestion
                SuggestionType stype = (SuggestionType) types[0];
                node.setSuggestionType(stype);
                if (suggestionsValues[0] != null && !suggestionsValues[0].equals("")) {
                    node.setSuggestionValue((String) suggestionsValues[0]);
                }
            }

            treeNodeService.update(node);

        } catch (NamingException e) {
            e.printStackTrace();
        }

        return;
    }

    /**
      * Takes care of computing the tree values (update metrics and 
      * compute QO/QI values based on that) starting from the root node.
      * @param projectRoot Node
      */
    public static void updateTreeWithParticularNode(TreeNode projectRoot, TreeNode projectTreeNode) {
        // Create a timestamp at the start of the tree update so that 
        // all the updated entities have the same value for the date. 
        setLatestTreeUpdateDate(new Date());
        logger.info("Updating the QA Project tree...");
        postorderWithParticularNode(projectRoot, projectTreeNode);
    }

    /**
     * Traverse the tree in postorder and update tree values
     * @param node
     */
    private static void postorderWithParticularNode(TreeNode node, TreeNode projectTreeNode) {

        if (node == null) {
            return;
        }

        if (projectTreeNode == null) {
            return;
        }

        logger.debug("------------postorder: " + projectTreeNode.getName() + "---------------");

        logger.debug("Traversing project tree in postorder..." + projectTreeNode.toString());
        // Update the value
        try {
            InitialContext ic = new InitialContext();
            AdapterDataService adapterDataService = new AdapterDataService();
            TreeNodeService treeNodeService = (TreeNodeService) ic.lookup("java:module/TreeNodeService");

            if (projectTreeNode instanceof Metric) {
                Metric metric = (Metric) projectTreeNode;
                logger.debug("Recomputing the value of the Metric " + projectTreeNode);
                Float value = null;
                if (metric.getMetricSource() == MetricSource.Manual) {
                    metric.updateQualityStatus();
                } else {
                    value = adapterDataService.getMetricValue(metric.getMetricSource(), metric.getMetricType(),
                            metric.getProject());
                    metric.setValue(value);
                }
                metric.setLastUpdated(getLatestTreeUpdateDate());
                metric.addHistoricValue();
                // End Metric node treatment 
            } else if (projectTreeNode instanceof QualityIndicator) {
                logger.info("Recomputing the value of the Quality Indicator " + projectTreeNode);
                QualityIndicator qi = (QualityIndicator) projectTreeNode;
                if (qi.getUseFormula()) {
                    String formulaToEval = Formula.parseFormula(qi.getViewFormula());
                    if (formulaToEval != null && !formulaToEval.isEmpty()) {

                        Float computedValue = Formula.evalFormula(formulaToEval);
                        if (computedValue != null && !computedValue.isNaN()) {
                            qi.setValue(computedValue);
                            qi.setLastUpdated(getLatestTreeUpdateDate());
                            treeNodeService.update(qi);
                        }

                    }
                } else {
                    float achieved = 0;
                    float denominator = 0;
                    for (final TreeNode me : qi.getChildren()) {
                        float weight = ((Metric) me).getWeight();
                        if (me.getQualityStatus() == QualityStatus.Green) {
                            achieved += weight;
                        }
                        denominator += weight;
                    }
                    if (denominator == 0)
                        qi.getChildren().size();
                    qi.setValue(achieved * 100 / denominator);
                }
                qi.setLastUpdated(getLatestTreeUpdateDate());
                qi.addHistoricValue();
                // End Q.Indicator node treatment 
            } else if (projectTreeNode instanceof QualityObjective) {
                logger.info("Recomputing the value of the Quality Objective " + projectTreeNode);
                QualityObjective qo = (QualityObjective) projectTreeNode;
                if (qo.getUseFormula()) {
                    String formulaToEval = Formula.parseFormula(qo.getViewFormula());
                    if (formulaToEval != null && !formulaToEval.isEmpty()) {

                        Float computedValue = Formula.evalFormula(formulaToEval);
                        if (computedValue != null && !computedValue.isNaN()) {
                            qo.setValue(computedValue);
                            qo.setLastUpdated(getLatestTreeUpdateDate());
                        }

                    }
                } else {
                    float denominator = 0;
                    float achieved = 0;
                    for (final TreeNode qi : qo.getChildren()) {
                        float weight = ((QualityIndicator) qi).getWeight();
                        if (qi.getQualityStatus() == QualityStatus.Green) {
                            achieved += weight;
                        }
                        denominator += weight;
                    }
                    qo.setValue(achieved * 100 / denominator);
                }
                qo.setLastUpdated(getLatestTreeUpdateDate());
                qo.addHistoricValue();
                // End Quality Objective node treatment 
            } else if (projectTreeNode instanceof Project) {
                logger.info("Recomputing the value of the Project " + projectTreeNode);
                Project prj = (Project) projectTreeNode;
                double qoValueSum = 0;
                double denominator = 0;
                for (Object o : projectTreeNode.getChildren()) {
                    QualityObjective qo = (QualityObjective) o;
                    if (qo.getWeight() == 0) {
                        continue;
                    }
                    qoValueSum += qo.getValue() * (prj.isFormulaAverage() ? qo.getWeight() : 1);
                    denominator += prj.isFormulaAverage() ? qo.getWeight() : 1;
                }

                // bad idea to divide something under 0
                if (denominator == 0) {
                    denominator = 1;
                }

                Double computedValue = qoValueSum / denominator;

                if (computedValue != null && !computedValue.isNaN() && !computedValue.isInfinite()) {
                    prj.setValue(computedValue);
                }

                prj.setLastUpdated(getLatestTreeUpdateDate());
                prj.addHistoricValue();
                logger.debug(" [" + qoValueSum + "] denominator [" + denominator + "] " + computedValue);
                // End Project node treatment 
            }

            // Get a (possible) suggestion for the tree node
            Multimap<?, ?> suggestions = getSuggestionForNode(projectTreeNode);
            //TODO: take all the suggestions into account
            Object[] types = suggestions.keys().toArray();
            Object[] suggestionsValues = suggestions.values().toArray();
            if (types.length > 0) {
                // for now use the first item as suggestion
                SuggestionType stype = (SuggestionType) types[0];
                projectTreeNode.setSuggestionType(stype);
                if (suggestionsValues[0] != null && !suggestionsValues[0].equals("")) {
                    projectTreeNode.setSuggestionValue((String) suggestionsValues[0]);
                }
            }

            treeNodeService.update(projectTreeNode);

        } catch (NamingException e) {
            e.printStackTrace();
        }

        // Iterate the node children
        TreeNode nodeChild = projectTreeNode.getParent();
        UQasarUtil.postorderWithParticularNode(projectTreeNode, nodeChild);

        return;
    }

    /**
     * 
     * @param node Node whose value is studied
     * @return
     */
    private static Multimap<SuggestionType, Object> getSuggestionForNode(TreeNode node) {

        // For storing the suggestion type and the payload
        Multimap<SuggestionType, Object> suggestionsMultimap = ArrayListMultimap.create();

        final String EMPTY = "";

        try {
            InitialContext ic = new InitialContext();
            ProjectSimilarityService projectSimilarityService = (ProjectSimilarityService) ic
                    .lookup("java:module/ProjectSimilarityService");
            QualityObjectiveSimilarityService qoSimilarityService = (QualityObjectiveSimilarityService) ic
                    .lookup("java:module/QualityObjectiveSimilarityService");
            //TODO: Finding similar metrics

            if (node instanceof QualityObjective) {
                QualityObjective qo = (QualityObjective) node;
                Float value = qo.getValue();

                // If the value of a quality objective cannot be computed, 
                // attempt to obtain a suggestion             
                if (value == null || value.isNaN()) {
                    // Attempt to find a suitable project 
                    Project proj = qo.getProject();
                    Project similarProject = null;
                    if (proj != null) {
                        // Get a list of similar projects
                        List<Project> similarProjects = projectSimilarityService.getSimilarProjects(proj);
                        if (similarProjects != null && similarProjects.size() > 0) {
                            // For now obtain the first suitable project
                            similarProject = similarProjects.get(0);
                        }
                    }

                    // If a suitable similar project was found, search for similar Quality Objective(s) to be suggested
                    if (similarProject != null) {
                        // Get similar QOs from a similar project
                        List<QualityObjective> qos = qoSimilarityService.getSimilarQOs(qo, similarProject);
                        // If results were found, construct a suggestion (for now obtain the first one). 
                        if (qos != null && qos.size() > 0) {
                            suggestionsMultimap.put(SuggestionType.QO_REPLACE, qos.get(0));
                            return suggestionsMultimap;
                        }
                    }

                    // Otherwise suggest the QO to be removed
                    suggestionsMultimap.put(SuggestionType.QO_REMOVE, null);
                    return suggestionsMultimap;
                }
            }
            // if a metric has no value / the value is 0, return a suggestion to 
            // remove the metric 
            if (node instanceof Metric) {

                Metric metric = (Metric) node;
                Float value = metric.getValue();

                if (value == null || value.isNaN() || value.isInfinite()) {
                    suggestionsMultimap.put(SuggestionType.METRIC_REMOVE, null);
                    return suggestionsMultimap;
                }
            }
        } catch (NamingException e) {
            e.printStackTrace();
        }

        // If no suggestion is to be provided, return an empty string 
        // (overwrite the possible existing suggestion). 
        suggestionsMultimap.put(SuggestionType.NO_SUGGESTION, "");
        return suggestionsMultimap;
    }

    /**
     * Get a list of Jenkins metrics
     * @return
     */
    public static List<String> getJenkinsMetricNames() {
        String metrics[] = { "JENKINS_PROJECTS", // Jenkins projects
                "JENKINS_LATEST_BUILD_SUCCESS", // State of the latest build
                "JENKINS_BUILD_HISTORY", };

        return Arrays.asList(metrics);
    }

    /**
     * Uses the classes from the DB to write the RDF files based on those.
     */
    public static void writeSemanticModelFiles() {
        logger.debug("Writing the context model to a file");

        // TODO: Complement the model with the other required entities 
        OntModel usersModel = writeUserEntries();
        OntModel projectsModel = writeProjectEntries();
        OntModel metadataModel = writeMetaDataModelEntries();

        //   uqModel.write(System.out, "RDF/XML");
        //   RDFDataMgr.write(System.out, uqModel, RDFFormat.RDFXML_PRETTY);

        // Write the individual models to a single file
        // holding all the triples
        final OntModel combined = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
        for (final OntModel part : new OntModel[] { usersModel, projectsModel, metadataModel }) {
            combined.add(part);
        }
        try {
            String dataDir = UQasarUtil.getDataDirPath();
            // TODO: Find out why this does not work in Linux
            //         String modelPath = "file:///" + dataDir + ONTOLOGYFILE;
            String modelPath = dataDir + ONTOLOGYFILE;

            combined.write(new FileOutputStream(modelPath, false));
            logger.debug("Context Model written to file " + modelPath);
            UQasarUtil.setUqModel(combined);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Writes the user entities to rdf
     */
    private static OntModel writeUserEntries() {
        OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
        try {
            thewebsemantic.Bean2RDF writer = new Bean2RDF(model);
            InitialContext ic = new InitialContext();
            UserService userService = (UserService) ic.lookup("java:module/UserService");
            List<User> users = userService.getAll();
            for (User u : users) {
                writer.save(u);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return model;
    }

    /**
     * Writes the project entities to rdf
     */
    private static OntModel writeProjectEntries() {
        OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
        try {
            thewebsemantic.Bean2RDF writer = new Bean2RDF(model);
            InitialContext ic = new InitialContext();
            TreeNodeService treeNodeService = (TreeNodeService) ic.lookup("java:module/TreeNodeService");
            List<Project> projects = treeNodeService.getAllProjects();
            for (Project proj : projects) {
                writer.save(proj);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return model;
    }

    /**
     * Write metadata entities from the beans to rdf model
     */
    private static OntModel writeMetaDataModelEntries() {
        OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
        thewebsemantic.Bean2RDF writer = new Bean2RDF(model);
        try {
            InitialContext ic = new InitialContext();
            for (final Class clazz : MetaData.getAllClasses()) {
                if (ContinuousIntegrationTool.class.isAssignableFrom(clazz)) {
                    ContinuousIntegrationToolService cits = (ContinuousIntegrationToolService) ic
                            .lookup("java:module/ContinuousIntegrationToolService");
                    List<ContinuousIntegrationTool> continuousIntegrationTools = cits.getAll();
                    for (ContinuousIntegrationTool continuousIntegrationTool : continuousIntegrationTools) {
                        writer.save(continuousIntegrationTool);
                    }
                } else if (CustomerType.class.isAssignableFrom(clazz)) {
                    CustomerTypeService cts = (CustomerTypeService) ic.lookup("java:module/CustomerTypeService");
                    List<CustomerType> customerTypes = cts.getAll();
                    for (CustomerType customerType : customerTypes) {
                        writer.save(customerType);
                    }
                } else if (IssueTrackingTool.class.isAssignableFrom(clazz)) {
                    IssueTrackingToolService itts = (IssueTrackingToolService) ic
                            .lookup("java:module/IssueTrackingToolService");
                    List<IssueTrackingTool> issueTrackingTools = itts.getAll();
                    for (IssueTrackingTool issueTrackingTool : issueTrackingTools) {
                        writer.save(issueTrackingTool);
                    }
                } else if (ProgrammingLanguage.class.isAssignableFrom(clazz)) {
                    ProgrammingLanguageService pls = (ProgrammingLanguageService) ic
                            .lookup("java:module/ProgrammingLanguageService");
                    List<ProgrammingLanguage> programmingLanguages = pls.getAll();
                    for (ProgrammingLanguage programmingLanguage : programmingLanguages) {
                        writer.save(programmingLanguage);
                    }
                } else if (ProjectType.class.isAssignableFrom(clazz)) {
                    ProjectTypeService pts = (ProjectTypeService) ic.lookup("java:module/ProjectTypeService");
                    List<ProjectType> projectTypes = pts.getAll();
                    for (ProjectType projectType : projectTypes) {
                        writer.save(projectType);
                    }
                } else if (SoftwareLicense.class.isAssignableFrom(clazz)) {
                    SoftwareLicenseService sls = (SoftwareLicenseService) ic
                            .lookup("java:module/SoftwareLicenseService");
                    List<SoftwareLicense> softwareLicenses = sls.getAll();
                    for (SoftwareLicense softwareLicense : softwareLicenses) {
                        writer.save(softwareLicense);
                    }
                } else if (SoftwareType.class.isAssignableFrom(clazz)) {
                    SoftwareTypeService sts = (SoftwareTypeService) ic.lookup("java:module/SoftwareTypeService");
                    List<SoftwareType> softwareTypes = sts.getAll();
                    for (SoftwareType softwareType : softwareTypes) {
                        writer.save(softwareType);
                    }
                } else if (SourceCodeManagementTool.class.isAssignableFrom(clazz)) {
                    SourceCodeManagementToolService scmts = (SourceCodeManagementToolService) ic
                            .lookup("java:module/SourceCodeManagementToolService");
                    List<SourceCodeManagementTool> sourceCodeManagementTools = scmts.getAll();
                    for (SourceCodeManagementTool sourceCodeManagementTool : sourceCodeManagementTools) {
                        writer.save(sourceCodeManagementTool);
                    }
                } else if (StaticAnalysisTool.class.isAssignableFrom(clazz)) {
                    StaticAnalysisToolService sats = (StaticAnalysisToolService) ic
                            .lookup("java:module/StaticAnalysisToolService");
                    List<StaticAnalysisTool> staticAnalysisTools = sats.getAll();
                    for (StaticAnalysisTool staticAnalysisTool : staticAnalysisTools) {
                        writer.save(staticAnalysisTool);
                    }
                } else if (TestManagementTool.class.isAssignableFrom(clazz)) {
                    TestManagementToolService tmts = (TestManagementToolService) ic
                            .lookup("java:module/TestManagementToolService");
                    List<TestManagementTool> testManagementTools = tmts.getAll();
                    for (TestManagementTool testManagementTool : testManagementTools) {
                        writer.save(testManagementTool);
                    }
                } else if (Topic.class.isAssignableFrom(clazz)) {
                    TopicService ts = (TopicService) ic.lookup("java:module/TopicService");
                    List<Topic> topics = ts.getAll();
                    for (Topic topic : topics) {
                        writer.save(topic);
                    }
                } else if (SoftwareDevelopmentMethodology.class.isAssignableFrom(clazz)) {
                    SoftwareDevelopmentMethodologyService sdms = (SoftwareDevelopmentMethodologyService) ic
                            .lookup("java:module/SoftwareDevelopmentMethodologyService");
                    List<SoftwareDevelopmentMethodology> softwareDevelopmentMethodologies = sdms.getAll();
                    for (SoftwareDevelopmentMethodology softwareDevelopmentMethodology : softwareDevelopmentMethodologies) {
                        writer.save(softwareDevelopmentMethodology);
                    }
                } else if (QModelTagData.class.isAssignableFrom(clazz)) {
                    QModelTagDataService qmtds = (QModelTagDataService) ic
                            .lookup("java:module/QModelTagDataService");
                    List<QModelTagData> qmodelTagData = qmtds.getAll();
                    for (QModelTagData qmtd : qmodelTagData) {
                        writer.save(qmtd);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return model;
    }

    /**
     * Read the RDF model from files.
     */
    public static void readSemanticModelFiles() {
        logger.debug("Reading the model from a file");
        // Read the model to an existing model
        String dataDir = UQasarUtil.getDataDirPath();
        String modelPath = "file:///" + dataDir + ONTOLOGYFILE;
        //      String modelPath = "file:///C:/nyrhinen/Programme/jboss-as-7.1.1.Final/standalone/data/uq-ontology-model.rdf";

        OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
        RDFDataMgr.read(model, modelPath);
        // Test output to standard output
        //      RDFDataMgr.write(System.out, uqModel, RDFFormat.RDFXML_PRETTY);
        logger.debug("Model read from file " + modelPath);
        UQasarUtil.setUqModel(model);
        System.out.println("Reading done.");
    }

    public static String execSparQLQuery(String query) {
        System.out.println("execSPINQuery");
        Model model = getUqModel();

        // Register system functions (such as sp:gt (>))
        SPINModuleRegistry.get().init();

        Query arqQuery = ARQFactory.get().createQuery(model, query);
        ARQ2SPIN arq2SPIN = new ARQ2SPIN(model);
        Select spinQuery = (Select) arq2SPIN.createQuery(arqQuery, null);

        System.out.println("SPIN query in Turtle:");
        model.write(System.out, FileUtils.langTurtle);

        System.out.println("-----");
        String str = spinQuery.toString();
        System.out.println("SPIN query:\n" + str);

        // Now turn it back into a Jena Query
        Query parsedBack = ARQFactory.get().createQuery(spinQuery);
        System.out.println("Jena query:\n" + parsedBack);

        com.hp.hpl.jena.query.Query arq = ARQFactory.get().createQuery(spinQuery);
        QueryExecution qexec = ARQFactory.get().createQueryExecution(arq, model);
        QuerySolutionMap arqBindings = new QuerySolutionMap();
        arqBindings.add("predicate", RDFS.label);
        qexec.setInitialBinding(arqBindings); // Pre-assign the arguments
        ResultSet rs = qexec.execSelect();

        //      System.out.println("#####################################################################");
        //      
        //      if (rs.hasNext()) {
        //         QuerySolution row = rs.next();
        //         System.out.println("Row: " +row.toString());
        //         RDFNode user = row.get("User");
        //         Literal label = row.getLiteral("label");
        //         System.out.println(user.toString());
        //      }
        //      RDFNode object = rs.next().get("object");
        //      System.out.println("Label is " + object);

        Collection<User> users = Sparql.exec(getUqModel(), User.class, query);

        String usersString = "";
        for (User user : users) {
            System.out.println("User: " + user.toString());
            usersString += user.toString() + "<br/>";
        }

        System.out.println("execSPINQuery() done.");
        return usersString;
    }

}