All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.antidot.semantic.rdf.rdb2rdf.r2rml.model.AbstractTermMap Maven / Gradle / Ivy

There is a newer version: 2.2
Show newest version
/* 
 * Copyright 2011 Antidot [email protected]
 * https://github.com/antidot/db2triples
 * 
 * DB2Triples is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of 
 * the License, or (at your option) any later version.
 * 
 * DB2Triples is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
/***************************************************************************
 *
 * R2RML Model : Abstract Term Map 
 *
 * Partial implementation of a term map.
 *
 ****************************************************************************/
package net.antidot.semantic.rdf.rdb2rdf.r2rml.model;

import java.io.UnsupportedEncodingException;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import net.antidot.semantic.rdf.model.tools.RDFDataValidator;
import net.antidot.semantic.rdf.rdb2rdf.commons.SQLToXMLS;
import net.antidot.semantic.rdf.rdb2rdf.r2rml.exception.InvalidR2RMLStructureException;
import net.antidot.semantic.rdf.rdb2rdf.r2rml.exception.InvalidR2RMLSyntaxException;
import net.antidot.semantic.rdf.rdb2rdf.r2rml.exception.R2RMLDataError;
import net.antidot.semantic.rdf.rdb2rdf.r2rml.tools.R2RMLToolkit;
import net.antidot.semantic.xmls.xsd.XSDLexicalTransformation;
import net.antidot.semantic.xmls.xsd.XSDType;
import net.antidot.sql.model.db.ColumnIdentifier;
import net.antidot.sql.model.db.ColumnIdentifierImpl;
import net.antidot.sql.model.tools.SQLDataValidator;
import net.antidot.sql.model.tools.SQLToolkit;
import net.antidot.sql.model.type.SQLType;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openrdf.model.Literal;
import org.openrdf.model.URI;
import org.openrdf.model.Value;

public abstract class AbstractTermMap implements TermMap {

	// Log
	private static Log log = LogFactory.getLog(AbstractTermMap.class);

	private Value constantValue;
	private XSDType dataType;
	private TermType termType;
	private XSDType implicitDataType;
	private String languageTag;
	private String stringTemplate;
	private ColumnIdentifier columnValue;
	private String inverseExpression;

	protected AbstractTermMap(Value constantValue, URI dataType,
			String languageTag, String stringTemplate, URI termType,
			String inverseExpression, ColumnIdentifier columnValue)
			throws R2RMLDataError, InvalidR2RMLStructureException,
			InvalidR2RMLSyntaxException {

		setConstantValue(constantValue);
		setColumnValue(columnValue);
		setLanguageTag(languageTag);
		setStringTemplate(stringTemplate);
		setTermType(termType, dataType);
		setDataType(dataType);

		setInversionExpression(inverseExpression);
		checkGlobalConsistency();
	}

	/**
	 * Check if the global structure of this TermMap is consistent and valid
	 * according to R2RML standard.
	 * 
	 * @throws InvalidR2RMLStructureException
	 */
	private void checkGlobalConsistency() throws InvalidR2RMLStructureException {
		// A term map must be exactly one term map type
		if (getTermMapType() == null)
			// In db2triples and contrary to the R2RML norm, we accepts
			// auto-assignments of blank nodes.
			if (getTermType() != TermType.BLANK_NODE)
				throw new InvalidR2RMLStructureException(
						"[AbstractTermMap:checkGlobalConsistency] A constant RDF Term,"
								+ " a column name or a string template must be specified.");

	}

	private void setInversionExpression(String inverseExpression)
			throws InvalidR2RMLSyntaxException, InvalidR2RMLStructureException {
		// An inverse expression is associated with
		// a column-valued term map or template-value term map
		if (inverseExpression != null && getTermMapType() != null
				&& getTermMapType() == TermMapType.CONSTANT_VALUED)
			throw new InvalidR2RMLStructureException(
					"[AbstractTermMap:setInversionExpression] An inverseExpression "
							+ "can not be associated with a constant-value term map.");
		// This property is optional
		if (inverseExpression != null)
			checkInverseExpression(inverseExpression);
		this.inverseExpression = inverseExpression;
	}

	private void checkInverseExpression(String inverseExpression)
			throws InvalidR2RMLSyntaxException {
		// An inverse expression must satisfy a lot of conditions
		if (!R2RMLToolkit.checkInverseExpression(inverseExpression))
			throw new InvalidR2RMLSyntaxException(
					"[AbstractTermMap:checkInverseExpression] Not a valid inverse "
							+ "expression : " + stringTemplate);

	}

