io.leishvl.core.prov.ProvFactory.java Source code

Java tutorial

Introduction

Here is the source code for io.leishvl.core.prov.ProvFactory.java

Source

/*
 * Copyright 2014-2015 EUBrazilCC (EU?Brazil Cloud Connect)
 * 
 * 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.
 * 
 * This product combines work with different licenses. See the "NOTICE" text
 * file for details on the various modules and licenses.
 * 
 * The "NOTICE" text file is part of the distribution. Any derivative works
 * that you distribute must include a readable copy of the "NOTICE" text file.
 */

package io.leishvl.core.prov;

import static com.google.common.base.Preconditions.checkArgument;
import static io.leishvl.core.data.AnnotationCollectionUtils.getCollectionName;
import static io.leishvl.core.prov.Provenance.LVL_PREFIX;
import static io.leishvl.core.prov.Provenance.PROVENANCE;
import static java.util.Arrays.asList;
import static java.util.Optional.ofNullable;
import static java.util.UUID.randomUUID;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trimToNull;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Optional;

import javax.annotation.Nullable;
import javax.sound.midi.Sequence;

import org.openprovenance.prov.model.Activity;
import org.openprovenance.prov.model.Agent;
import org.openprovenance.prov.model.Attribute;
import org.openprovenance.prov.model.Bundle;
import org.openprovenance.prov.model.Document;
import org.openprovenance.prov.model.Entity;
import org.openprovenance.prov.model.QualifiedName;
import org.openprovenance.prov.model.Role;
import org.openprovenance.prov.model.Statement;
import org.openprovenance.prov.model.StatementOrBundle;
import org.openprovenance.prov.model.Used;
import org.openprovenance.prov.model.WasAssociatedWith;
import org.openprovenance.prov.model.WasInformedBy;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;

import com.google.common.collect.Lists;

import io.leishvl.core.Citation;
import io.leishvl.core.security.User;
import io.leishvl.core.xml.GbSeqXmlBinder;
import io.leishvl.core.xml.PubMedXmlBinder;

/**
 * Provides provenance factory methods.
 * @author Erik Torres <ertorser@upv.es>
 */
public final class ProvFactory {

    /* Document factory methods */

