/*
* Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com>
*
* 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.
*/
package com.obidea.semantika.mapping.parser.termalxml;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import com.obidea.semantika.datatype.DataType;
import com.obidea.semantika.datatype.exception.UnsupportedDataTypeException;
import com.obidea.semantika.expression.base.ITerm;
import com.obidea.semantika.mapping.UriTemplate;
import com.obidea.semantika.mapping.base.TermType;
import com.obidea.semantika.mapping.base.sql.SqlColumn;
import com.obidea.semantika.mapping.exception.MappingParserException;
import com.obidea.semantika.util.StringUtils;
public abstract class AbstractMappingElementHandler extends AbstractTermalElementHandler
{
private TermMap mTermMap;
protected String mTermType;
private String mValue;
private String mDatatype;
private String mLanguage;
protected boolean bUserDefinedTermType = false;
protected enum TermMap { COLUMN_VALUE, CONSTANT_VALUE, TEMPLATE_VALUE };
public AbstractMappingElementHandler(TermalXmlParserHandler handler)
{
super(handler);
}
@Override
protected MappingElementHandler getParentElement()
{
return (MappingElementHandler) super.getParentElement();
}
protected void setTermMap(TermMap termMap)
{
mTermMap = termMap;
if (!bUserDefinedTermType) {
decideDefaultTermType();
}
}
/**
* If the term map does not have a rr:termType property, then its term type is:
* <ol>
* <li>rr:Literal, if it is an object map and at least one of the following conditions is true:
* <ul>
* <li>It is a column-based term map.</li>
* <li>It has a rr:language property (and thus a specified language tag).</li>
* <li>It has a rr:datatype property (and thus a specified datatype).</li>
* </ul>
* </li>
* <li>rr:IRI, otherwise.</li>
* </ol>
* (Reference: http://www.w3.org/TR/r2rml/#termtype)
*/
protected abstract void decideDefaultTermType();
protected TermMap getTermMap()
{
return mTermMap;
}
protected void setTermType(String type)
{
mTermType = type;
bUserDefinedTermType = true;
}
protected String getTermType()
{
return mTermType;
}
protected void setValue(String value)
{
mValue = value;
}
protected String getValue()
{
return mValue;
}
protected void setDatatype(String datatype)
{
mDatatype = datatype;
}
protected String getDatatype()
{
return mDatatype;
}
/**
* Returns <code>true</code> if the map has specified explicitly the data
* type, or <code>false</code> otherwise.
*/
protected boolean hasDatatype()
{
return (StringUtils.isEmpty(mDatatype)) ? false : true;
}
protected void setLanguage(String language)
{
mLanguage = language;
}
protected String getLanguage()
{
return mLanguage;
}
/**
* Returns <code>true</code> if the map has language tag specified, or
* <code>false</code> otherwise.
*/
protected boolean hasLanguageTag()
{
return (StringUtils.isEmpty(mLanguage)) ? false : true;
}
protected SqlColumn getColumnTerm(String columnName, String termType, String datatype) throws MappingParserException
{
if (termType.equals(R2RmlVocabulary.IRI.getUri())) {
if (!StringUtils.isEmpty(datatype)) {
throw illegalTermalMappingException("Cannot use rr:datatype together with term type rr:IRI"); //$NON-NLS-1$
}
SqlColumn column = getColumnTerm(columnName);
column.setTermType(TermType.URI_TYPE);
return column;
}
else if (termType.equals(R2RmlVocabulary.LITERAL.getUri())) {
SqlColumn column = getColumnTerm(columnName);
column.setTermType(TermType.LITERAL_TYPE);
if (!StringUtils.isEmpty(datatype)) {
overrideColumn(column, datatype); // set as datatype-override RDF literal
}
return column;
}
else if (termType.equals(R2RmlVocabulary.BLANK_NODE.getUri())) {
throw unsupportedTermTypeException("rr:BlankNode"); //$NON-NLS-1$
}
throw unknownTermTypeException(termType);
}
protected ITerm getLiteralTerm(String value, String termType, String datatype) throws MappingParserException
{
if (termType.equals(R2RmlVocabulary.IRI.getUri())) {
if (!StringUtils.isEmpty(datatype)) {
throw illegalTermalMappingException("Cannot use rr:datatype together with term type rr:IRI"); //$NON-NLS-1$
}
return getExpressionObjectFactory().getUriReference(getUri(value));
}
else if (termType.equals(R2RmlVocabulary.LITERAL.getUri())) {
return (StringUtils.isEmpty(datatype)) ?
getExpressionObjectFactory().getLiteral(value, DataType.STRING) : // by default
getExpressionObjectFactory().getLiteral(value, datatype);
}
else if (termType.equals(R2RmlVocabulary.BLANK_NODE.getUri())) {
throw unsupportedTermTypeException("rr:BlankNode"); //$NON-NLS-1$
}
throw unknownTermTypeException(termType);
}
protected ITerm getTemplateTerm(String value, String termType, String datatype) throws MappingParserException
{
if (termType.equals(R2RmlVocabulary.IRI.getUri())) {
if (!StringUtils.isEmpty(datatype)) {
throw illegalTermalMappingException("Cannot use rr:datatype together with term type rr:IRI"); //$NON-NLS-1$
}
return getUriTemplateFunction(value);
}
else if (termType.equals(R2RmlVocabulary.LITERAL.getUri())) {
throw illegalTermalMappingException("Cannot use rr:template together with term type rr:Literal");
}
else if (termType.equals(R2RmlVocabulary.BLANK_NODE.getUri())) {
throw unsupportedTermTypeException("rr:BlankNode"); //$NON-NLS-1$
}
throw unknownTermTypeException(termType);
}
protected URI getUri(String abbreviatedUri) throws PrefixNotFoundException
{
String normalizedAbbreviatedUri = normalizedAbbreviatedUri(abbreviatedUri);
int colonPos = normalizedAbbreviatedUri.indexOf(":");
String prefixName = normalizedAbbreviatedUri.substring(0, colonPos);
String localName = normalizedAbbreviatedUri.substring(colonPos + 1);
String namespace = getPrefixMapper().get(prefixName);
if (!StringUtils.isEmpty(namespace)) {
return URI.create(namespace + localName);
}
else {
throw prefixNotFoundException(prefixName);
}
}
@Override
protected void handleChild(MappingElementHandler handler)
{
// NO-OP: No child node afterwards
}
@Override
protected void handleChild(LogicalTableElementHandler handler)
{
// NO-OP: No child node afterwards
}
@Override
protected void handleChild(SubjectMapElementHandler handler)
{
// NO-OP: No child node afterwards
}
@Override
protected void handleChild(PredicateObjectMapElementHandler handler)
{
// NO-OP: No child node afterwards
}
/*
* Private helper methods
*/
private String normalizedAbbreviatedUri(String input)
{
return (input.indexOf(":") != -1) ? input : ":" + input; //$NON-NLS-1$ //$NON-NLS-2$
}
private UriTemplate getUriTemplateFunction(String functionCall) throws MappingParserException
{
try {
TermalTemplate template = new TermalTemplate(functionCall, getUriTemplateMapper());
String templateString = template.getTemplateString();
List<SqlColumn> parameters = getColumnTerms(template.getColumnNames());
return getMappingObjectFactory().createUriTemplate(templateString, parameters);
}
catch (Exception e) {
throw illegalTemplateCallException(e.getMessage());
}
}
private SqlColumn getColumnTerm(String columnName) throws MappingParserException
{
SqlColumn column = (SqlColumn) getParentElement().getSourceQuery().findSelectItemExpression(columnName);
if (column != null) {
return column;
}
throw columnNotFoundException(columnName);
}
private List<SqlColumn> getColumnTerms(List<String> columnNames) throws MappingParserException
{
List<SqlColumn> toReturn = new ArrayList<SqlColumn>();
for (String columnName : columnNames) {
toReturn.add(getColumnTerm(columnName));
}
return toReturn;
}
private void overrideColumn(SqlColumn column, String datatype) throws MappingParserException
{
try {
column.overrideDatatype(datatype);
}
catch (UnsupportedDataTypeException e) {
throw unsupportedXmlDataTypeException(e.getMessage());
}
catch (IllegalArgumentException e) {
throw datatypeOverrideException(e.getMessage());
}
}
}