class QuantizedMeshEnvoy extends AbstractEnvoy implements DataRegistryDataProvider {

    @Override
    public void query(DataModelCategory category, Collection<? extends Satisfaction> satisfactions,
            List<? extends PropertyMatcher<?>> parameters, List<? extends OrderSpecifier> orderSpecifiers, int limit,
            Collection<? extends PropertyDescriptor<?>> propertyDescriptors, CacheDepositReceiver queryReceiver)
        throws InterruptedException, QueryException
    {
        if (parameters.size() != 1 || !(parameters.get(0) instanceof ZYXKeyPropertyMatcher))
        {
            throw new IllegalArgumentException(ZYXKeyPropertyMatcher.class.getSimpleName() + " was not found in parameters.");
        }

        ZYXKeyPropertyMatcher param = (ZYXKeyPropertyMatcher)parameters.get(0);
        ZYXImageKey key = param.getImageKey();
        TileSetMetadata metadata = getTileMetadata(category.getCategory());

        if (metadata != null)
        {
            String tmsString = metadata.getTiles().get(0);
            tmsString = tmsString.replace("{z}", String.valueOf(key.getZ()));
            tmsString = tmsString.replace("{y}", String.valueOf(key.getY()));
            tmsString = tmsString.replace("{x}", String.valueOf(key.getX()));
            tmsString = tmsString.replace("{version}", String.valueOf(metadata.getVersion()));

            try
            {
                URL url = new URL(myServerUrl + Constants.TILE_SETS_URL + "/" + category.getCategory() + Constants.TILES_URL + "/"
                        + tmsString);
                HttpServer server = getToolbox().getServerProviderRegistry().getProvider(HttpServer.class).getServer(url);
                ResponseValues response = new ResponseValues();
                try
                {
                    try (CancellableInputStream stream = server.sendGet(url, Constants.QUANTIZED_MESH_ACCEPT_HEADER, response))
                    {
                        if (response.getResponseCode() == HttpURLConnection.HTTP_OK)
                        {
                            StreamReader meshReader = new StreamReader(stream);
                            ByteBuffer buffer = meshReader.readStreamIntoBuffer();

                            QuantizedMesh mesh = new QuantizedMesh(buffer);
                            Collection<PropertyAccessor<QuantizedMesh, ?>> accessors = New.collection();
                            accessors.add(SerializableAccessor.<QuantizedMesh, String>getSingletonAccessor(
                                    Constants.KEY_PROPERTY_DESCRIPTOR, param.getOperand()));
                            accessors.add(SerializableAccessor.<QuantizedMesh, QuantizedMesh>getSingletonAccessor(
                                    Constants.QUANTIZED_MESH_PROPERTY_DESCRIPTOR, mesh));

                            CacheDeposit<QuantizedMesh> deposit = new DefaultCacheDeposit<QuantizedMesh>(
                                    new DataModelCategory(myServerUrl, category.getFamily(), category.getCategory()), accessors,
                                    Collections.singleton(mesh), true, TimeInstant.get().plus(Constants.TILE_EXPIRATION).toDate(),
                                    false);
                            queryReceiver.receive(deposit);
                        }
                        else if (response.getResponseCode() != HttpURLConnection.HTTP_NOT_FOUND)
                        {
                            StreamReader errorMessageReader = new StreamReader(stream);
                            throw new QueryException(url.toString() + " returned code " + response.getResponseCode() + " "
                                    + response.getResponseMessage() + " message "
                                    + errorMessageReader.readStreamIntoString(StringUtilities.DEFAULT_CHARSET));
                        }
                    }
                }
                catch (IOException | URISyntaxException | CacheException e)
                {
                    throw new QueryException(e.getMessage(), e);
                }
            }
            catch (MalformedURLException e)
            {
                throw new QueryException(e.getMessage(), e);
            }
        }
        else
        {
            throw new QueryException("Could not retrieve terrain for " + category.toString() + " " + key.toString());
        }
    }

    public  QuantizedMeshEnvoy(Toolbox toolbox, String serverUrl);

}