/**
* Copyright (c) 2016 Lemur Consulting Ltd.
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 uk.co.flax.biosolr.ontology.core;
import org.apache.commons.lang3.StringUtils;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.co.flax.biosolr.ontology.core.ols.OLSHttpClient;
import uk.co.flax.biosolr.ontology.core.ols.OLSOntologyConfiguration;
import uk.co.flax.biosolr.ontology.core.ols.OLSOntologyHelper;
import uk.co.flax.biosolr.ontology.core.ols.OLSTermsOntologyHelper;
import uk.co.flax.biosolr.ontology.core.owl.OWLOntologyConfiguration;
import uk.co.flax.biosolr.ontology.core.owl.OWLOntologyHelper;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadFactory;
/**
* Generic builder class for the OntologyHelper implementations.
*
* <p>
* This should be used instead of instantiating OntologyHelper
* implementations directly. Depending on the settings passed, it will
* determine the required implementation and build it with those
* settings. For example:
* </p>
*
* <pre>
OntologyHelper helper = new OntologyHelperBuilder()
.olsBaseUrl("http://www.ebi.ac.uk/ols/beta")
.ontology("efo")
.build();
* </pre>
*
* <p>Created by Matt Pearce on 23/02/16.</p>
* @author Matt Pearce
*/
public class OntologyHelperBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(OntologyHelperBuilder.class);
// General properties
private String nodePathSeparator = OntologyHelperConfiguration.NODE_PATH_SEPARATOR;
private String nodeLabelSeparator = OntologyHelperConfiguration.NODE_LABEL_SEPARATOR;
// OWL configuration properties
private String ontologyUri;
private String[] labelPropertyUris;
private String[] synonymPropertyUris;
private String[] definitionPropertyUris;
private String[] ignorePropertyUris;
// OLS configuration properties
private String olsBaseUrl;
private String ontology;
private int pageSize = OLSOntologyHelper.PAGE_SIZE;
private int threadpoolSize = OLSOntologyHelper.THREADPOOL_SIZE;
private ThreadFactory threadFactory;
/**
* Set the separator to use between nodes in a parentPath string.
* @param separator the separator.
* @return the current object.
*/
public OntologyHelperBuilder nodePathSeparator(String separator) {
this.nodePathSeparator = separator;
return this;
}
/**
* Set the separator to use between IRIs and labels in a parentPath string.
* @param separator the separator.
* @return the current object.
*/
public OntologyHelperBuilder nodeLabelSeparator(String separator) {
this.nodeLabelSeparator = separator;
return this;
}
/**
* Set the ontology URI to use. This implies that the required
* OntologyHelper will be for OWL.
* @param uri the ontology URI, either a file URI or URL.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder ontologyUri(String uri) {
this.ontologyUri = uri;
return this;
}
/**
* Set the label property URIs (used by OWL).
* @param uris the URIs.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder labelPropertyUris(String[] uris) {
this.labelPropertyUris = uris;
return this;
}
/**
* Set the synonym property URIs (used by OWL).
* @param uris the URIs.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder synonymPropertyUris(String[] uris) {
this.synonymPropertyUris = uris;
return this;
}
/**
* Set the definition property URIs (used by OWL).
* @param uris the URIs.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder definitionPropertyUris(String[] uris) {
this.definitionPropertyUris = uris;
return this;
}
/**
* Set the ignore property URIs (used by OWL).
* @param uris the URIs.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder ignorePropertyUris(String[] uris) {
this.ignorePropertyUris = uris;
return this;
}
/**
* Set the OLS base URL (required for an OLS OntologyHelper).
* @param url the URL.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder olsBaseUrl(String url) {
this.olsBaseUrl = url;
return this;
}
/**
* Set the OLS ontology in use (used by OLS, optional).
* @param ontology the ontology.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder ontology(String ontology) {
this.ontology = ontology;
return this;
}
/**
* Set the maximum page size to use when calling OLS (OLS only).
* @param pageSize the page size.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder pageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}
/**
* Set the maximum number of threads to use when calling OLS (OLS only).
* @param tpSize the thread pool size.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder threadpoolSize(int tpSize) {
this.threadpoolSize = tpSize;
return this;
}
/**
* Set the thread factory to use when calling OLS (OLS only).
* @param tf the thread factory.
* @return the current OntologyHelperBuilder object.
*/
public OntologyHelperBuilder threadFactory(ThreadFactory tf) {
this.threadFactory = tf;
return this;
}
/**
* Build the appropriate OntologyHelper instance, dependent on which
* properties have been supplied. Note that if both an ontologyURI and
* an OLS base URL have been given, the returned helper will be for
* OWL.
* @return an OntologyHelper implementation.
* @throws OntologyHelperException if there are not enough properties
* to decide which type of helper to build, or the ontology URI is not
* in a valid format.
*/
public OntologyHelper build() throws OntologyHelperException {
validateParameters();
OntologyHelper helper;
OntologyHelperConfiguration configuration;
if (StringUtils.isNotBlank(ontologyUri)) {
try {
configuration = new OWLOntologyConfiguration(ontologyUri,
arrayToList(labelPropertyUris, OWLOntologyConfiguration.LABEL_PROPERTY_URI),
arrayToList(synonymPropertyUris, OWLOntologyConfiguration.SYNONYM_PROPERTY_URI),
arrayToList(definitionPropertyUris, OWLOntologyConfiguration.DEFINITION_PROPERTY_URI),
arrayToList(ignorePropertyUris));
helper = new OWLOntologyHelper((OWLOntologyConfiguration) configuration);
} catch (URISyntaxException e) {
LOGGER.error("Invalid ontology URI {}: {}", ontologyUri, e.getMessage());
throw new OntologyHelperException(e);
}
} else if (StringUtils.isNotBlank(olsBaseUrl)) {
configuration = new OLSOntologyConfiguration(olsBaseUrl, ontology, pageSize);
OLSHttpClient httpClient = new OLSHttpClient(threadpoolSize, threadFactory);
if (StringUtils.isNotBlank(ontology)) {
helper = new OLSOntologyHelper((OLSOntologyConfiguration) configuration, httpClient);
} else {
helper = new OLSTermsOntologyHelper((OLSOntologyConfiguration) configuration, httpClient);
}
} else {
throw new OntologyHelperException("Could not create OntologyHelper - not enough configuration");
}
configuration.setNodeLabelSeparator(nodeLabelSeparator);
configuration.setNodePathSeparator(nodePathSeparator);
return helper;
}
/**
* Validate that we have enough parameters to build an OntologyHelper.
* @throws OntologyHelperException if the validation fails.
*/
private void validateParameters() throws OntologyHelperException {
if (StringUtils.isBlank(ontologyUri) &&
StringUtils.isBlank(olsBaseUrl)) {
throw new OntologyHelperException("No ontology URI or OLS base URL set - need one or the other!");
}
}
private static List<String> arrayToList(String[] array, String... defaults) {
List<String> ret;
if (array == null || array.length == 0) {
ret = Arrays.asList(defaults);
} else {
ret = new ArrayList<>(array.length);
for (String entry : array) {
String[] parts = entry.split(",\\s*");
ret.addAll(Arrays.asList(parts));
}
}
return ret;
}
}