/*
* 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.
*
* Contributions from 2013-2017 where performed either by US government
* employees, or under US Veterans Health Administration contracts.
*
* US Veterans Health Administration contributions by government employees
* are work of the U.S. Government and are not subject to copyright
* protection in the United States. Portions contributed by government
* employees are USGovWork (17USC ยง105). Not subject to copyright.
*
* Contribution by contractors to the US Veterans Health Administration
* during this period are contractually contributed under the
* Apache License, Version 2.0.
*
* See: https://www.usa.gov/government-works
*
* Contributions prior to 2013:
*
* Copyright (C) International Health Terminology Standards Development Organisation.
* Licensed under the Apache License, Version 2.0.
*
*/
package sh.isaac.api;
//~--- JDK imports ------------------------------------------------------------
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
//~--- non-JDK imports --------------------------------------------------------
import javafx.concurrent.Task;
//~--- JDK imports ------------------------------------------------------------
import javax.inject.Singleton;
//~--- non-JDK imports --------------------------------------------------------
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jvnet.hk2.annotations.Service;
import sh.isaac.api.chronicle.LatestVersion;
import sh.isaac.api.collections.ConceptSequenceSet;
import sh.isaac.api.commit.ChangeSetWriterService;
import sh.isaac.api.commit.CommitService;
import sh.isaac.api.commit.PostCommitService;
import sh.isaac.api.commit.StampService;
import sh.isaac.api.component.concept.ConceptBuilderService;
import sh.isaac.api.component.concept.ConceptService;
import sh.isaac.api.component.concept.ConceptSnapshotService;
import sh.isaac.api.component.concept.ConceptSpecification;
import sh.isaac.api.component.sememe.SememeBuilderService;
import sh.isaac.api.component.sememe.SememeChronology;
import sh.isaac.api.component.sememe.SememeService;
import sh.isaac.api.component.sememe.version.DescriptionSememe;
import sh.isaac.api.component.sememe.version.SememeVersion;
import sh.isaac.api.coordinate.CoordinateFactory;
import sh.isaac.api.externalizable.BinaryDataDifferService;
import sh.isaac.api.externalizable.BinaryDataReaderQueueService;
import sh.isaac.api.externalizable.BinaryDataReaderService;
import sh.isaac.api.externalizable.BinaryDataServiceFactory;
import sh.isaac.api.externalizable.DataWriterService;
import sh.isaac.api.externalizable.OchreExternalizable;
import sh.isaac.api.externalizable.OchreExternalizableSpliterator;
import sh.isaac.api.index.GenerateIndexes;
import sh.isaac.api.index.IndexServiceBI;
import sh.isaac.api.logic.LogicService;
import sh.isaac.api.logic.LogicalExpressionBuilderService;
import sh.isaac.api.metacontent.MetaContentService;
import sh.isaac.api.progress.ActiveTasks;
import sh.isaac.api.util.WorkExecutors;
//~--- classes ----------------------------------------------------------------
/**
* Provides simple static access to common services, in a lookup service aware
* way. Intended to be used in place of static fields placed in classes that
* frequently use a common service. This class was added specifically to address
* problems when a service is used in a mojo that spans more than one project,
* by ensuring that static initialization of services does not provide a way to
* retain stale services.
*
* @author kec
*/
@Service
@Singleton
public class Get
implements OchreCache {
/** The Constant LOG. */
private static final Logger LOG = LogManager.getLogger();
/** The active task set. */
private static ActiveTasks activeTaskSet;
/** The configuration service. */
private static ConfigurationService configurationService;
/** The commit service. */
private static CommitService commitService;
/** The concept active service. */
private static ConceptActiveService conceptActiveService;
/** The concept service. */
private static ConceptService conceptService;
/** The meta content service. */
private static MetaContentService metaContentService;
/** The concept snapshot. */
private static ConceptSnapshotService conceptSnapshot;
/** The identified object service. */
private static IdentifiedObjectService identifiedObjectService;
/** The identifier service. */
private static IdentifierService identifierService;
/** The language coordinate service. */
private static LanguageCoordinateService languageCoordinateService;
/** The logical expression builder service. */
private static LogicalExpressionBuilderService logicalExpressionBuilderService;
/** The logic service. */
private static LogicService logicService;
/** The binary data differ service. */
private static BinaryDataDifferService binaryDataDifferService;
/** The path service. */
private static PathService pathService;
/** The sememe builder service. */
private static SememeBuilderService<?> sememeBuilderService;
/** The sememe service. */
private static SememeService sememeService;
/** The coordinate factory. */
private static CoordinateFactory coordinateFactory;
/** The taxonomy service. */
private static TaxonomyService taxonomyService;
/** The work executors. */
private static WorkExecutors workExecutors;
/** The concept builder service. */
private static ConceptBuilderService conceptBuilderService;
/** The stamp service. */
private static StampService stampService;
/** The post commit service. */
private static PostCommitService postCommitService;
/** The change set writer service. */
private static ChangeSetWriterService changeSetWriterService;
//~--- constructors --------------------------------------------------------
/**
* Instantiates a new gets the.
*/
public Get() {}
//~--- methods -------------------------------------------------------------
/**
* Active tasks.
*
* @return the active tasks
*/
public static ActiveTasks activeTasks() {
if (activeTaskSet == null) {
activeTaskSet = getService(ActiveTasks.class);
}
return activeTaskSet;
}
/**
* Binary data differ service.
*
* @return the binary data differ service
*/
public static BinaryDataDifferService binaryDataDifferService() {
if (binaryDataDifferService == null) {
binaryDataDifferService = getService(BinaryDataDifferService.class);
}
return binaryDataDifferService;
}
/**
* Binary data queue reader.
*
* @param dataPath the data path
* @return the binary data reader queue service
* @throws FileNotFoundException the file not found exception
*/
public static BinaryDataReaderQueueService binaryDataQueueReader(Path dataPath)
throws FileNotFoundException {
return getService(BinaryDataServiceFactory.class).getQueueReader(dataPath);
}
/**
* Binary data reader.
*
* @param dataPath the data path
* @return the binary data reader service
* @throws FileNotFoundException the file not found exception
*/
public static BinaryDataReaderService binaryDataReader(Path dataPath)
throws FileNotFoundException {
return getService(BinaryDataServiceFactory.class).getReader(dataPath);
}
/**
* Binary data writer.
*
* @param dataPath the data path
* @return the data writer service
* @throws IOException Signals that an I/O exception has occurred.
*/
public static DataWriterService binaryDataWriter(Path dataPath)
throws IOException {
return getService(BinaryDataServiceFactory.class).getWriter(dataPath);
}
/**
* Change set writer service.
*
* @return the change set writer service
*/
public static ChangeSetWriterService changeSetWriterService() {
if (changeSetWriterService == null) {
changeSetWriterService = getService(ChangeSetWriterService.class);
}
return changeSetWriterService;
}
/**
* Commit service.
*
* @return the commit service
*/
public static CommitService commitService() {
if (commitService == null) {
commitService = getService(CommitService.class);
}
return commitService;
}
/**
* Concept active service.
*
* @return the concept active service
*/
public static ConceptActiveService conceptActiveService() {
if (conceptActiveService == null) {
conceptActiveService = getService(ConceptActiveService.class);
}
return conceptActiveService;
}
/**
* Concept builder service.
*
* @return the concept builder service
*/
public static ConceptBuilderService conceptBuilderService() {
if (conceptBuilderService == null) {
conceptBuilderService = getService(ConceptBuilderService.class);
}
return conceptBuilderService;
}
/**
* Simple method for getting text of the description of a concept. This
* method will try first to return the fully specified description, or the
* preferred description, as specified in the default
* {@code StampCoordinate} and the default {@code LanguageCoordinate}.
*
* @param conceptId nid or sequence of the concept to get the description
* for
* @return a description for this concept. If no description can be found,
* {@code "No desc for: " + conceptId;} will be returned.
*/
public static String conceptDescriptionText(int conceptId) {
final Optional<LatestVersion<DescriptionSememe<?>>> descriptionOptional =
conceptSnapshot().getDescriptionOptional(conceptId);
if (descriptionOptional.isPresent()) {
return descriptionOptional.get()
.value()
.getText();
}
return "No desc for: " + conceptId;
}
/**
* Concept description text list.
*
* @param conceptIds the concept ids
* @return the string
*/
public static String conceptDescriptionTextList(ConceptSequenceSet conceptIds) {
return conceptDescriptionTextList(conceptIds.asArray());
}
/**
* Concept description text list.
*
* @param conceptIds the concept ids
* @return the string
*/
public static String conceptDescriptionTextList(int[] conceptIds) {
if ((conceptIds != null) && (conceptIds.length > 0)) {
final StringBuilder builder = new StringBuilder();
builder.append("[");
Arrays.stream(conceptIds).forEach((conceptId) -> {
builder.append(conceptDescriptionText(conceptId));
builder.append(", ");
});
builder.delete(builder.length() - 2, builder.length());
builder.append("]");
return builder.toString();
}
return "[]";
}
/**
* Concept description text list.
*
* @param conceptIds the concept ids
* @return the string
*/
public static String conceptDescriptionTextList(List<Integer> conceptIds) {
return conceptDescriptionTextList(conceptIds.stream()
.mapToInt((boxedInt) -> (int) boxedInt)
.toArray());
}
/**
* Concept service.
*
* @return the concept service
*/
public static ConceptService conceptService() {
if (conceptService == null) {
conceptService = getService(ConceptService.class);
}
return conceptService;
}
/**
* Concept snapshot.
*
* @return a {@code ConceptSnapshotService} configured using the default
* {@code StampCoordinate} and {@code LanguageCoordinate} provided by the
* configuration service.
*/
public static ConceptSnapshotService conceptSnapshot() {
if (conceptSnapshot == null) {
conceptSnapshot = getService(ConceptService.class).getSnapshot(Get.configurationService()
.getDefaultStampCoordinate(),
Get.configurationService()
.getDefaultLanguageCoordinate());
}
return conceptSnapshot;
}
/**
* Note, this method may fail during bootstrap, if concept being requested is not already loaded
* into the concept service.
* @param id either a nid or a concept sequence.
* @return A concept specification for the corresponding identifier
*/
public static ConceptSpecification conceptSpecification(int id) {
id = identifierService().getConceptNid(id);
return new ConceptProxy(conceptDescriptionText(id), identifierService().getUuidArrayForNid(id));
}
/**
* Configuration service.
*
* @return the configuration service
*/
public static ConfigurationService configurationService() {
if (configurationService == null) {
configurationService = getService(ConfigurationService.class);
}
return configurationService;
}
/**
* Coordinate factory.
*
* @return the coordinate factory
*/
public static CoordinateFactory coordinateFactory() {
if (coordinateFactory == null) {
coordinateFactory = getService(CoordinateFactory.class);
}
return coordinateFactory;
}
/**
* Identified object service.
*
* @return the identified object service
*/
public static IdentifiedObjectService identifiedObjectService() {
if (identifiedObjectService == null) {
identifiedObjectService = getService(IdentifiedObjectService.class);
}
return identifiedObjectService;
}
/**
* Identifier service.
*
* @return the identifier service
*/
public static IdentifierService identifierService() {
if (identifierService == null) {
identifierService = getService(IdentifierService.class);
}
return identifierService;
}
/**
* Inferred definition chronology.
*
* @param conceptId either a concept nid or sequence.
* @return the inferred definition chronology for the specified concept
* according to the default logic coordinate.
*/
public static Optional<SememeChronology<? extends SememeVersion<?>>> inferredDefinitionChronology(int conceptId) {
conceptId = identifierService().getConceptNid(conceptId);
return sememeService().getSememesForComponentFromAssemblage(conceptId,
configurationService().getDefaultLogicCoordinate()
.getInferredAssemblageSequence())
.findAny();
}
/**
* Language coordinate service.
*
* @return the language coordinate service
*/
public static LanguageCoordinateService languageCoordinateService() {
if (languageCoordinateService == null) {
languageCoordinateService = getService(LanguageCoordinateService.class);
}
return languageCoordinateService;
}
/**
* Logic service.
*
* @return the logic service
*/
public static LogicService logicService() {
if (logicService == null) {
logicService = getService(LogicService.class);
}
return logicService;
}
/**
* Logical expression builder service.
*
* @return the logical expression builder service
*/
public static LogicalExpressionBuilderService logicalExpressionBuilderService() {
if (logicalExpressionBuilderService == null) {
logicalExpressionBuilderService = getService(LogicalExpressionBuilderService.class);
}
return logicalExpressionBuilderService;
}
/**
* Meta content service.
*
* @return the meta content service
*/
public static MetaContentService metaContentService() {
if (metaContentService == null) {
metaContentService = getService(MetaContentService.class);
}
return metaContentService;
}
/**
* Ochre externalizable stream.
*
* @return the stream
*/
public static Stream<OchreExternalizable> ochreExternalizableStream() {
return StreamSupport.stream(new OchreExternalizableSpliterator(), false);
}
/**
* Path service.
*
* @return the path service
*/
public static PathService pathService() {
if (pathService == null) {
pathService = getService(PathService.class);
}
return pathService;
}
/**
* Post commit service.
*
* @return the post commit service
*/
public static PostCommitService postCommitService() {
if (postCommitService == null) {
postCommitService = getService(PostCommitService.class);
}
return postCommitService;
}
/**
* Reset.
*/
@Override
public void reset() {
LOG.info("Resetting service cache.");
activeTaskSet = null;
configurationService = null;
commitService = null;
conceptBuilderService = null;
conceptActiveService = null;
conceptService = null;
metaContentService = null;
conceptSnapshot = null;
coordinateFactory = null;
identifiedObjectService = null;
identifierService = null;
languageCoordinateService = null;
logicalExpressionBuilderService = null;
logicService = null;
pathService = null;
sememeBuilderService = null;
sememeService = null;
taxonomyService = null;
workExecutors = null;
stampService = null;
binaryDataDifferService = null;
postCommitService = null;
changeSetWriterService = null;
}
/**
* Sememe builder service.
*
* @return the sememe builder service<? extends sememe chronology<? extends sememe version<?>>>
*/
public static SememeBuilderService<? extends SememeChronology<? extends SememeVersion<?>>> sememeBuilderService() {
if (sememeBuilderService == null) {
sememeBuilderService = getService(SememeBuilderService.class);
}
return sememeBuilderService;
}
/**
* Sememe service.
*
* @return the sememe service
*/
public static SememeService sememeService() {
if (sememeService == null) {
sememeService = getService(SememeService.class);
}
return sememeService;
}
/**
* Sememe service available.
*
* @return true, if successful
*/
public static boolean sememeServiceAvailable() {
if (sememeService == null) {
sememeService = LookupService.getService(SememeService.class);
}
return sememeService != null;
}
/**
* Stamp service.
*
* @return the stamp service
*/
public static StampService stampService() {
if (stampService == null) {
stampService = getService(StampService.class);
}
return stampService;
}
/**
* Perform indexing according to all installed indexers.
*
* Cause all index generators implementing the {@link IndexServiceBI} to first
* <code>clearIndex()</code> then iterate over all sememes in the database
* and pass those chronicles to {@link IndexServiceBI#index(sh.isaac.api.chronicle.ObjectChronology)}
* and when complete, to call <code>commitWriter()</code>.
* {@link IndexServiceBI} services will be discovered using the HK2 dependency injection framework.
* @param indexersToReindex - if null or empty - all indexes found via HK2 will be cleared and
* reindexed. Otherwise, only clear and reindex the instances of {@link IndexServiceBI} which match the specified
* class list. Classes passed in should be an extension of {@link IndexServiceBI}
*
* @return Task that indicates progress.
*/
public static Task<Void> startIndexTask(
@SuppressWarnings("unchecked") Class<? extends IndexServiceBI>... indexersToReindex) {
final GenerateIndexes indexingTask = new GenerateIndexes(indexersToReindex);
LookupService.getService(WorkExecutors.class)
.getExecutor()
.execute(indexingTask);
return indexingTask;
}
/**
* Stated definition chronology.
*
* @param conceptId either a concept nid or sequence.
* @return the stated definition chronology for the specified concept
* according to the default logic coordinate.
*/
public static Optional<SememeChronology<? extends SememeVersion<?>>> statedDefinitionChronology(int conceptId) {
conceptId = identifierService().getConceptNid(conceptId);
return sememeService().getSememesForComponentFromAssemblage(conceptId,
configurationService().getDefaultLogicCoordinate()
.getStatedAssemblageSequence())
.findAny();
}
/**
* Taxonomy service.
*
* @return the taxonomy service
*/
public static TaxonomyService taxonomyService() {
if (taxonomyService == null) {
taxonomyService = getService(TaxonomyService.class);
}
return taxonomyService;
}
/**
* Work executors.
*
* @return the work executors
*/
public static WorkExecutors workExecutors() {
if (workExecutors == null) {
workExecutors = getService(WorkExecutors.class);
}
return workExecutors;
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the service.
*
* @param <T> the generic type
* @param clazz the clazz
* @return the service
*/
private static <T> T getService(Class<T> clazz) {
final T service = LookupService.getService(clazz);
if (service == null) {
throw new RuntimeException("No service for contract '" + clazz.getName() +
"'... Is the service provider on the classpath?");
}
return service;
}
}