<commit_before>package it.unibz.krdb.obda.io;

import it.unibz.krdb.obda.exception.DuplicateMappingException;
import it.unibz.krdb.obda.exception.UnsupportedTagException;
import it.unibz.krdb.obda.gui.swing.exception.Indicator;
import it.unibz.krdb.obda.gui.swing.exception.InvalidMappingException;
import it.unibz.krdb.obda.gui.swing.exception.InvalidPredicateDeclarationException;
import it.unibz.krdb.obda.model.CQIE;
import it.unibz.krdb.obda.model.OBDADataFactory;
import it.unibz.krdb.obda.model.OBDADataSource;
import it.unibz.krdb.obda.model.OBDAMappingAxiom;
import it.unibz.krdb.obda.model.OBDAModel;
import it.unibz.krdb.obda.model.OBDAQuery;
import it.unibz.krdb.obda.model.impl.RDBMSourceParameterConstants;
import it.unibz.krdb.obda.parser.TargetQueryParser;
import it.unibz.krdb.obda.parser.TargetQueryParserException;
import it.unibz.krdb.obda.parser.TurtleOBDASyntaxParser;
import it.unibz.krdb.obda.parser.TurtleSyntaxParser;
import it.unibz.krdb.obda.parser.UnparsableTargetQueryException;
import it.unibz.krdb.obda.renderer.SourceQueryRenderer;
import it.unibz.krdb.obda.renderer.TargetQueryRenderer;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class manages saving and loading an OBDA file.
 */
public class ModelIOManager {

    private enum Label {
        /* Source decl.: */sourceUri, connectionUrl, username, password, driverClass,
        /* Mapping decl.: */mappingId, target, source
    }

    private static final String PREFIX_DECLARATION_TAG = "[PrefixDeclaration]";
    private static final String CLASS_DECLARATION_TAG = "[ClassDeclaration]";
    private static final String OBJECT_PROPERTY_DECLARATION_TAG = "[ObjectPropertyDeclaration]";
    private static final String DATA_PROPERTY_DECLARATION_TAG = "[DataPropertyDeclaration]";
    private static final String SOURCE_DECLARATION_TAG = "[SourceDeclaration]";
    private static final String MAPPING_DECLARATION_TAG = "[MappingDeclaration]";

    private static final String START_COLLECTION_SYMBOL = "@collection [[";
    private static final String END_COLLECTION_SYMBOL = "]]";
    private static final String COMMENT_SYMBOL = ";";
    
    private OBDAModel model;
    private PrefixManager prefixManager;
    private OBDADataFactory dataFactory;
    
    private List<Indicator> invalidMappingIndicators = new ArrayList<Indicator>();
    
    private List<TargetQueryParser> listOfParsers = new ArrayList<TargetQueryParser>();
    
    private static final Logger log = LoggerFactory.getLogger(ModelIOManager.class);
    
    /**
     * Create an IO manager for saving/loading the OBDA model.
     * 
     * @param model
     *          The target OBDA model.
     */
    public ModelIOManager(OBDAModel model) {
        this.model = model;
        prefixManager = model.getPrefixManager();
        dataFactory = model.getDataFactory();

        // Register available parsers for target query
        register(new TurtleOBDASyntaxParser(prefixManager));
        register(new TurtleSyntaxParser(prefixManager));
    }
    
    private void register(TargetQueryParser parser) {
    	listOfParsers.add(parser);
    }

    private List<TargetQueryParser> getParsers() {
    	return listOfParsers;
    }
    
    /**
     * The save/write operation.
     * 
     * @param fileLocation
     *          The target file location to which the model is saved.
     * @throws IOException
     */
    public void save(String fileLocation) throws IOException {
        save(new File(fileLocation));
    }