	private void setColumnValue(ColumnIdentifier columnValue)
			throws InvalidR2RMLSyntaxException, InvalidR2RMLStructureException {
		// The value of the rr:column property MUST be a valid column name.
//		if (columnValue != null)
//			checkColumnValue(columnValue);
		this.columnValue = columnValue;
	}

//	private void checkColumnValue(String columnValue)
//			throws InvalidR2RMLSyntaxException {
//		if (!SQLDataValidator.isValidSQLIdentifier(columnValue))
//			throw new InvalidR2RMLSyntaxException(
//					"[AbstractTermMap:checkColumnValue] Not a valid column "
//							+ "value : " + termType);
//	}

	protected void setTermType(URI termType, URI dataType)
			throws InvalidR2RMLSyntaxException, R2RMLDataError,
			InvalidR2RMLStructureException {
		if (termType == null) {
			// If the term map does not have a rr:termType property :
			// rr:Literal by default, if it is an object map and at
			// least one of the following conditions is true
			if ((this instanceof StdObjectMap)
					&& (getColumnValue() != null || dataType != null
							|| getLanguageTag() != null || constantValue instanceof Literal)) {
				this.termType = TermType.LITERAL;
				log.debug("[AbstractTermMap:setTermType] No term type specified : use Literal by default.");
			} else {
				// otherwise its term type is IRI
				this.termType = TermType.IRI;
				log.debug("[AbstractTermMap:setTermType] No term type specified : use IRI by default.");
			}

		} else {
			TermType tt = null;

			if (termType != null)
				tt = checkTermType(termType);
			this.termType = tt;
		}
	}

	private TermType checkTermType(URI termType)
			throws InvalidR2RMLSyntaxException, InvalidR2RMLStructureException,
			R2RMLDataError {
		// Its value MUST be an IRI
		if (!RDFDataValidator.isValidURI(termType.stringValue()))
			throw new R2RMLDataError(
					"[AbstractTermMap:checkTermType] Not a valid URI : "
							+ termType);
		// (IRIs, blank nodes or literals)
		TermType tt = TermType.toTermType(termType.stringValue());
		if (tt == null)
			throw new InvalidR2RMLSyntaxException(
					"[AbstractTermMap:checkTermType] Not a valid term type : "
							+ termType);
		// Check rules in function of term map nature (subject, predicate ...)
		checkSpecificTermType(tt);
		return tt;
	}

	protected abstract void checkSpecificTermType(TermType tt)
			throws InvalidR2RMLStructureException;

	private void setStringTemplate(String stringTemplate)
			throws InvalidR2RMLSyntaxException, InvalidR2RMLStructureException {
		// he value of the rr:template property MUST be a
		// valid string template.
		if (stringTemplate != null)
			checkStringTemplate(stringTemplate);

		this.stringTemplate = stringTemplate;
	}

	/**
	 * A string template is a format string that can be used to build strings
	 * from multiple components. It can reference column names by enclosing them
	 * in curly braces.
	 * 
	 * @throws R2RMLDataError
	 */
	private void checkStringTemplate(String stringTemplate)
			throws InvalidR2RMLSyntaxException {
		// Its value MUST be an IRI
		if (!R2RMLToolkit.checkStringTemplate(stringTemplate))
			throw new InvalidR2RMLSyntaxException(
					"[AbstractTermMap:checkStringTemplate] Not a valid string "
							+ "template : " + stringTemplate);
	}

	private void setLanguageTag(String languageTag) throws R2RMLDataError {
		// its value MUST be a valid language tag
		if (languageTag != null)
			checkLanguageTag(languageTag);
		this.languageTag = languageTag;
	}

	/**
	 * Check if language tag is valid, as defined by [RFC-3066]
	 * 
	 * @throws R2RMLDataError
	 */
	private void checkLanguageTag(String languageTag) throws R2RMLDataError {
		// Its value MUST be an IRI
		if (!RDFDataValidator.isValidLanguageTag(languageTag))
			throw new R2RMLDataError(
					"[AbstractTermMap:checkLanguageTag] Not a valid language tag : "
							+ languageTag);
	}

	/**
	 * Check if constant value is correctly defined. Constant value is an IRI or
	 * literal in function of this term map type.
	 */
	protected abstract void checkConstantValue(Value constantValue)
			throws R2RMLDataError;

	public void setConstantValue(Value constantValue) throws R2RMLDataError,
			InvalidR2RMLStructureException {
		// Check if constant value is valid
		if (constantValue != null)
			checkConstantValue(constantValue);
		this.constantValue = constantValue;
	}

	/**
	 * Check if datatype is correctly defined.
	 * 
	 * @throws R2RMLDataError
	 */
	public void checkDataType(URI dataType) throws R2RMLDataError {
		// Its value MUST be an IRI
		if (!RDFDataValidator.isValidDatatype(dataType.stringValue()))
			throw new R2RMLDataError(
					"[AbstractTermMap:checkDataType] Not a valid URI : "
							+ dataType);
	}