    public static Document newObjectImportProv(final ProvDataSource ds, final String lvlId,
            final @Nullable ProvGeocoding gc) {
        final ProvDataSource ds2 = ProvDataSource.validate(ds);
        final String lvlId2 = parseParam(lvlId);
        final ProvGeocoding gc2 = (gc != null ? ProvGeocoding.validate(gc) : null);

        final Document graph = newProvDocument();
        final Bundle bundle = getBundle(graph);
        final Agent system = getSystem(bundle);

        // import activity
        final Agent importer = PROVENANCE.softwareAgent(ds2.importer);
        bundle.getStatement().addAll(
                asList(importer, PROVENANCE.factory().newActedOnBehalfOf(null, importer.getId(), system.getId())));

        final Activity assignAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("assign"));
        final WasAssociatedWith assignAssoc = PROVENANCE.factory().newWasAssociatedWith(null, assignAct.getId(),
                system.getId());
        final Activity importAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("import"));
        final WasInformedBy importInf = PROVENANCE.factory().newWasInformedBy(null, assignAct.getId(),
                importAct.getId());
        final WasAssociatedWith importAssoc = PROVENANCE.factory().newWasAssociatedWith(null, importAct.getId(),
                importer.getId());
        bundle.getStatement().addAll(asList(assignAct, assignAssoc, importAct, importInf, importAssoc));

        final Agent dataSource = PROVENANCE.factory().newAgent(PROVENANCE.qn(ds2.name),
                asList(new Attribute[] { PROVENANCE.dataCatalogType(), PROVENANCE.urlAttr(ds2.url) }));
        final Entity entity = PROVENANCE.entity(LVL_PREFIX, ds2.type);
        final Entity ent1 = PROVENANCE.entity(LVL_PREFIX, ds2.objectId, PROVENANCE.datasetType());
        bundle.getStatement()
                .addAll(asList(dataSource, entity, ent1,
                        PROVENANCE.factory().newSpecializationOf(ent1.getId(), entity.getId()),
                        PROVENANCE.factory().newWasAttributedTo(null, ent1.getId(), dataSource.getId()),
                        PROVENANCE.factory().newUsed(null, importAct.getId(), ent1.getId())));

        // download activity
        final Agent downloader = PROVENANCE.softwareAgent(ds2.downloader);
        final Activity downloadAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("download"));
        PROVENANCE.factory().addType(downloadAct, PROVENANCE.downloadActionType());
        final Entity sequenceFormat = PROVENANCE.entity(LVL_PREFIX, ds2.format,
                PROVENANCE.type(LVL_PREFIX, "DataFormat"));
        final Entity entRaw = PROVENANCE.entity(LVL_PREFIX, "file1");
        bundle.getStatement()
                .addAll(asList(downloader, downloadAct, sequenceFormat, entRaw,
                        PROVENANCE.factory().newActedOnBehalfOf(null, downloader.getId(), importer.getId()),
                        PROVENANCE.factory().newWasAssociatedWith(null, downloadAct.getId(), downloader.getId()),
                        PROVENANCE.factory().newUsed(null, downloadAct.getId(), ent1.getId()),
                        PROVENANCE.factory().newSpecializationOf(entRaw.getId(), sequenceFormat.getId()),
                        PROVENANCE.factory().newWasGeneratedBy(null, entRaw.getId(), downloadAct.getId(),
                                PROVENANCE.factory().newTimeNow(), null)));

        // parse activity
        final Agent parser = PROVENANCE.softwareAgent(ds2.parser);
        final Activity parseAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("parse"));
        final Entity entObj1 = PROVENANCE.entity(LVL_PREFIX, "obj1");
        bundle.getStatement()
                .addAll(asList(parser, parseAct, entObj1,
                        PROVENANCE.factory().newActedOnBehalfOf(null, parser.getId(), importer.getId()),
                        PROVENANCE.factory().newWasAssociatedWith(null, parseAct.getId(), parser.getId()),
                        PROVENANCE.factory().newUsed(null, parseAct.getId(), entRaw.getId()),
                        PROVENANCE.factory().newWasGeneratedBy(null, entObj1.getId(), parseAct.getId())));

        Entity coord = null;
        if (gc2 != null) {
            // infer geographic coordinates (geocode) activity
            final Agent geocoder = PROVENANCE.softwareAgent(gc2.geocoder);
            final Activity geocodeAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("geocode"));
            coord = PROVENANCE.entity(LVL_PREFIX, "coord1", PROVENANCE.locationAttr(gc2.point));
            bundle.getStatement()
                    .addAll(asList(geocoder, geocodeAct, coord,
                            PROVENANCE.factory().newActedOnBehalfOf(null, geocoder.getId(), importer.getId()),
                            PROVENANCE.factory().newWasAssociatedWith(null, geocodeAct.getId(), geocoder.getId()),
                            PROVENANCE.factory().newUsed(null, geocodeAct.getId(), entObj1.getId()),
                            PROVENANCE.factory().newWasGeneratedBy(null, coord.getId(), geocodeAct.getId())));
        }

        // create database record combining the different sources of information            
        final Activity combineAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("combine"));
        final Entity entObj2 = PROVENANCE.entity(LVL_PREFIX, "obj2");
        final List<Statement> statements = Lists.<Statement>newArrayList(combineAct, entObj2,
                PROVENANCE.factory().newWasAssociatedWith(null, combineAct.getId(), importer.getId()),
                PROVENANCE.factory().newUsed(null, combineAct.getId(), entObj1.getId()),
                PROVENANCE.factory().newWasGeneratedBy(null, entObj2.getId(), combineAct.getId()));
        if (coord != null)
            statements.add(PROVENANCE.factory().newUsed(null, combineAct.getId(), coord.getId()));
        bundle.getStatement().addAll(statements);

        // add provenance information
        final Activity createProvAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("createProv"));
        final Entity prov = PROVENANCE.entity(LVL_PREFIX, "prov1", PROVENANCE.bundleType());

        final Activity embedProvAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("embedProv"));
        final Entity entObj3 = PROVENANCE.entity(LVL_PREFIX, "obj3");

        bundle.getStatement().addAll(asList(createProvAct, prov,
                PROVENANCE.factory().newWasAssociatedWith(null, createProvAct.getId(), importer.getId()),
                PROVENANCE.factory().newUsed(null, createProvAct.getId(), entObj2.getId()),
                PROVENANCE.factory().newWasGeneratedBy(null, prov.getId(), createProvAct.getId()), embedProvAct,
                entObj3, PROVENANCE.factory().newWasAssociatedWith(null, embedProvAct.getId(), importer.getId()),
                PROVENANCE.factory().newUsed(null, embedProvAct.getId(), entObj2.getId()),
                PROVENANCE.factory().newUsed(null, embedProvAct.getId(), prov.getId()),
                PROVENANCE.factory().newWasDerivedFrom(null, entObj3.getId(), entObj2.getId(), embedProvAct.getId(),
                        null, null, null),
                PROVENANCE.factory().newWasDerivedFrom(null, entObj3.getId(), prov.getId(), embedProvAct.getId(),
                        null, null, null),
                PROVENANCE.factory().newWasGeneratedBy(null, entObj3.getId(), embedProvAct.getId())));

        // insert document draft in the database
        final Agent collection = PROVENANCE.factory().newAgent(PROVENANCE.qn(ds2.collection),
                asList(new Attribute[] { PROVENANCE.dataCatalogType(), }));
        final Agent dbClient = PROVENANCE.softwareAgent(ds2.dbObject);
        final Activity insertIntoDbAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("register"));
        final Entity entityDocument = PROVENANCE.entity(LVL_PREFIX, "LvlDocument");
        final Entity entObj4 = PROVENANCE.entity(LVL_PREFIX, lvlId2, PROVENANCE.datasetType());
        bundle.getStatement()
                .addAll(asList(collection, dbClient, insertIntoDbAct, entityDocument, entObj4,
                        PROVENANCE.factory().newActedOnBehalfOf(null, dbClient.getId(), importer.getId()),
                        PROVENANCE.factory().newWasAssociatedWith(null, insertIntoDbAct.getId(), dbClient.getId()),
                        PROVENANCE.factory().newUsed(null, insertIntoDbAct.getId(), entObj3.getId()),
                        PROVENANCE.factory().newSpecializationOf(entObj4.getId(), entityDocument.getId()),
                        PROVENANCE.factory().newWasAttributedTo(null, entObj4.getId(), collection.getId()),
                        PROVENANCE.factory().newWasGeneratedBy(null, entObj4.getId(), importAct.getId()),
                        PROVENANCE.factory().newWasDerivedFrom(null, entObj4.getId(), entObj3.getId(),
                                insertIntoDbAct.getId(), null, null, null),
                        PROVENANCE.factory().newWasEndedBy(null, importAct.getId(), entObj4.getId(),
                                insertIntoDbAct.getId())));
        return graph;
    }

    public static Document newCustomObjectProv(final User creator, final String lvlId) {
        final String lvlId2 = parseParam(lvlId);
        checkArgument(creator != null, "Uninitialized creator");
        checkArgument(isNotBlank(creator.getUserid()), "Uninitialized user Id");
        checkArgument(isNotBlank(creator.getProvider()), "Uninitialized identity provider");

        final Document graph = newProvDocument();
        final Bundle bundle = getBundle(graph);
        final Agent system = getSystem(bundle);

        // create activity
        final Entity entObj1 = PROVENANCE.entity(LVL_PREFIX, lvlId2, PROVENANCE.datasetType());
        final Agent creatorAgent = PROVENANCE.personAgent(creator);
        final Activity createAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("create"));
        bundle.getStatement()
                .addAll(asList(entObj1, creatorAgent, createAct,
                        PROVENANCE.factory().newUsed(null, createAct.getId(), entObj1.getId()),
                        PROVENANCE.factory().newWasGeneratedBy(null, entObj1.getId(), createAct.getId()),
                        PROVENANCE.factory().newActedOnBehalfOf(null, creatorAgent.getId(), system.getId()),
                        PROVENANCE.factory().newWasAssociatedWith(null, createAct.getId(), creatorAgent.getId())));
        return graph;
    }

    public static Document newReleaseProv(final User editor, final String lvlId, final String original,
            final String revision) {
        final String lvlId2 = parseParam(lvlId);
        checkArgument(editor != null, "Uninitialized editor");
        checkArgument(isNotBlank(editor.getUserid()), "Uninitialized user Id");
        checkArgument(isNotBlank(editor.getProvider()), "Uninitialized identity provider");

        final Document graph = newProvDocument();
        final Bundle bundle = getBundle(graph);
        final Agent system = getSystem(bundle);

        // edit activity
        final Agent curatorAgent = PROVENANCE.personAgent(editor);
        final Entity entObj1 = PROVENANCE.entity(LVL_PREFIX, lvlId2 + original);
        final Entity entObj2 = PROVENANCE.entity(LVL_PREFIX, lvlId2 + revision);
        final Activity editAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("edit"));
        final Role curatorRole = PROVENANCE.factory().newRole("Curator", PROVENANCE.qn("Curator"));
        final Used usedObject = PROVENANCE.factory().newUsed(null, editAct.getId(), entObj1.getId());
        PROVENANCE.factory().addRole(usedObject, curatorRole);
        bundle.getStatement().addAll(asList(curatorAgent, editAct, entObj1, entObj2,
                PROVENANCE.factory().newActedOnBehalfOf(null, curatorAgent.getId(), system.getId()),
                PROVENANCE.factory().newWasAssociatedWith(null, editAct.getId(), curatorAgent.getId()), usedObject,
                PROVENANCE.factory().newWasInvalidatedBy(null, entObj1.getId(), editAct.getId()),
                PROVENANCE.factory().newWasGeneratedBy(null, entObj2.getId(), editAct.getId(),
                        PROVENANCE.factory().newTimeNow(), null),
                PROVENANCE.factory().newWasDerivedFrom(null, entObj2.getId(), entObj1.getId(), editAct.getId(),
                        null, null, null)));
        return graph;
    }

    public static Document newObsoleteProv(final User editor, final String lvlId) {
        final String lvlId2 = parseParam(lvlId);
        checkArgument(editor != null, "Uninitialized editor");
        checkArgument(isNotBlank(editor.getUserid()), "Uninitialized user Id");
        checkArgument(isNotBlank(editor.getProvider()), "Uninitialized identity provider");

        final Document graph = newProvDocument();
        final Bundle bundle = getBundle(graph);
        final Agent system = getSystem(bundle);

        // edit activity
        final Agent curatorAgent = PROVENANCE.personAgent(editor);
        final Entity entObj1 = PROVENANCE.entity(LVL_PREFIX, lvlId2);
        final Activity invalidateAct = PROVENANCE.factory().newActivity(PROVENANCE.qn("invalidate"));
        final Role curatorRole = PROVENANCE.factory().newRole("Curator", PROVENANCE.qn("Curator"));
        final Used usedObject = PROVENANCE.factory().newUsed(null, invalidateAct.getId(), entObj1.getId());
        PROVENANCE.factory().addRole(usedObject, curatorRole);
        bundle.getStatement()
                .addAll(asList(curatorAgent, invalidateAct, entObj1,
                        PROVENANCE.factory().newActedOnBehalfOf(null, curatorAgent.getId(), system.getId()),
                        PROVENANCE.factory().newWasAssociatedWith(null, invalidateAct.getId(),
                                curatorAgent.getId()),
                        usedObject, PROVENANCE.factory().newWasInvalidatedBy(null, entObj1.getId(),
                                invalidateAct.getId(), PROVENANCE.factory().newTimeNow(), null)));
        return graph;
    }

    public static Document combineProv(final Document... documents) {
        final Document graph = PROVENANCE.factory().newDocument();
        for (final Document doc : documents) {
            for (final StatementOrBundle item : doc.getStatementOrBundle()) {
                graph.getStatementOrBundle().add(item);
            }
        }
        graph.setNamespace(PROVENANCE.ns());
        return graph;
    }

    /* Type factory methods */

    public static ProvDataSource newGenBankSequence(final String objectId, final String collection) {
        ProvDataSource ds = null;
        try {
            ds = new ProvDataSource("GenBank", new URL("http://www.ncbi.nlm.nih.gov/genbank/"), objectId,
                    Sequence.class.getSimpleName(), EntrezHelper.class, HttpClientProvider.class,
                    GbSeqXmlBinder.class, "GBSeqXML", Sequence.class, collection);
        } catch (MalformedURLException ignore) {
        }
        return ds;
    }

    public static ProvDataSource newPubMedArticle(final String objectId) {
        ProvDataSource ds = null;
        try {
            ds = new ProvDataSource("PubMed", new URL("http://www.ncbi.nlm.nih.gov/pubmed/"), objectId,
                    Citation.class.getSimpleName(), EntrezHelper.class, HttpClientProvider.class,
                    PubMedXmlBinder.class, "PubMedXML", Citation.class, getCollectionName(Citation.class));
        } catch (MalformedURLException ignore) {
        }
        return ds;
    }

    public static ProvGeocoding newGeocoding(final GeoJsonPoint point) {
        return new ProvGeocoding(point, GeocodingHelper.class);
    }

    /* Document modifiers */

    public static void addEditProv(final Document graph, final User editor, final String lvlId) {
        final String lvlId2 = parseParam(lvlId);
        checkArgument(editor != null, "Uninitialized editor");
        checkArgument(isNotBlank(editor.getUserid()), "Uninitialized user Id");
        checkArgument(isNotBlank(editor.getProvider()), "Uninitialized identity provider");

        final Bundle bundle = getBundle(graph);
        final Agent system = getSystem(bundle);

        // imported draft is open to future editions
        final QualifiedName editActQn = PROVENANCE.qn("edit");
        final QualifiedName revisedDraftQn = PROVENANCE.qn(LVL_PREFIX, "RevisedDraft");
        final Optional<Statement> revisedDraftOpt = ofNullable(bundle.getStatement().stream()
                .filter(stmt -> stmt instanceof Entity && revisedDraftQn.equals(((Entity) stmt).getId()))
                .findFirst().orElse(null));
        final Entity revisedDraft = (Entity) revisedDraftOpt.orElse(PROVENANCE.entity(LVL_PREFIX, "RevisedDraft"));
        if (!revisedDraftOpt.isPresent()) {
            final Activity editAct = PROVENANCE.factory().newActivity(editActQn);
            final QualifiedName objQn = PROVENANCE.qn(LVL_PREFIX, lvlId2);
            bundle.getStatement()
                    .addAll(asList(editAct, revisedDraft,
                            PROVENANCE.factory().newUsed(null, editAct.getId(), objQn),
                            PROVENANCE.factory().newWasDerivedFrom(null, revisedDraft.getId(), objQn),
                            PROVENANCE.factory().newWasGeneratedBy(null, revisedDraft.getId(), editAct.getId())));
        }

        // add editor
        final QualifiedName editorQn = PROVENANCE.qn(LVL_PREFIX, editor.getUserid());
        final Optional<Statement> editorAgentOpt = ofNullable(bundle.getStatement().stream()
                .filter(stmt -> stmt instanceof Agent && editorQn.equals(((Agent) stmt).getId())).findFirst()
                .orElse(null));
        final Agent editorAgent = (Agent) editorAgentOpt.orElse(PROVENANCE.personAgent(editor));
        if (!editorAgentOpt.isPresent()) {
            bundle.getStatement()
                    .addAll(asList(editorAgent,
                            PROVENANCE.factory().newActedOnBehalfOf(null, editorAgent.getId(), system.getId()),
                            PROVENANCE.factory().newWasAssociatedWith(null, editActQn, editorAgent.getId())));
        }
    }

    /* Auxiliary methods */

    private static Bundle getBundle(final Document graph) {
        checkArgument(graph != null, "Uninitialized provenance document");
        final StatementOrBundle node = graph.getStatementOrBundle().stream().filter(stmt -> stmt != null)
                .findFirst().orElse(null);
        checkArgument(node != null && node instanceof Bundle, "Uninitialized or invalid provenance bundle");
        return (Bundle) node;
    }

    private static Agent getSystem(final Bundle bundle) {
        final QualifiedName systemQn = PROVENANCE.lvlAgent().getId();
        return (Agent) bundle.getStatement().stream()
                .filter(stmt -> stmt instanceof Agent && systemQn.equals(((Agent) stmt).getId())).findFirst()
                .orElse(null);
    }

    private static String parseParam(final String param) {
        String param2 = null;
        checkArgument((param2 = trimToNull(param)) != null, "Uninitialized or invalid parameter");
        return param2;
    }

    private static Document newProvDocument() {
        final Document graph = PROVENANCE.factory().newDocument();

        // system initialization
        final String provId = randomProvId();
        final Bundle bundle = PROVENANCE.factory().newNamedBundle(PROVENANCE.qn(provId), PROVENANCE.ns(),
                Lists.<Statement>newArrayList());
        final Agent system = PROVENANCE.lvlAgent();
        final Entity provBundle = PROVENANCE.entity(LVL_PREFIX, provId, PROVENANCE.bundleType());
        bundle.getStatement().addAll(asList(system, provBundle, PROVENANCE.factory()
                .newWasAttributedTo(PROVENANCE.qn("attr"), provBundle.getId(), system.getId())));

        graph.getStatementOrBundle().add(bundle);
        graph.setNamespace(PROVENANCE.ns());
        return graph;
    }

    private static String randomProvId() {
        return "PROV-" + randomUUID().toString().replace("-", "");
    }

    /* Inner types */

    public static class ProvDataSource {
        private final String name;
        private final URL url;
        private final String objectId;
        private final String type;

        private final Class<?> importer;
        private final Class<?> downloader;
        private final Class<?> parser;
        private final String format;

        private final Class<?> dbObject;
        private final String collection;

        public ProvDataSource(final String name, final URL url, final String objectId, final String type,
                final Class<?> importer, final Class<?> downloader, final Class<?> parser, final String format,
                final Class<?> dbObject, final String collection) {
            this.name = name;
            this.url = url;
            this.objectId = objectId;
            this.type = type;
            this.importer = importer;
            this.downloader = downloader;
            this.parser = parser;
            this.format = format;
            this.dbObject = dbObject;
            this.collection = collection;
        }

        public static ProvDataSource validate(final ProvDataSource original) {
            checkArgument(original != null, "Uninitialized data source");
            String name2 = null;
            checkArgument((name2 = trimToNull(original.name)) != null, "Uninitialized or invalid name");
            checkArgument(original.url != null, "Uninitialized URL");
            String objectId2 = null;
            checkArgument((objectId2 = trimToNull(original.objectId)) != null,
                    "Uninitialized or invalid object Id");
            String type2 = null;
            checkArgument((type2 = trimToNull(original.type)) != null, "Uninitialized or invalid type");
            checkArgument(original.importer != null, "Uninitialized importer");
            checkArgument(original.downloader != null, "Uninitialized downloader");
            checkArgument(original.parser != null, "Uninitialized parser");
            String format2 = null;
            checkArgument((format2 = trimToNull(original.format)) != null, "Uninitialized or invalid data format");
            checkArgument(original.dbObject != null, "Uninitialized database object");
            String collection2 = null;
            checkArgument((collection2 = trimToNull(original.collection)) != null,
                    "Uninitialized or invalid collection");
            return new ProvDataSource(name2, original.url, objectId2, type2, original.importer, original.downloader,
                    original.parser, format2, original.dbObject, collection2);
        }
    }

    public static class ProvGeocoding {
        private final GeoJsonPoint point;
        private final Class<?> geocoder;

        public ProvGeocoding(final GeoJsonPoint point, final Class<?> geocoder) {
            this.point = point;
            this.geocoder = geocoder;
        }

        public static ProvGeocoding validate(final ProvGeocoding original) {
            checkArgument(original != null, "Uninitialized geocoding");
            checkArgument(original.point != null, "Uninitialized location point");
            checkArgument(original.geocoder != null, "Uninitialized geocoder");
            return original;
        }
    }

    // TODO

    public static class EntrezHelper {
    } // TODO

    public static class HttpClientProvider {
    } // TODO

    public static class GeocodingHelper {
    } // TODO

}