eu.trentorise.smartcampus.permissionprovider.controller.PermissionController.java Source code

Java tutorial

Introduction

Here is the source code for eu.trentorise.smartcampus.permissionprovider.controller.PermissionController.java

Source

/**
 *    Copyright 2012-2013 Trento RISE
 *
 *    Licensed 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 eu.trentorise.smartcampus.permissionprovider.controller;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import eu.trentorise.smartcampus.permissionprovider.Config.RESOURCE_VISIBILITY;
import eu.trentorise.smartcampus.permissionprovider.jaxbmodel.ResourceDeclaration;
import eu.trentorise.smartcampus.permissionprovider.jaxbmodel.ResourceMapping;
import eu.trentorise.smartcampus.permissionprovider.jaxbmodel.Service;
import eu.trentorise.smartcampus.permissionprovider.manager.ResourceManager;
import eu.trentorise.smartcampus.permissionprovider.model.ClientAppInfo;
import eu.trentorise.smartcampus.permissionprovider.model.ClientDetailsEntity;
import eu.trentorise.smartcampus.permissionprovider.model.Permissions;
import eu.trentorise.smartcampus.permissionprovider.model.Resource;
import eu.trentorise.smartcampus.permissionprovider.model.ResourceParameter;
import eu.trentorise.smartcampus.permissionprovider.model.Response;
import eu.trentorise.smartcampus.permissionprovider.model.Response.RESPONSE;
import eu.trentorise.smartcampus.permissionprovider.repository.ClientDetailsRepository;
import eu.trentorise.smartcampus.permissionprovider.repository.ResourceParameterRepository;
import eu.trentorise.smartcampus.permissionprovider.repository.ResourceRepository;

/**
 * Controller for managing the permissions of the apps
 * @author raman
 *
 */
@Controller
public class PermissionController extends AbstractController {

    private static final Integer RA_NONE = 0;
    private static final Integer RA_APPROVED = 1;
    private static final Integer RA_REJECTED = 2;
    private static final Integer RA_PENDING = 3;
    private static Log logger = LogFactory.getLog(PermissionController.class);
    @Autowired
    private ResourceManager resourceManager;
    @Autowired
    private ClientDetailsRepository clientDetailsRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private ResourceParameterRepository resourceParameterRepository;

    /**
     * Save permissions requested by the app.
     * @param permissions
     * @param clientId
     * @param serviceId
     * @return {@link Response} entity containing the processed app {@link Permissions} descriptor
     */
    @RequestMapping(value = "/dev/permissions/{clientId}/{serviceId:.*}", method = RequestMethod.PUT)
    public @ResponseBody Response savePermissions(@RequestBody Permissions permissions,
            @PathVariable String clientId, @PathVariable String serviceId) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            // check that the client is owned by the current user
            checkClientIdOwnership(clientId);
            ClientDetailsEntity clientDetails = clientDetailsRepository.findByClientId(clientId);
            ClientAppInfo info = ClientAppInfo.convert(clientDetails.getAdditionalInformation());