	public void setDataType(URI dataType) throws R2RMLDataError,
			InvalidR2RMLStructureException {
		if (!isTypeable() && dataType != null)
			throw new InvalidR2RMLStructureException(
					"[AbstractTermMap:setDataType] A term map that is not "
							+ "a typeable term map MUST NOT have an rr:datatype"
							+ " property.");
		if (dataType != null) {
			// Check if datatype is valid
			checkDataType(dataType);
			this.dataType = XSDType.toXSDType(dataType.stringValue());
		}
	}

	public Value getConstantValue() {
		return constantValue;
	}

	public XSDType getDataType() {
		return dataType;
	}

	public XSDType getImplicitDataType() {
		return implicitDataType;
	}

	public XSDLexicalTransformation.Transformation getImplicitTransformation() {
		if (implicitDataType == null)
			return null;
		else
			return XSDLexicalTransformation
					.getLexicalTransformation(implicitDataType);
	}

	public String getInverseExpression() {
		return inverseExpression;
	}

	public String getLanguageTag() {
		return languageTag;
	}

	public Set getReferencedColumns() {
		Set referencedColumns = new HashSet();
		switch (getTermMapType()) {
		case CONSTANT_VALUED:
			// The referenced columns of a constant-valued term map is the
			// empty set.
			break;

		case COLUMN_VALUED:
			// The referenced columns of a column-valued term map is
			// the singleton set containing the value of rr:column.
			// referencedColumns.add(R2RMLToolkit.deleteBackSlash(columnValue));
			referencedColumns.add(columnValue);
			break;

		case TEMPLATE_VALUED:
			// The referenced columns of a template-valued term map is
			// the set of column names enclosed in unescaped curly braces
			// in the template string.
		    	for(String colName : R2RMLToolkit
					.extractColumnNamesFromStringTemplate(stringTemplate)) {
		    	    referencedColumns.add(ColumnIdentifierImpl.buildFromR2RMLConfigFile(colName));
		    	}
			break;

		default:
			break;
		}
		log.debug("[AbstractTermMap:getReferencedColumns] ReferencedColumns are now : "
			+ referencedColumns);		
		return referencedColumns;
	}

	public String getStringTemplate() {
		return stringTemplate;
	}

	public TermMapType getTermMapType() {
		if (constantValue != null)
			return TermMapType.CONSTANT_VALUED;
		else if (columnValue != null)
			return TermMapType.COLUMN_VALUED;
		else if (stringTemplate != null)
			return TermMapType.TEMPLATE_VALUED;
		else if (termType == TermType.BLANK_NODE)
			return TermMapType.NO_VALUE_FOR_BNODE;
		return null;
	}

	public TermType getTermType() {
		return termType;
	}

	public ColumnIdentifier getColumnValue() {
		return columnValue;
	}

	public boolean isOveridden() {
		if (implicitDataType == null) {
			// No implicit datatype extracted for yet
			// Return false by default
			return false;
		}
		return dataType != implicitDataType;
	}

	public boolean isTypeable() {
		return (termType == TermType.LITERAL) && (languageTag == null);
	}

	public void setImplicitDataType(XSDType implicitDataType) {
		this.implicitDataType = implicitDataType;
	}

	public String getValue(Map dbValues,
			ResultSetMetaData dbTypes) throws R2RMLDataError, SQLException,
			UnsupportedEncodingException {

		log.debug("[AbstractTermMap:getValue] Extract value of termType with termMapType : "
				+ getTermMapType());
		switch (getTermMapType()) {
		case CONSTANT_VALUED:
			return constantValue.stringValue();

		case COLUMN_VALUED:
			if (dbValues.keySet().isEmpty())
				throw new IllegalStateException(
						"[AbstractTermMap:getValue] impossible to extract from an empty database value set.");
			byte[] bytesResult = dbValues.get(columnValue);
			/* Extract the SQLType in dbValues from the key which is
			 * equals to "columnValue" */
			SQLType sqlType = null;			
			for(ColumnIdentifier colId : dbValues.keySet()) {
			    if(colId.equals(columnValue)) {
				sqlType = colId.getSqlType();
				break;
			    }
			}			    
			// Apply cast to string to the SQL data value
			String result;
			if (sqlType != null) {
				XSDType xsdType = SQLToXMLS.getEquivalentType(sqlType);
				result = XSDLexicalTransformation.extractNaturalRDFFormFrom(
						xsdType, bytesResult);
			}
			else
			{
			    result = new String(bytesResult, "UTF-8");
			}
			return result;

		case TEMPLATE_VALUED:
			if (dbValues.keySet().isEmpty())
				throw new IllegalStateException(
						"[AbstractTermMap:getValue] impossible to extract from an empty database value set.");
			result = R2RMLToolkit.extractColumnValueFromStringTemplate(
					stringTemplate, dbValues, dbTypes);
			return result;

		default:
			return null;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy