com.novartis.pcs.ontology.service.OntologyTermServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.novartis.pcs.ontology.service.OntologyTermServiceImpl.java

Source

/* 
    
Copyright 2015 Novartis Institutes for Biomedical Research
    
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.
    
*/
package com.novartis.pcs.ontology.service;

import java.util.Collection;
import java.util.Set;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;

import com.novartis.pcs.ontology.dao.ControlledVocabularyTermDAOLocal;
import com.novartis.pcs.ontology.entity.ControlledVocabularyTerm;
import com.novartis.pcs.ontology.entity.CrossReference;
import com.novartis.pcs.ontology.entity.Curator;
import com.novartis.pcs.ontology.entity.Datasource;
import com.novartis.pcs.ontology.entity.DuplicateEntityException;
import com.novartis.pcs.ontology.entity.InvalidEntityException;
import com.novartis.pcs.ontology.entity.Ontology;
import com.novartis.pcs.ontology.entity.Relationship;
import com.novartis.pcs.ontology.entity.RelationshipType;
import com.novartis.pcs.ontology.entity.Synonym;
import com.novartis.pcs.ontology.entity.Term;
import com.novartis.pcs.ontology.entity.Version;
import com.novartis.pcs.ontology.entity.VersionedEntity.Status;
import com.novartis.pcs.ontology.service.search.OntologySearchServiceListener;
import com.novartis.pcs.ontology.service.search.OntologySearchServiceLocal;
import com.novartis.pcs.ontology.service.util.StatusChecker;

/**
 * Session Bean implementation class OntologyTermService
 */
