org.n52.sos.ds.hibernate.util.HibernateObservationUtilities.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.sos.ds.hibernate.util.HibernateObservationUtilities.java

Source

/**
 * Copyright (C) 2013
 * by 52 North Initiative for Geospatial Open Source Software GmbH
 *
 * Contact: Andreas Wytzisk
 * 52 North Initiative for Geospatial Open Source Software GmbH
 * Martin-Luther-King-Weg 24
 * 48155 Muenster, Germany
 * info@52north.org
 *
 * This program is free software; you can redistribute and/or modify it under
 * the terms of the GNU General Public License version 2 as published by the
 * Free Software Foundation.
 *
 * This program is distributed WITHOUT ANY WARRANTY; even without 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 (see gnu-gpl v2.txt). If not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA or
 * visit the Free Software Foundation web page, http://www.fsf.org.
 */
package org.n52.sos.ds.hibernate.util;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.n52.sos.cache.ContentCache;
import org.n52.sos.ds.FeatureQueryHandler;
import org.n52.sos.ds.hibernate.entities.BlobObservation;
import org.n52.sos.ds.hibernate.entities.BooleanObservation;
import org.n52.sos.ds.hibernate.entities.CategoryObservation;
import org.n52.sos.ds.hibernate.entities.CountObservation;
import org.n52.sos.ds.hibernate.entities.FeatureOfInterest;
import org.n52.sos.ds.hibernate.entities.GeometryObservation;
import org.n52.sos.ds.hibernate.entities.NumericObservation;
import org.n52.sos.ds.hibernate.entities.ObservableProperty;
import org.n52.sos.ds.hibernate.entities.Observation;
import org.n52.sos.ds.hibernate.entities.ObservationConstellation;
import org.n52.sos.ds.hibernate.entities.Offering;
import org.n52.sos.ds.hibernate.entities.Procedure;
import org.n52.sos.ds.hibernate.entities.SweDataArrayObservation;
import org.n52.sos.ds.hibernate.entities.TextObservation;
import org.n52.sos.exception.CodedException;
import org.n52.sos.exception.ows.NoApplicableCodeException;
import org.n52.sos.ogc.gml.CodeWithAuthority;
import org.n52.sos.ogc.gml.time.Time;
import org.n52.sos.ogc.gml.time.TimeInstant;
import org.n52.sos.ogc.gml.time.TimePeriod;
import org.n52.sos.ogc.om.AbstractPhenomenon;
import org.n52.sos.ogc.om.MultiObservationValues;
import org.n52.sos.ogc.om.ObservationValue;
import org.n52.sos.ogc.om.OmObservableProperty;
import org.n52.sos.ogc.om.OmObservation;
import org.n52.sos.ogc.om.OmObservationConstellation;
import org.n52.sos.ogc.om.SingleObservationValue;
import org.n52.sos.ogc.om.features.AbstractFeature;
import org.n52.sos.ogc.om.quality.SosQuality;
import org.n52.sos.ogc.om.values.BooleanValue;
import org.n52.sos.ogc.om.values.CategoryValue;
import org.n52.sos.ogc.om.values.CountValue;
import org.n52.sos.ogc.om.values.NilTemplateValue;
import org.n52.sos.ogc.om.values.QuantityValue;
import org.n52.sos.ogc.om.values.SweDataArrayValue;
import org.n52.sos.ogc.om.values.TextValue;
import org.n52.sos.ogc.om.values.UnknownValue;
import org.n52.sos.ogc.om.values.Value;
import org.n52.sos.ogc.ows.OwsExceptionReport;
import org.n52.sos.ogc.sensorML.SensorML;
import org.n52.sos.ogc.sos.SosConstants;
import org.n52.sos.ogc.sos.SosProcedureDescription;
import org.n52.sos.ogc.sos.SosProcedureDescriptionUnknowType;
import org.n52.sos.ogc.swe.SweAbstractDataComponent;
import org.n52.sos.ogc.swe.SweDataArray;
import org.n52.sos.ogc.swe.SweDataRecord;
import org.n52.sos.ogc.swe.simpleType.SweBoolean;
import org.n52.sos.ogc.swe.simpleType.SweCategory;
import org.n52.sos.ogc.swe.simpleType.SweCount;
import org.n52.sos.ogc.swe.simpleType.SweQuantity;
import org.n52.sos.ogc.swe.simpleType.SweText;
import org.n52.sos.ogc.swe.simpleType.SweTime;
import org.n52.sos.ogc.swe.simpleType.SweTimeRange;
import org.n52.sos.service.Configurator;
import org.n52.sos.service.ServiceConfiguration;
import org.n52.sos.service.profile.Profile;
import org.n52.sos.util.CodingHelper;
import org.n52.sos.util.DateTimeHelper;
import org.n52.sos.util.SosHelper;
import org.n52.sos.util.StringHelper;
import org.n52.sos.util.XmlHelper;

