/* * This file is part of ADDIS (Aggregate Data Drug Information System). * ADDIS is distributed from http://drugis.org/. * Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen. * Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels, * Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel * Reid. * Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin * Schimbinschi. * Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter * Reckman. * Copyright © 2013 Gert van Valkenhoef, Joël Kuiper. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.drugis.addis.entities; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.collections15.Predicate; import org.drugis.addis.entities.analysis.BenefitRiskAnalysis; import org.drugis.addis.entities.analysis.MetaAnalysis; import org.drugis.addis.entities.analysis.MetaBenefitRiskAnalysis; import org.drugis.addis.entities.analysis.NetworkMetaAnalysis; import org.drugis.addis.entities.analysis.PairWiseMetaAnalysis; import org.drugis.addis.entities.analysis.StudyBenefitRiskAnalysis; import org.drugis.addis.entities.treatment.TreatmentCategorization; import org.drugis.addis.entities.treatment.TreatmentDefinition; import org.drugis.common.beans.FilteredObservableList; import org.drugis.common.beans.SortedSetModel; import com.jgoodies.binding.beans.BeanUtils; import com.jgoodies.binding.list.ArrayListModel; import com.jgoodies.binding.list.ObservableList; public class DomainImpl extends Domain { private static final EntityCategory CATEGORY_UNITS = new EntityCategory("units", Unit.class); private static final EntityCategory CATEGORY_INDICATIONS = new EntityCategory("indications", Indication.class); private static final EntityCategory CATEGORY_DRUGS = new EntityCategory("drugs", Drug.class); private static final EntityCategory CATEGORY_TREATMENTCATEGORIZATIONS = new EntityCategory("treatmentCategorizations", TreatmentCategorization.class); private static final EntityCategory CATEGORY_ENDPOINTS = new EntityCategory("endpoints", Endpoint.class); private static final EntityCategory CATEGORY_ADVERSE_EVENTS = new EntityCategory("adverseEvents", AdverseEvent.class); private static final EntityCategory CATEGORY_POPULATION_CHARACTERISTICS = new EntityCategory("populationCharacteristics", PopulationCharacteristic.class); private static final EntityCategory CATEGORY_STUDIES = new EntityCategory("studies", Study.class); private static final EntityCategory CATEGORY_PAIR_WISE_META_ANALYSES = new EntityCategory("pairWiseMetaAnalyses", PairWiseMetaAnalysis.class); private static final EntityCategory CATEGORY_NETWORK_META_ANALYSES = new EntityCategory("networkMetaAnalyses", NetworkMetaAnalysis.class); private static final EntityCategory CATEGORY_BENEFIT_RISK_ANALYSES = new EntityCategory("benefitRiskAnalyses", BenefitRiskAnalysis.class); private static final List<EntityCategory> CATEGORIES = Arrays.asList(new EntityCategory[] { CATEGORY_UNITS, CATEGORY_INDICATIONS, CATEGORY_DRUGS, CATEGORY_TREATMENTCATEGORIZATIONS, CATEGORY_ENDPOINTS, CATEGORY_ADVERSE_EVENTS, CATEGORY_POPULATION_CHARACTERISTICS, CATEGORY_STUDIES, CATEGORY_PAIR_WISE_META_ANALYSES, CATEGORY_NETWORK_META_ANALYSES, CATEGORY_BENEFIT_RISK_ANALYSES }); private class DomainSortedSetModel<E extends Entity> extends SortedSetModel<E> { @Override public void add(int index, E element) { if (element == null) { throw new NullPointerException("Entity added to the Domain may not be null"); } if (contains(element)) { throw new EntityIdExistsException(element.getLabel()); } checkDependencies(element); super.add(index, element); }; @Override public E remove(int index) { checkDependents(get(index)); return super.remove(index); } @Override public boolean remove(Object o) { if (o instanceof Entity) { checkDependents((Entity)o); } return super.remove(o); } } private SortedSetModel<Endpoint> d_endpoints = new DomainSortedSetModel<Endpoint>(); private SortedSetModel<Study> d_studies = new DomainSortedSetModel<Study>(); private SortedSetModel<MetaAnalysis> d_metaAnalyses = new DomainSortedSetModel<MetaAnalysis>(); private SortedSetModel<Drug> d_drugs = new DomainSortedSetModel<Drug>(); private ObservableList<TreatmentCategorization> d_treatments = new ArrayListModel<TreatmentCategorization>(); private SortedSetModel<Indication> d_indications = new DomainSortedSetModel<Indication>(); private SortedSetModel<Unit> d_units = new DomainSortedSetModel<Unit>(); private SortedSetModel<PopulationCharacteristic> d_populationCharacteristics = new DomainSortedSetModel<PopulationCharacteristic>(); private SortedSetModel<AdverseEvent> d_adverseEvents = new DomainSortedSetModel<AdverseEvent>(); private SortedSetModel<BenefitRiskAnalysis<?>> d_benefitRiskAnalyses = new DomainSortedSetModel<BenefitRiskAnalysis<?>>(); private FilteredObservableList<MetaAnalysis> d_networkMetaAnalyses; private FilteredObservableList<MetaAnalysis> d_pairWiseMetaAnalyses; public DomainImpl() { d_pairWiseMetaAnalyses = new FilteredObservableList<MetaAnalysis>(getMetaAnalyses(), new Predicate<MetaAnalysis>() { public boolean evaluate(MetaAnalysis obj) { return obj instanceof PairWiseMetaAnalysis; } }); d_networkMetaAnalyses = new FilteredObservableList<MetaAnalysis>(getMetaAnalyses(), new Predicate<MetaAnalysis>() { public boolean evaluate(MetaAnalysis obj) { return obj instanceof NetworkMetaAnalysis; } }); d_units.add(GRAM); d_units.add(LITER); } public void addOutcomeMeasure(OutcomeMeasure om) { if (om instanceof Endpoint) getEndpoints().add(((Endpoint) om)); else if (om instanceof AdverseEvent) { getAdverseEvents().add(((AdverseEvent) om)); } else { throw new IllegalStateException("Illegal OutcomeMeasure type " + om.getClass()); } } public ObservableList<Study> getStudies(Variable e) throws NullPointerException { if (e == null) { throw new NullPointerException("Variable must not be null"); } if (e instanceof Endpoint) { return new FilteredObservableList<Study>(getStudies(), new EndpointFilter((Endpoint)e)); } if (e instanceof AdverseEvent) { return new FilteredObservableList<Study>(getStudies(), new AdverseEventFilter((AdverseEvent)e)); } if (e instanceof PopulationCharacteristic) { return new FilteredObservableList<Study>(getStudies(), new PopulationCharacteristicFilter((PopulationCharacteristic)e)); } throw new RuntimeException(e.getClass() + " not supported"); } /** * Creates new trivial TreatmentDefinitions based on drug * @param the drug to create a list for */ public ObservableList<Study> getStudies(Drug d) { return new FilteredObservableList<Study>(getStudies(), new TreatmentDefinitionFilter(TreatmentDefinition.createTrivial(d))); } public ObservableList<Study> getStudies(Indication i) { return new FilteredObservableList<Study>(getStudies(), new IndicationFilter(i)); } public ObservableList<TreatmentCategorization> getCategorizations(final Drug drug) { return new FilteredObservableList<TreatmentCategorization>(getTreatmentCategorizations(), new Predicate<TreatmentCategorization>() { public boolean evaluate(TreatmentCategorization obj) { return obj.getDrug().equals(drug); } }); } @Override public boolean equals(Object o) { if (o instanceof Domain) { Domain other = (Domain)o; return ( getEndpoints().equals(other.getEndpoints()) && getDrugs().equals(other.getDrugs()) && getTreatmentCategorizations().equals(other.getTreatmentCategorizations()) && getIndications().equals(other.getIndications()) && getAdverseEvents().equals(other.getAdverseEvents()) && getPopulationCharacteristics().equals(other.getPopulationCharacteristics()) && getStudies().equals(other.getStudies()) && getMetaAnalyses().equals(other.getMetaAnalyses()) && getBenefitRiskAnalyses().equals(other.getBenefitRiskAnalyses()) ); } return false; } @Override public int hashCode() { int hash = 1; hash = hash * 31 + getEndpoints().hashCode(); hash = hash * 31 + getDrugs().hashCode(); hash = hash * 31 + getStudies().hashCode(); return hash; } public Set<Entity> getDependents(Entity e) { Set<Entity> deps = new HashSet<Entity>(); for (Study s : getStudies().getSet()) { if (s.getDependencies().contains(e)) { deps.add(s); } } for (MetaAnalysis s : getMetaAnalyses().getSet()) { if (s.getDependencies().contains(e)) { deps.add(s); } } for (BenefitRiskAnalysis<?> s : getBenefitRiskAnalyses().getSet()) { if (s.getDependencies().contains(e)) { deps.add(s); } } return deps; } public void deleteEntity(Entity entity) throws DependentEntitiesException { if (entity instanceof Drug) { getDrugs().remove(((Drug) entity)); } else if (entity instanceof TreatmentCategorization) { getTreatmentCategorizations().remove(((TreatmentCategorization) entity)); } else if (entity instanceof Endpoint) { getEndpoints().remove(((Endpoint) entity)); } else if (entity instanceof AdverseEvent) { getAdverseEvents().remove(((OutcomeMeasure) entity)); } else if (entity instanceof PopulationCharacteristic) { getPopulationCharacteristics().remove(((PopulationCharacteristic) entity)); } else if (entity instanceof Study) { getStudies().remove(((Study) entity)); } else if (entity instanceof MetaAnalysis) { getMetaAnalyses().remove(((MetaAnalysis) entity)); } else if (entity instanceof MetaBenefitRiskAnalysis) { getBenefitRiskAnalyses().remove(((MetaBenefitRiskAnalysis) entity)); } else if (entity instanceof StudyBenefitRiskAnalysis) { getBenefitRiskAnalyses().remove(((StudyBenefitRiskAnalysis) entity)); } else if (entity instanceof Indication) { getIndications().remove(((Indication) entity)); } else if (entity instanceof Unit) { getUnits().remove(((Unit) entity)); } else { throw new RuntimeException("Unhandled entity type " + entity.getClass().getSimpleName()); } } /** * Checks whether an entity is being depended upon by other entities currently in the Domain. * @param d The entity to check for. * @throws DependentEntitiesException if the entity is being depended upon. */ private void checkDependents(Entity d) throws DependentEntitiesException { Set<Entity> deps = getDependents(d); if (!deps.isEmpty()) { throw new DependentEntitiesException(deps); } } /** * Checks whether an entity has unsatisfied dependencies. * @param d The entity to check for. * @throws EntityMissingDependenciesException if the entity has missing dependencies. */ private void checkDependencies(Entity d) throws EntityMissingDependenciesException { List<Entity> unsatisfied = new ArrayList<Entity>(); for (Entity e : d.getDependencies()) { EntityCategory c = getCategory(e); if (!getCategoryContents(c).contains(e)) { unsatisfied.add(e); } } if (!unsatisfied.isEmpty()) { throw new EntityMissingDependenciesException(unsatisfied); } } public boolean hasDependents(Entity entity) { return !getDependents(entity).isEmpty(); } public List<EntityCategory> getCategories() { return CATEGORIES; } public EntityCategory getCategory(Entity entity) { return getCategory(entity.getClass()); } public EntityCategory getCategory(Class<? extends Entity> entityClass) { for (EntityCategory cat : getCategories()) { if (cat.getEntityClass().isAssignableFrom(entityClass)) { return cat; } } return null; } @SuppressWarnings("unchecked") public ObservableList<? extends Entity> getCategoryContents(EntityCategory node) { if (node == null) { return null; } try { PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor( Domain.class, node.getPropertyName()); return (ObservableList<? extends Entity>)BeanUtils.getValue(this, propertyDescriptor); } catch (IntrospectionException e) { throw new RuntimeException(e); } } @Override public SortedSetModel<Drug> getDrugs() { return d_drugs; } @Override public ObservableList<TreatmentCategorization> getTreatmentCategorizations() { return d_treatments; } @Override public SortedSetModel<Indication> getIndications() { return d_indications; } @Override public SortedSetModel<AdverseEvent> getAdverseEvents() { return d_adverseEvents; } @Override public SortedSetModel<Endpoint> getEndpoints() { return d_endpoints; } @Override public SortedSetModel<PopulationCharacteristic> getPopulationCharacteristics() { return d_populationCharacteristics; } @Override public SortedSetModel<Study> getStudies() { return d_studies; } @Override public SortedSetModel<MetaAnalysis> getMetaAnalyses() { return d_metaAnalyses; } @Override public ObservableList<MetaAnalysis> getPairWiseMetaAnalyses() { return d_pairWiseMetaAnalyses; } @Override public ObservableList<MetaAnalysis> getNetworkMetaAnalyses() { return d_networkMetaAnalyses; } @Override public SortedSetModel<BenefitRiskAnalysis<?>> getBenefitRiskAnalyses() { return d_benefitRiskAnalyses; } @Override public SortedSetModel<Unit> getUnits() { return d_units; } public static class EndpointFilter implements Predicate<Study> { private Endpoint d_endpoint; public EndpointFilter(Endpoint e) { d_endpoint = e; } public boolean evaluate(Study s) { return Study.extractVariables(s.getEndpoints()).contains(d_endpoint); } } public static class AdverseEventFilter implements Predicate<Study> { private AdverseEvent d_adverseEvent; public AdverseEventFilter(AdverseEvent ade) { d_adverseEvent = ade; } public boolean evaluate(Study s) { return Study.extractVariables(s.getAdverseEvents()).contains(d_adverseEvent); } } public static class PopulationCharacteristicFilter implements Predicate<Study> { private PopulationCharacteristic d_popChar; public PopulationCharacteristicFilter(PopulationCharacteristic e) { d_popChar = e; } public boolean evaluate(Study s) { return Study.extractVariables(s.getPopulationChars()).contains(d_popChar); } } public static class IndicationFilter implements Predicate<Study> { private final Indication d_indication; public IndicationFilter(Indication indication) { d_indication = indication; } public boolean evaluate(Study s) { return s.getIndication().equals(d_indication); } } public class TreatmentDefinitionFilter implements Predicate<Study> { private final TreatmentDefinition d_treatmentDefinition; public TreatmentDefinitionFilter(TreatmentDefinition td) { d_treatmentDefinition = td; } public boolean evaluate(Study s) { for (Arm a : s.getArms()) { if (d_treatmentDefinition.match(s, a)) { return true; } } return false; } } }