it.geosolutions.geostore.services.rest.impl.RESTStoredDataServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for it.geosolutions.geostore.services.rest.impl.RESTStoredDataServiceImpl.java

Source

/*
 *  Copyright (C) 2007 - 2016 GeoSolutions S.A.S.
 *  http://www.geo-solutions.it
 *
 *  GPLv3 + Classpath exception
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package it.geosolutions.geostore.services.rest.impl;

import it.geosolutions.geostore.core.model.StoredData;
import it.geosolutions.geostore.core.model.User;
import it.geosolutions.geostore.services.SecurityService;
import it.geosolutions.geostore.services.StoredDataService;
import it.geosolutions.geostore.services.exception.NotFoundServiceEx;
import it.geosolutions.geostore.services.rest.RESTStoredDataService;
import it.geosolutions.geostore.services.rest.exception.BadRequestWebEx;
import it.geosolutions.geostore.services.rest.exception.ForbiddenErrorWebEx;
import it.geosolutions.geostore.services.rest.exception.InternalErrorWebEx;
import it.geosolutions.geostore.services.rest.exception.NotFoundWebEx;
import it.geosolutions.geostore.services.rest.model.enums.RawFormat;
import it.geosolutions.geostore.services.rest.utils.DataURIDecoder;

import java.io.StringReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;

import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;

import net.sf.json.JSON;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.xml.XMLSerializer;
import org.apache.commons.codec.binary.Base64;

import org.apache.log4j.Logger;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * Class RESTStoredDataServiceImpl.
 * 
 * @author ETj (etj at geo-solutions.it)
 * @author Tobia di Pisa (tobia.dipisa at geo-solutions.it)
 * 
 */
public class RESTStoredDataServiceImpl extends RESTServiceImpl implements RESTStoredDataService {

    private final static Logger LOGGER = Logger.getLogger(RESTStoredDataServiceImpl.class);

    private StoredDataService storedDataService;

    /**
     * @param storedDataService
     */
    public void setStoredDataService(StoredDataService storedDataService) {
        this.storedDataService = storedDataService;
    }

    /* (non-Javadoc)
     * @see it.geosolutions.geostore.services.rest.impl.RESTServiceImpl#getSecurityService()
     */
    @Override
    protected SecurityService getSecurityService() {
        return storedDataService;
    }

    /*
     * (non-Javadoc)
     * 
     * @see it.geosolutions.geostore.services.rest.RESTStoredDataService#update(long, java.lang.String)
     */
    @Override
    public long update(SecurityContext sc, long id, String data) throws NotFoundWebEx {
        try {
            if (data == null)
                throw new BadRequestWebEx("Data is null");

            //
            // Authorization check.
            //
            boolean canUpdate = false;
            User authUser = extractAuthUser(sc);
            canUpdate = resourceAccessWrite(authUser, id); // The ID is also the resource ID

            if (canUpdate) {
                storedDataService.update(id, data);
            } else {
                throw new ForbiddenErrorWebEx("This user cannot update or create this store !");
            }

            return id;
        } catch (NotFoundServiceEx ex) {
            LOGGER.warn("Data not found (" + id + "): " + ex.getMessage(), ex);
            throw new NotFoundWebEx("Data not found");
        }
    }

    // /* (non-Javadoc)
    // * @see it.geosolutions.geostore.services.rest.RESTStoredDataService#getAll()
    // */
    // @Override
    // public StoredDataList getAll(SecurityContext sc) {
    // return new StoredDataList(storedDataService.getAll());
    // }

    /*
     * (non-Javadoc)
     * 
     * @see it.geosolutions.geostore.services.rest.RESTStoredDataService#delete(long)
     */
    @Override
    public void delete(SecurityContext sc, long id) throws NotFoundWebEx {
        //
        // Authorization check.
        //
        boolean canDelete = false;
        User authUser = extractAuthUser(sc);
        canDelete = resourceAccessWrite(authUser, id);

        if (canDelete) {
            boolean ret = storedDataService.delete(id);
            if (!ret)
                throw new NotFoundWebEx("Data not found");
        } else
            throw new ForbiddenErrorWebEx("This user cannot delete this store !");
    }

    private final static Collection<MediaType> GET_XML_MEDIA_TYPES = Arrays.asList(MediaType.TEXT_XML_TYPE,
            MediaType.APPLICATION_XML_TYPE);

    private final static Collection<MediaType> GET_JSON_MEDIA_TYPES = Arrays
            .asList(MediaType.APPLICATION_JSON_TYPE);

    private final static Collection<MediaType> GET_TEXT_MEDIA_TYPES = Arrays.asList(MediaType.TEXT_PLAIN_TYPE);