public class HibernateObservationUtilities {

    private static Configuration configuration;

    protected static Configuration getConfiguration() {
        if (configuration == null) {
            configuration = new Configuration();
        }
        return configuration;
    }

    /**
     * Set the configuration for this Helper to decouple it from the
     * Configurator.
     * 
     * @param configuration
     *            the configuration
     */
    protected static void setConfiguration(final Configuration configuration) {
        HibernateObservationUtilities.configuration = configuration;
    }

    public static ContentCache getCache() {
        return getConfiguration().getCache();
    }

    public static Profile getActiveProfile() {
        return getConfiguration().getActiveProfile();
    }

    public static String getTokenSeparator() {
        return getConfiguration().getTokenSeparator();
    }

    public static String getTupleSeparator() {
        return getConfiguration().getTupleSeparator();
    }

    public static FeatureQueryHandler getFeatureQueryHandler() {
        return getConfiguration().getFeatureQueryHandler();
    }

    public static boolean isSupportsQuality() {
        return getConfiguration().isSupportsQuality();
    }

    /**
     * Create SOS internal observation from Observation objects
     * 
     * @param responseFormat
     * 
     * @param observations
     *            List of Observation objects
     * @param request
     *            the request
     * @param session
     *            Hibernate session
     * @return SOS internal observation
     * 
     * 
     * @throws OwsExceptionReport
     *             * If an error occurs
     */
    public static List<OmObservation> createSosObservationsFromObservations(
            final Collection<Observation> observations, final String version, final String resultModel,
            final Session session) throws OwsExceptionReport {
        final List<OmObservation> observationCollection = new ArrayList<OmObservation>(0);

        final Map<String, AbstractFeature> features = new HashMap<String, AbstractFeature>(0);
        final Map<String, AbstractPhenomenon> obsProps = new HashMap<String, AbstractPhenomenon>(0);
        final Map<String, SosProcedureDescription> procedures = new HashMap<String, SosProcedureDescription>(0);
        final Map<Integer, OmObservationConstellation> observationConstellations = new HashMap<Integer, OmObservationConstellation>(
                0);
        if (observations != null) {
            // now iterate over resultset and create Measurement for each row
            for (final Observation hObservation : observations) {
                // check remaining heap size and throw exception if minimum is
                // reached
                SosHelper.checkFreeMemory();
                final FeatureOfInterest hFeatureOfInterest = hObservation.getFeatureOfInterest();

                // TODO get full description
                final Procedure hProcedure = hObservation.getProcedure();
                final String procedureIdentifier = hProcedure.getIdentifier();
                SosProcedureDescription procedure;
                if (procedures.containsKey(procedureIdentifier)) {
                    procedure = procedures.get(procedureIdentifier);
                } else {
                    if (getConfiguration().getActiveProfile().isEncodeProcedureInObservation()) {
                        procedure = new HibernateProcedureConverter().createSosProcedureDescription(hProcedure,
                                procedureIdentifier,
                                hProcedure.getProcedureDescriptionFormat().getProcedureDescriptionFormat(), version,
                                session);
                    } else {
                        procedure = new SosProcedureDescriptionUnknowType(procedureIdentifier,
                                hProcedure.getProcedureDescriptionFormat().getProcedureDescriptionFormat(), null);
                    }
                    procedures.put(procedureIdentifier, procedure);
                }

                // feature of interest
                final String foiID = hFeatureOfInterest.getIdentifier();
                if (!features.containsKey(foiID)) {
                    final AbstractFeature featureByID = getConfiguration().getFeatureQueryHandler()
                            .getFeatureByID(foiID, session, version, -1);
                    features.put(foiID, featureByID);
                }

                // phenomenon
                final ObservableProperty hObservableProperty = hObservation.getObservableProperty();
                final String phenID = hObservation.getObservableProperty().getIdentifier();
                final String description = hObservation.getObservableProperty().getDescription();
                if (!obsProps.containsKey(phenID)) {
                    obsProps.put(phenID, new OmObservableProperty(phenID, description, null, null));
                }

                // TODO: add offering ids to response if needed later.
                // String offeringID =
                // hObservationConstellation.getOffering().getIdentifier();
                // String mimeType = SosConstants.PARAMETER_NOT_SET;

                final Value<?> value = getValueFromObservation(hObservation);
                if (value != null) {
                    if (hObservation.getUnit() != null) {
                        value.setUnit(hObservation.getUnit().getUnit());
                    }
                    checkOrSetObservablePropertyUnit(obsProps.get(phenID), value.getUnit());
                    final OmObservationConstellation obsConst = new OmObservationConstellation(procedure,
                            obsProps.get(phenID), features.get(foiID));
                    /* get the offerings to find the templates */
                    if (obsConst.getOfferings() == null) {
                        final HashSet<String> offerings = new HashSet<String>(
                                getCache().getOfferingsForObservableProperty(
                                        obsConst.getObservableProperty().getIdentifier()));
                        offerings.retainAll(
                                getCache().getOfferingsForProcedure(obsConst.getProcedure().getIdentifier()));
                        obsConst.setOfferings(offerings);
                    }
                    final int obsConstHash = obsConst.hashCode();
                    if (!observationConstellations.containsKey(obsConstHash)) {
                        if (StringHelper.isNotEmpty(resultModel)) {
                            obsConst.setObservationType(resultModel);
                        }
                        final ObservationConstellation hObservationConstellation = getObservationConstellation(
                                hProcedure, hObservableProperty, hObservation.getOfferings(), session);
                        if (hObservationConstellation != null) {
                            final String observationType = hObservationConstellation.getObservationType()
                                    .getObservationType();
                            obsConst.setObservationType(observationType);
                        }
                        observationConstellations.put(obsConstHash, obsConst);
                    }
                    final OmObservation sosObservation = createNewObservation(observationConstellations,
                            hObservation, value, obsConstHash);
                    observationCollection.add(sosObservation);
                    session.evict(hObservation);
                    // TODO check for ScrollableResult vs setFetchSize/setMaxResult
                    // + setFirstResult
                }
            }
        }
        return observationCollection;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Collection<? extends OmObservation> createSosObservationFromObservationConstellation(
            final ObservationConstellation observationConstellation,
            final List<String> featureOfInterestIdentifiers, final String version, final Session session)
            throws OwsExceptionReport {
        final List<OmObservation> observations = new ArrayList<OmObservation>(0);
        if (observationConstellation != null && featureOfInterestIdentifiers != null) {
            final String procID = observationConstellation.getProcedure().getIdentifier();
            final SensorML procedure = new SensorML();
            procedure.setIdentifier(procID);
            // phenomenon
            final String phenID = observationConstellation.getObservableProperty().getIdentifier();
            final String description = observationConstellation.getObservableProperty().getDescription();
            final OmObservableProperty obsProp = new OmObservableProperty(phenID, description, null, null);

            for (final String featureIdentifier : featureOfInterestIdentifiers) {
                final AbstractFeature feature = getFeatureQueryHandler().getFeatureByID(featureIdentifier, session,
                        version, -1);

                final OmObservationConstellation obsConst = new OmObservationConstellation(procedure, obsProp, null,
                        feature, null);
                /* get the offerings to find the templates */
                if (obsConst.getOfferings() == null) {
                    final Set<String> offerings = new HashSet<String>(
                            getCache().getOfferingsForProcedure(obsConst.getProcedure().getIdentifier()));
                    offerings.retainAll(new HashSet<String>(
                            getCache().getOfferingsForProcedure(obsConst.getProcedure().getIdentifier())));
                    obsConst.setOfferings(offerings);
                }
                final OmObservation sosObservation = new OmObservation();
                sosObservation.setNoDataValue(getActiveProfile().getResponseNoDataPlaceholder());
                sosObservation.setTokenSeparator(getTokenSeparator());
                sosObservation.setTupleSeparator(getTupleSeparator());
                sosObservation.setObservationConstellation(obsConst);
                final NilTemplateValue value = new NilTemplateValue();
                value.setUnit(obsProp.getUnit());
                sosObservation.setValue(
                        new SingleObservationValue(new TimeInstant(), value, new ArrayList<SosQuality>(0)));
                observations.add(sosObservation);
            }
        }
        return observations;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static OmObservation createNewObservation(
            final Map<Integer, OmObservationConstellation> observationConstellations,
            final Observation hObservation, final Value<?> value, final int obsConstHash) {
        final OmObservation sosObservation = new OmObservation();
        sosObservation.setObservationID(Long.toString(hObservation.getObservationId()));
        if (hObservation.isSetIdentifier()
                && !hObservation.getIdentifier().startsWith(SosConstants.GENERATED_IDENTIFIER_PREFIX)) {
            final CodeWithAuthority identifier = new CodeWithAuthority(hObservation.getIdentifier());
            if (hObservation.isSetCodespace()) {
                identifier.setCodeSpace(hObservation.getCodespace().getCodespace());
            }
            sosObservation.setIdentifier(identifier);
        }
        sosObservation.setNoDataValue(getActiveProfile().getResponseNoDataPlaceholder());
        sosObservation.setTokenSeparator(getTokenSeparator());
        sosObservation.setTupleSeparator(getTupleSeparator());
        sosObservation.setObservationConstellation(observationConstellations.get(obsConstHash));
        sosObservation.setResultTime(new TimeInstant(new DateTime(hObservation.getResultTime(), DateTimeZone.UTC)));
        sosObservation.setValue(new SingleObservationValue(getPhenomenonTime(hObservation), value));
        return sosObservation;
    }

    private static Time getPhenomenonTime(final Observation hObservation) {
        // create time element
        final DateTime phenStartTime = new DateTime(hObservation.getPhenomenonTimeStart(), DateTimeZone.UTC);
        DateTime phenEndTime;
        if (hObservation.getPhenomenonTimeEnd() != null) {
            phenEndTime = new DateTime(hObservation.getPhenomenonTimeEnd(), DateTimeZone.UTC);
        } else {
            phenEndTime = phenStartTime;
        }
        Time phenomenonTime;
        if (phenStartTime.equals(phenEndTime)) {
            phenomenonTime = new TimeInstant(phenStartTime, "");
        } else {
            phenomenonTime = new TimePeriod(phenStartTime, phenEndTime);
        }
        return phenomenonTime;
    }

    private static void checkOrSetObservablePropertyUnit(final AbstractPhenomenon abstractSosPhenomenon,
            final String unit) {
        if (abstractSosPhenomenon instanceof OmObservableProperty) {
            final OmObservableProperty obsProp = (OmObservableProperty) abstractSosPhenomenon;
            if (obsProp.getUnit() == null && unit != null) {
                obsProp.setUnit(unit);
            }
        }
    }

    /**
     * Get observation value from all value tables for an Observation object
     * 
     * @param hObservation
     *            Observation object
     * @return Observation value
     * @throws OwsExceptionReport 
     * @throws CodedException 
     */
    private static Value<?> getValueFromObservation(final Observation hObservation)
            throws CodedException, OwsExceptionReport {
        if (hObservation instanceof NumericObservation) {
            return new QuantityValue(((NumericObservation) hObservation).getValue());
        } else if (hObservation instanceof BooleanObservation) {
            return new org.n52.sos.ogc.om.values.BooleanValue(
                    Boolean.valueOf(((BooleanObservation) hObservation).getValue()));
        } else if (hObservation instanceof CategoryObservation) {
            return new org.n52.sos.ogc.om.values.CategoryValue(((CategoryObservation) hObservation).getValue());
        } else if (hObservation instanceof CountObservation) {
            return new org.n52.sos.ogc.om.values.CountValue(
                    Integer.valueOf(((CountObservation) hObservation).getValue()));
        } else if (hObservation instanceof TextObservation) {
            return new org.n52.sos.ogc.om.values.TextValue(((TextObservation) hObservation).getValue().toString());
        } else if (hObservation instanceof GeometryObservation) {
            return new org.n52.sos.ogc.om.values.GeometryValue(((GeometryObservation) hObservation).getValue());
        } else if (hObservation instanceof BlobObservation) {
            return new UnknownValue(((BlobObservation) hObservation).getValue());
        } else if (hObservation instanceof SweDataArrayObservation) {
            SweDataArrayValue sweDataArrayValue = new SweDataArrayValue();
            sweDataArrayValue.setValue((SweDataArray) CodingHelper.decodeXmlElement(
                    XmlHelper.parseXmlString(((SweDataArrayObservation) hObservation).getValue())));
            return sweDataArrayValue;
        }
        return null;
    }

    @SuppressWarnings("rawtypes")
    public static List<OmObservation> unfoldObservation(final OmObservation multiObservation)
            throws OwsExceptionReport {
        if (multiObservation.getValue() instanceof SingleObservationValue) {
            return Collections.singletonList(multiObservation);
        } else {

            final SweDataArrayValue arrayValue = ((SweDataArrayValue) ((MultiObservationValues) multiObservation
                    .getValue()).getValue());
            final List<List<String>> values = arrayValue.getValue().getValues();
            final List<OmObservation> observationCollection = new ArrayList<OmObservation>(values.size());
            SweDataRecord elementType = null;
            if (arrayValue.getValue().getElementType() != null
                    && arrayValue.getValue().getElementType() instanceof SweDataRecord) {
                elementType = (SweDataRecord) arrayValue.getValue().getElementType();
            } else {
                throw new NoApplicableCodeException().withMessage("sweElementType type \"%s\" not supported",
                        elementType != null ? elementType.getClass().getName() : "null");
            }

            for (final List<String> block : values) {
                int tokenIndex = 0;
                Time phenomenonTime = null;
                final List<Value<?>> observedValues = new LinkedList<Value<?>>();
                // map to store the observed properties
                final Map<Value<?>, String> definitionsForObservedValues = new HashMap<Value<?>, String>();
                Value<?> observedValue = null;
                for (final String token : block) {
                    // get values from block via definition in
                    // SosSweDataArray#getElementType
                    final SweAbstractDataComponent fieldForToken = elementType.getFields().get(tokenIndex)
                            .getElement();
                    /*
                     * get phenomenon time
                     */
                    if (fieldForToken instanceof SweTime) {
                        try {
                            phenomenonTime = new TimeInstant(DateTimeHelper.parseIsoString2DateTime(token));
                        } catch (final OwsExceptionReport e) {
                            throw e;
                        } catch (final Exception e) {
                            /*
                             * FIXME what is the valid exception code if the
                             * result is not correct?
                             */
                            throw new NoApplicableCodeException().causedBy(e)
                                    .withMessage("Error while parse time String to DateTime!");
                        }
                    } else if (fieldForToken instanceof SweTimeRange) {
                        try {
                            final String[] subTokens = token.split("/");
                            phenomenonTime = new TimePeriod(DateTimeHelper.parseIsoString2DateTime(subTokens[0]),
                                    DateTimeHelper.parseIsoString2DateTime(subTokens[1]));
                        } catch (final OwsExceptionReport e) {
                            throw e;
                        } catch (final Exception e) {
                            /*
                             * FIXME what is the valid exception code if the
                             * result is not correct?
                             */
                            throw new NoApplicableCodeException().causedBy(e)
                                    .withMessage("Error while parse time String to DateTime!");
                        }
                    }
                    /*
                     * observation values
                     */
                    else if (fieldForToken instanceof SweQuantity) {
                        observedValue = new QuantityValue(new BigDecimal(token));
                        observedValue.setUnit(((SweQuantity) fieldForToken).getUom());
                    } else if (fieldForToken instanceof SweBoolean) {
                        observedValue = new BooleanValue(Boolean.parseBoolean(token));
                    } else if (fieldForToken instanceof SweText) {
                        observedValue = new TextValue(token);
                    } else if (fieldForToken instanceof SweCategory) {
                        observedValue = new CategoryValue(token);
                        observedValue.setUnit(((SweCategory) fieldForToken).getCodeSpace());
                    } else if (fieldForToken instanceof SweCount) {
                        observedValue = new CountValue(Integer.parseInt(token));
                    } else {
                        throw new NoApplicableCodeException().withMessage("sweField type '%s' not supported",
                                fieldForToken != null ? fieldForToken.getClass().getName() : "null");
                    }
                    if (observedValue != null) {
                        definitionsForObservedValues.put(observedValue, fieldForToken.getDefinition());
                        observedValues.add(observedValue);
                        observedValue = null;
                    }
                    tokenIndex++;
                }
                for (final Value<?> iValue : observedValues) {
                    final OmObservation newObservation = createSingleValueObservation(multiObservation,
                            phenomenonTime, iValue);
                    observationCollection.add(newObservation);
                }
            }
            return observationCollection;
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static OmObservation createSingleValueObservation(final OmObservation multiObservation,
            final Time phenomenonTime, final Value<?> iValue) {
        final ObservationValue<?> value = new SingleObservationValue(phenomenonTime, iValue);
        final OmObservation newObservation = new OmObservation();
        newObservation.setNoDataValue(multiObservation.getNoDataValue());
        /*
         * TODO create new ObservationConstellation only with the specified
         * observed property and observation type
         */
        final OmObservationConstellation obsConst = multiObservation.getObservationConstellation();
        /*
         * createObservationConstellationForSubObservation ( multiObservation .
         * getObservationConstellation ( ) , iValue ,
         * definitionsForObservedValues . get ( iValue ) )
         */
        newObservation.setObservationConstellation(obsConst);
        newObservation.setValidTime(multiObservation.getValidTime());
        newObservation.setResultTime(multiObservation.getResultTime());
        newObservation.setTokenSeparator(multiObservation.getTokenSeparator());
        newObservation.setTupleSeparator(multiObservation.getTupleSeparator());
        newObservation.setResultType(multiObservation.getResultType());
        newObservation.setValue(value);
        return newObservation;
    }

    public static ObservationConstellation getObservationConstellation(final Procedure procedure,
            final ObservableProperty observableProperty, final Collection<Offering> offerings,
            final Session session) {
        @SuppressWarnings("unchecked")
        final List<ObservationConstellation> observationConstellations = session
                .createCriteria(ObservationConstellation.class)
                .add(Restrictions.eq(ObservationConstellation.DELETED, false))
                .add(Restrictions.eq(ObservationConstellation.PROCEDURE, procedure))
                .add(Restrictions.in(ObservationConstellation.OFFERING, offerings))
                .add(Restrictions.eq(ObservationConstellation.OBSERVABLE_PROPERTY, observableProperty)).list();
        final Iterator<ObservationConstellation> iterator = observationConstellations.iterator();
        return iterator.hasNext() ? iterator.next() : null;
    }

    private HibernateObservationUtilities() {
    }

    /**
     * Class to make this Helper more testable. Test cases may overwrite methods
     * to decouple this class from the Configurator.
     */
    protected static class Configuration {

        /**
         * @see ServiceConfiguration#getTupleSeparator()
         */
        protected String getTupleSeparator() {
            return ServiceConfiguration.getInstance().getTupleSeparator();
        }

        /**
         * @see ServiceConfiguration#getTokenSeparator()
         */
        protected String getTokenSeparator() {
            return ServiceConfiguration.getInstance().getTokenSeparator();
        }

        /**
         * @see Configurator#getCapabilitiesCacheController()
         */
        protected ContentCache getCache() {
            return Configurator.getInstance().getCache();
        }

        /**
         * @see Configurator#getActiveProfile()
         */
        protected Profile getActiveProfile() {
            return Configurator.getInstance().getProfileHandler().getActiveProfile();
        }

        /**
         * @see Configurator#getFeatureQueryHandler()
         */
        protected FeatureQueryHandler getFeatureQueryHandler() {
            return Configurator.getInstance().getFeatureQueryHandler();
        }

        /**
         * @see ServiceConfiguration#isSupportsQuality()
         */
        protected boolean isSupportsQuality() {
            return ServiceConfiguration.getInstance().isSupportsQuality();
        }
    }
}