gov.nih.nci.cananolab.service.sample.helper.AdvancedSampleServiceHelper.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.cananolab.service.sample.helper.AdvancedSampleServiceHelper.java

Source

/*L
 *  Copyright SAIC
 *  Copyright SAIC-Frederick
 *
 *  Distributed under the OSI-approved BSD 3-Clause License.
 *  See http://ncip.github.com/cananolab/LICENSE.txt for details.
 */

package gov.nih.nci.cananolab.service.sample.helper;

import gov.nih.nci.cananolab.domain.common.Datum;
import gov.nih.nci.cananolab.domain.common.Finding;
import gov.nih.nci.cananolab.domain.common.PointOfContact;
import gov.nih.nci.cananolab.domain.particle.Characterization;
import gov.nih.nci.cananolab.domain.particle.Function;
import gov.nih.nci.cananolab.domain.particle.FunctionalizingEntity;
import gov.nih.nci.cananolab.domain.particle.NanomaterialEntity;
import gov.nih.nci.cananolab.domain.particle.Sample;
import gov.nih.nci.cananolab.dto.particle.AdvancedSampleBean;
import gov.nih.nci.cananolab.dto.particle.AdvancedSampleSearchBean;
import gov.nih.nci.cananolab.dto.particle.CharacterizationQueryBean;
import gov.nih.nci.cananolab.dto.particle.CompositionQueryBean;
import gov.nih.nci.cananolab.dto.particle.SampleQueryBean;
import gov.nih.nci.cananolab.exception.NoAccessException;
import gov.nih.nci.cananolab.security.enums.SecureClassesEnum;
import gov.nih.nci.cananolab.security.service.SpringSecurityAclService;
import gov.nih.nci.cananolab.system.applicationservice.CaNanoLabApplicationService;
import gov.nih.nci.cananolab.util.ClassUtils;
import gov.nih.nci.cananolab.util.Comparators;
import gov.nih.nci.cananolab.util.Constants;
import gov.nih.nci.cananolab.util.StringUtils;
import gov.nih.nci.cananolab.util.TextMatchMode;
import gov.nih.nci.system.client.ApplicationServiceProvider;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.FetchMode;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Junction;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Helper class providing implementations of advanced sample search methods
 * needed for both local implementation of SampleService and grid service *
 * 
 * @author pansu
 * 
 */
@Component("advancedSampleServiceHelper")
public class AdvancedSampleServiceHelper {
    private static Logger logger = Logger.getLogger(AdvancedSampleServiceHelper.class);

    @Autowired
    private SpringSecurityAclService springSecurityAclService;

    /**
     * Find sample names based on advanced search parameters
     * 
     * @param searchBean
     * @return
     * @throws Exception
     */
    public List<String> findSampleIdsByAdvancedSearch(AdvancedSampleSearchBean searchBean) throws Exception {
        List<String> sampleIds = new ArrayList<String>();
        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        // AND or all empty
        if (searchBean.getLogicalOperator().equals("and")
                || searchBean.getSampleQueries().isEmpty() && searchBean.getCharacterizationQueries().isEmpty()
                        && searchBean.getCompositionQueries().isEmpty()) {
            DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                    .setProjection(Projections.distinct(Property.forName("id")));
            setSampleCriteria(searchBean, crit);
            setCompositionCriteria(searchBean, crit);
            setCharacterizationCriteria(searchBean, crit);
            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {
                String sampleId = results.get(i).toString();
                sampleIds.add(sampleId);
            }
        }
        // OR union the results
        else {
            Set<String> sampleIdSet = new HashSet<String>();
            // sample
            if (!searchBean.getSampleQueries().isEmpty()) {
                DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                        .setProjection(Projections.distinct(Property.forName("id")));
                setSampleCriteria(searchBean, crit);
                List results = appService.query(crit);
                for (int i = 0; i < results.size(); i++) {
                    String sampleId = results.get(i).toString();
                    sampleIds.add(sampleId);
                }
            }
            // composition
            if (!searchBean.getCompositionQueries().isEmpty()) {
                if (searchBean.getCompositionLogicalOperator().equals("and")) {
                    for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
                        List<String> subSampleIds = new ArrayList<String>();
                        DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                                .setProjection(Projections.distinct(Property.forName("id")));
                        setSampleCriteria(searchBean, crit);
                        setCharacterizationCriteria(searchBean, crit);
                        setCompositionCriteriaBase(searchBean, crit);

                        if (query.getCompositionType().equals("function")) {
                            DetachedCriteria subCrit = getFunctionSubquery(query, "inherentFunction.", "function.",
                                    "id");
                            crit.add(Subqueries.exists(subCrit));
                        } else if (query.getCompositionType().equals("nanomaterial entity")) {
                            DetachedCriteria subCrit = getNanomaterialEntitySubquery(query, "nanoEntity.", "id");
                            crit.add(Subqueries.exists(subCrit));
                        } else if (query.getCompositionType().equals("functionalizing entity")) {
                            DetachedCriteria subCrit = getFunctionalizingEntitySubquery(query, "funcEntity.", "id");
                            crit.add(Subqueries.exists(subCrit));
                        }

                        List results = appService.query(crit);
                        for (int i = 0; i < results.size(); i++) {
                            String sampleId = results.get(i).toString();
                            subSampleIds.add(sampleId);
                        }

                        if (sampleIds.size() > 0)
                            sampleIds.retainAll(subSampleIds);
                        else
                            sampleIds.addAll(subSampleIds);
                    }
                } else {
                    DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                            .setProjection(Projections.distinct(Property.forName("id")));
                    setCompositionCriteria(searchBean, crit);
                    List results = appService.query(crit);
                    for (int i = 0; i < results.size(); i++) {
                        String sampleId = results.get(i).toString();
                        sampleIds.add(sampleId);
                    }
                }
            }
            if (!searchBean.getCharacterizationQueries().isEmpty()) {
                // characterization
                DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                        .setProjection(Projections.distinct(Property.forName("id")));
                setCharacterizationCriteria(searchBean, crit);
                List results = appService.query(crit);
                for (int i = 0; i < results.size(); i++) {
                    String sampleId = results.get(i).toString();
                    sampleIds.add(sampleId);
                }
            }
        }