            if (info.getResourceApprovals() == null)
                info.setResourceApprovals(new HashMap<String, Boolean>());
            Collection<String> resourceIds = new HashSet<String>(clientDetails.getResourceIds());
            Collection<String> scopes = new HashSet<String>(clientDetails.getScope());
            for (String r : permissions.getSelectedResources().keySet()) {
                Resource resource = resourceRepository.findOne(Long.parseLong(r));
                // if not checked, remove from permissions and from pending requests
                if (!permissions.getSelectedResources().get(r)) {
                    info.getResourceApprovals().remove(r);
                    resourceIds.remove(r);
                    scopes.remove(resource.getResourceUri());
                    // if checked but requires approval, check whether
                    // - is the resource of the same client, so add automatically   
                    // - already approved (i.e., included in client resourceIds)
                    // - already requested (i.e., included in additional info approval requests map)   
                } else if (!clientId.equals(resource.getClientId()) && resource.isApprovalRequired()) {
                    if (!resourceIds.contains(r) && !info.getResourceApprovals().containsKey(r)) {
                        info.getResourceApprovals().put(r, true);
                    }
                    // if approval is not required, include directly in client resource ids   
                } else {
                    resourceIds.add(r);
                    scopes.add(resource.getResourceUri());
                }
            }
            clientDetails.setResourceIds(StringUtils.collectionToCommaDelimitedString(resourceIds));
            clientDetails.setScope(StringUtils.collectionToCommaDelimitedString(scopes));
            clientDetails.setAdditionalInformation(info.toJson());
            clientDetailsRepository.save(clientDetails);
            response.setData(buildPermissions(clientDetails, serviceId));
        } catch (Exception e) {
            logger.error("Failure saving permissions model: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;

    }

    /**
     * Read permissions of the specified app and service
     * @param clientId
     * @param serviceId
     * @return {@link Response} entity containing the app {@link Permissions} descriptor
     */
    @RequestMapping(value = "/dev/permissions/{clientId}/{serviceId:.*}", method = RequestMethod.GET)
    public @ResponseBody Response getPermissions(@PathVariable String clientId, @PathVariable String serviceId) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            checkClientIdOwnership(clientId);
            ClientDetailsEntity clientDetails = clientDetailsRepository.findByClientId(clientId);
            Permissions permissions = buildPermissions(clientDetails, serviceId);
            response.setData(permissions);
        } catch (Exception e) {
            logger.error("Failure reading permissions model: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Read services
     * @param clientId
     * @return {@link Response} entity containing the service {@link Service} descriptors
     */
    @RequestMapping(value = "/dev/services/{clientId}", method = RequestMethod.GET)
    public @ResponseBody Response getServices(@PathVariable String clientId) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            checkClientIdOwnership(clientId);
            response.setData(resourceManager.getServiceObjects());
        } catch (Exception e) {
            logger.error("Failure reading permissions model: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Read services defined by the current user
     * @return {@link Response} entity containing the service {@link Service} descriptors
     */
    @RequestMapping(value = "/dev/services/my", method = RequestMethod.GET)
    public @ResponseBody Response myServices() {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            response.setData(resourceManager.getServiceObjects("" + getUserId()));
        } catch (Exception e) {
            logger.error("Failure reading permissions model: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * save service data (name, id, description)
     * @param sd
     * @return stored {@link Service} object
     */
    @RequestMapping(value = "/dev/services/my", method = RequestMethod.POST)
    public @ResponseBody Response saveService(@RequestBody Service sd) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            response.setData(resourceManager.saveServiceObject(sd, getUserId()));
        } catch (Exception e) {
            logger.error("Failure saving service: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Delete service object if possible
     * @param serviceId
     * @return
     */
    @RequestMapping(value = "/dev/services/my/{serviceId:.*}", method = RequestMethod.DELETE)
    public @ResponseBody Response deleteService(@PathVariable String serviceId) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            resourceManager.checkServiceOwnership(serviceId, getUserId().toString());
            resourceManager.deleteService(serviceId, getUserId().toString());
        } catch (Exception e) {
            logger.error("Failure deleting service: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Add resource parameter declaration to the service object if possible
     * @param serviceId
     * @return
     */
    @RequestMapping(value = "/dev/services/my/{serviceId}/parameter", method = RequestMethod.PUT)
    public @ResponseBody Response addParameter(@PathVariable String serviceId,
            @RequestBody ResourceDeclaration decl) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            resourceManager.checkServiceOwnership(serviceId, getUserId().toString());
            response.setData(resourceManager.addResourceDeclaration(serviceId, decl, getUserId().toString()));
        } catch (Exception e) {
            logger.error("Failure adding parameter to service: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Delete resource parameter declaration from the service object if possible
     * @param serviceId
     * @param id 
     * @return
     */
    @RequestMapping(value = "/dev/services/my/{serviceId}/parameter/{id:.*}", method = RequestMethod.DELETE)
    public @ResponseBody Response deleteParameter(@PathVariable String serviceId, @PathVariable String id) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            resourceManager.checkServiceOwnership(serviceId, getUserId().toString());
            response.setData(resourceManager.removeResourceDeclaration(serviceId, id, getUserId().toString()));
        } catch (Exception e) {
            logger.error("Failure deleting parameter from service: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Add resource parameter to the service object if possible
     * @param serviceId
     * @return
     */
    @RequestMapping(value = "/dev/services/my/{serviceId}/mapping", method = RequestMethod.PUT)
    public @ResponseBody Response addMapping(@PathVariable String serviceId, @RequestBody ResourceMapping mapping) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            resourceManager.checkServiceOwnership(serviceId, getUserId().toString());
            response.setData(resourceManager.addMapping(serviceId, mapping, getUserId().toString()));
        } catch (Exception e) {
            logger.error("Failure adding parameter to service: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Delete resource parameter declaration from the service object if possible
     * @param serviceId
     * @param id 
     * @return
     */
    @RequestMapping(value = "/dev/services/my/{serviceId}/mapping/{id:.*}", method = RequestMethod.DELETE)
    public @ResponseBody Response deleteMapping(@PathVariable String serviceId, @PathVariable String id) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            resourceManager.checkServiceOwnership(serviceId, getUserId().toString());
            response.setData(resourceManager.removeMapping(serviceId, id, getUserId().toString()));
        } catch (Exception e) {
            logger.error("Failure deleting mapping from service: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }

        return response;
    }

    /**
     * Create {@link Permissions} descriptors from the client app data.
     * @param clientId
     * @param clientDetails
     * @param serviceId 
     * @return
     */
    protected Permissions buildPermissions(ClientDetailsEntity clientDetails, String serviceId) {
        Permissions permissions = new Permissions();
        permissions.setService(resourceManager.getServiceObject(serviceId));
        Map<String, List<ResourceParameter>> ownResources = new HashMap<String, List<ResourceParameter>>();
        // read resource parameters owned by the client and create 'parameter-values' map
        List<ResourceParameter> resourceParameters = resourceManager
                .getOwnResourceParameters(clientDetails.getClientId());
        if (resourceParameters != null) {
            for (ResourceParameter resourceParameter : resourceParameters) {
                List<ResourceParameter> sublist = ownResources.get(resourceParameter.getParameter());
                if (sublist == null) {
                    sublist = new ArrayList<ResourceParameter>();
                    ownResources.put(resourceParameter.getParameter(), sublist);
                }
                sublist.add(resourceParameter);
            }
        }
        permissions.setOwnResources(ownResources);
        // read all available resources and assign permission status
        Map<String, List<Resource>> otherResourcesMap = new HashMap<String, List<Resource>>();
        // map resources selected by the client
        Map<String, Boolean> selectedResources = new HashMap<String, Boolean>();
        // map resource approval state
        Map<String, Integer> resourceApprovals = new HashMap<String, Integer>();
        Set<String> set = clientDetails.getResourceIds();
        if (set == null)
            set = Collections.emptySet();

        List<Resource> otherResources = resourceManager.getAvailableResources(clientDetails.getClientId(),
                getUserId());
        // read approval status for the resources that require approval explicitly
        ClientAppInfo info = ClientAppInfo.convert(clientDetails.getAdditionalInformation());
        if (info.getResourceApprovals() == null)
            info.setResourceApprovals(Collections.<String, Boolean>emptyMap());

        if (otherResources != null) {
            for (Resource resource : otherResources) {
                String rId = resource.getResourceId().toString();
                List<Resource> sublist = otherResourcesMap.get(resource.getResourceType());
                if (sublist == null) {
                    sublist = new ArrayList<Resource>();
                    otherResourcesMap.put(resource.getResourceType(), sublist);
                }
                sublist.add(resource);
                selectedResources.put(rId, set.contains(rId) || info.getResourceApprovals().containsKey(rId));
                // set the resource approval status
                if (selectedResources.containsKey(rId) && selectedResources.get(rId)) {
                    // the resource is approved if it is in the client resource Ids
                    if (set.contains(rId))
                        resourceApprovals.put(rId, RA_APPROVED);
                    // if resource is not in the resource approvals map, then it is rejected
                    else if (!info.getResourceApprovals().get(rId))
                        resourceApprovals.put(rId, RA_REJECTED);
                    // resource is waiting for approval
                    else
                        resourceApprovals.put(rId, RA_PENDING);
                } else {
                    resourceApprovals.put(rId, RA_NONE);
                }
            }
        }
        Map<String, List<Resource>> serviceMap = new TreeMap<String, List<Resource>>();
        serviceMap.put("__", new ArrayList<Resource>());
        for (ResourceMapping rm : permissions.getService().getResourceMapping()) {
            List<Resource> list = otherResourcesMap.get(rm.getId());
            if (list != null) {
                for (Resource r : list) {
                    String key = r.getResourceParameter() == null ? "__"
                            : (r.getResourceParameter().getParameter() + "__"
                                    + r.getResourceParameter().getValue());
                    List<Resource> targetList = serviceMap.get(key);
                    if (targetList == null) {
                        targetList = new ArrayList<Resource>();
                        serviceMap.put(key, targetList);
                    }
                    targetList.add(r);
                }
            }
        }

        permissions.setResourceApprovals(resourceApprovals);
        permissions.setSelectedResources(selectedResources);
        permissions.setAvailableResources(serviceMap);
        return permissions;
    }

    /**
     * Create new resource property
     * @param rp
     * @param serviceId
     * @return {@link Response} entity containing the stored {@link ResourceParameter} descriptor
     */
    @RequestMapping(value = "/dev/resourceparams", method = RequestMethod.POST)
    public @ResponseBody Response createProperty(@RequestBody ResourceParameter rp) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            checkClientIdOwnership(rp.getClientId());
            resourceManager.storeResourceParameter(rp, rp.getService().getServiceId());
            response.setData(rp);
        } catch (Exception e) {
            logger.error("Failure creating resource parameter: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }
        return response;
    }

    /**
     * Change the visibility of the owned resource property
     * @param clientId client owning the resource
     * @param resourceId id of the resource parameter
     * @param value parameter value
     * @param vis visibility
     * @return {@link Response} entity containing the processed {@link ResourceParameter} descriptor
     */
    @RequestMapping(value = "/dev/resourceparams/{id:.*}", method = RequestMethod.PUT)
    public @ResponseBody Response updatePropertyVisibility(@PathVariable Long id,
            @RequestParam RESOURCE_VISIBILITY vis) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            ResourceParameter rp = resourceParameterRepository.findOne(id);
            checkClientIdOwnership(rp.getClientId());
            rp = resourceManager.updateResourceParameterVisibility(id, vis);
            response.setData(rp);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Failure Failure updating resource parameter visibility: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }
        return response;
    }

    /**
     * Delete the specified resource parameter
     * @param clientId client owning the property
     * @param resourceId id of the parameter
     * @param value parameter value
     * @return
     */
    @RequestMapping(value = "/dev/resourceparams/{id:.*}", method = RequestMethod.DELETE)
    public @ResponseBody Response deleteProperty(@PathVariable Long id) {
        Response response = new Response();
        response.setResponseCode(RESPONSE.OK);
        try {
            ResourceParameter rp = resourceParameterRepository.findOne(id);
            checkClientIdOwnership(rp.getClientId());
            resourceManager.removeResourceParameter(id);
        } catch (Exception e) {
            logger.error("Failure deleting resource parameter: " + e.getMessage(), e);
            response.setErrorMessage(e.getMessage());
            response.setResponseCode(RESPONSE.ERROR);
        }
        return response;
    }
}