/*******************************************************************************
* Copyright (c) 2012, Directors of the Tyndale STEP Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* Neither the name of the Tyndale House, Cambridge (www.TyndaleHouse.com)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package com.tyndalehouse.step.rest.controllers;
import com.google.inject.Inject;
import com.tyndalehouse.step.core.data.EntityDoc;
import com.tyndalehouse.step.core.exceptions.UserExceptionType;
import com.tyndalehouse.step.core.models.BibleInstaller;
import com.tyndalehouse.step.core.models.BibleVersion;
import com.tyndalehouse.step.core.models.VocabResponse;
import com.tyndalehouse.step.core.service.ModuleService;
import com.tyndalehouse.step.core.service.MorphologyService;
import com.tyndalehouse.step.core.service.SwingService;
import com.tyndalehouse.step.core.service.VocabularyService;
import com.tyndalehouse.step.models.info.Info;
import com.tyndalehouse.step.models.info.MorphInfo;
import com.tyndalehouse.step.models.info.VocabInfo;
import com.yammer.metrics.annotation.Timed;
import org.crosswire.jsword.book.BookCategory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.tyndalehouse.step.core.exceptions.UserExceptionType.CONTROLLER_INITIALISATION_ERROR;
import static com.tyndalehouse.step.core.exceptions.UserExceptionType.USER_MISSING_FIELD;
import static com.tyndalehouse.step.core.utils.StringUtils.isNotBlank;
import static com.tyndalehouse.step.core.utils.StringUtils.split;
import static com.tyndalehouse.step.core.utils.ValidateUtils.notEmpty;
import static com.tyndalehouse.step.core.utils.ValidateUtils.notNull;
/**
* The Module Controller servicing requests for module information
*/
public class ModuleController {
private static final Logger LOGGER = LoggerFactory.getLogger(ModuleController.class);
private final ModuleService moduleService;
private final MorphologyService morphology;
private final VocabularyService vocab;
private final SwingService swingService;
/**
* sets up the controller to access module information
*
* @param moduleService the service allowing access to module information
* @param morphology the morphology service
* @param vocabulary the vocabulary service
*/
@Inject
public ModuleController(final ModuleService moduleService,
final MorphologyService morphology,
final VocabularyService vocabulary,
final SwingService swingService) {
notNull(moduleService,
"Intialising the module service in the module administration controller failed",
CONTROLLER_INITIALISATION_ERROR);
notNull(morphology,
"Intialising the morphology service failed in the module administration controller",
CONTROLLER_INITIALISATION_ERROR);
notNull(swingService,
"Intialising the swing service failed in the module administration controller",
CONTROLLER_INITIALISATION_ERROR);
this.swingService = swingService;
this.moduleService = moduleService;
this.morphology = morphology;
this.vocab = vocabulary;
}
/**
* a REST method that returns version of the Bible that are available
*
* @return all versions of modules that are considered to be Bibles.
*/
public List<BibleVersion> getAllModules() {
return this.moduleService.getAvailableModules();
}
/**
* a REST method that returns version of the Bible that are not yet installed
*
* @param installerIndex the index of the installer to look up
* @param types a comma-delimited list of categories of modules to include
* @return all versions of modules that are considered to be modules and usable by STEP.
*/
public List<BibleVersion> getAllInstallableModules(final String installerIndex, final String types) {
notNull(types, "No types of modules were provided", UserExceptionType.SERVICE_VALIDATION_ERROR);
notNull(installerIndex, "No index to installer", UserExceptionType.SERVICE_VALIDATION_ERROR);
final String[] values = split(types, ",");
final BookCategory[] categories = new BookCategory[values.length];
for (int i = 0; i < values.length; i++) {
categories[i] = BookCategory.valueOf(values[i]);
}
return this.moduleService.getAllInstallableModules(Integer.parseInt(installerIndex), categories);
}
/**
* Creates and returns a bible installer
*
* @return the bible installer that was created
*/
public BibleInstaller addDirectoryInstaller() {
return this.swingService.addDirectoryInstaller();
}
/**
* a method that returns all the definitions for a particular key
*
* @param vocabIdentifiers the strong number
* @param reference the reference in which this can be found
* @return the definition(s) that can be resolved from the reference provided
*/
public Info getInfo(final String version, final String reference, final String vocabIdentifiers) {
return this.getInfo(version, reference, vocabIdentifiers, null);
}
/**
* a method that returns all the definitions for a particular key
*
* @param version the version that holds the reference
* @param reference the reference in which this can be found
* @param vocabIdentifiers the strong number
* @param morphIdentifiers the morphology code to lookup
* @return the definition(s) that can be resolved from the reference provided
*/
@Timed(name = "full-vocab", group = "analysis", rateUnit = TimeUnit.SECONDS, durationUnit = TimeUnit.MILLISECONDS)
public Info getInfo(
final String version,
final String reference,
final String vocabIdentifiers,
final String morphIdentifiers) {
LOGGER.debug("Getting information for [{}], [{}], [{}]", new Object[]{reference, this.vocab, morphIdentifiers});
final Info i = new Info();
i.setMorphInfos(translateToInfo(this.morphology.getMorphology(morphIdentifiers), true));
if (isNotBlank(vocabIdentifiers)) {
i.setVocabInfos(translateToVocabInfo(this.vocab.getDefinitions(version, reference, vocabIdentifiers), true));
}
return i;
}
/**
* a method that returns all the definitions for a particular key
*
*
* @param version the version that holds the reference
* @param reference the reference in which this can be found
* @param vocabIdentifiers the strong number
* @return the definition(s) that can be resolved from the reference provided
*/
@Timed(name = "quick-vocab", group = "analysis", rateUnit = TimeUnit.SECONDS, durationUnit = TimeUnit.MILLISECONDS)
public Info getQuickInfo(final String version, final String reference, final String vocabIdentifiers) {
return getQuickInfo(version, reference, vocabIdentifiers, null);
}
/**
* a method that returns all the definitions for a particular key
*
* @param version the version that holds the reference
* @param vocabIdentifiers the strong number
* @param morphIdentifiers the morphology code to lookup
* @return the definition(s) that can be resolved from the reference provided
* @parma reference the verse in which the word is found
*/
@Timed(name = "quick-vocab", group = "analysis", rateUnit = TimeUnit.SECONDS, durationUnit = TimeUnit.MILLISECONDS)
public Info getQuickInfo(final String version, final String reference, final String vocabIdentifiers, final String morphIdentifiers) {
// notEmpty(strong, "A reference must be provided to obtain a definition", USER_MISSING_FIELD);
LOGGER.debug("Getting quick information for [{}], [{}]",
new Object[]{this.vocab, morphIdentifiers});
final Info i = new Info();
i.setMorphInfos(translateToInfo(this.morphology.getQuickMorphology(morphIdentifiers), false));
if (isNotBlank(vocabIdentifiers)) {
i.setVocabInfos(translateToVocabInfo(this.vocab.getQuickDefinitions(version, reference, vocabIdentifiers), false));
}
return i;
}
/**
* Copies over information.
*
* @param vocabResponse the vocab response, including the definitions and the mappings to their related words
* @param includeAllInfo true to include all information
* @return a list of infos
*/
private List<VocabInfo> translateToVocabInfo(final VocabResponse vocabResponse,
final boolean includeAllInfo) {
final List<VocabInfo> morphologyInfos = new ArrayList<VocabInfo>(
vocabResponse.getDefinitions().length);
EntityDoc[] definitions = vocabResponse.getDefinitions();
for (int i = 0; i < definitions.length; i++) {
EntityDoc d = definitions[i];
morphologyInfos.add(new VocabInfo(d, vocabResponse.getRelatedWords(), includeAllInfo));
}
return morphologyInfos;
}
/**
* Morphology to information for the UI
*
* @param morphologies the list of all morphologies
* @param includeAllInfo true to include all information
* @return the morphology information pojo
*/
private List<MorphInfo> translateToInfo(final List<EntityDoc> morphologies, final boolean includeAllInfo) {
final List<MorphInfo> morphologyInfos = new ArrayList<MorphInfo>(morphologies.size());
for (final EntityDoc m : morphologies) {
morphologyInfos.add(new MorphInfo(m, includeAllInfo));
}
return morphologyInfos;
}
}