        //filter out redundant ones and non-accessible ones
        List<String> filteredSampleIds = new ArrayList<String>();
        for (String sampleId : sampleIds) {
            if (!filteredSampleIds.contains(sampleId) && (springSecurityAclService
                    .currentUserHasReadPermission(Long.valueOf(sampleId), SecureClassesEnum.SAMPLE.getClazz())
                    || springSecurityAclService.currentUserHasWritePermission(Long.valueOf(sampleId),
                            SecureClassesEnum.SAMPLE.getClazz()))) {
                filteredSampleIds.add(sampleId);
            } else { // ignore no access exception
                logger.debug("User doesn't have access to sample with id " + sampleId);
            }
        }
        return filteredSampleIds;
    }

    /**
     * Find sample names based on advanced search parameters
     * 
     * @param searchBean
     * @return
     * @throws Exception
     */
    public Map<String, String> findSampleIdNamesByAdvancedSearch(AdvancedSampleSearchBean searchBean)
            throws Exception {
        List<String> sampleIds = new ArrayList<String>();

        Map<String, String> sampleIdNameMap = new HashMap<String, String>();

        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();

        ProjectionList projList = Projections.projectionList();
        projList.add(Property.forName("id"));
        projList.add(Property.forName("name"));

        // AND or all empty
        if (searchBean.getLogicalOperator().equals("and")
                || searchBean.getSampleQueries().isEmpty() && searchBean.getCharacterizationQueries().isEmpty()
                        && searchBean.getCompositionQueries().isEmpty()) {
            DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                    .setProjection(Projections.distinct(projList));
            //Projections.distinct(Property.forName("id")));
            setSampleCriteria(searchBean, crit);
            setCompositionCriteria(searchBean, crit);
            setCharacterizationCriteria(searchBean, crit);
            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {

                Object[] row = (Object[]) results.get(i);
                String id = row[0].toString();
                String name = row[1].toString();

                logger.debug("id is: " + id);
                logger.debug("name is: " + name);
                String sampleId = id;

                sampleIds.add(sampleId);

                sampleIdNameMap.put(id, name);

            }
        }
        // OR union the results
        else {
            Set<String> sampleIdSet = new HashSet<String>();
            // sample
            if (!searchBean.getSampleQueries().isEmpty()) {

                //            ProjectionList projList = Projections.projectionList();
                //            projList.add(Property.forName("id"));
                //            projList.add(Property.forName("name"));

                DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                        .setProjection(Projections.distinct(projList));
                //Projections.distinct(Property.forName("id")));
                setSampleCriteria(searchBean, crit);
                List results = appService.query(crit);
                for (int i = 0; i < results.size(); i++) {

                    Object[] row = (Object[]) results.get(i);
                    String id = row[0].toString();
                    String name = row[1].toString();
                    logger.debug("id is: " + id);
                    logger.debug("name is: " + name);
                    String sampleId = id;
                    sampleIds.add(sampleId);

                    sampleIdNameMap.put(id, name);
                }
            }

            //         // composition
            if (!searchBean.getCompositionQueries().isEmpty()) {
                if (searchBean.getCompositionLogicalOperator().equals("and")) {
                    for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
                        List<String> subSampleIds = new ArrayList<String>();
                        DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                                .setProjection(Projections.distinct(projList));
                        //Projections.distinct(Property.forName("id")));
                        setSampleCriteria(searchBean, crit);
                        setCharacterizationCriteria(searchBean, crit);
                        setCompositionCriteriaBase(searchBean, crit);

                        if (query.getCompositionType().equals("function")) {
                            DetachedCriteria subCrit = getFunctionSubquery(query, "inherentFunction.", "function.",
                                    "id");
                            crit.add(Subqueries.exists(subCrit));
                        } else if (query.getCompositionType().equals("nanomaterial entity")) {
                            DetachedCriteria subCrit = getNanomaterialEntitySubquery(query, "nanoEntity.", "id");
                            crit.add(Subqueries.exists(subCrit));
                        } else if (query.getCompositionType().equals("functionalizing entity")) {
                            DetachedCriteria subCrit = getFunctionalizingEntitySubquery(query, "funcEntity.", "id");
                            crit.add(Subqueries.exists(subCrit));
                        }

                        List results = appService.query(crit);
                        for (int i = 0; i < results.size(); i++) {
                            Object[] row = (Object[]) results.get(i);
                            String id = row[0].toString();
                            String name = row[1].toString();
                            logger.debug("id is: " + id);
                            logger.debug("name is: " + name);
                            String sampleId = id;
                            //String sampleId = obj.toString();
                            subSampleIds.add(sampleId);

                            sampleIdNameMap.put(id, name);
                        }

                        if (sampleIds.size() > 0)
                            sampleIds.retainAll(subSampleIds);
                        else
                            sampleIds.addAll(subSampleIds);
                    }
                } else {
                    DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                            .setProjection(Projections.distinct(projList));
                    //Projections.distinct(Property.forName("id")));
                    setCompositionCriteria(searchBean, crit);
                    List results = appService.query(crit);
                    for (int i = 0; i < results.size(); i++) {

                        Object[] row = (Object[]) results.get(i);
                        String id = row[0].toString();
                        String name = row[1].toString();
                        logger.debug("id is: " + id);
                        logger.debug("name is: " + name);
                        String sampleId = id;
                        //String sampleId = obj.toString();
                        sampleIds.add(sampleId);

                        sampleIdNameMap.put(id, name);
                    }
                }
            }
            if (!searchBean.getCharacterizationQueries().isEmpty()) {
                // characterization
                DetachedCriteria crit = DetachedCriteria.forClass(Sample.class, "rootCrit")
                        .setProjection(Projections.distinct(projList));
                //Projections.distinct(Property.forName("id")));
                setCharacterizationCriteria(searchBean, crit);
                List results = appService.query(crit);
                for (int i = 0; i < results.size(); i++) {
                    Object[] row = (Object[]) results.get(i);
                    String id = row[0].toString();
                    String name = row[1].toString();
                    logger.debug("id is: " + id);
                    logger.debug("name is: " + name);
                    String sampleId = id;
                    //String sampleId = obj.toString();
                    sampleIds.add(sampleId);
                    sampleIdNameMap.put(id, name);
                }
            }
        }

        Iterator<String> ite = sampleIdNameMap.keySet().iterator();
        while (ite.hasNext()) {
            Long sampleId = Long.valueOf(ite.next());
            if (!springSecurityAclService.currentUserHasReadPermission(sampleId,
                    SecureClassesEnum.SAMPLE.getClazz())
                    && !springSecurityAclService.currentUserHasWritePermission(sampleId,
                            SecureClassesEnum.SAMPLE.getClazz())) {
                logger.debug("User doesn't have access to sample with id " + sampleId);
                ite.remove();
            }
        }

        //filter out redundant ones and non-accessible ones
        //      List<String>filteredSampleIds=new ArrayList<String>();
        //      for (String sampleId: sampleIds) {
        //         if (!filteredSampleIds.contains(sampleId)
        //               && StringUtils.containsIgnoreCase(getAccessibleData(),
        //                     sampleId)) {
        //            filteredSampleIds.add(sampleId);
        //         } else { // ignore no access exception
        //            logger.debug("User doesn't have access to sample with id "
        //                  + sampleId);
        //         }
        //      }

        return sampleIdNameMap;
    }

    /**
     * Find sample details as an AdvancedSampleBean for the given sample name
     * and advanced search parameters
     * 
     * @param sampleId
     * @param searchBean
     * @return
     * @throws Exception
     */
    public AdvancedSampleBean findAdvancedSampleByAdvancedSearch(String sampleId,
            AdvancedSampleSearchBean searchBean) throws Exception {
        if (!springSecurityAclService.currentUserHasReadPermission(Long.valueOf(sampleId),
                SecureClassesEnum.SAMPLE.getClazz())
                && !springSecurityAclService.currentUserHasWritePermission(Long.valueOf(sampleId),
                        SecureClassesEnum.SAMPLE.getClazz())) {
            throw new NoAccessException();
        }
        // load sample first with point of contact info and function info and
        // datum info
        DetachedCriteria crit = DetachedCriteria.forClass(Sample.class)
                .add(Restrictions.eq("id", new Long(sampleId)));
        crit.setFetchMode("primaryPointOfContact", FetchMode.JOIN);
        crit.setFetchMode("primaryPointOfContact.organization", FetchMode.JOIN);
        crit.setFetchMode("otherPointOfContactCollection", FetchMode.JOIN);
        crit.setFetchMode("otherPointOfContactCollection.organization", FetchMode.JOIN);
        crit.setFetchMode("sampleComposition.nanomaterialEntityCollection", FetchMode.JOIN);
        crit.setFetchMode("sampleComposition.nanomaterialEntityCollection.composingElementCollection",
                FetchMode.JOIN);
        crit.setFetchMode(
                "sampleComposition.nanomaterialEntityCollection.composingElementCollection.inherentFunctionCollection",
                FetchMode.JOIN);

        crit.setFetchMode("sampleComposition.functionalizingEntityCollection", FetchMode.JOIN);
        crit.setFetchMode("sampleComposition.functionalizingEntityCollection.functionCollection", FetchMode.JOIN);
        crit.setFetchMode("characterizationCollection", FetchMode.JOIN);
        crit.setFetchMode("characterizationCollection.findingCollection", FetchMode.JOIN);
        crit.setFetchMode("characterizationCollection.findingCollection.datumCollection", FetchMode.JOIN);
        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
        List result = appService.query(crit);
        Sample sample = null;
        if (!result.isEmpty()) {
            sample = (Sample) result.get(0);
        }

        List<PointOfContact> pocs = findPointOfContactsBy(sample, searchBean);
        List<Function> functions = findFunctionsBy(sampleId, searchBean);
        List<NanomaterialEntity> nanoEntities = findNanomaterialEntitiesBy(sampleId, searchBean);
        List<FunctionalizingEntity> funcEntities = findFunctionalizingEntitiesBy(sampleId, searchBean);
        List<Characterization> charas = findCharacterizationsBy(sampleId, searchBean);
        List<Datum> data = findDataBy(sample, searchBean);
        AdvancedSampleBean advancedSampleBean = new AdvancedSampleBean(sampleId, pocs, functions, nanoEntities,
                funcEntities, charas, data, searchBean, sample);
        return advancedSampleBean;
    }

    private List<Characterization> findCharacterizationsBy(String sampleId, AdvancedSampleSearchBean searchBean)
            throws Exception {
        List<Characterization> chars = new ArrayList<Characterization>();
        if (searchBean.getCharacterizationQueries().isEmpty()) {
            return chars;
        }
        Long id = new Long(sampleId);
        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        if (searchBean.getCharacterizationQueries().size() == 1
                || searchBean.getCharacterizationLogicalOperator().equals("or")) {
            DetachedCriteria crit = DetachedCriteria.forClass(Characterization.class, "rootCrit");
            crit.createAlias("sample", "sample");
            // join finding and datum
            if (searchBean.getHasDatum()) {
                crit.createAlias("findingCollection", "finding", CriteriaSpecification.LEFT_JOIN);
                crit.createAlias("finding.datumCollection", "datum", CriteriaSpecification.LEFT_JOIN);
            }
            crit.add(Restrictions.eq("sample.id", id));
            Disjunction charDisjunction = getCharacterizationDisjunction(searchBean, crit, "");
            crit.add(charDisjunction);
            crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {
                Characterization achar = (Characterization) results.get(i);
                chars.add(achar);
            }
        } else {
            // hibernate doesn't support union have to execute the query one at
            // a time union the result in Java
            for (CharacterizationQueryBean charQuery : searchBean.getCharacterizationQueries()) {
                DetachedCriteria crit = DetachedCriteria.forClass(Characterization.class, "rootCrit");
                crit.createAlias("sample", "sample");
                crit.add(Restrictions.eq("sample.id", id));
                DetachedCriteria subCrit = getCharacterizationSubquery(charQuery, "id");
                crit.add(Subqueries.exists(subCrit));
                crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
                List results = appService.query(crit);
                for (int i = 0; i < results.size(); i++) {
                    Characterization achar = (Characterization) results.get(i);
                    if (!chars.contains(achar)) {
                        chars.add(achar);
                    }
                }
            }
        }
        Collections.sort(chars, new Comparators.CharacterizationNameAssayTypeDateComparator());
        return chars;
    }

    private Junction getDatumJunction(AdvancedSampleSearchBean searchBean) {
        // if AND and more than one type of datum, don't use junction
        if (searchBean.getCharacterizationLogicalOperator().equals("and") && searchBean.getDatumTypeCount() > 1) {
            return null;
        }
        Disjunction datumDisjunction = Restrictions.disjunction();
        Conjunction datumConjunction = Restrictions.conjunction();
        for (CharacterizationQueryBean charQuery : searchBean.getCharacterizationQueries()) {
            Criterion datumCrit = getDatumCriterion(charQuery);
            if (datumCrit != null) {
                datumDisjunction.add(datumCrit);
                if (searchBean.getDatumTypeCount() == 1) {
                    datumConjunction.add(datumCrit);
                }
            }
        }
        // default to or if only one query
        Junction junction = (searchBean.getCharacterizationLogicalOperator().equals("or")
                || searchBean.getCharacterizationQueries().size() == 1) ? datumDisjunction : datumConjunction;
        return junction;
    }

    private DetachedCriteria getDatumSubquery(CharacterizationQueryBean charQuery, String projectionProperty) {
        DetachedCriteria subCrit = DetachedCriteria.forClass(Datum.class, "subCrit");
        subCrit.setProjection(Projections.distinct(Property.forName(projectionProperty)));
        Criterion datumCrit = getDatumCriterion(charQuery);
        subCrit.add(datumCrit);
        subCrit.add(Restrictions.eqProperty("subCrit." + projectionProperty, "rootCrit.id"));
        return subCrit;
    }

    private Criterion getDatumCriterion(CharacterizationQueryBean charQuery) {
        Criterion datumCrit = null;
        // datum name
        if (!StringUtils.isEmpty(charQuery.getDatumName())) {
            datumCrit = Restrictions.eq("name", charQuery.getDatumName());
        }
        // datum value
        if (!StringUtils.isEmpty(charQuery.getDatumValue())) {
            Float datumValue = new Float(charQuery.getDatumValue());
            datumCrit = Restrictions.and(datumCrit, Restrictions.eq("valueUnit", charQuery.getDatumValueUnit()));
            if ("=".equals(charQuery.getOperand())) {
                datumCrit = Restrictions.and(datumCrit, Expression.eq("value", datumValue));
            } else if (">".equals(charQuery.getOperand())) {
                datumCrit = Restrictions.and(datumCrit, Expression.gt("value", datumValue));
            } else if (">=".equals(charQuery.getOperand())) {
                datumCrit = Restrictions.and(datumCrit, Expression.ge("value", datumValue));
            } else if ("<".equals(charQuery.getOperand())) {
                datumCrit = Restrictions.and(datumCrit, Expression.lt("value", datumValue));
            } else if ("<=".equals(charQuery.getOperand())) {
                datumCrit = Restrictions.and(datumCrit, Expression.le("value", datumValue));
            }
        }
        return datumCrit;
    }

    private List<Datum> findDataBy(Sample sample, AdvancedSampleSearchBean searchBean) throws Exception {
        List<Datum> data = new ArrayList<Datum>();
        Boolean hasDatum = searchBean.getHasDatum();
        if (!hasDatum) {
            return data;
        }
        List<Datum> sampleData = new ArrayList<Datum>();
        for (Characterization achar : sample.getCharacterizationCollection()) {
            for (Finding finding : achar.getFindingCollection()) {
                sampleData.addAll(finding.getDatumCollection());
            }
        }
        DetachedCriteria crit = DetachedCriteria.forClass(Datum.class);
        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        Junction datumJunction = getDatumJunction(searchBean);
        if (datumJunction != null) {
            crit.add(datumJunction);
            crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {
                Datum datum = (Datum) results.get(i);
                if (sampleData.contains(datum)) {
                    data.add(datum);
                }
            }
        } else {
            // hibernate doesn't support union have to execute the query one at
            // a time union the result in Java
            for (CharacterizationQueryBean charQuery : searchBean.getCharacterizationQueries()) {
                // query for datum only when datum is specified as a search
                // criterion
                if (!StringUtils.isEmpty(charQuery.getDatumName())) {
                    crit = DetachedCriteria.forClass(Datum.class, "rootCrit");
                    DetachedCriteria subCrit = getDatumSubquery(charQuery, "id");
                    crit.add(Subqueries.exists(subCrit));
                    crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
                    List results = appService.query(crit);
                    for (int i = 0; i < results.size(); i++) {
                        Datum datum = (Datum) results.get(i);
                        if (sampleData.contains(datum)) {
                            data.add(datum);
                        }
                    }
                }
            }
        }

        return data;
    }

    private List<FunctionalizingEntity> findFunctionalizingEntitiesBy(String sampleId,
            AdvancedSampleSearchBean searchBean) throws Exception {
        List<FunctionalizingEntity> entities = new ArrayList<FunctionalizingEntity>();
        if (!searchBean.getHasAgentMaterial()) {
            return entities;
        }
        Long id = new Long(sampleId);
        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        DetachedCriteria crit = DetachedCriteria.forClass(FunctionalizingEntity.class);
        Junction junction = getFunctionalizingEntityJunction(searchBean, crit);
        if (junction != null) {
            crit.createAlias("sampleComposition", "comp", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("comp.sample", "sample", CriteriaSpecification.LEFT_JOIN);
            crit.add(Restrictions.eq("sample.id", id));
            crit.add(junction);
            crit.setFetchMode("functionCollection", FetchMode.JOIN);
            crit.setFetchMode("functionCollection.targetCollection", FetchMode.JOIN);
            crit.setFetchMode("fileCollection", FetchMode.JOIN);
            crit.setFetchMode("fileCollection.keywordCollection", FetchMode.JOIN);
            crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {
                FunctionalizingEntity entity = (FunctionalizingEntity) results.get(i);
                entities.add(entity);
            }
        } else if (searchBean.getFuncEntityCount() > 1) {
            // Hibernate Criteria API doesn't support union, union in java
            for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
                if (query.getCompositionType().equals("functionalizing entity")) {
                    crit = DetachedCriteria.forClass(FunctionalizingEntity.class);
                    crit.createAlias("sampleComposition", "comp", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("comp.sample", "sample", CriteriaSpecification.LEFT_JOIN);
                    crit.add(Restrictions.eq("sample.id", id));
                    DetachedCriteria subCrit = getFunctionalizingEntitySubquery(query, "", "id");
                    crit.add(Subqueries.exists(subCrit));
                    crit.setFetchMode("functionCollection", FetchMode.JOIN);
                    crit.setFetchMode("functionCollection.targetCollection", FetchMode.JOIN);
                    crit.setFetchMode("fileCollection", FetchMode.JOIN);
                    crit.setFetchMode("fileCollection.keywordCollection", FetchMode.JOIN);
                    crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
                    List results = appService.query(crit);
                    for (int i = 0; i < results.size(); i++) {
                        FunctionalizingEntity entity = (FunctionalizingEntity) results.get(i);
                        if (!entities.contains(entity)) {
                            entities.add(entity);
                        }
                    }
                }
            }
        }
        return entities;
    }

    private List<Function> findFunctionsBy(String sampleId, AdvancedSampleSearchBean searchBean) throws Exception {
        List<Function> functions = new ArrayList<Function>();
        if (!searchBean.getHasFunction()) {
            return functions;
        }
        Long id = new Long(sampleId);
        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        DetachedCriteria crit = DetachedCriteria.forClass(Function.class);
        Junction junction = getFunctionJunction(searchBean, crit);
        if (junction != null) {
            crit.createAlias("composingElement", "ce", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("ce.nanomaterialEntity", "nanoEntity", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("nanoEntity.sampleComposition", "comp", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("comp.sample", "sample", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("functionalizingEntity", "funcEntity", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("funcEntity.sampleComposition", "comp2", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("comp2.sample", "sample2", CriteriaSpecification.LEFT_JOIN);
            crit.add(Restrictions.or(Restrictions.eq("sample.id", id), Restrictions.eq("sample2.id", id)));
            crit.add(junction);
            crit.setFetchMode("targetCollection", FetchMode.JOIN);

            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {
                Function function = (Function) results.get(i);
                functions.add(function);
            }
        } else if (searchBean.getFuncCount() > 1) {
            // Hibernate Criteria API doesn't support union, union in java
            for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
                if (query.getCompositionType().equals("function")) {
                    crit = DetachedCriteria.forClass(Function.class);
                    crit.createAlias("composingElement", "ce", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("ce.nanomaterialEntity", "nanoEntity", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("nanoEntity.sampleComposition", "comp", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("comp.sample", "sample", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("functionalizingEntity", "funcEntity", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("funcEntity.sampleComposition", "comp2", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("comp2.sample", "sample2", CriteriaSpecification.LEFT_JOIN);
                    crit.add(Restrictions.or(Restrictions.eq("sample.id", id), Restrictions.eq("sample2.id", id)));
                    DetachedCriteria subCrit = getFunctionSubquery(query, "", "", "id");
                    crit.add(Subqueries.exists(subCrit));
                    crit.setFetchMode("targetCollection", FetchMode.JOIN);
                    crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
                    List results = appService.query(crit);
                    for (int i = 0; i < results.size(); i++) {
                        Function function = (Function) results.get(i);
                        if (!functions.contains(function)) {
                            functions.add(function);
                        }
                    }
                }
            }
        }
        return functions;
    }

    private List<NanomaterialEntity> findNanomaterialEntitiesBy(String sampleId,
            AdvancedSampleSearchBean searchBean) throws Exception {
        List<NanomaterialEntity> entities = new ArrayList<NanomaterialEntity>();
        Long id = new Long(sampleId);
        if (!searchBean.getHasNanomaterial()) {
            return entities;
        }
        DetachedCriteria crit = DetachedCriteria.forClass(NanomaterialEntity.class);
        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        Junction junction = getNanomaterialEntityJunction(searchBean, crit);
        if (junction != null) {
            // join nanomaterialEntity
            if (searchBean.getHasNanomaterial() && !searchBean.getHasFunction()) {
                if (searchBean.getHasChemicalName()) {
                    crit.createAlias("composingElementCollection", "compElement", CriteriaSpecification.LEFT_JOIN);
                }
            }
            crit.createAlias("sampleComposition", "comp");
            crit.createAlias("comp.sample", "sample");
            crit.add(Restrictions.eq("sample.id", id));
            crit.add(junction);
            crit.setFetchMode("fileCollection", FetchMode.JOIN);
            crit.setFetchMode("fileCollection.keywordCollection", FetchMode.JOIN);
            crit.setFetchMode("composingElementCollection", FetchMode.JOIN);
            crit.setFetchMode("composingElementCollection.inherentFunctionCollection", FetchMode.JOIN);
            crit.setFetchMode("composingElementCollection.inherentFunctionCollection.targetCollection",
                    FetchMode.JOIN);
            crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {
                NanomaterialEntity entity = (NanomaterialEntity) results.get(i);
                entities.add(entity);
            }
        } else if (searchBean.getNanoEntityCount() > 1) {
            // Hibernate Criteria API doesn't support union, union in java
            for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
                if (query.getCompositionType().equals("nanomaterial entity")) {
                    crit = DetachedCriteria.forClass(NanomaterialEntity.class);
                    crit.createAlias("sampleComposition", "comp", CriteriaSpecification.LEFT_JOIN);
                    crit.createAlias("comp.sample", "sample", CriteriaSpecification.LEFT_JOIN);
                    if (!StringUtils.isEmpty(query.getChemicalName())) {
                        crit.createAlias("composingElementCollection", "compElement");
                    }
                    crit.add(Restrictions.eq("sample.id", id));
                    crit.setFetchMode("fileCollection", FetchMode.JOIN);
                    crit.setFetchMode("fileCollection.keywordCollection", FetchMode.JOIN);
                    crit.setFetchMode("composingElementCollection", FetchMode.JOIN);
                    crit.setFetchMode("composingElementCollection.inherentFunctionCollection", FetchMode.JOIN);
                    crit.setFetchMode("composingElementCollection.inherentFunctionCollection.targetCollection",
                            FetchMode.JOIN);
                    DetachedCriteria subCrit = getNanomaterialEntitySubquery(query, "", "id");
                    crit.add(Subqueries.exists(subCrit));
                    crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
                    List results = appService.query(crit);
                    for (int i = 0; i < results.size(); i++) {
                        NanomaterialEntity entity = (NanomaterialEntity) results.get(i);
                        if (!entities.contains(entity)) {
                            entities.add(entity);
                        }
                    }
                }
            }
        }
        return entities;
    }

    private List<PointOfContact> findPointOfContactsBy(Sample sample, AdvancedSampleSearchBean searchBean)
            throws Exception {
        if (!searchBean.getHasPOC()) {
            return null;
        }

        // get POCs associated with the sample
        List<PointOfContact> samplePOCs = new ArrayList<PointOfContact>();
        samplePOCs.add(sample.getPrimaryPointOfContact());
        samplePOCs.addAll(sample.getOtherPointOfContactCollection());
        List<PointOfContact> pocs = new ArrayList<PointOfContact>(samplePOCs);

        CaNanoLabApplicationService appService = (CaNanoLabApplicationService) ApplicationServiceProvider
                .getApplicationService();
        if (searchBean.getCharacterizationQueries().size() == 1
                || searchBean.getSampleLogicalOperator().equals("or")) {
            DetachedCriteria crit = DetachedCriteria.forClass(PointOfContact.class);
            crit.createAlias("organization", "organization");
            crit.add(getPointOfContactDisjunction(searchBean, "", ""));
            crit.setFetchMode("organization", FetchMode.JOIN);
            List results = appService.query(crit);
            for (int i = 0; i < results.size(); i++) {
                PointOfContact poc = (PointOfContact) results.get(i);
                // check if in sample POCs
                if (!samplePOCs.contains(poc)) {
                    pocs.remove(poc);
                }
            }
        } else {
            for (SampleQueryBean query : searchBean.getSampleQueries()) {
                if (query.getNameType().equals("point of contact name")) {
                    DetachedCriteria crit = DetachedCriteria.forClass(PointOfContact.class);
                    crit.createAlias("organization", "organization");
                    DetachedCriteria subCrit = getPointOfContactSubquery(query, "", "", "id");
                    crit.add(Subqueries.exists(subCrit));
                    crit.setFetchMode("organization", FetchMode.JOIN);
                    List results = appService.query(crit);
                    for (int i = 0; i < results.size(); i++) {
                        PointOfContact poc = (PointOfContact) results.get(i);
                        // check if in sample POCs
                        if (!samplePOCs.contains(poc)) {
                            pocs.remove(poc);
                        }
                    }
                }
            }
        }
        return pocs;
    }

    private Criterion getCharacterizationCriterion(CharacterizationQueryBean charQuery, String charAlias) {
        String charClassName = ClassUtils.getShortClassNameFromDisplayName(charQuery.getCharacterizationName());
        Criterion charCrit = null;
        if (charClassName == null) {
            Criterion otherCharCrit1 = Restrictions.eq(charAlias + "class", "OtherCharacterization");
            Criterion otherCharCrit2 = Restrictions.eq(charAlias + "name", charQuery.getCharacterizationName());
            charCrit = Restrictions.and(otherCharCrit1, otherCharCrit2);
        } else {
            charCrit = Restrictions.eq(charAlias + "class", charClassName);
        }
        // assay type
        if (!StringUtils.isEmpty(charQuery.getAssayType())) {
            charCrit = Restrictions.and(charCrit,
                    Restrictions.eq(charAlias + "assayType", charQuery.getAssayType()));
        }
        // datum name
        if (!StringUtils.isEmpty(charQuery.getDatumName())) {
            charCrit = Restrictions.and(charCrit, Restrictions.eq("datum.name", charQuery.getDatumName()));
        }
        // datum value
        if (!StringUtils.isEmpty(charQuery.getDatumValue())) {
            Float datumValue = new Float(charQuery.getDatumValue());
            charCrit = Restrictions.and(charCrit,
                    Restrictions.eq("datum.valueUnit", charQuery.getDatumValueUnit()));
            if (charQuery.getOperand().equals("=") || charQuery.getOperand().equals("is")) {
                charCrit = Restrictions.and(charCrit, Expression.eq("datum.value", datumValue));
            } else if (charQuery.getOperand().equals(">")) {
                charCrit = Restrictions.and(charCrit, Expression.gt("datum.value", datumValue));
            } else if (charQuery.getOperand().equals(">=")) {
                charCrit = Restrictions.and(charCrit, Expression.ge("datum.value", datumValue));
            } else if (charQuery.getOperand().equals("<")) {
                charCrit = Restrictions.and(charCrit, Expression.lt("datum.value", datumValue));
            } else if (charQuery.getOperand().equals("<=")) {
                charCrit = Restrictions.and(charCrit, Expression.le("datum.value", datumValue));
            }
            // ignore the bogus place holder entered for emtpy datum/condition
            // cells
            charCrit = Restrictions.and(charCrit, Expression
                    .not(Expression.ilike("datum.createdBy", Constants.PLACEHOLDER_DATUM_CONDITION_CREATED_BY)));
        }
        return charCrit;
    }

    private Disjunction getCharacterizationDisjunction(AdvancedSampleSearchBean searchBean, DetachedCriteria crit,
            String charAlias) {
        Disjunction charDisjunction = Restrictions.disjunction();
        for (CharacterizationQueryBean charQuery : searchBean.getCharacterizationQueries()) {
            Criterion charCrit = getCharacterizationCriterion(charQuery, charAlias);
            if (charCrit != null) {
                charDisjunction.add(charCrit);
            }
        }
        return charDisjunction;
    }

    private DetachedCriteria getCharacterizationSubquery(CharacterizationQueryBean charQuery,
            String projectionProperty) {
        DetachedCriteria subCrit = DetachedCriteria.forClass(Characterization.class, "subCrit");
        subCrit.setProjection(Projections.distinct(Property.forName(projectionProperty)));
        // join finding and datum
        if (!StringUtils.isEmpty(charQuery.getDatumName())) {
            subCrit.createAlias("subCrit.findingCollection", "finding", CriteriaSpecification.LEFT_JOIN);
            subCrit.createAlias("finding.datumCollection", "datum", CriteriaSpecification.LEFT_JOIN);
        }
        Criterion charCrit = getCharacterizationCriterion(charQuery, "");
        subCrit.add(charCrit);
        subCrit.add(Restrictions.eqProperty("subCrit." + projectionProperty, "rootCrit.id"));
        return subCrit;
    }

    /**
     * Get the junction used in composition queries
     * 
     * @param searchBean
     * @param crit
     * @return
     * @throws Exception
     */
    private Junction getCompositionJunction(AdvancedSampleSearchBean searchBean, DetachedCriteria crit)
            throws Exception {
        // if AND and more than one query per type, don't use junction
        if (searchBean.getCompositionLogicalOperator().equals("and") && searchBean.getFuncCount() > 1
                && searchBean.getNanoEntityCount() > 1 && searchBean.getFuncEntityCount() > 1) {
            return null;
        }
        Disjunction compDisjunction = Restrictions.disjunction();
        Conjunction compConjunction = Restrictions.conjunction();
        for (CompositionQueryBean compQuery : searchBean.getCompositionQueries()) {
            // function
            if (compQuery.getCompositionType().equals("function")) {
                Criterion funcCrit = this.getFunctionCriterion(compQuery, "inherentFunction.", "function.");
                if (funcCrit != null) {
                    compDisjunction.add(funcCrit);
                    // only add to conjunction if there is only one query for
                    // the type
                    if (searchBean.getFuncCount() == 1) {
                        compConjunction.add(funcCrit);
                    }
                }
            }
            // nanomaterial entity
            else if (compQuery.getCompositionType().equals("nanomaterial entity")) {
                Criterion nanoEntityCrit = getNanomaterialEntityCriterion(compQuery, "nanoEntity.");
                if (nanoEntityCrit != null) {
                    compDisjunction.add(nanoEntityCrit);
                    // only add to conjunction if there is only one query for
                    // the type
                    if (searchBean.getNanoEntityCount() == 1) {
                        compConjunction.add(nanoEntityCrit);
                    }
                }
            }
            // functionalizing entity
            else if (compQuery.getCompositionType().equals("functionalizing entity")) {
                Criterion funcEntityCrit = getFunctionalizingEntityCriterion(compQuery, "funcEntity.");
                if (funcEntityCrit != null) {
                    compDisjunction.add(funcEntityCrit);
                    // only add to conjunction if there is only one query for
                    // the type
                    if (searchBean.getFuncEntityCount() == 1) {
                        compConjunction.add(funcEntityCrit);
                    }
                }
            }
        }
        // default to or if only one query
        Junction junction = (searchBean.getCompositionLogicalOperator().equals("or")
                || searchBean.getCompositionQueries().size() == 1) ? compDisjunction : compConjunction;
        return junction;
    }

    /**
     * Get the junction used in function queries
     * 
     * @param searchBean
     * @param crit
     * @return
     * @throws Exception
     */
    private Junction getFunctionJunction(AdvancedSampleSearchBean searchBean, DetachedCriteria crit)
            throws Exception {
        // if AND and more than one query per type, don't use junction
        if (searchBean.getCompositionLogicalOperator().equals("and") && searchBean.getFuncCount() > 1) {
            return null;
        }
        Disjunction compDisjunction = Restrictions.disjunction();
        Conjunction compConjunction = Restrictions.conjunction();
        for (CompositionQueryBean compQuery : searchBean.getCompositionQueries()) {
            // function
            if (compQuery.getCompositionType().equals("function")) {
                Criterion funcCrit = this.getFunctionCriterion(compQuery, "", "");
                if (funcCrit != null) {
                    compDisjunction.add(funcCrit);
                    // only add to conjunction if there is only one query for
                    // the type
                    if (searchBean.getFuncCount() == 1) {
                        compConjunction.add(funcCrit);
                    }
                }
            }
        }
        // default to or if only one query
        Junction junction = (searchBean.getCompositionLogicalOperator().equals("or")
                || searchBean.getCompositionQueries().size() == 1) ? compDisjunction : compConjunction;
        return junction;
    }

    /**
     * Get the junction used in nanomaterial entity queries
     * 
     * @param searchBean
     * @param crit
     * @return
     * @throws Exception
     */
    private Junction getNanomaterialEntityJunction(AdvancedSampleSearchBean searchBean, DetachedCriteria crit)
            throws Exception {
        // if AND and more than one query per type, don't use junction
        if (searchBean.getCompositionLogicalOperator().equals("and") && searchBean.getNanoEntityCount() > 1) {
            return null;
        }
        Disjunction compDisjunction = Restrictions.disjunction();
        Conjunction compConjunction = Restrictions.conjunction();
        for (CompositionQueryBean compQuery : searchBean.getCompositionQueries()) {
            // nanomaterial entity
            if (compQuery.getCompositionType().equals("nanomaterial entity")) {
                Criterion nanoEntityCrit = getNanomaterialEntityCriterion(compQuery, "");
                if (nanoEntityCrit != null) {
                    compDisjunction.add(nanoEntityCrit);
                    // only add to conjunction if there is only one query for
                    // the type
                    if (searchBean.getNanoEntityCount() == 1) {
                        compConjunction.add(nanoEntityCrit);
                    }
                }
            }
        }
        // default to or if only one query
        Junction junction = (searchBean.getCompositionLogicalOperator().equals("or")
                || searchBean.getCompositionQueries().size() == 1) ? compDisjunction : compConjunction;
        return junction;
    }

    /**
     * Get the junction used in functionalizing entity queries
     * 
     * @param searchBean
     * @param crit
     * @return
     * @throws Exception
     */
    private Junction getFunctionalizingEntityJunction(AdvancedSampleSearchBean searchBean, DetachedCriteria crit)
            throws Exception {
        // if AND and more than one query per type, don't use junction
        if (searchBean.getCompositionLogicalOperator().equals("and") && searchBean.getFuncEntityCount() > 1) {
            return null;
        }
        Disjunction compDisjunction = Restrictions.disjunction();
        Conjunction compConjunction = Restrictions.conjunction();
        for (CompositionQueryBean compQuery : searchBean.getCompositionQueries()) {
            // functionalizing entity
            if (compQuery.getCompositionType().equals("functionalizing entity")) {
                Criterion funcEntityCrit = getFunctionalizingEntityCriterion(compQuery, "");
                if (funcEntityCrit != null) {
                    compDisjunction.add(funcEntityCrit);
                    // only add to conjunction if there is only one query for
                    // the type
                    if (searchBean.getFuncEntityCount() == 1) {
                        compConjunction.add(funcEntityCrit);
                    }
                }
            }
        }
        // default to or if only one query
        Junction junction = (searchBean.getCompositionLogicalOperator().equals("or")
                || searchBean.getCompositionQueries().size() == 1) ? compDisjunction : compConjunction;
        return junction;
    }

    private Criterion getFunctionalizingEntityCriterion(CompositionQueryBean compQuery, String entityAlias)
            throws Exception {
        TextMatchMode chemicalNameMatchMode = null;
        if (compQuery.getOperand().equals("equals")) {
            chemicalNameMatchMode = new TextMatchMode(compQuery.getChemicalName());
        } else if (compQuery.getOperand().equals(Constants.STRING_OPERAND_CONTAINS)) {
            chemicalNameMatchMode = new TextMatchMode("*" + compQuery.getChemicalName() + "*");
        }
        String funcEntityClassName = ClassUtils.getShortClassNameFromDisplayName(compQuery.getEntityType());
        Class clazz = ClassUtils.getFullClass("agentmaterial." + funcEntityClassName);
        Criterion funcEntityCrit = null;
        // other entity type
        if (clazz == null) {
            /*Criterion otherFuncCrit1 = Restrictions.eq(entityAlias + "class",
                  "OtherFunctionalizingEntity");
            Criterion otherFuncCrit2 = Restrictions.eq(entityAlias + "type",
                  compQuery.getEntityType());
            funcEntityCrit = Restrictions.and(otherFuncCrit1, otherFuncCrit2);*/

            Integer funcClassNameInteger = Constants.FUNCTIONALIZING_ENTITY_SUBCLASS_ORDER_MAP
                    .get("OtherFunctionalizingEntity");
            funcEntityCrit = Restrictions.eq(entityAlias + "class", funcClassNameInteger);

        } else {
            Integer funcClassNameInteger = Constants.FUNCTIONALIZING_ENTITY_SUBCLASS_ORDER_MAP
                    .get(funcEntityClassName);
            funcEntityCrit = Restrictions.eq(entityAlias + "class", funcClassNameInteger);
        }
        if (!StringUtils.isEmpty(compQuery.getChemicalName()) && !StringUtils.isEmpty(compQuery.getOperand())) {
            Criterion chemicalNameCrit = Restrictions.ilike(entityAlias + "name",
                    chemicalNameMatchMode.getUpdatedText(), chemicalNameMatchMode.getMatchMode());
            funcEntityCrit = Restrictions.and(funcEntityCrit, chemicalNameCrit);
        }
        return funcEntityCrit;
    }

    private DetachedCriteria getFunctionalizingEntitySubquery(CompositionQueryBean query, String funcEntityAlias,
            String projectionProperty) throws Exception {
        DetachedCriteria subCrit = DetachedCriteria.forClass(FunctionalizingEntity.class, "subCrit");
        subCrit.setProjection(Projections.distinct(Property.forName(projectionProperty)));
        Criterion funcCrit = getFunctionalizingEntityCriterion(query, "");
        subCrit.add(funcCrit);
        subCrit.add(Restrictions.eqProperty("subCrit." + projectionProperty, funcEntityAlias + "id"));
        return subCrit;
    }

    private DetachedCriteria getFunctionSubquery(CompositionQueryBean query, String funcAlias1, String funcAlias2,
            String projectionProperty) throws Exception {
        DetachedCriteria subCrit = DetachedCriteria.forClass(Function.class, "subCrit");
        subCrit.setProjection(Projections.distinct(Property.forName(projectionProperty)));
        Criterion funcCrit = getFunctionCriterion(query, "", "");
        subCrit.add(funcCrit);
        if (funcAlias1.equals(funcAlias2)) {
            subCrit.add(Restrictions.eqProperty("subCrit." + projectionProperty, funcAlias1 + "id"));
        } else {
            subCrit.add(Restrictions.or(Restrictions.eqProperty("subCrit." + projectionProperty, funcAlias1 + "id"),
                    Restrictions.eqProperty("subCrit." + projectionProperty, funcAlias2 + "id")));
        }
        return subCrit;
    }

    private Criterion getFunctionCriterion(CompositionQueryBean compQuery, String functionAlias1,
            String functionAlias2) throws Exception {
        String funcClassName = ClassUtils.getShortClassNameFromDisplayName(compQuery.getEntityType());
        Class clazz = ClassUtils.getFullClass("function." + funcClassName);
        Criterion funcCrit, funcCrit1, funcCrit2 = null;
        // other function type
        if (clazz == null) {
            if (!functionAlias1.equals(functionAlias2)) {
                // inherent function
                Criterion otherFuncCrit1 = Restrictions.eq(functionAlias1 + "class", "OtherFunction");
                Criterion otherFuncCrit2 = Restrictions.eq(functionAlias1 + "type", compQuery.getEntityType());
                funcCrit1 = Restrictions.and(otherFuncCrit1, otherFuncCrit2);
                // function
                Criterion otherFuncCrit3 = Restrictions.eq(functionAlias2 + "class", "OtherFunction");
                Criterion otherFuncCrit4 = Restrictions.eq(functionAlias2 + "type", compQuery.getEntityType());
                funcCrit2 = Restrictions.and(otherFuncCrit3, otherFuncCrit4);
                funcCrit = Restrictions.or(funcCrit1, funcCrit2);
            } else {
                Criterion otherFuncCrit1 = Restrictions.eq(functionAlias1 + "class", "OtherFunction");
                Criterion otherFuncCrit2 = Restrictions.eq(functionAlias1 + "type", compQuery.getEntityType());
                funcCrit = Restrictions.and(otherFuncCrit1, otherFuncCrit2);
            }
        } else {
            if (!functionAlias1.equals(functionAlias2)) {
                funcCrit1 = Restrictions.eq(functionAlias1 + "class", funcClassName);
                funcCrit2 = Restrictions.eq(functionAlias2 + "class", funcClassName);
                funcCrit = Restrictions.and(funcCrit1, funcCrit2);
            } else {
                funcCrit = Restrictions.eq(functionAlias1 + "class", funcClassName);
            }
        }
        return funcCrit;
    }

    private Criterion getNanomaterialEntityCriterion(CompositionQueryBean compQuery, String entityAlias)
            throws Exception {
        TextMatchMode chemicalNameMatchMode = null;
        if (compQuery.getOperand().equals("equals")) {
            chemicalNameMatchMode = new TextMatchMode(compQuery.getChemicalName());
        } else if (compQuery.getOperand().equals(Constants.STRING_OPERAND_CONTAINS)) {
            chemicalNameMatchMode = new TextMatchMode("*" + compQuery.getChemicalName() + "*");
        }
        String nanoEntityClassName = ClassUtils.getShortClassNameFromDisplayName(compQuery.getEntityType());
        Class clazz = ClassUtils.getFullClass("nanomaterial." + nanoEntityClassName);
        Criterion nanoEntityCrit = null;
        // other entity type
        if (clazz == null) {
            Criterion otherNanoCrit1 = Restrictions.eq(entityAlias + "class", "OtherNanomaterialEntity");
            Criterion otherNanoCrit2 = Restrictions.eq(entityAlias + "type", compQuery.getEntityType());
            nanoEntityCrit = Restrictions.and(otherNanoCrit1, otherNanoCrit2);
        } else {
            nanoEntityCrit = Restrictions.eq(entityAlias + "class", nanoEntityClassName);
        }
        if (!StringUtils.isEmpty(compQuery.getChemicalName()) && !StringUtils.isEmpty(compQuery.getOperand())) {
            Criterion chemicalNameCrit = Restrictions.ilike("compElement.name",
                    chemicalNameMatchMode.getUpdatedText(), chemicalNameMatchMode.getMatchMode());
            nanoEntityCrit = Restrictions.and(nanoEntityCrit, chemicalNameCrit);
        }
        return nanoEntityCrit;
    }

    /**
     * Set the disjunction used in point of contact queries
     * 
     *
     */
    private Disjunction getPointOfContactDisjunction(AdvancedSampleSearchBean searchBean, String pocAlias,
            String otherPOCAlias) {
        Disjunction disjunction = Restrictions.disjunction();
        for (SampleQueryBean query : searchBean.getSampleQueries()) {
            if (query.getNameType().equals("point of contact name")) {
                Disjunction pocDisjunction = getPointOfContactDisjunctionPerQuery(query, pocAlias, otherPOCAlias);
                if (pocDisjunction != null)
                    disjunction.add(pocDisjunction);
            }
        }
        return disjunction;
    }

    private Disjunction getPointOfContactDisjunctionPerQuery(SampleQueryBean query, String pocAlias,
            String otherPOCAlias) {
        String pocCritStrs[] = null;
        if (StringUtils.isEmpty(otherPOCAlias)) {
            pocCritStrs = new String[] { pocAlias + "lastName", pocAlias + "firstName", "organization.name" };
        } else {
            pocCritStrs = new String[] { pocAlias + "lastName", pocAlias + "firstName", "organization.name",
                    otherPOCAlias + "lastName", otherPOCAlias + "firstName", "otherOrg.name" };
        }
        TextMatchMode nameMatchMode = null;
        if (query.getOperand().equals("equals")) {
            nameMatchMode = new TextMatchMode(query.getName());
        } else if (query.getOperand().equals(Constants.STRING_OPERAND_CONTAINS)) {
            nameMatchMode = new TextMatchMode("*" + query.getName() + "*");
        }
        Disjunction pocDisjunction = Restrictions.disjunction();
        for (String critStr : pocCritStrs) {
            Criterion pocCrit = Restrictions.ilike(critStr, nameMatchMode.getUpdatedText(),
                    nameMatchMode.getMatchMode());
            pocDisjunction.add(pocCrit);
        }
        return pocDisjunction;
    }

    /**
     * Get the sample name junction used in sample queries
     * 
     *
     */
    private Junction getSampleNameJunction(AdvancedSampleSearchBean searchBean) throws Exception {
        Disjunction sampleDisjunction = Restrictions.disjunction();
        Conjunction sampleConjunction = Restrictions.conjunction();
        for (SampleQueryBean query : searchBean.getSampleQueries()) {
            if (query.getNameType().equals("sample name")) {
                Criterion sampleNameCrit = getSampleNameCriterion(query);
                if (sampleNameCrit != null) {
                    sampleDisjunction.add(sampleNameCrit);
                    sampleConjunction.add(sampleNameCrit);
                }
            }
        }
        Junction junction = (searchBean.getSampleLogicalOperator().equals("or")
                || searchBean.getSampleQueries().size() == 1) ? sampleDisjunction : sampleConjunction;
        return junction;
    }

    /**
     * Get the sample disjunction used in sample queries
     * 
     *
     */
    private Junction getSampleJunction(AdvancedSampleSearchBean searchBean) throws Exception {
        // if there are more than one POC query in AND, don't use junction.
        if (searchBean.getSampleLogicalOperator().equals("and") && searchBean.getPocCount() > 1) {
            return null;
        }
        Disjunction sampleDisjunction = Restrictions.disjunction();
        Conjunction sampleConjunction = Restrictions.conjunction();
        for (SampleQueryBean query : searchBean.getSampleQueries()) {
            if (query.getNameType().equals("sample name")) {
                Criterion sampleNameCrit = getSampleNameCriterion(query);
                if (sampleNameCrit != null) {
                    sampleDisjunction.add(sampleNameCrit);
                    sampleConjunction.add(sampleNameCrit);
                }
            }
            if (query.getNameType().equals("point of contact name")) {
                Disjunction pocDisjunction = getPointOfContactDisjunction(searchBean, "poc.", "otherPOC.");
                if (pocDisjunction != null) {
                    sampleDisjunction.add(pocDisjunction);
                    if (searchBean.getPocCount() == 1) {
                        sampleConjunction.add(pocDisjunction);
                    }
                }
            }
        }
        Junction junction = (searchBean.getSampleLogicalOperator().equals("or")
                || searchBean.getSampleQueries().size() == 1) ? sampleDisjunction : sampleConjunction;
        return junction;
    }

    /**
     * Get the criterion used for sample name query
     * 
     * @param query
     * @return
     */
    private Criterion getSampleNameCriterion(SampleQueryBean query) {
        if (query.getNameType().equals("sample name")) {
            TextMatchMode nameMatchMode = null;
            if (query.getOperand().equals("equals")) {
                nameMatchMode = new TextMatchMode(query.getName());
            } else if (query.getOperand().equals(Constants.STRING_OPERAND_CONTAINS)) {
                nameMatchMode = new TextMatchMode("*" + query.getName() + "*");
            }
            Criterion sampleNameCrit = Restrictions.ilike("name", nameMatchMode.getUpdatedText(),
                    nameMatchMode.getMatchMode());
            return sampleNameCrit;
        } else {
            return null;
        }
    }

    private void setCharacterizationAndCriteria(AdvancedSampleSearchBean searchBean, DetachedCriteria crit,
            String projectionProperty) {
        if (searchBean.getCharacterizationQueries().isEmpty()) {
            return;
        }
        for (CharacterizationQueryBean charQuery : searchBean.getCharacterizationQueries()) {
            DetachedCriteria subCrit = getCharacterizationSubquery(charQuery, projectionProperty);
            crit.add(Subqueries.exists(subCrit));
        }
    }

    private void setCharacterizationCriteria(AdvancedSampleSearchBean searchBean, DetachedCriteria crit) {
        if (searchBean.getCharacterizationQueries().isEmpty()) {
            return;
        }
        // if only one query default to disjunction
        if (searchBean.getCharacterizationQueries().size() == 1
                || searchBean.getCharacterizationLogicalOperator().equals("or")) {
            // join characterization
            crit.createAlias("characterizationCollection", "chara", CriteriaSpecification.LEFT_JOIN);

            // join finding and datum
            if (searchBean.getHasDatum()) {
                crit.createAlias("chara.findingCollection", "finding", CriteriaSpecification.LEFT_JOIN);
                crit.createAlias("finding.datumCollection", "datum", CriteriaSpecification.LEFT_JOIN);
            }
            crit.add(getCharacterizationDisjunction(searchBean, crit, "chara."));
        } else {
            setCharacterizationAndCriteria(searchBean, crit, "sample.id");
        }
    }

    /**
     * Set the DetachedCriteria used for composition queries
     * 
     * @param searchBean
     * @param crit
     * @throws Exception
     */
    private void setCompositionCriteria(AdvancedSampleSearchBean searchBean, DetachedCriteria crit)
            throws Exception {
        if (searchBean.getCompositionQueries().isEmpty()) {
            return;
        }

        setCompositionCriteriaBase(searchBean, crit);

        if (searchBean.getCompositionLogicalOperator().equals("and")) {
            if (searchBean.getNanoEntityCount() > 1) {
                setNanomaterialEntityAndCriteria(searchBean, crit, "id");
            }
            if (searchBean.getFuncEntityCount() > 1) {
                setFunctionalizingEntityAndCriteria(searchBean, crit, "id");
            }
            if (searchBean.getFuncCount() > 1) {
                setFunctionAndCriteria(searchBean, crit, "id");
            }
        }
    }

    /**
     * Set the DetachedCriteria used for composition queries
     * 
     * @param searchBean
     * @param crit
     * @throws Exception
     */
    private void setCompositionCriteriaBase(AdvancedSampleSearchBean searchBean, DetachedCriteria crit)
            throws Exception {
        if (searchBean.getCompositionQueries().isEmpty()) {
            return;
        }
        // composition queries
        crit.createAlias("sampleComposition", "comp", CriteriaSpecification.LEFT_JOIN);
        Boolean hasChemicalName = searchBean.getHasChemicalName();
        // join function
        if (searchBean.getHasFunction()) {
            crit.createAlias("comp.nanomaterialEntityCollection", "nanoEntity", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("nanoEntity.composingElementCollection", "compElement",
                    CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("compElement.inherentFunctionCollection", "inherentFunction",
                    CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("comp.functionalizingEntityCollection", "funcEntity", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("funcEntity.functionCollection", "function", CriteriaSpecification.LEFT_JOIN);
        }
        // join nanomaterialEntity
        if (searchBean.getHasNanomaterial() && !searchBean.getHasFunction()) {
            crit.createAlias("comp.nanomaterialEntityCollection", "nanoEntity", CriteriaSpecification.LEFT_JOIN);
            if (hasChemicalName) {
                crit.createAlias("nanoEntity.composingElementCollection", "compElement",
                        CriteriaSpecification.LEFT_JOIN);
            }
        }
        // join functionalizing entity
        if (searchBean.getHasAgentMaterial() && !searchBean.getHasFunction()) {
            crit.createAlias("comp.functionalizingEntityCollection", "funcEntity", CriteriaSpecification.LEFT_JOIN);
        }
        Junction junction = getCompositionJunction(searchBean, crit);
        if (junction != null) {
            crit.add(junction);
        }
        /*      if (searchBean.getNanoEntityCount() > 1) {
                 setNanomaterialEntityAndCriteria(searchBean, crit, "id");
              }
              if (searchBean.getFuncEntityCount() > 1) {
                 setFunctionalizingEntityAndCriteria(searchBean, crit, "id");
              }
              if (searchBean.getFuncCount() > 1) {
                 setFunctionAndCriteria(searchBean, crit, "id");
              }  */
    }

    private void setFunctionalizingEntityAndCriteria(AdvancedSampleSearchBean searchBean, DetachedCriteria crit,
            String projectionProperty) throws Exception {
        for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
            if (query.getCompositionType().equals("functionalizing entity")) {
                DetachedCriteria subCrit = getFunctionalizingEntitySubquery(query, "funcEntity.",
                        projectionProperty);
                crit.add(Subqueries.exists(subCrit));
            }
        }
    }

    private void setFunctionAndCriteria(AdvancedSampleSearchBean searchBean, DetachedCriteria crit,
            String projectionProperty) throws Exception {
        for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
            if (query.getCompositionType().equals("function")) {
                DetachedCriteria subCrit = getFunctionSubquery(query, "inherentFunction.", "function.",
                        projectionProperty);
                crit.add(Subqueries.exists(subCrit));
            }
        }
    }

    private void setNanomaterialEntityAndCriteria(AdvancedSampleSearchBean searchBean, DetachedCriteria crit,
            String projectionProperty) throws Exception {
        for (CompositionQueryBean query : searchBean.getCompositionQueries()) {
            if (query.getCompositionType().equals("nanomaterial entity")) {
                DetachedCriteria subCrit = getNanomaterialEntitySubquery(query, "nanoEntity.", projectionProperty);
                crit.add(Subqueries.exists(subCrit));
            }
        }
    }

    private DetachedCriteria getNanomaterialEntitySubquery(CompositionQueryBean query, String nanoEntityAlias,
            String projectionProperty) throws Exception {
        DetachedCriteria subCrit = DetachedCriteria.forClass(NanomaterialEntity.class, "subCrit");
        subCrit.setProjection(Projections.distinct(Property.forName(projectionProperty)));
        // join composing element
        if (!StringUtils.isEmpty(query.getChemicalName())) {
            subCrit.createAlias("subCrit.composingElementCollection", "compElement",
                    CriteriaSpecification.LEFT_JOIN);
        }
        Criterion nanoCrit = getNanomaterialEntityCriterion(query, "");
        subCrit.add(nanoCrit);
        subCrit.add(Restrictions.eqProperty("subCrit." + projectionProperty, nanoEntityAlias + "id"));
        return subCrit;
    }

    private DetachedCriteria getPointOfContactSubquery(SampleQueryBean query, String pocAlias1, String pocAlias2,
            String projectionProperty) {
        DetachedCriteria subCrit = DetachedCriteria.forClass(PointOfContact.class, "subCrit");
        subCrit.createAlias("subCrit.organization", "organization", CriteriaSpecification.LEFT_JOIN);
        subCrit.setProjection(Projections.distinct(Property.forName("id")));
        Disjunction pocDisjunction = getPointOfContactDisjunctionPerQuery(query, "", "");
        subCrit.add(pocDisjunction);
        if (pocAlias1.equals(pocAlias2)) {
            subCrit.add(Restrictions.eqProperty("subCrit." + projectionProperty, pocAlias1 + "id"));
        } else {
            subCrit.add(Restrictions.or(Restrictions.eqProperty("subCrit." + projectionProperty, pocAlias1 + "id"),
                    Restrictions.eqProperty("subCrit." + projectionProperty, pocAlias2 + "id")));
        }
        return subCrit;
    }

    /**
     * Set the DetachedCriteria for sample queries
     * 
     * @param searchBean
     * @param crit
     * @throws Exception
     */
    private void setSampleCriteria(AdvancedSampleSearchBean searchBean, DetachedCriteria crit) throws Exception {
        if (searchBean.getSampleQueries().isEmpty()) {
            return;
        }
        // join POC
        if (searchBean.getHasPOC()) {
            crit.createAlias("primaryPointOfContact", "poc");
            crit.createAlias("poc.organization", "organization");
            crit.createAlias("otherPointOfContactCollection", "otherPOC", CriteriaSpecification.LEFT_JOIN);
            crit.createAlias("otherPOC.organization", "otherOrg", CriteriaSpecification.LEFT_JOIN);
        }
        Junction junction = getSampleJunction(searchBean);
        if (junction != null) {
            crit.add(junction);
        }
        // more than one POC and AND
        else {
            crit.add(getSampleNameJunction(searchBean));
            for (SampleQueryBean query : searchBean.getSampleQueries()) {
                if (query.getNameType().equals("point of contact name")) {
                    DetachedCriteria subCrit = getPointOfContactSubquery(query, "poc.", "otherPOC.", "id");
                    crit.add(Subqueries.exists(subCrit));
                }
            }
        }
    }

}