com.msopentech.odatajclient.testservice.AbstractServices.java Source code

Java tutorial

Introduction

Here is the source code for com.msopentech.odatajclient.testservice.AbstractServices.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.msopentech.odatajclient.testservice;

import com.msopentech.odatajclient.testservice.utils.Accept;
import com.msopentech.odatajclient.testservice.utils.XMLUtilities;
import com.msopentech.odatajclient.testservice.utils.JSONUtilities;
import com.msopentech.odatajclient.testservice.utils.ODataVersion;
import com.msopentech.odatajclient.testservice.utils.FSManager;

import static com.msopentech.odatajclient.testservice.utils.Constants.*;

import com.msopentech.odatajclient.testservice.methods.MERGE;
import com.msopentech.odatajclient.testservice.methods.PATCH;
import com.msopentech.odatajclient.testservice.utils.AbstractUtilities;
import com.msopentech.odatajclient.testservice.utils.Commons;
import com.msopentech.odatajclient.testservice.utils.LinkInfo;
import java.io.File;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractServices {

    /**
     * Logger.
     */
    protected static final Logger LOG = LoggerFactory.getLogger(AbstractServices.class);

    protected abstract ODataVersion getVersion();

    protected final XMLUtilities xml;

    protected final JSONUtilities json;

    public AbstractServices() throws Exception {
        this.xml = new XMLUtilities(getVersion());
        this.json = new JSONUtilities(getVersion());
    }

    /**
     * Provide sample services.
     *
     * @param accept Accept header.
     * @return OData services.
     */
    @GET
    public Response getSevices(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept) {
        try {
            final Accept acceptType = Accept.parse(accept, getVersion());

            if (acceptType == Accept.ATOM) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            return xml.createResponse(FSManager.instance(getVersion()).readFile(SERVICES, acceptType), null,
                    acceptType);
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    /**
     * Provide sample metadata.
     *
     * @return metadata.
     */
    @GET
    @Path("/$metadata")
    @Produces("application/xml")
    public Response getMetadata() {
        return getMetadata(METADATA);
    }

    /**
     * Provide sample lartge metadata.
     *
     * @return metadata.
     */
    @GET
    @Path("/large/$metadata")
    @Produces("application/xml")
    public Response getLargeMetadata() {
        return getMetadata("large" + StringUtils.capitalize(METADATA));
    }

    private Response getMetadata(final String filename) {
        try {
            return xml.createResponse(FSManager.instance(getVersion()).readFile(filename, Accept.XML), null,
                    Accept.XML);
        } catch (Exception e) {
            return xml.createFaultResponse(Accept.XML.toString(), e);
        }
    }

    @MERGE
    @Path("/{entitySetName}({entityId})")
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    public Response mergeEntity(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
            @HeaderParam("If-Match") @DefaultValue(StringUtils.EMPTY) String ifMatch,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            final String changes) {

        return patchEntity(accept, prefer, ifMatch, entitySetName, entityId, changes);
    }

    @PATCH
    @Path("/{entitySetName}({entityId})")
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    public Response patchEntity(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
            @HeaderParam("If-Match") @DefaultValue(StringUtils.EMPTY) String ifMatch,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            final String changes) {

        try {
            final Accept acceptType = Accept.parse(accept, getVersion());

            if (acceptType == Accept.XML || acceptType == Accept.TEXT) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            final AbstractUtilities util = acceptType == Accept.ATOM ? xml : json;
            InputStream res = util.patchEntity(entitySetName, entityId, IOUtils.toInputStream(changes), acceptType,
                    ifMatch);

            final Response response;
            if ("return-content".equalsIgnoreCase(prefer)) {
                response = xml.createResponse(res, null, acceptType, Response.Status.OK);
            } else {
                res.close();
                response = xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
            }

            if (StringUtils.isNotBlank(prefer)) {
                response.getHeaders().put("Preference-Applied", Collections.<Object>singletonList(prefer));
            }

            return response;
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    @PUT
    @Path("/{entitySetName}({entityId})")
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    public Response putNewEntity(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            final String entity) {
        try {
            final Accept acceptType = Accept.parse(accept, getVersion());

            if (acceptType == Accept.XML || acceptType == Accept.TEXT) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            InputStream res;
            if (acceptType == Accept.ATOM) {
                res = xml.addOrReplaceEntity(entityId, entitySetName, IOUtils.toInputStream(entity));
            } else {
                res = json.addOrReplaceEntity(entityId, entitySetName, IOUtils.toInputStream(entity));
            }

            final Response response;
            if ("return-content".equalsIgnoreCase(prefer)) {
                response = xml.createResponse(res, null, acceptType, Response.Status.OK);
            } else {
                res.close();
                response = xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
            }

            if (StringUtils.isNotBlank(prefer)) {
                response.getHeaders().put("Preference-Applied", Collections.<Object>singletonList(prefer));
            }

            return response;
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    @POST
    @Path("/{entitySetName}")
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
    public Response postNewEntity(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
            @PathParam("entitySetName") String entitySetName, final String entity) {

        try {
            final Accept acceptType = Accept.parse(accept, getVersion());

            if (acceptType == Accept.XML || acceptType == Accept.TEXT) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            final InputStream res;
            if (acceptType == Accept.ATOM) {
                res = xml.addOrReplaceEntity(entitySetName, IOUtils.toInputStream(entity));
            } else {
                res = json.addOrReplaceEntity(entitySetName, IOUtils.toInputStream(entity));
            }

            final Response response;
            if ("return-no-content".equalsIgnoreCase(prefer)) {
                res.close();
                response = xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
            } else {
                response = xml.createResponse(res, null, acceptType, Response.Status.CREATED);
            }

            if (StringUtils.isNotBlank(prefer)) {
                response.getHeaders().put("Preference-Applied", Collections.<Object>singletonList(prefer));
            }

            return response;
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    /**
     * Retrieve entity set or function execution sample.
     *
     * @param accept Accept header.
     * @param name entity set or function name.
     * @param format format query option.
     * @param inlinecount inlinecount query option.
     * @param filter filter query option.
     * @param orderby orderby query option.
     * @param skiptoken skiptoken query option.
     * @return entity set or function result.
     */
    @GET
    @Path("/{name}")
    public Response getEntitySet(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @PathParam("name") String name, @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format,
            @QueryParam("$inlinecount") @DefaultValue(StringUtils.EMPTY) String inlinecount,
            @QueryParam("$filter") @DefaultValue(StringUtils.EMPTY) String filter,
            @QueryParam("$orderby") @DefaultValue(StringUtils.EMPTY) String orderby,
            @QueryParam("$skiptoken") @DefaultValue(StringUtils.EMPTY) String skiptoken) {

        try {
            final Accept acceptType;
            if (StringUtils.isNotBlank(format)) {
                acceptType = Accept.valueOf(format.toUpperCase());
            } else {
                acceptType = Accept.parse(accept, getVersion());
            }

            if (acceptType == Accept.XML || acceptType == Accept.TEXT) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            try {
                // search for function ...
                final InputStream func = FSManager.instance(getVersion()).readFile(name, acceptType);
                return xml.createResponse(func, null, acceptType);
            } catch (NotFoundException e) {
                // search for entitySet ...
                final String basePath = name + File.separatorChar;

                final StringBuilder builder = new StringBuilder();
                builder.append(basePath);

                if (StringUtils.isNotBlank(orderby)) {
                    builder.append(ORDERBY).append(File.separatorChar).append(orderby).append(File.separatorChar);
                }

                if (StringUtils.isNotBlank(filter)) {
                    builder.append(FILTER).append(File.separatorChar).append(filter.replaceAll("/", "."));
                } else if (StringUtils.isNotBlank(skiptoken)) {
                    builder.append(SKIP_TOKEN).append(File.separatorChar).append(skiptoken);
                } else {
                    builder.append(FEED);
                }

                InputStream feed = FSManager.instance(getVersion()).readFile(builder.toString(), acceptType);
                if ("allpages".equals(inlinecount)) {
                    int count = xml.countAllElements(name);
                    feed.close();
                    if (acceptType == Accept.ATOM) {
                        feed = xml.addAtomInlinecount(
                                FSManager.instance(getVersion()).readFile(builder.toString(), acceptType), count,
                                acceptType);
                    } else {
                        feed = json.addJsonInlinecount(
                                FSManager.instance(getVersion()).readFile(builder.toString(), acceptType), count,
                                acceptType);
                    }
                }

                return xml.createResponse(feed, Commons.getETag(basePath, getVersion()), acceptType);
            }
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    /**
     * Retrieve entity sample.
     *
     * @param accept Accept header.
     * @param entitySetName Entity set name.
     * @param entityId entity id.
     * @param format format query option.
     * @param expand expand query option.
     * @param select select query option.
     * @return entity.
     */
    @GET
    @Path("/{entitySetName}({entityId})")
    public Response getEntity(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format,
            @QueryParam("$expand") @DefaultValue(StringUtils.EMPTY) String expand,
            @QueryParam("$select") @DefaultValue(StringUtils.EMPTY) String select) {

        try {

            final Accept acceptType;
            if (StringUtils.isNotBlank(format)) {
                acceptType = Accept.valueOf(format.toUpperCase());
            } else {
                acceptType = Accept.parse(accept, getVersion());
            }

            final Map.Entry<String, InputStream> entityInfo = xml.readEntity(entitySetName, entityId, acceptType);

            InputStream entity = entityInfo.getValue();

            if (StringUtils.isNotBlank(select)) {
                if (acceptType == Accept.ATOM) {
                    entity = xml.selectEntity(entity, select.split(","));
                } else {
                    entity = json.selectEntity(entity, select.split(","));
                }
            }

            if (StringUtils.isNotBlank(expand)) {
                if (acceptType == Accept.XML || acceptType == Accept.TEXT) {
                    throw new UnsupportedMediaTypeException("Unsupported media type");
                } else if (acceptType == Accept.ATOM) {
                    for (String exp : expand.split(",")) {
                        entity = xml.expandEntity(entitySetName, entityId, entity, exp);
                    }
                } else {
                    for (String exp : expand.split(",")) {
                        entity = json.expandEntity(entitySetName, entityId, entity, exp);
                    }
                }
            }

            return xml.createResponse(entity, Commons.getETag(entityInfo.getKey(), getVersion()), acceptType);
        } catch (Exception e) {
            LOG.error("Error retrieving entity", e);
            return xml.createFaultResponse(accept, e);
        }
    }

    @DELETE
    @Path("/{entitySetName}({entityId})")
    public Response removeEntity(@PathParam("entitySetName") String entitySetName,
            @PathParam("entityId") String entityId) {

        try {
            final String basePath = entitySetName + File.separatorChar + Commons.getEntityKey(entityId)
                    + File.separatorChar;

            FSManager.instance(getVersion()).deleteFile(basePath + ENTITY);

            return xml.createResponse(null, null, null, Response.Status.NO_CONTENT);
        } catch (Exception e) {
            return xml.createFaultResponse(Accept.XML.toString(), e);
        }
    }

    /**
     * Retrieve property sample.
     *
     * @param accept Accept header.
     * @param entitySetName Entity set name.
     * @param entityId entity id.
     * @param path path.
     * @param format format query option.
     * @return property.
     */
    @GET
    @Path("/{entitySetName}({entityId})/{path:.*}")
    public Response getPath(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @PathParam("path") String path, @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {

        try {
            boolean searchForValue = path.endsWith("$value");
            Accept acceptType = null;
            if (StringUtils.isNotBlank(format)) {
                acceptType = Accept.valueOf(format.toUpperCase());
            } else if (StringUtils.isNotBlank(accept)) {
                acceptType = Accept.parse(accept, getVersion(), null);
            }

            final String basePath = entitySetName + File.separatorChar + Commons.getEntityKey(entityId)
                    + File.separatorChar;

            InputStream stream;

            try {
                final LinkInfo linkInfo = xml.readLinks(entitySetName, entityId, path, Accept.XML);
                final Map.Entry<String, List<String>> links = XMLUtilities.extractLinkURIs(linkInfo.getLinks());

                switch (acceptType) {
                case JSON:
                case JSON_FULLMETA:
                case JSON_NOMETA:
                    stream = json.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed());
                    stream = json.wrapJsonEntities(stream);
                    break;
                default:
                    stream = xml.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed());
                }
            } catch (NotFoundException e) {
                // if the given path is not about any link then search for property
                LOG.info("Retrieve property {}", path);

                stream = FSManager.instance(getVersion()).readFile(basePath + ENTITY,
                        acceptType == null || acceptType == Accept.TEXT ? Accept.XML : acceptType);

                if (searchForValue) {
                    stream = xml.getAtomPropertyValue(stream, path.split("/"));
                } else {
                    if (acceptType == null || acceptType == Accept.XML || acceptType == Accept.ATOM) {
                        // retrieve xml
                        stream = xml.getAtomProperty(stream, path.split("/"));
                    } else {
                        // retrieve Edm type from xml
                        final String edmType = xml.getEdmTypeFromXML(
                                FSManager.instance(getVersion()).readFile(basePath + ENTITY, Accept.XML),
                                path.split("/"));
                        // retrieve json property
                        stream = json.getJsonProperty(stream, path.split("/"), edmType);
                    }
                }

                if ((searchForValue && acceptType != null && acceptType != Accept.TEXT)
                        || acceptType == Accept.ATOM) {
                    throw new UnsupportedMediaTypeException("Unsupported media type " + acceptType);
                }
            }

            return xml.createResponse(stream, Commons.getETag(basePath, getVersion()), acceptType);
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    /**
     * Retrieve links sample.
     *
     * @param accept Accept header.
     * @param entitySetName Entity set name.
     * @param entityId entity id.
     * @param linkName link name.
     * @param format format query option.
     * @return links.
     */
    @GET
    @Path("/{entitySetName}({entityId})/$links/{linkName}")
    public Response getLinks(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @PathParam("linkName") String linkName,
            @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
        try {
            final Accept acceptType;
            if (StringUtils.isNotBlank(format)) {
                acceptType = Accept.valueOf(format.toUpperCase());
            } else {
                acceptType = Accept.parse(accept, getVersion());
            }

            if (acceptType == Accept.ATOM) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            final LinkInfo links = xml.readLinks(entitySetName, entityId, linkName, acceptType);

            return xml.createResponse(links.getLinks(), links.getEtag(), acceptType);
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    @POST
    @Path("/{entitySetName}({entityId})/$links/{linkName}")
    public Response postLink(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @PathParam("linkName") String linkName, String link,
            @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
        try {
            final Accept acceptType;
            if (StringUtils.isNotBlank(format)) {
                acceptType = Accept.valueOf(format.toUpperCase());
            } else {
                acceptType = Accept.parse(accept, getVersion());
            }

            if (acceptType == Accept.ATOM) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            final Accept content;
            if (StringUtils.isNotBlank(contentType)) {
                content = Accept.parse(contentType, getVersion());
            } else {
                content = acceptType;
            }

            final AbstractUtilities utils = getUtilities(acceptType);

            final List<String> links;
            if (content == Accept.XML || content == Accept.TEXT || content == Accept.ATOM) {
                links = XMLUtilities.extractLinkURIs(IOUtils.toInputStream(link)).getValue();
            } else {
                links = JSONUtilities.extractLinkURIs(IOUtils.toInputStream(link)).getValue();
            }

            utils.putLinksInMemory(Commons.getEntityBasePath(entitySetName, entityId), entitySetName, entityId,
                    linkName, links);

            return xml.createResponse(null, null, null, Response.Status.NO_CONTENT);
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    @MERGE
    @Path("/{entitySetName}({entityId})/$links/{linkName}")
    public Response mergeLink(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @PathParam("linkName") String linkName, String link,
            @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
        return putLink(accept, contentType, entitySetName, entityId, linkName, link, format);
    }

    @PATCH
    @Path("/{entitySetName}({entityId})/$links/{linkName}")
    public Response patchLink(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @PathParam("linkName") String linkName, String link,
            @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
        return putLink(accept, contentType, entitySetName, entityId, linkName, link, format);
    }

    @PUT
    @Path("/{entitySetName}({entityId})/$links/{linkName}")
    public Response putLink(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @PathParam("linkName") String linkName, String link,
            @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
        try {
            final Accept acceptType;
            if (StringUtils.isNotBlank(format)) {
                acceptType = Accept.valueOf(format.toUpperCase());
            } else {
                acceptType = Accept.parse(accept, getVersion());
            }

            if (acceptType == Accept.ATOM) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            final Accept content;
            if (StringUtils.isNotBlank(contentType)) {
                content = Accept.parse(contentType, getVersion());
            } else {
                content = acceptType;
            }

            final AbstractUtilities utils = getUtilities(acceptType);

            final List<String> links;
            if (content == Accept.XML || content == Accept.TEXT || content == Accept.ATOM) {
                links = XMLUtilities.extractLinkURIs(IOUtils.toInputStream(link)).getValue();
            } else {
                links = JSONUtilities.extractLinkURIs(IOUtils.toInputStream(link)).getValue();
            }

            utils.putLinksInMemory(Commons.getEntityBasePath(entitySetName, entityId), entitySetName, linkName,
                    links);

            return xml.createResponse(null, null, null, Response.Status.NO_CONTENT);
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    @DELETE
    @Path("/{entitySetName}({entityId})/$links/{linkName}({linkId})")
    public Response deleteLink(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType,
            @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId,
            @PathParam("linkName") String linkName, @PathParam("linkId") String linkId,
            @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
        try {
            final Accept acceptType;
            if (StringUtils.isNotBlank(format)) {
                acceptType = Accept.valueOf(format.toUpperCase());
            } else {
                acceptType = Accept.parse(accept, getVersion());
            }

            if (acceptType == Accept.ATOM) {
                throw new UnsupportedMediaTypeException("Unsupported media type");
            }

            final AbstractUtilities utils = getUtilities(acceptType);

            final Map.Entry<String, List<String>> currents = JSONUtilities.extractLinkURIs(
                    utils.readLinks(entitySetName, entityId, linkName, Accept.JSON_FULLMETA).getLinks());

            final Map.Entry<String, List<String>> toBeRemoved = JSONUtilities.extractLinkURIs(
                    utils.readLinks(entitySetName, entityId, linkName + "(" + linkId + ")", Accept.JSON_FULLMETA)
                            .getLinks());

            final List<String> remains = currents.getValue();
            remains.removeAll(toBeRemoved.getValue());

            utils.putLinksInMemory(Commons.getEntityBasePath(entitySetName, entityId), entitySetName, linkName,
                    remains);

            return xml.createResponse(null, null, null, Response.Status.NO_CONTENT);
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    /**
     * Count sample.
     *
     * @param accept Accept header.
     * @param entitySetName entity set name.
     * @return count.
     */
    @GET
    @Path("/{entitySetName}/$count")
    public Response count(@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
            @PathParam("entitySetName") String entitySetName) {
        try {
            final Accept acceptType = Accept.parse(accept, getVersion(), Accept.TEXT);

            if (acceptType != Accept.TEXT) {
                throw new UnsupportedMediaTypeException("Unsupported type " + accept);
            }

            int count = xml.countAllElements(entitySetName);

            final Response.ResponseBuilder builder = Response.ok();
            builder.entity(count);

            return builder.build();
        } catch (Exception e) {
            return xml.createFaultResponse(accept, e);
        }
    }

    private AbstractUtilities getUtilities(final Accept accept) {
        final AbstractUtilities utils;
        if (accept == Accept.XML || accept == Accept.TEXT || accept == Accept.ATOM) {
            utils = xml;
        } else {
            utils = json;
        }

        return utils;
    }
}