    /**
     * The save/write operation.
     * 
     * @param file
     *          The target file object to which the model is saved.
     * @throws IOException
     */
    public void save(File file) throws IOException {
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(file));
            writePrefixDeclaration(writer);
            for (OBDADataSource source : model.getSources()) {
                writeSourceDeclaration(source, writer);
                writeMappingDeclaration(source, writer);
            }
            writer.flush();
            writer.close();
        } catch (IOException e) {
            throw new IOException(String.format("Error while saving the OBDA model to file located at %s.\n" +
                    "Make sure you have the write permission at the location specified.", file.getAbsolutePath()));
        }
    }

    /**
     * The load/read operation.
     * 
     * @param fileLocation
     *          The target file location from which the model is loaded.
     * @throws IOException
     * @throws InvalidPredicateDeclarationException
     * @throws InvalidMappingException 
     */
    public void load(String fileLocation) throws IOException, InvalidPredicateDeclarationException, InvalidMappingException {
        load(new File(fileLocation));
    }
    
    /**
     * The load/read operation.
     * 
     * @param fileLocation
     *          The target file object from which the model is loaded.
     * @throws IOException
     * @throws InvalidPredicateDeclarationException
     * @throws InvalidMappingException 
     */
    public void load(File file) throws IOException, InvalidMappingException {
        if (!file.exists()) {
            log.warn("WARNING: Cannot locate OBDA file at: " + file.getPath());
            return;
        }
        if (!file.canRead()) {
            throw new IOException(String.format("Error while reading the file located at %s.\n" +
                    "Make sure you have the read permission at the location specified.", file.getAbsolutePath()));
        }
        
        // Clean the model first before loading
        model.reset();
        
        LineNumberReader reader = new LineNumberReader(new FileReader(file));
        String line = "";
        URI sourceUri = null;
        while ((line = reader.readLine()) != null) {
        	try {
	            if (isCommentLine(line) || line.isEmpty()) {
	                continue; // skip comment lines and blank lines
	            }
	            if (line.contains(PREFIX_DECLARATION_TAG)) {
	                readPrefixDeclaration(reader);
	            } else if (line.contains(CLASS_DECLARATION_TAG)) {
	            	// deprecated tag
	            	throw new UnsupportedTagException(CLASS_DECLARATION_TAG);
	            } else if (line.contains(OBJECT_PROPERTY_DECLARATION_TAG)) {
	            	// deprecated tag
	            	throw new UnsupportedTagException(OBJECT_PROPERTY_DECLARATION_TAG);
	            } else if (line.contains(DATA_PROPERTY_DECLARATION_TAG)) {
	            	// deprecated tag
	            	throw new UnsupportedTagException(DATA_PROPERTY_DECLARATION_TAG);
	            } else if (line.contains(SOURCE_DECLARATION_TAG)) {
	                sourceUri = readSourceDeclaration(reader);
	            } else if (line.contains(MAPPING_DECLARATION_TAG)) {
	                readMappingDeclaration(reader, sourceUri);
	            } else {
	                throw new IOException("Unknown syntax: " + line);
	            }
        	} catch (Exception e) {
        		throw new IOException(String.format("Problem at line: %s", reader.getLineNumber()), e);
        	}
        }
        
        // Throw some validation exceptions
        if (!invalidMappingIndicators.isEmpty()) {
            throw new InvalidMappingException(invalidMappingIndicators);
        }
    }

    /*
     * Helper methods related to save file.
     */

    private void writePrefixDeclaration(BufferedWriter writer) throws IOException {
        final Map<String, String> prefixMap = model.getPrefixManager().getPrefixMap();

        if (prefixMap.size() == 0) {
            return; // do nothing if there is no prefixes to write
        }

        writer.write(PREFIX_DECLARATION_TAG);
        writer.write("\n");
        for (String prefix : prefixMap.keySet()) {
            String uri = prefixMap.get(prefix);
            writer.write(prefix + (prefix.length() >= 9 ? "\t" : "\t\t") + uri + "\n");
        }
        writer.write("\n");
    }
    
    private void writeSourceDeclaration(OBDADataSource source, BufferedWriter writer) throws IOException {
        writer.write(SOURCE_DECLARATION_TAG);<commit_msg>Improved Exception message when cannot read .obda file due to unsupported tags<commit_after>package it.unibz.krdb.obda.io;

import it.unibz.krdb.obda.exception.DuplicateMappingException;
import it.unibz.krdb.obda.exception.UnsupportedTagException;
import it.unibz.krdb.obda.gui.swing.exception.Indicator;
import it.unibz.krdb.obda.gui.swing.exception.InvalidMappingException;
import it.unibz.krdb.obda.gui.swing.exception.InvalidPredicateDeclarationException;
import it.unibz.krdb.obda.model.CQIE;
import it.unibz.krdb.obda.model.OBDADataFactory;
import it.unibz.krdb.obda.model.OBDADataSource;
import it.unibz.krdb.obda.model.OBDAMappingAxiom;
import it.unibz.krdb.obda.model.OBDAModel;
import it.unibz.krdb.obda.model.OBDAQuery;
import it.unibz.krdb.obda.model.impl.RDBMSourceParameterConstants;
import it.unibz.krdb.obda.parser.TargetQueryParser;
import it.unibz.krdb.obda.parser.TargetQueryParserException;
import it.unibz.krdb.obda.parser.TurtleOBDASyntaxParser;
import it.unibz.krdb.obda.parser.TurtleSyntaxParser;
import it.unibz.krdb.obda.parser.UnparsableTargetQueryException;
import it.unibz.krdb.obda.renderer.SourceQueryRenderer;
import it.unibz.krdb.obda.renderer.TargetQueryRenderer;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class manages saving and loading an OBDA file.
 */
public class ModelIOManager {

    private enum Label {
        /* Source decl.: */sourceUri, connectionUrl, username, password, driverClass,
        /* Mapping decl.: */mappingId, target, source
    }

    private static final String PREFIX_DECLARATION_TAG = "[PrefixDeclaration]";
    private static final String CLASS_DECLARATION_TAG = "[ClassDeclaration]";
    private static final String OBJECT_PROPERTY_DECLARATION_TAG = "[ObjectPropertyDeclaration]";
    private static final String DATA_PROPERTY_DECLARATION_TAG = "[DataPropertyDeclaration]";
    private static final String SOURCE_DECLARATION_TAG = "[SourceDeclaration]";
    private static final String MAPPING_DECLARATION_TAG = "[MappingDeclaration]";

    private static final String START_COLLECTION_SYMBOL = "@collection [[";
    private static final String END_COLLECTION_SYMBOL = "]]";
    private static final String COMMENT_SYMBOL = ";";
    
    private OBDAModel model;
    private PrefixManager prefixManager;
    private OBDADataFactory dataFactory;
    
    private List<Indicator> invalidMappingIndicators = new ArrayList<Indicator>();
    
    private List<TargetQueryParser> listOfParsers = new ArrayList<TargetQueryParser>();
    
    private static final Logger log = LoggerFactory.getLogger(ModelIOManager.class);
    
    /**
     * Create an IO manager for saving/loading the OBDA model.
     * 
     * @param model
     *          The target OBDA model.
     */
    public ModelIOManager(OBDAModel model) {
        this.model = model;
        prefixManager = model.getPrefixManager();
        dataFactory = model.getDataFactory();

        // Register available parsers for target query
        register(new TurtleOBDASyntaxParser(prefixManager));
        register(new TurtleSyntaxParser(prefixManager));
    }
    
    private void register(TargetQueryParser parser) {
    	listOfParsers.add(parser);
    }

    private List<TargetQueryParser> getParsers() {
    	return listOfParsers;
    }
    
    /**
     * The save/write operation.
     * 
     * @param fileLocation
     *          The target file location to which the model is saved.
     * @throws IOException
     */
    public void save(String fileLocation) throws IOException {
        save(new File(fileLocation));
    }

    /**
     * The save/write operation.
     * 
     * @param file
     *          The target file object to which the model is saved.
     * @throws IOException
     */
    public void save(File file) throws IOException {
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(file));
            writePrefixDeclaration(writer);
            for (OBDADataSource source : model.getSources()) {
                writeSourceDeclaration(source, writer);
                writeMappingDeclaration(source, writer);
            }
            writer.flush();
            writer.close();
        } catch (IOException e) {
            throw new IOException(String.format("Error while saving the OBDA model to file located at %s.\n" +
                    "Make sure you have the write permission at the location specified.", file.getAbsolutePath()));
        }
    }

    /**
     * The load/read operation.
     * 
     * @param fileLocation
     *          The target file location from which the model is loaded.
     * @throws IOException
     * @throws InvalidPredicateDeclarationException
     * @throws InvalidMappingException 
     */
    public void load(String fileLocation) throws IOException, InvalidPredicateDeclarationException, InvalidMappingException {
        load(new File(fileLocation));
    }
    
    /**
     * The load/read operation.
     * 
     * @param fileLocation
     *          The target file object from which the model is loaded.
     * @throws IOException
     * @throws InvalidPredicateDeclarationException
     * @throws InvalidMappingException 
     */
    public void load(File file) throws IOException, InvalidMappingException {
        if (!file.exists()) {
            log.warn("WARNING: Cannot locate OBDA file at: " + file.getPath());
            return;
        }
        if (!file.canRead()) {
            throw new IOException(String.format("Error while reading the file located at %s.\n" +
                    "Make sure you have the read permission at the location specified.", file.getAbsolutePath()));
        }
        
        // Clean the model first before loading
        model.reset();
        
        LineNumberReader reader = new LineNumberReader(new FileReader(file));
        String line = "";
        URI sourceUri = null;
        while ((line = reader.readLine()) != null) {
        	try {
	            if (isCommentLine(line) || line.isEmpty()) {
	                continue; // skip comment lines and blank lines
	            }
	            if (line.contains(PREFIX_DECLARATION_TAG)) {
	                readPrefixDeclaration(reader);
	            } else if (line.contains(CLASS_DECLARATION_TAG)) {
	            	// deprecated tag
	            	throw new UnsupportedTagException(CLASS_DECLARATION_TAG);
	            } else if (line.contains(OBJECT_PROPERTY_DECLARATION_TAG)) {
	            	// deprecated tag
	            	throw new UnsupportedTagException(OBJECT_PROPERTY_DECLARATION_TAG);
	            } else if (line.contains(DATA_PROPERTY_DECLARATION_TAG)) {
	            	// deprecated tag
	            	throw new UnsupportedTagException(DATA_PROPERTY_DECLARATION_TAG);
	            } else if (line.contains(SOURCE_DECLARATION_TAG)) {
	                sourceUri = readSourceDeclaration(reader);
	            } else if (line.contains(MAPPING_DECLARATION_TAG)) {
	                readMappingDeclaration(reader, sourceUri);
	            } else {
	                throw new IOException("Unknown syntax: " + line);
	            }
        	} catch (Exception e) {
        		throw new IOException(String.format("ERROR reading .obda file at line: %s", reader.getLineNumber() + " \nMESSAGE: " + e.getMessage()), e);
        	}
        }
        
        // Throw some validation exceptions
        if (!invalidMappingIndicators.isEmpty()) {
            throw new InvalidMappingException(invalidMappingIndicators);
        }
    }

    /*
     * Helper methods related to save file.
     */

    private void writePrefixDeclaration(BufferedWriter writer) throws IOException {
        final Map<String, String> prefixMap = model.getPrefixManager().getPrefixMap();

        if (prefixMap.size() == 0) {
            return; // do nothing if there is no prefixes to write
        }

        writer.write(PREFIX_DECLARATION_TAG);
        writer.write("\n");
        for (String prefix : prefixMap.keySet()) {
            String uri = prefixMap.get(prefix);
            writer.write(prefix + (prefix.length() >= 9 ? "\t" : "\t\t") + uri + "\n");
        }
        writer.write("\n");
    }
    
    private void writeSourceDeclaration(OBDADataSource source, BufferedWriter writer) throws IOException {
        writer.write(SOURCE_DECLARATION_TAG);
{'fraction_non_alphanumeric': 0.09311150029188558, 'fraction_numerical': 0.0004670169293636894, 'mean_word_length': 2.708811431045681, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3020923', 'n_tokens_mistral': 4729, 'n_tokens_neox': 4658, 'n_words': 1124}