io.konig.spreadsheet.WorkbookProcessorImpl.java Source code

Java tutorial

Introduction

Here is the source code for io.konig.spreadsheet.WorkbookProcessorImpl.java

Source

package io.konig.spreadsheet;

/*
 * #%L
 * Konig Spreadsheet
 * %%
 * Copyright (C) 2015 - 2019 Gregory McFall
 * %%
 * 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.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.openrdf.model.Namespace;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.model.util.URIUtil;
import org.openrdf.model.vocabulary.OWL;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.model.vocabulary.SKOS;
import org.openrdf.model.vocabulary.XMLSchema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.konig.core.Graph;
import io.konig.core.NamespaceManager;
import io.konig.core.OwlReasoner;
import io.konig.core.impl.SimpleLocalNameService;
import io.konig.core.path.NamespaceMapAdapter;
import io.konig.core.util.StringUtil;
import io.konig.core.vocab.AS;
import io.konig.core.vocab.AWS;
import io.konig.core.vocab.CADL;
import io.konig.core.vocab.DC;
import io.konig.core.vocab.GCP;
import io.konig.core.vocab.Konig;
import io.konig.core.vocab.PROV;
import io.konig.core.vocab.SH;
import io.konig.core.vocab.Schema;
import io.konig.core.vocab.VANN;
import io.konig.rio.turtle.NamespaceMap;
import io.konig.shacl.ShapeManager;

public class WorkbookProcessorImpl implements WorkbookProcessor {

    private static final Logger logger = LoggerFactory.getLogger(WorkbookProcessorImpl.class);

    private ServiceManager serviceManager = new ServiceManager();
    private DataFormatter dataFormatter = new DataFormatter(true);
    private List<Action> actionList = new ArrayList<>();

    private List<SheetProcessor> sheetProcessors = new ArrayList<>();
    private List<WorkbookListener> bookListeners = new ArrayList<>();

    private io.konig.spreadsheet.nextgen.Workbook activeBook;

    // Graph specific fields

    private Graph graph;
    private OwlReasoner owlReasoner;
    private ValueFactory vf = new ValueFactoryImpl();
    private NamespaceHandler nsHandler;
    //   private NamespaceManager nsManager;
    private ShapeManager shapeManager;

    private boolean normalizeTerms;
    private Map<String, String> normalizedMap = new HashMap<>();
    private Set<String> normalizedTerms = new HashSet<>();
    private SettingsSheet settings;
    private File templateDir;

    private int maxErrorCount = 0;
    private int errorCount;
    private boolean showStackTrace = false;
    private String acceptProject;

    public WorkbookProcessorImpl(Graph graph, ShapeManager shapeManager, File templateDir) {
        this.templateDir = templateDir;
        this.graph = graph;
        this.shapeManager = shapeManager;
    }

    /**
     * Get the identifier for the Maven project to accept, in the form "{groupId}:{artifactId}"
     */
    public String getAcceptProject() {
        return acceptProject;
    }

    /**
     * Set the identifier for the Maven project to accept, in the form "{groupId}:{artifactId}"
     */
    public void setAcceptProject(String acceptProject) {
        this.acceptProject = acceptProject;
    }

    public void init() {

        if (nsHandler == null) {
            this.nsHandler = new NamespaceHandler(graph);
            this.owlReasoner = new OwlReasoner(graph);

            serviceManager.setListener(new BaseServiceListener());

            addNamespaces();
            addTerms();
            addServices();
            sortBookListeners();
        }
    }

    private void addTerms() {
        graph.edge(Schema.isPartOf, RDF.TYPE, OWL.OBJECTPROPERTY);
        graph.edge(Konig.receivesDataFrom, RDF.TYPE, OWL.OBJECTPROPERTY);
    }

    public boolean isShowStackTrace() {
        return showStackTrace;
    }

    public void setShowStackTrace(boolean showStackTrace) {
        this.showStackTrace = showStackTrace;
    }

    private void sortBookListeners() {
        DependencyManager<WorkbookListener> sorter = new DependencyManager<WorkbookListener>();
        sorter.sort(bookListeners);
    }

    public int getErrorCount() {
        return errorCount;
    }

    public int getMaxErrorCount() {
        return maxErrorCount;
    }

    public void setMaxErrorCount(int maxErrorCount) {
        this.maxErrorCount = maxErrorCount;
    }

    private void addServices() {
        settings = new SettingsSheet(this);
        addService(SettingsSheet.class, settings);
        NamespaceManager nsManager = graph.getNamespaceManager();
        DataSourceGeneratorFactory dataSourceGeneratorFactory = new DataSourceGeneratorFactory(nsManager,
                templateDir, settings);

        addService(WorkbookProcessor.class, this);
        addService(dataSourceGeneratorFactory);
        addService(Graph.class, graph);
        addService(NamespaceManager.class, nsManager);
        addService(ValueFactory.class, vf);
        addService(ShapeManager.class, shapeManager);
        addService(NamespaceMap.class, new NamespaceMapAdapter(nsManager));

        addSheetProcessor(new OntologySheet(this, nsManager));
        addSheetProcessor(settings);
        addSheetProcessor(new ClassSheet(this, settings));
        addSheetProcessor(new PropertySheet(this));
        addSheetProcessor(new IndividualSheet(this, settings));
        addSheetProcessor(new ShapeSheet(this, dataSourceGeneratorFactory));
        addSheetProcessor(new PropertyConstraintSheet(this, owlReasoner));
        addSheetProcessor(new TripleSheet(this));
        addSheetProcessor(new LabelSheet(this));
        addSheetProcessor(new CubeSheet(this));
        addSheetProcessor(new SourceDataDictionarySheet(this, settings, service(IndividualSheet.class)));
        addSheetProcessor(new AbbreviationSheet(this, settings));

    }

    private void addNamespaces() {

        nsHandler.addNamespace("vann", VANN.NAMESPACE);
        nsHandler.addNamespace("owl", OWL.NAMESPACE);
        nsHandler.addNamespace("sh", SH.NAMESPACE);
        nsHandler.addNamespace("rdf", RDF.NAMESPACE);
        nsHandler.addNamespace("rdfs", RDFS.NAMESPACE);
        nsHandler.addNamespace("konig", Konig.NAMESPACE);
        nsHandler.addNamespace("xsd", XMLSchema.NAMESPACE);
        nsHandler.addNamespace("schema", Schema.NAMESPACE);
        nsHandler.addNamespace("dc", DC.NAMESPACE);
        nsHandler.addNamespace("prov", PROV.NAMESPACE);
        nsHandler.addNamespace("as", AS.NAMESPACE);
        nsHandler.addNamespace("gcp", GCP.NAMESPACE);
        nsHandler.addNamespace("aws", AWS.NAMESPACE);
        nsHandler.addNamespace("skos", SKOS.NAMESPACE);
        nsHandler.addNamespace("cadl", CADL.NAMESPACE);

    }

    public void addService(Object service) {
        if (service != null) {
            serviceManager.addService(service);
        }
    }

    public void addService(Class<?> type, Object service) {
        serviceManager.addService(type, service);
    }

    private String cellStringValue(Cell cell) {
        if (cell == null) {
            return null;
        }
        String text = dataFormatter.formatCellValue(cell);
        if (text != null && !text.startsWith("HYPERLINK(")) {
            text = text.trim();
            if (text.length() == 0) {
                text = null;
            }
        } else {

            Hyperlink link = cell.getHyperlink();
            if (link != null) {
                text = link.getLabel();
                if (text == null) {
                    text = link.getAddress();
                }
                if (text != null) {
                    text = text.trim();

                }
            }
        }
        return text;
    }

    @Override
    public String stringValue(SheetRow sheetRow, SheetColumn col) {
        if (!col.exists()) {
            return null;
        }
        Row row = sheetRow.getRow();
        if (row == null) {
            return null;
        }
        String text = null;
        int column = col.getIndex();
        if (column >= 0) {
            Cell cell = row.getCell(column);
            text = cellStringValue(cell);
        }

        return text == null || text.isEmpty() ? null : text.replaceAll("(^\\h*)|(\\h*$)", "");
    }

    private String locationMessage(SheetRow row, SheetColumn column, String message) {
        return locationMessage(location(row, column), message);
    }

    private String locationMessage(WorkbookLocation location, String message) {
        String ellipsis = "";
        StringBuilder builder = new StringBuilder();
        if (location.getWorkbookName() != null) {
            builder.append(location.getWorkbookName());
            builder.append(" - ");
        }

        if (location.getRowNum() != null) {
            builder.append("At row ");
            builder.append(location.getRowNum() + 1);
            ellipsis = " ... ";
        }

        if (location.getColumnName() != null) {
            builder.append(", column '");
            builder.append(location.getColumnName());
            builder.append("'");
            ellipsis = " ... ";
        }

        if (location.getSheetName() != null) {
            builder.append(" on sheet '");
            builder.append(location.getSheetName());
            builder.append("'");
            ellipsis = " ... ";
        }

        if (message != null) {
            builder.append(ellipsis);
            builder.append(message);
        }
        return builder.toString();
    }

    protected void error(Throwable cause, WorkbookLocation location, String message) throws SpreadsheetException {

        String text = locationMessage(location, message);

        throw new SpreadsheetException(text, cause);

    }

    protected void error(SheetRow row, SheetColumn col, String pattern, Object... args)
            throws SpreadsheetException {
        error((Throwable) null, row, col, pattern, args);

    }

    private void error(Throwable cause, SheetRow row, SheetColumn col, String pattern, Object... args)
            throws SpreadsheetException {
        String message = MessageFormat.format(pattern, args);
        String bookName = activeBook == null ? null : activeBook.getFile().getName();
        String sheetName = row == null ? null : row.getSheetName();
        Integer rowNum = row == null ? null : row.getRowNum();
        String columnName = col == null ? null : col.getName();

        WorkbookLocation location = new WorkbookLocation(bookName, sheetName, rowNum, columnName);
        error(cause, location, message);
    }

    protected void warn(SheetRow row, SheetColumn col, String pattern, Object... args) {
        if (logger.isWarnEnabled()) {
            String message = locationMessage(row, col, MessageFormat.format(pattern, args));
            logger.warn(message);
        }

    }
    //
    //   private String format(SheetRow row, SheetColumn col, String pattern, Object...args) {
    //      if (col == null) {
    //         return format(row, pattern, args);
    //      }
    //      String prefix = format("At row {0}, column ''{1}'' on sheet ''{2}''...", 
    //            row.getRowNum(), col.getName(), row.getSheetName());
    //      String suffix = format(pattern, args);
    //      return prefix + suffix;
    //   }
    //
    //   private String format(SheetRow row, String pattern, Object...args) {
    //      if (row == null) {
    //         return format(pattern, args);
    //      }
    //
    //      String prefix = format("At row {0} on sheet ''{1}''...", 
    //            row.getRowNum(),  row.getSheetName());
    //      String suffix = format(pattern, args);
    //      return prefix + suffix;
    //   }
    //
    //   protected String format(String pattern, Object...args) {
    //      
    //      return MessageFormat.format(pattern, args);
    //   }

    @Override
    public void defer(Action action) {
        actionList.add(action);
    }

    @Override
    public void executeDeferredActions() throws SpreadsheetException {

        // It is possible that some actions may add new deferred actions.
        // To support that scenario, we run two loops.

        // The outer loop moves the current actionList to an 'oldList' variable,
        // and replaces actionList with a new ArrayList that is ready to 
        // accept new deferred actions.

        // The inner loop executes actions in the oldList.
        // The entire process ends when there are no more actions to execute.

        while (!actionList.isEmpty()) {
            List<Action> oldList = actionList;
            actionList = new ArrayList<>();
            for (Action action : oldList) {
                try {
                    action.execute();
                } catch (SpreadsheetException e) {
                    handle(e);
                }
            }
        }

        // We have a single action that must run after all the other actions..
        if (nsHandler != null) {
            nsHandler.execute();
        }

    }

    @Override
    public void process(File workbookFile) throws SpreadsheetException {
        init();
        activeBook = new io.konig.spreadsheet.nextgen.Workbook(workbookFile);
        Collections.sort(sheetProcessors);
        Workbook workbook = createWorkbook(workbookFile);
        beginWorkbook();
        List<WorkbookSheet> sheetList = listSheets(workbook);
        for (WorkbookSheet sheet : sheetList) {
            visitSheet(sheet);
        }
        endWorkbook();
        activeBook = null;
    }

    private void endWorkbook() {
        for (WorkbookListener listener : bookListeners) {
            listener.endWorkbook(activeBook);
        }

    }

    private void beginWorkbook() {
        logger.debug("beginWorkbook({})", activeBook.getFile().getName());
        for (WorkbookListener listener : bookListeners) {
            listener.beginWorkbook(activeBook);
        }

    }

    private void visitSheet(WorkbookSheet bookSheet) throws SpreadsheetException {

        String sheetName = bookSheet.getSheet().getSheetName();
        if (settings.getIgnoreSheets().contains(sheetName)) {
            logger.debug("Ignoring Sheet ... {}", sheetName);
            return;
        }
        logger.debug("visitSheet({})", sheetName);
        List<SheetColumn> undeclaredColumns = new ArrayList<>();
        assignColumnIndexes(bookSheet, undeclaredColumns);
        SheetProcessor processor = bookSheet.getProcessor();
        Sheet sheet = bookSheet.getSheet();

        int rowSize = sheet.getLastRowNum() + 1;

        SheetColumn projectColumn = filterByProject(bookSheet);

        // Skip the first row since it is the column header row
        for (int i = sheet.getFirstRowNum() + 1; i < rowSize; i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                SheetRow sheetRow = new SheetRow(bookSheet, row);
                sheetRow.setUndeclaredColumns(undeclaredColumns);
                try {
                    if (accept(sheetRow, processor, projectColumn)) {
                        processor.visit(sheetRow);
                    }
                } catch (SpreadsheetException e) {
                    handle(e);
                }
            }
        }

    }

    private SheetColumn filterByProject(WorkbookSheet bookSheet) {
        if (acceptProject != null) {
            return bookSheet.getProcessor().findColumnByName("Project");
        }
        return null;
    }

    private boolean accept(SheetRow sheetRow, SheetProcessor processor, SheetColumn projectColumn)
            throws SpreadsheetException {
        Row row = sheetRow.getRow();
        boolean foundAny = false;

        if (projectColumn != null && projectColumn.getIndex() >= 0) {
            String projectListText = stringValue(sheetRow, projectColumn);

            if (projectListText == null) {
                return false;
            }

            StringTokenizer tokenizer = new StringTokenizer(projectListText, " \r\n\t");
            boolean ok = false;
            while (tokenizer.hasMoreTokens() && !ok) {
                String projectId = tokenizer.nextToken();
                ok = projectId.equals(acceptProject);
            }

            if (!ok) {
                return false;
            }

        }
        List<String> missingRequired = null;
        for (SheetColumn column : processor.getColumns()) {

            if (column.isRequired()) {
                if (column.getIndex() < 0) {
                    return false;
                }
                Cell cell = row.getCell(column.getIndex());

                if (cell == null) {
                    missingRequired = append(missingRequired, column.getName());
                } else {
                    //               if (sheetRow.getSheetName().equals("Property Constraints")) {
                    //                  String value = cellStringValue(cell);
                    //                  logger.debug("accept - sheet: {}, column: {}, value: {}", sheetRow.getSheetName(), column.getName(), value);
                    //               }
                    @SuppressWarnings("deprecation")
                    CellType cellType = cell.getCellTypeEnum();
                    switch (cellType) {
                    case _NONE:
                    case BLANK:
                        missingRequired = append(missingRequired, column.getName());
                        break;

                    default:
                        foundAny = true;
                    }
                }

            } else if (!foundAny && column.getIndex() >= 0) {
                Cell cell = row.getCell(column.getIndex());
                foundAny = cell != null && cellStringValue(cell) != null;
            }
        }
        if (foundAny && missingRequired != null) {
            StringBuilder text = new StringBuilder();
            text.append("Values are required for: ");
            String comma = "";
            for (String name : missingRequired) {
                text.append(comma);
                comma = ", ";
                text.append('[');
                text.append(name);
                text.append(']');
            }

            warn(sheetRow, null, text.toString());
        }
        return missingRequired == null;
    }

    private List<String> append(List<String> list, String value) {
        if (list == null) {
            list = new ArrayList<>();
        }
        list.add(value);
        return list;
    }

    private List<WorkbookSheet> listSheets(Workbook workbook) throws SpreadsheetException {

        List<WorkbookSheet> list = new ArrayList<>();
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            Sheet sheet = workbook.getSheetAt(i);
            int bestRank = 0;
            SheetProcessor best = null;
            for (SheetProcessor p : sheetProcessors) {
                int rank = rank(sheet, p);
                if (rank > bestRank) {
                    bestRank = rank;
                    best = p;
                }
            }
            if (best != null) {
                list.add(new WorkbookSheet(sheet, best));
            }
        }
        Collections.sort(list);
        return list;
    }

    private void assignColumnIndexes(WorkbookSheet s, List<SheetColumn> undeclaredColumns) {
        logger.debug("assignColumnIndexes({})", s.getSheet().getSheetName());
        undeclaredColumns.clear();
        Sheet sheet = s.getSheet();
        SheetProcessor p = s.getProcessor();

        for (SheetColumn c : p.getColumns()) {
            c.setIndex(-1);
        }

        int firstRow = sheet.getFirstRowNum();
        Row row = sheet.getRow(firstRow);

        int colSize = row.getLastCellNum() + 1;
        for (int i = row.getFirstCellNum(); i < colSize; i++) {

            Cell cell = row.getCell(i);
            if (cell != null) {

                String columnName = cellStringValue(cell);
                if (columnName != null) {
                    SheetColumn column = p.findColumnByName(columnName);
                    if (column != null) {
                        column.setIndex(i);
                        logger.debug("assignColumnIndexes - {} index = {}", column, i);

                    } else {
                        SheetColumn c = new SheetColumn(columnName);
                        c.setIndex(i);
                        undeclaredColumns.add(c);
                    }
                }
            }
        }

    }

    private int rank(Sheet sheet, SheetProcessor p) throws SpreadsheetException {

        int count = 0;

        int firstRow = sheet.getFirstRowNum();
        Row row = sheet.getRow(firstRow);

        int colSize = row.getLastCellNum() + 1;
        for (int i = row.getFirstCellNum(); i < colSize; i++) {

            Cell cell = row.getCell(i);
            if (cell != null) {
                String text = cellStringValue(cell);
                if (text != null) {
                    SheetColumn column = p.findColumnByName(text);
                    if (column != null) {
                        count++;
                    }
                }
            }
        }

        return count;
    }

    private Workbook createWorkbook(File workbookFile) throws SpreadsheetException {

        try {
            return WorkbookFactory.create(workbookFile);
        } catch (Throwable e) {
            throw new SpreadsheetException("Failed to create workbook: " + workbookFile.getName(), e);
        }
    }

    @Override
    public ServiceManager getServiceManager() {
        return serviceManager;
    }

    @Override
    public void addSheetProcessor(SheetProcessor processor) {
        sheetProcessors.add(processor);
        serviceManager.addService(processor);
    }

    protected class BaseServiceListener implements ServiceListener {

        @Override
        public void onCreateService(Object service) {

            if (service instanceof SheetProcessor) {
                addSheetProcessor((SheetProcessor) service);
            }
            if (service instanceof SimpleLocalNameService) {
                defer(new BuildLocalNameServiceAction((SimpleLocalNameService) service, graph, shapeManager));
            }

            if (service instanceof Action) {
                defer((Action) service);
            }
        }

        @Override
        public void onRegister(Object service) {
            if (service instanceof WorkbookListener) {
                WorkbookListener listener = (WorkbookListener) service;
                if (!bookListeners.contains(listener)) {
                    bookListeners.add(listener);
                }
                if (activeBook != null) {
                    listener.beginWorkbook(activeBook);
                }
            }

        }

    }

    @Override
    public void fail(Throwable cause, SheetRow row, SheetColumn column, String pattern, Object... arg)
            throws SpreadsheetException {
        String message = MessageFormat.format(pattern, arg);
        error(cause, row, column, message);

    }

    public boolean isNormalizeTerms() {
        return normalizeTerms;
    }

    public void setNormalizeTerms(boolean normalizeTerms) {
        this.normalizeTerms = normalizeTerms;
    }

    @Override
    public URI iriValue(SheetRow sheetRow, SheetColumn col) throws SpreadsheetException {

        if (!col.exists()) {
            return null;
        }
        String text = stringValue(sheetRow, col);
        return expandCurie(text, sheetRow, col);
    }

    @Override
    public URI iriValue(String text, SheetRow sheetRow, SheetColumn col) throws SpreadsheetException {
        if (!col.exists()) {
            return null;
        }
        return expandCurie(text, sheetRow, col);
    }

    @Override
    public URI expandCurie(String text, WorkbookLocation location) throws SpreadsheetException {
        if (text == null) {
            return null;
        }
        if (text.startsWith("http://") || text.startsWith("https://") || text.startsWith("urn:")) {
            return vf.createURI(text);
        }
        int colon = text.indexOf(':');
        if (colon < 1) {
            fail(location, "Invalid URI: {0} ", text);
        }
        String prefix = text.substring(0, colon);
        Namespace ns = graph.getNamespaceManager().findByPrefix(prefix);
        if (ns == null) {
            error(location, MessageFormat.format("Namespace not found for prefix ''{0}''", prefix));
        }
        StringBuilder builder = new StringBuilder();
        builder.append(ns.getName());

        String localName = text.substring(colon + 1);
        if (normalizeTerms) {

            String normalized = StringUtil.normalizedLocalName(localName);
            if (!localName.equals(normalized)) {
                String prior = normalizedMap.get(localName);
                if (prior != null) {
                    normalized = prior;
                } else if (normalizedTerms.contains(normalized)) {

                    for (int count = 2; count < 102; count++) {
                        String candidate = normalized + count;
                        if (!normalizedTerms.contains(candidate)) {
                            normalized = candidate;
                            break;
                        }
                    }
                    normalizedMap.put(localName, normalized);
                    normalizedTerms.add(normalized);
                }
                localName = normalized;
                warn(location, "{0} has been normalized as {1}:{2}", text, prefix, normalized);
            }
        }

        builder.append(localName);

        if (localName.indexOf('/') >= 0) {
            StringBuilder err = new StringBuilder();
            err.append("The localname of a CURIE should not contain a slash, but found '");
            err.append(text);
            err.append("'");
        }

        String iriValue = builder.toString();
        if (!URIUtil.isValidURIReference(iriValue)) {
            error(location, "Invalid IRI <{0}>", text);
        }

        return vf.createURI(builder.toString());
    }

    @Override
    public void warn(WorkbookLocation location, String pattern, Object... args) {
        if (logger.isWarnEnabled()) {
            String message = locationMessage(location, MessageFormat.format(pattern, args));
            logger.warn(message);
        }

    }

    private void error(WorkbookLocation location, String pattern, Object... args) throws SpreadsheetException {
        String message = MessageFormat.format(pattern, args);
        error(null, location, message);
    }

    @Override
    public URI expandCurie(String text, SheetRow row, SheetColumn col) throws SpreadsheetException {
        if (text == null || !col.exists()) {
            return null;
        }
        if (text.startsWith("http://") || text.startsWith("https://") || text.startsWith("urn:")) {
            return vf.createURI(text);
        }
        int colon = text.indexOf(':');
        if (colon < 1) {
            fail(location(row, col), "Invalid URI: {0} ", text);
        }
        String prefix = text.substring(0, colon);
        Namespace ns = graph.getNamespaceManager().findByPrefix(prefix);
        if (ns == null) {
            error(row, col, "Namespace not found for prefix ''{0}''", prefix);
        }
        StringBuilder builder = new StringBuilder();
        builder.append(ns.getName());

        String localName = text.substring(colon + 1);
        if (normalizeTerms) {

            String normalized = StringUtil.normalizedLocalName(localName);
            if (!localName.equals(normalized)) {
                String prior = normalizedMap.get(localName);
                if (prior != null) {
                    normalized = prior;
                } else if (normalizedTerms.contains(normalized)) {

                    for (int count = 2; count < 102; count++) {
                        String candidate = normalized + count;
                        if (!normalizedTerms.contains(candidate)) {
                            normalized = candidate;
                            break;
                        }
                    }
                    normalizedMap.put(localName, normalized);
                    normalizedTerms.add(normalized);
                }
                localName = normalized;
                warn(row, col, "{0} has been normalized as {1}:{2}", text, prefix, normalized);
            }
        }

        builder.append(localName);

        if (localName.indexOf('/') >= 0) {
            StringBuilder err = new StringBuilder();
            err.append("The localname of a CURIE should not contain a slash, but found '");
            err.append(text);
            err.append("'");
            warn(row, col, err.toString());
        }

        String iriValue = builder.toString();
        if (!URIUtil.isValidURIReference(iriValue)) {
            error(row, col, "Invalid IRI <{0}>", text);
        }

        return vf.createURI(builder.toString());
    }

    @Override
    public Graph getGraph() {
        return graph;
    }

    @Override
    public void fail(Throwable cause, WorkbookLocation location, String pattern, Object... arg)
            throws SpreadsheetException {

        error(cause, location, MessageFormat.format(pattern, arg));

    }

    @Override
    public void fail(WorkbookLocation location, String pattern, Object... arg) throws SpreadsheetException {
        fail(null, location, pattern, arg);
    }

    @Override
    public URI uri(String stringValue) {
        return stringValue == null ? null : new URIImpl(stringValue);
    }

    @Override
    public WorkbookLocation location(SheetRow row, SheetColumn column) {
        String workbookName = activeBook == null ? null : activeBook.getFile().getName();
        String sheetName = row == null ? null : row.getSheetName();
        Integer rowNum = row == null ? null : row.getRowNum();
        String colName = column == null ? null : column.getName();

        return new WorkbookLocation(workbookName, sheetName, rowNum, colName);
    }

    @Override
    public OwlReasoner getOwlReasoner() {
        return owlReasoner;
    }

    @Override
    public String getSetting(String name) {
        return settings.getProperties().getProperty(name);
    }

    @Override
    public ShapeManager getShapeManager() {
        return shapeManager;
    }

    @Override
    public io.konig.spreadsheet.nextgen.Workbook getActiveWorkbook() {
        return activeBook;
    }

    @Override
    public <T> T service(Class<T> javaClass) {
        return serviceManager.service(javaClass);
    }

    @Override
    public void processAll(List<File> files) throws SpreadsheetException {

        for (File file : files) {
            process(file);
        }
        executeDeferredActions();

    }

    @Override
    public void handle(SpreadsheetException e) throws SpreadsheetException {
        if (++errorCount > maxErrorCount) {
            throw e;
        }
        if (showStackTrace) {
            logger.error("Workbook Error #" + errorCount, e);
        } else {
            Throwable cause = e.getCause();
            if (cause == null) {
                logger.error("Workbook Error #{}. {}", errorCount, e.getMessage());
            } else {
                logger.error("Workbook Error #{}. {} ... {}", errorCount, e.getMessage(), cause.getMessage());
            }
        }

    }

}