    /*
     * (non-Javadoc)
     * 
     * @see it.geosolutions.geostore.services.rest.RESTStoredDataService#get(long)
     */
    @Override
    public String get(SecurityContext sc, HttpHeaders headers, long id) throws NotFoundWebEx {
        if (id == -1)
            return "dummy payload";

        //
        // Authorization check.
        //
        boolean canRead = false;
        User authUser = extractAuthUser(sc);
        canRead = resourceAccessRead(authUser, id); // The ID is also the resource ID
        if (!canRead) {
            throw new ForbiddenErrorWebEx("This user cannot read this stored data !");
        }

        StoredData storedData;
        try {
            storedData = storedDataService.get(id);
        } catch (NotFoundServiceEx e) {
            throw new NotFoundWebEx("Data not found");
        }

        String data = storedData == null ? "" : storedData.getData();

        // prefer no transformation
        if (headers.getAcceptableMediaTypes().contains(MediaType.WILDCARD_TYPE)) {
            return data;
        } else if (!Collections.disjoint(GET_TEXT_MEDIA_TYPES, headers.getAcceptableMediaTypes())) {
            return data;
        } else if (!Collections.disjoint(GET_JSON_MEDIA_TYPES, headers.getAcceptableMediaTypes())) {
            return toJSON(data);
        } else if (!Collections.disjoint(GET_XML_MEDIA_TYPES, headers.getAcceptableMediaTypes())) {
            return toXML(data);
        } else
            throw new InternalErrorWebEx("Illegal state (" + headers.getAcceptableMediaTypes() + ")");
    }

    private String toJSON(String data) {

        try {
            // ////////////////////////
            // XML to JSON
            // ////////////////////////
            XMLSerializer xmlSerializer = new XMLSerializer();
            JSON json = xmlSerializer.read(data);
            String ret = json.toString();
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Transformed XML -> JSON");
            return ret;
        } catch (JSONException exc) {
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Data is not in native XML format.");
        }

        try {
            // ///////////////////////
            // data To JSON conversion
            // ///////////////////////
            JSONSerializer.toJSON(data);
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Data is in native JSON format.");
            return data;

        } catch (JSONException e) {
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Data is not in native JSON format.");
        }

        JSONObject jsonObj = new JSONObject();
        jsonObj.put("data", data);
        String ret = jsonObj.toString();
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Transformed plaintext -> JSON");

        return ret;
    }

    private String toXML(String data) {

        // Try XML source
        try {
            StringReader reader = new StringReader(data);
            SAXBuilder builder = new SAXBuilder();
            builder.build(reader);
            // no errors: return the original data
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Data is in native XML format.");
            return data;
        } catch (Exception e) {
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Data is not in native XML format.");
        }

        // Try JSON source
        try {
            // ///////////////////////
            // JSON To XML conversion
            // ///////////////////////
            JSON json = JSONSerializer.toJSON(data);
            XMLSerializer xmlSerializer = new XMLSerializer();
            String ret = xmlSerializer.write(json);
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Transformed JSON -> XML");
            return ret;

        } catch (JSONException exc) {
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("Data is not in native JSON format.");
        }

        // Force XML format
        Element element = new Element("data");
        element.addContent(data);

        XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
        String ret = outputter.outputString(element);
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Transformed plaintext -> XML");

        return ret;
    }

    @Override
    public Response getRaw(SecurityContext sc, HttpHeaders headers, long id, String decodeFormat)
            throws NotFoundWebEx {
        if (id == -1)
            return Response.ok().entity("dummy payload").build();

        StoredData storedData;
        try {
            storedData = storedDataService.get(id);
        } catch (NotFoundServiceEx e) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        if (storedData == null) {
            return Response.noContent().build();
        }

        String data = storedData.getData();

        // prefer no transformation
        if (decodeFormat == null) {
            return Response.ok().entity(data).build();
        } else if (decodeFormat.equalsIgnoreCase(RawFormat.BASE64.name())) {
            byte[] decoded = Base64.decodeBase64(data);
            return Response.ok().entity(decoded).build();
        } else if (decodeFormat.equalsIgnoreCase(RawFormat.DATAURI.name())) {
            return decodeDataURI(data);
        } else {
            LOGGER.warn("Unknown decode format '" + decodeFormat + "'");
            return Response.ok().entity(data).build();
        }
    }

    private Response decodeDataURI(String data) {
        if (!data.startsWith("data:")) {
            return Response.status(Response.Status.BAD_REQUEST).entity("Not a data URI").build();
        }

        String[] split = data.split(",", 2);

        if (split.length < 2) {
            return Response.status(Response.Status.BAD_REQUEST).entity("Bad data, comma is missing").build();
        }

        DataURIDecoder dud = new DataURIDecoder(split[0]);

        if (!dud.isValid()) {
            LOGGER.warn("Could not parse data URI '" + split[0] + "'");
            return Response.status(Response.Status.BAD_REQUEST).entity("Bad data URI").build();
        }

        if (dud.getCharset() != null) {
            LOGGER.warn("TODO: Charset '" + dud.getCharset() + "' should be handled.");
        }

        if (dud.getEncoding() != null && !dud.isBase64Encoded()) {
            LOGGER.warn("TODO: Encoding '" + dud.getEncoding() + "' should be handled.");
        }

        Object entity = dud.isBase64Encoded() ? Base64.decodeBase64(split[1]) : split[1];

        return Response.ok().type(dud.getNormalizedMediatype()).entity(entity).build();
    }

    /**
     * @param id
     * @return long
     * @throws BadRequestWebEx
     */
    @SuppressWarnings("unused")
    private long parseId(String id) throws BadRequestWebEx {
        try {
            return Long.parseLong(id);
        } catch (Exception e) {
            LOGGER.info("Bad id requested '" + id + "'");
            throw new BadRequestWebEx("Bad id");
        }
    }
}