@Stateless
@Local({ OntologyTermServiceLocal.class })
@Remote({ OntologyTermServiceRemote.class })
public class OntologyTermServiceImpl extends OntologyService
        implements OntologyTermServiceRemote, OntologyTermServiceLocal {
    @EJB
    private OntologySearchServiceLocal serachService;

    @EJB
    private ControlledVocabularyTermDAOLocal vocabTermDAO;

    /**
     * Default constructor. 
     */
    public OntologyTermServiceImpl() {

    }

    @Override
    public Collection<Term> loadAll(String ontologyName) {
        Ontology ontology = ontologyDAO.loadByName(ontologyName);
        Collection<Term> terms = termDAO.loadAll(ontology);
        StatusChecker.removeInvalid(terms);
        return terms;
    }

    @Override
    public Collection<Term> loadRoots() {
        Collection<Term> terms = termDAO.loadRoots();
        StatusChecker.removeInvalid(terms);
        return terms;
    }

    @Override
    public Collection<Term> loadLastCreated(int max) {
        Collection<Term> terms = termDAO.loadLastCreated(max);
        StatusChecker.removeInvalid(terms);
        return terms;
    }

    @Override
    public Term loadByReferenceId(String referenceId) {
        return termDAO.loadByReferenceId(referenceId.trim(), true);
    }

    @Override
    public Collection<RelationshipType> loadAllRelationshipTypes() {
        Collection<RelationshipType> types = relationshipTypeDAO.loadAll();
        StatusChecker.removeInvalid(types);
        return types;
    }

    @Override
    @SuppressWarnings({ "unchecked", "unused" })
    @Interceptors({ OntologySearchServiceListener.class })
    public Term addRelationship(String termRefId, String relatedTermRefId, String relationshipType,
            String curatorUsername) throws DuplicateEntityException, InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Version version = lastUnpublishedVersion(curator);
        RelationshipType type = relationshipTypeDAO.loadByRelationship(relationshipType);
        Term term = termDAO.loadByReferenceId(termRefId, true);
        Term relatedTerm = termDAO.loadByReferenceId(relatedTermRefId);

        if (curator == null || !curator.isActive()) {
            throw new InvalidEntityException(curator, "Curator is invalid/inactive");
        }

        StatusChecker.validate(type, term, term.getOntology(), relatedTerm);

        for (Relationship duplicate : term.getRelationships()) {
            if (duplicate.getRelatedTerm().equals(relatedTerm) && duplicate.getType().equals(type)) {
                throw new DuplicateEntityException(duplicate, "Relationship already exists");
            }
        }

        Relationship relationship = new Relationship(term, relatedTerm, type, curator, version);

        return term;
    }

    @Override
    @SuppressWarnings("unchecked")
    @Interceptors({ OntologySearchServiceListener.class })
    public Term addSynonym(String termRefId, ControlledVocabularyTerm vocabTerm, Synonym.Type type,
            String curatorUsername) throws DuplicateEntityException, InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Version version = lastUnpublishedVersion(curator);
        Term term = termDAO.loadByReferenceId(termRefId, true);
        vocabTerm = vocabTermDAO.load(vocabTerm.getId());

        if (curator == null || !curator.isActive()) {
            throw new InvalidEntityException(curator, "Curator is invalid/inactive");
        }

        StatusChecker.validate(term, term.getOntology());

        Set<Ontology> ontologies = vocabTerm.getControlledVocabulary().getDomain().getOntologies();
        if (!ontologies.contains(term.getOntology())) {
            throw new InvalidEntityException(term,
                    "Cannot map controlled vocabulary term from "
                            + vocabTerm.getControlledVocabulary().getDomain().getName() + " domain to "
                            + term.getOntology().getName() + " ontology/codelist");
        }

        Collection<Synonym> duplicates = synonymDAO.loadByCtrldVocabTermId(vocabTerm);
        for (Synonym duplicate : duplicates) {
            if (StatusChecker.isValid(duplicate)) {
                throw new DuplicateEntityException(duplicate,
                        "Synonym already exists for controlled vocabulary term: " + vocabTerm.getName());
            }
        }

        duplicates = synonymDAO.loadBySynonym(vocabTerm.getName());
        for (Synonym duplicate : duplicates) {
            if (StatusChecker.isValid(duplicate) && ontologies.contains(duplicate.getTerm().getOntology())
                    && !duplicate.getTerm().equals(term)) {
                throw new DuplicateEntityException(duplicate,
                        "Similar synonym has been mapped to a different "
                                + duplicate.getTerm().getOntology().getName() + " ontology term: "
                                + duplicate.getTerm().getName());
            }
        }

        Synonym newSynonym = new Synonym(term, vocabTerm.getName(), type, curator, version);
        newSynonym.setControlledVocabularyTerm(vocabTerm);

        return term;
    }

    @Override
    @Interceptors({ OntologySearchServiceListener.class })
    @SuppressWarnings("unchecked")
    public Term addSynonym(String termRefId, String synonym, Synonym.Type type, String datasourceAcronym,
            String referenceId, String curatorUsername) throws DuplicateEntityException, InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Version version = lastUnpublishedVersion(curator);
        Term term = termDAO.loadByReferenceId(termRefId, true);
        Collection<Synonym> duplicates = synonymDAO.loadBySynonym(synonym);
        Datasource datasource = null;

        if (datasourceAcronym != null) {
            datasource = datasourceDAO.loadByAcronym(datasourceAcronym);
            if (datasource == null) {
                throw new InvalidEntityException(datasource, "Datasource does not exist: " + datasourceAcronym);
            }
        }

        if (curator == null || !curator.isActive()) {
            throw new InvalidEntityException(curator, "Curator is invalid/inactive");
        }

        StatusChecker.validate(term, term.getOntology());

        for (Synonym duplicate : duplicates) {
            if (StatusChecker.isValid(duplicate) && duplicate.getControlledVocabularyTerm() == null
                    && ObjectUtils.equals(duplicate.getDatasource(), datasource)) {
                throw new DuplicateEntityException(duplicate, "Synonym already exists for: " + synonym);
            }
        }

        Synonym newSynonym = new Synonym(term, synonym, type, curator, version);
        if (datasource != null) {
            newSynonym.setDatasource(datasource);
            newSynonym.setReferenceId(referenceId);
        }

        return term;
    }

    @Override
    @Interceptors({ OntologySearchServiceListener.class })
    public Term addSynonyms(String termRefId, Collection<ControlledVocabularyTerm> terms, Synonym.Type synonymType,
            String curatorUsername) throws DuplicateEntityException, InvalidEntityException {
        Term term = null;
        for (ControlledVocabularyTerm vocabTerm : terms) {
            term = addSynonym(termRefId, vocabTerm, synonymType, curatorUsername);
        }
        return term;
    }

    @Override
    @Interceptors({ OntologySearchServiceListener.class })
    public Term createTerm(String ontologyName, String termName, String definition, String url, String comments,
            String relatedTermRefId, String relationshipType, String curatorUsername)
            throws DuplicateEntityException, InvalidEntityException {
        return createTerm(ontologyName, termName, definition, url, comments, relatedTermRefId, relationshipType,
                null, null, null, null, curatorUsername);
    }

    @Override
    @SuppressWarnings({ "unchecked", "unused" })
    @Interceptors({ OntologySearchServiceListener.class })
    public Term createTerm(String ontologyName, String termName, String definition, String url, String comments,
            String relatedTermRefId, String relationshipType, String datasourceAcronym, String sourceReferenceId,
            Collection<ControlledVocabularyTerm> synonyms, Synonym.Type synonymType, String curatorUsername)
            throws DuplicateEntityException, InvalidEntityException {
        // Lock ontology because of update of term reference id value
        Ontology ontology = ontologyDAO.loadByName(ontologyName, true);
        Curator curator = curatorDAO.loadByUsername(curatorUsername);

        StatusChecker.validate(ontology);

        if (curator == null || !curator.isActive()) {
            throw new InvalidEntityException(curator, "Curator is invalid/inactive");
        }

        Term duplicate = termDAO.loadByName(termName, ontology);
        if (duplicate != null) {
            throw new DuplicateEntityException(duplicate, "Term already exists");
        }

        Version version = lastUnpublishedVersion(curator);
        String referenceId = nextReferenceId(ontology);

        Term newTerm = new Term(ontology, termName, referenceId, curator, version);

        if (definition != null && definition.trim().length() > 0) {
            newTerm.setDefinition(definition.trim());
        }

        if (url != null && url.trim().length() > 0) {
            newTerm.setUrl(url.trim());
        }

        if (comments != null && comments.trim().length() > 0) {
            newTerm.setComments(comments.trim());
        }

        if (relatedTermRefId != null) {
            Term relatedTerm = termDAO.loadByReferenceId(relatedTermRefId);
            RelationshipType type = relationshipTypeDAO.loadByRelationship(relationshipType);

            StatusChecker.validate(type, relatedTerm);

            Relationship relationship = new Relationship(newTerm, relatedTerm, type, curator, version);
        }

        if (datasourceAcronym != null) {
            Datasource datasource = datasourceDAO.loadByAcronym(datasourceAcronym);
            if (datasource == null) {
                throw new InvalidEntityException(datasource, "Datasource does not exist: " + datasourceAcronym);
            }
            CrossReference xref = new CrossReference(newTerm, datasource, sourceReferenceId, curator);
        }

        if (synonyms != null) {
            for (ControlledVocabularyTerm vocabTerm : synonyms) {
                Collection<Synonym> existingSynonyms = synonymDAO.loadByCtrldVocabTermId(vocabTerm);
                for (Synonym existingSynonym : existingSynonyms) {
                    if (StatusChecker.isValid(existingSynonym)) {
                        throw new DuplicateEntityException(existingSynonym,
                                "Synonym already exists for controlled vocabulary term: " + vocabTerm);
                    }
                }

                Collection<Synonym> duplicateSynonyms = synonymDAO.loadBySynonym(vocabTerm.getName());
                for (Synonym duplicateSynonym : duplicateSynonyms) {
                    if (StatusChecker.isValid(duplicateSynonym)) {
                        throw new DuplicateEntityException(duplicate,
                                "Similar synonym has been mapped to a different ontology term: "
                                        + duplicateSynonym.getTerm().getName());
                    }
                }

                Synonym synonym = new Synonym(newTerm, vocabTerm.getName(), synonymType, curator, version);
                synonym.setControlledVocabularyTerm(vocabTerm);
            }
        }

        termDAO.save(newTerm);
        return newTerm;
    }

    @Override
    public Term updateTerm(long termId, String definition, String url, String comments, String curatorUsername)
            throws InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Term term = termDAO.load(termId, true);

        if (curator == null || !curator.isActive()) {
            throw new InvalidEntityException(curator, "Curator is invalid/inactive");
        }

        StatusChecker.validate(term);

        if (definition != null && definition.trim().length() > 0) {
            term.setDefinition(definition.trim());
        } else {
            term.setDefinition(null);
        }

        if (url != null && url.trim().length() > 0) {
            term.setUrl(url.trim());
        } else {
            term.setUrl(null);
        }

        if (comments != null && comments.trim().length() > 0) {
            term.setComments(comments.trim());
        } else {
            term.setComments(null);
        }

        return term;
    }

    @Override
    public Synonym updateSynonym(long synonymId, Synonym.Type type, String curatorUsername)
            throws InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Synonym synonym = synonymDAO.load(synonymId);

        if (curator == null || !curator.isActive()) {
            throw new InvalidEntityException(curator, "Curator is invalid/inactive");
        }

        StatusChecker.validate(synonym);

        synonym.setType(type);

        return synonym;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Relationship updateRelationship(long relationshipId, String relationshipType, String curatorUsername)
            throws InvalidEntityException, DuplicateEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Relationship relationship = relationshipDAO.load(relationshipId);
        RelationshipType type = relationshipTypeDAO.loadByRelationship(relationshipType);

        if (curator == null || !curator.isActive()) {
            throw new InvalidEntityException(curator, "Curator is invalid/inactive");
        }

        StatusChecker.validate(type, relationship);

        Term term = relationship.getTerm();
        Term relatedTerm = relationship.getRelatedTerm();
        for (Relationship duplicate : term.getRelationships()) {
            if (duplicate.getRelatedTerm().equals(relatedTerm) && duplicate.getType().equals(type)) {
                throw new DuplicateEntityException(duplicate, "Relationship already exists");
            }
        }

        relationship.setType(type);

        return relationship;
    }

    @Override
    public void deleteTerm(long termId, String curatorUsername) throws InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Term term = termDAO.load(termId, true);
        if (term != null) {
            if (curator == null || !curator.isActive()) {
                throw new InvalidEntityException(curator, "Curator is invalid/inactive");
            }

            if (!term.getStatus().equals(Status.PENDING)) {
                throw new InvalidEntityException(term, "Cannot delete non-pending term");
            }

            if (!term.getCreatedBy().equals(curator)) {
                throw new InvalidEntityException(term, "Cannot delete term created by another curator");
            }

            Collection<Relationship> descendents = relationshipDAO.loadByRelatedTermId(termId);
            for (Relationship relationship : descendents) {
                Term childTerm = relationship.getTerm();
                childTerm.getRelationships().remove(relationship);
                relationshipDAO.delete(relationship);
            }

            termDAO.delete(term);
            serachService.delete(term);
        }
    }

    @Override
    public void deleteSynonym(long synonymId, String curatorUsername) throws InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Synonym synonym = synonymDAO.load(synonymId);
        if (synonym != null) {
            Term term = synonym.getTerm();

            if (curator == null || !curator.isActive()) {
                throw new InvalidEntityException(curator, "Curator is invalid/inactive");
            }

            if (!synonym.getStatus().equals(Status.PENDING)) {
                throw new InvalidEntityException(synonym, "Cannot delete non-pending synonym");
            }

            if (!synonym.getCreatedBy().equals(curator)) {
                throw new InvalidEntityException(synonym, "Cannot delete synonym created by another curator");
            }

            term.getSynonyms().remove(synonym);
            synonymDAO.delete(synonym);
            serachService.update(term);
        }
    }

    @Override
    public void deleteRelationship(long relationshipId, String curatorUsername) throws InvalidEntityException {
        Curator curator = curatorDAO.loadByUsername(curatorUsername);
        Relationship relationship = relationshipDAO.load(relationshipId);
        if (relationship != null) {
            Term term = relationship.getTerm();

            if (curator == null || !curator.isActive()) {
                throw new InvalidEntityException(curator, "Curator is invalid/inactive");
            }

            if (!relationship.getStatus().equals(Status.PENDING)) {
                throw new InvalidEntityException(relationship, "Cannot delete non-pending relationship");
            }

            if (!relationship.getCreatedBy().equals(curator)) {
                throw new InvalidEntityException(relationship,
                        "Cannot delete relationship created by another curator");
            }

            term.getRelationships().remove(relationship);
            relationshipDAO.delete(relationship);
        }
    }

    // Ontology must be locked before calling this
    // i.e. ontologyDao.loadByName(name, true);
    private String nextReferenceId(Ontology ontology) {
        StringBuilder referenceId = new StringBuilder();
        String prefix = ontology.getReferenceIdPrefix();
        if (prefix != null && prefix.length() > 0) {
            referenceId.append(prefix).append(':');
        }

        int value = ontology.getReferenceIdValue() + 1;
        ontology.setReferenceIdValue(value);

        referenceId.append(StringUtils.leftPad(Integer.toString(value), 7, "0"));

        return referenceId.toString();
    }
}