Java tutorial
/** * 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.manager; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; 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.List; import java.util.Map; import java.util.Set; import javax.annotation.PostConstruct; import javax.persistence.EntityNotFoundException; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.util.UriTemplate; import eu.trentorise.smartcampus.permissionprovider.Config; import eu.trentorise.smartcampus.permissionprovider.Config.AUTHORITY; import eu.trentorise.smartcampus.permissionprovider.Config.RESOURCE_VISIBILITY; import eu.trentorise.smartcampus.permissionprovider.common.PatternMatcher; import eu.trentorise.smartcampus.permissionprovider.common.ResourceException; import eu.trentorise.smartcampus.permissionprovider.common.Utils; 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.jaxbmodel.Services; import eu.trentorise.smartcampus.permissionprovider.model.ClientDetailsEntity; import eu.trentorise.smartcampus.permissionprovider.model.Resource; import eu.trentorise.smartcampus.permissionprovider.model.ResourceParameter; import eu.trentorise.smartcampus.permissionprovider.model.ServiceDescriptor; import eu.trentorise.smartcampus.permissionprovider.oauth.ResourceStorage; import eu.trentorise.smartcampus.permissionprovider.repository.ClientDetailsRepository; import eu.trentorise.smartcampus.permissionprovider.repository.ResourceParameterRepository; import eu.trentorise.smartcampus.permissionprovider.repository.ResourceRepository; import eu.trentorise.smartcampus.permissionprovider.repository.ServiceRepository; /** * Class used to operate resource model. * @author raman * */ @Component @Transactional public class ResourceManager { private static Log logger = LogFactory.getLog(ResourceManager.class); @Autowired private ResourceStorage resourceStorage; @Autowired private ResourceParameterRepository resourceParameterRepository; @Autowired private ResourceRepository resourceRepository; @Autowired private ClientDetailsRepository clientDetailsRepository; @Autowired private ServiceRepository serviceRepository; @PostConstruct public void init() throws ResourceException { List<Service> services = loadResourceTemplates(); processServiceObjects(services, null); } /** * Save resource parameter. Check the uniqueness of the parameter value across all the * parameters with the same resource parameter definition ID. Instantiate * all the derived resources. * @param rp */ public void storeResourceParameter(ResourceParameter rp, String serviceId) { validateResourceParameterData(rp); ResourceParameter rpold = rp.getId() == null ? null : resourceParameterRepository.findOne(rp.getId()); // check uniqueness String clientId = rp.getClientId(); if (rpold != null && !clientId.equals(clientId)) { throw new IllegalArgumentException("A parameter already used by another app"); } else if (rpold == null) { ServiceDescriptor sd = serviceRepository.findOne(serviceId); if (sd == null) { throw new IllegalArgumentException("Unknown service: " + serviceId); } else { Service s = Utils.toServiceObject(sd); boolean found = false; for (ResourceDeclaration rd : s.getResource()) { if (rd.getId().equals(rp.getParameter())) { found = true; break; } } if (!found) { throw new IllegalArgumentException( "Unknown parameter '" + rp.getParameter() + "' for service: " + serviceId); } rp.setService(sd); } resourceParameterRepository.save(rp); // derived resources Map<String, ResourceMapping> mappings = findResourceURIs(rp); // store new resources entailed by the resource parameter if (mappings != null) { Set<String> newSet = new HashSet<String>(); Set<String> newScopes = new HashSet<String>(); for (String uri : mappings.keySet()) { ResourceMapping resourceMapping = mappings.get(uri); Resource r = prepareResource(clientId, rp, uri, resourceMapping, rp.getVisibility()); r.setService(sd); resourceRepository.save(r); newSet.add(r.getResourceId().toString()); newScopes.add(r.getResourceUri()); } // add automatically the resources entailed by own resource parameters to the client resourceIds ClientDetailsEntity cd = clientDetailsRepository.findByClientId(clientId); Set<String> oldSet = cd.getResourceIds(); if (oldSet != null) newSet.addAll(oldSet); cd.setResourceIds(StringUtils.collectionToCommaDelimitedString(newSet)); // add automatically the resources entailed by own resource parameters to the client scope oldSet = cd.getScope(); if (oldSet != null) newScopes.addAll(oldSet); cd.setScope(StringUtils.collectionToCommaDelimitedString(newScopes)); clientDetailsRepository.save(cd); } } else { throw new IllegalArgumentException("A parameter already exists"); } } /** * Validate parameter data * @param rp */ private void validateResourceParameterData(ResourceParameter rp) { if (!StringUtils.hasText(rp.getValue())) { throw new IllegalArgumentException("empty parameter value"); } } /** * Update the visibility of the resource parameter. This only affects the child resources * in case of more restrictive policy applied. If the changes are in conflict with the * clients that use the corresponding resources, an exception is thrown. Also, if the new * visibility is more relaxing than that of the parent, the exception is thrown. * * @param id id of the changed resource parameter * @param visibility new visibility value * @return changed parameter */ public ResourceParameter updateResourceParameterVisibility(Long id, RESOURCE_VISIBILITY visibility) { assert visibility != null; ResourceParameter rpdb = resourceParameterRepository.findOne(id); if (rpdb != null) { String clientId = rpdb.getClientId(); ClientDetailsEntity client = clientDetailsRepository.findByClientId(clientId); Map<String, RESOURCE_VISIBILITY> visibilityMap = new HashMap<String, Config.RESOURCE_VISIBILITY>(); rpdb.setVisibility(visibility); for (String uri : findResourceURIs(rpdb).keySet()) { visibilityMap.put(uri, visibility); Resource res = resourceRepository.findByResourceUri(uri); res.setVisibility(visibility); resourceRepository.save(res); } if (!checkUsages(visibilityMap, clientId, client.getDeveloperId())) { throw new IllegalArgumentException("Resource is in use, cannot reduce visibility"); } List<Resource> resources = resourceRepository.findByResourceParameter(rpdb);//.findByClientId(clientId); if (resources != null) { for (Resource r : resources) { r.setVisibility(rpdb.getVisibility()); } } } else { throw new IllegalArgumentException("No resource parameter found"); } return rpdb; } /** * Check the visibility of the specified resources managed by the specified client and its owner by all the clients registered * @param visibilityMap contains the resource URI and its target visibility * @return true if at least one of the specified resources violates visibility constraint */ private boolean checkUsages(Map<String, RESOURCE_VISIBILITY> visibilityMap, String clientId, Long developerId) { List<ClientDetailsEntity> clients = clientDetailsRepository.findAll(); for (ClientDetailsEntity client : clients) { // owned resources are visible, skip if (clientId.equals(client.getClientId())) continue; // Set<String> uris = client.getScope(); for (String uri : visibilityMap.keySet()) { if (uris.contains(uri)) { switch (visibilityMap.get(uri)) { // if should be visible only by the owning client app - violation case CLIENT_APP: return false; // if should be visible only by the owning developer - violation case DEVELOPER: if (!client.getDeveloperId().equals(developerId)) { return false; } default: break; } } } } return true; } /** * Try to remove the resource parameter and its children. Operation is recursive. * If one of the derived resources is already in use, an exception is thrown. * @param rpId */ public void removeResourceParameter(Long rpId) { // main parameter ResourceParameter rpdb = resourceParameterRepository.findOne(rpId); if (rpdb != null) { String clientId = rpdb.getClientId(); Set<String> ids = new HashSet<String>(); Set<String> scopes = new HashSet<String>(); // aggregate all derived resource uris Collection<String> uris = findResourceURIs(rpdb).keySet(); for (String uri : uris) { Resource r = resourceRepository.findByResourceUri(uri); if (r != null) { ids.add(r.getResourceId().toString()); scopes.add(r.getResourceUri()); } } ClientDetailsEntity owner = null; // check the resource uri usages for (ClientDetailsEntity cd : clientDetailsRepository.findAll()) { if (cd.getClientId().equals(clientId)) { owner = cd; continue; } if (!Collections.disjoint(cd.getResourceIds(), ids)) { throw new IllegalArgumentException("Resource is in use by other client app."); } } // delete main and its children for (String id : ids) { resourceRepository.delete(Long.parseLong(id)); } if (owner != null) { Set<String> oldScopes = new HashSet<String>(owner.getScope()); oldScopes.removeAll(scopes); owner.setScope(StringUtils.collectionToCommaDelimitedString(oldScopes)); Set<String> oldIds = new HashSet<String>(owner.getResourceIds()); oldIds.removeAll(ids); owner.setResourceIds(StringUtils.collectionToCommaDelimitedString(oldIds)); clientDetailsRepository.save(owner); } resourceParameterRepository.delete(rpdb); } } /** * Find all the resource uris derived from the specified resource parameter and its parent parameters. * @param rpdb * @return map with URIs as the keys and mapping definitions as values. */ private Map<String, ResourceMapping> findResourceURIs(ResourceParameter rpdb) { Map<String, ResourceMapping> res = new HashMap<String, ResourceMapping>(); Map<String, String> params = new HashMap<String, String>(); params.put(rpdb.getParameter(), rpdb.getValue()); // the service where parameter is defined ServiceDescriptor sd = rpdb.getService(); if (sd == null) { throw new IllegalArgumentException("ServiceDescriptor is not found."); } Service s = Utils.toServiceObject(sd); // all the service resource mappings List<ResourceMapping> list = s.getResourceMapping(); if (list != null) { for (ResourceMapping rm : list) { UriTemplate template = new UriTemplate(rm.getUri()); // if the extracted parameters contain all the template parameters, the mapping is updated if (template.getVariableNames() != null) { if (new HashSet<String>(template.getVariableNames()).equals(params.keySet())) { URI uri = template.expand(params); res.put(uri.toString(), rm); } } } } return res; } /** * Read resource parameters owned by the specified client, optionally restricting * to the specified service and resource parameter ID * @param clientId * @return */ public List<ResourceParameter> getOwnResourceParameters(String clientId) { if (clientId == null) { return Collections.emptyList(); } return resourceParameterRepository.findByClientId(clientId); } /** * Read the resources from the XML descriptor * @return */ private List<Service> loadResourceTemplates() { try { JAXBContext jaxb = JAXBContext.newInstance(ServiceDescriptor.class, Services.class, ResourceMapping.class, ResourceDeclaration.class); Unmarshaller unm = jaxb.createUnmarshaller(); JAXBElement<Services> element = (JAXBElement<Services>) unm.unmarshal( new StreamSource(getClass().getResourceAsStream("resourceTemplates.xml")), Services.class); return element.getValue().getService(); } catch (JAXBException e) { logger.error("Failed to load resource templates: " + e.getMessage(), e); return Collections.emptyList(); } } private void processServiceObjects(List<Service> services, String ownerId) throws ResourceException { checkServiceListConsistency(services); List<ServiceDescriptor> dbServices = serviceRepository.findByOwnerId(ownerId); Map<String, ServiceDescriptor> dbServiceMap = new HashMap<String, ServiceDescriptor>(); for (ServiceDescriptor s : dbServices) { dbServiceMap.put(s.getServiceId(), s); } // split objects in created/updated/deleted Set<ServiceDescriptor> deleted = new HashSet<ServiceDescriptor>(); Map<Service, ServiceDescriptor> updated = new HashMap<Service, ServiceDescriptor>(); Set<Service> created = new HashSet<Service>(); Set<String> newOnes = new HashSet<String>(); for (Service s : services) { if (!dbServiceMap.containsKey(s.getId())) { created.add(s); } else { updated.put(s, dbServiceMap.get(s.getId())); } newOnes.add(s.getId()); } for (ServiceDescriptor s : dbServices) { if (!newOnes.contains(s.getServiceId())) { deleted.add(s); } } // process changes for (ServiceDescriptor s : deleted) { deleteService(s, ownerId); } for (Service service : updated.keySet()) { updateService(service, updated.get(service), ownerId); } for (Service service : created) { createService(service, ownerId); } } /** * Check input service list consistency: * <ul> * <li> in the input list: </li> * <li> check duplicate rm IDs in the service </li> * <li> check duplicate r IDs in the service </li> * <li> check matching URIs across services </li> * <li> with respect to DB data: </li> * <li> check matching URIs across stored services (if matching, should be of the same service) </li> * </ul> * @param services * @throws ResourceException */ private void checkServiceListConsistency(List<Service> services) throws ResourceException { Map<String, String> uriServiceMap = new HashMap<String, String>(); Set<ServiceKey> rmIDServiceSet = new HashSet<ServiceKey>(); Set<ServiceKey> resIDServiceSet = new HashSet<ServiceKey>(); for (Service s : services) { for (ResourceMapping rm : s.getResourceMapping()) { // check duplicate URIs in the list if (uriServiceMap.containsKey(rm.getUri())) { throw new ResourceException("Duplicate mapping URI in service resources: " + rm.getUri()); } uriServiceMap.put(rm.getUri(), s.getId()); // check duplicate mappings for the same service ServiceKey key = new ServiceKey(rm.getId(), s.getId()); if (rmIDServiceSet.contains(key)) { throw new ResourceException("Duplicate mapping in service resources: " + rm.getId()); } rmIDServiceSet.add(key); } for (ResourceDeclaration res : s.getResource()) { // check duplicate parameters for the same service ServiceKey key = new ServiceKey(res.getId(), s.getId()); if (rmIDServiceSet.contains(key)) { throw new ResourceException( "Duplicate resource parameter in service resources: " + res.getId()); } resIDServiceSet.add(key); } } // read DB uri mappings Map<String, String> dbUriServiceMap = new HashMap<String, String>(); List<ServiceDescriptor> dbServices = serviceRepository.findAll(); for (ServiceDescriptor sd : dbServices) { Service s = Utils.toServiceObject(sd); for (ResourceMapping rm : s.getResourceMapping()) { dbUriServiceMap.put(rm.getUri(), s.getId()); } } for (String inUri : uriServiceMap.keySet()) { // check if the same uri is already used by the same if (dbUriServiceMap.containsKey(inUri)) { if (!dbUriServiceMap.get(inUri).equals(uriServiceMap.get(inUri))) { throw new ResourceException("Resource URI mapping '" + inUri + "' is in use by another service: " + dbUriServiceMap.get(inUri)); } dbUriServiceMap.remove(inUri); continue; } for (String dbUri : dbUriServiceMap.keySet()) { if (new PatternMatcher(inUri, dbUri).compute()) { if (!dbUriServiceMap.get(dbUri).equals(uriServiceMap.get(inUri))) { throw new ResourceException("Resource URI mapping '" + inUri + "' matches another pattern '" + dbUri + "' of service: " + dbUriServiceMap.get(dbUri)); } } } } } /** * @param newService * @param oldSd * @param ownerId * @return * @throws ResourceException */ private Service updateService(Service newService, ServiceDescriptor oldSd, String ownerId) throws ResourceException { Service oldService = Utils.toServiceObject(oldSd); Map<String, ResourceMapping> oldMappings = new HashMap<String, ResourceMapping>(); Map<String, ResourceDeclaration> oldParams = new HashMap<String, ResourceDeclaration>(); for (ResourceMapping rm : oldService.getResourceMapping()) { oldMappings.put(rm.getId(), rm); } for (ResourceDeclaration rd : oldService.getResource()) { oldParams.put(rd.getId(), rd); } List<Resource> resourcesToCreate = new ArrayList<Resource>(); List<Resource> resourcesToDelete = new ArrayList<Resource>(); List<ResourceParameter> paramsToDelete = new ArrayList<ResourceParameter>(); for (ResourceMapping rm : newService.getResourceMapping()) { // if a mapping is new or has the URI changed, mark it as new (or deleted/new) if (!oldMappings.containsKey(rm.getId()) || !oldMappings.get(rm.getId()).getUri().equals(rm.getUri())) { extractResources(rm, resourcesToCreate); // if remains the same, remove it from oldMappings so it will not be deleted } else { oldMappings.remove(rm.getId()); } } for (ResourceDeclaration rd : newService.getResource()) { // if parameter exists, remove it from oldParams so it will not be deleted if (oldParams.containsKey(rd.getId())) { oldParams.remove(rd.getId()); } } // extract resources to be deleted, if possible (not used) for (ResourceMapping rm : oldMappings.values()) { resourcesToDelete.addAll(resourceRepository.findByServiceAndResourceType(oldSd, rm.getId())); } // extract parameters to be deleted, if possible (not used) for (ResourceDeclaration rd : oldParams.values()) { paramsToDelete.addAll(resourceParameterRepository.findByServiceAndParameter(oldSd, rd.getId())); } cleanServiceResources(resourcesToDelete, paramsToDelete); ServiceDescriptor service = Utils.toServiceEntity(newService); service.setOwnerId(ownerId); serviceRepository.save(service); storeServiceResources(service, resourcesToCreate); return newService; } /** * @param s * @param ownerId * @throws ResourceException */ private void deleteService(ServiceDescriptor s, String ownerId) throws ResourceException { List<Resource> resources = resourceRepository.findByService(s); List<ResourceParameter> parameters = resourceParameterRepository.findByService(s); // clean up unused resources and parameters cleanServiceResources(resources, parameters); // delete service serviceRepository.delete(s); } /** * Delete specified resources and parameters if not in use by some client * @param resources * @param parameters * @throws ResourceException */ private void cleanServiceResources(List<Resource> resources, List<ResourceParameter> parameters) throws ResourceException { // check the service resources are in use by the clients if (resources != null && !resources.isEmpty()) { Set<String> ids = new HashSet<String>(); for (Resource r : resources) { ids.add("" + r.getResourceId()); } List<ClientDetailsEntity> clients = clientDetailsRepository.findAll(); for (ClientDetailsEntity c : clients) { if (!Collections.disjoint(ids, c.getResourceIds())) { throw new ResourceException("Resource in use by client: " + c.getClientId()); } } } resourceRepository.delete(resources); resourceParameterRepository.delete(parameters); } /** * Create new service for the specified owner * @param service * @param ownerId * @return created {@link Service} object * @throws ResourceException */ private Service createService(Service service, String ownerId) throws ResourceException { ServiceDescriptor entity = Utils.toServiceEntity(service); entity.setOwnerId(ownerId); // saving new service entity = serviceRepository.save(entity); // read non-parametric service resources List<Resource> resourcesToStore = extractResources(service); // store resources storeServiceResources(entity, resourcesToStore); return Utils.toServiceObject(entity); } private void storeServiceResources(ServiceDescriptor sd, List<Resource> resourcesToStore) throws ResourceException { if (resourcesToStore != null && !resourcesToStore.isEmpty()) { for (Iterator<Resource> iterator = resourcesToStore.iterator(); iterator.hasNext();) { Resource r = iterator.next(); Resource existing = resourceRepository.findByResourceUri(r.getResourceUri()); // if resource already exists and belongs to a different service, throw an exception if (existing != null && !existing.getService().getServiceId().equals(sd.getServiceId())) { throw new ResourceException("resource not unique: " + r.getResourceUri()); } else if (existing != null) { iterator.remove(); } else { r.setService(sd); } } // store new non-parametric resources resourceStorage.storeResources(resourcesToStore); } } /** * Update the specified service object * @param s * @param ownerId * @return updated {@link Service} object * @throws ResourceException */ private Service updateService(Service s, String ownerId) throws ResourceException { checkServiceListConsistency(Collections.singletonList(s)); ServiceDescriptor old = serviceRepository.findOne(s.getId()); return updateService(s, old, ownerId); } private List<Resource> extractResources(Service s) { List<Resource> resources = new ArrayList<Resource>(); // process resource mappings if (s.getResourceMapping() != null) { for (ResourceMapping rm : s.getResourceMapping()) { // extract resource mappings recursively extractResources(rm, resources); } } return resources; } /** * Extract resource mappings recursively * @param rm * @param resources */ private void extractResources(ResourceMapping rm, List<Resource> resources) { // add non-parametric resources to the target list if (!isParametric(rm)) { resources.add(prepareResource(null, null, rm.getUri(), rm, RESOURCE_VISIBILITY.PUBLIC)); } } /** * @param rm * @return true if the mapping definition is parametric to the service resource parameters */ private boolean isParametric(ResourceMapping rm) { UriTemplate template = new UriTemplate(rm.getUri()); return template.getVariableNames() != null && template.getVariableNames().size() > 0; } /** * @param clientId * @param rp * @param uri * @param rm * @param visibility * @return {@link Resource} instance out of mapping, clientID, and resource URI. */ protected Resource prepareResource(String clientId, ResourceParameter rp, String uri, ResourceMapping rm, RESOURCE_VISIBILITY visibility) { Resource r = new Resource(); r.setAccessibleByOthers(rm.isAccessibleByOthers()); r.setApprovalRequired(rm.isApprovalRequired()); r.setAuthority(AUTHORITY.valueOf(rm.getAuthority().value())); r.setClientId(clientId); r.setResourceParameter(rp); UriTemplate template = new UriTemplate(rm.getUri()); Map<String, String> params = template.match(uri); template = new UriTemplate(rm.getDescription()); try { r.setDescription(URLDecoder.decode(template.expand(params).toString(), "utf8")); } catch (UnsupportedEncodingException e) { r.setDescription(rm.getDescription()); } template = new UriTemplate(rm.getName()); try { r.setName(URLDecoder.decode(template.expand(params).toString(), "utf8")); } catch (UnsupportedEncodingException e) { r.setName(rm.getName()); } r.setResourceType(rm.getId()); r.setResourceUri(uri); r.setVisibility(visibility); return r; } /** * @return */ public Service getServiceObject(String serviceId) { ServiceDescriptor service = serviceRepository.findOne(serviceId); return Utils.toServiceObject(service); } /** * @return all the services */ public List<Service> getServiceObjects() { List<ServiceDescriptor> services = serviceRepository.findAll(); List<Service> res = new ArrayList<Service>(); for (ServiceDescriptor sd : services) { res.add(Utils.toServiceObject(sd)); } return res; } /** * @return all the services of the specified user */ public List<Service> getServiceObjects(String ownerId) { List<ServiceDescriptor> services = serviceRepository.findByOwnerId(ownerId); List<Service> res = new ArrayList<Service>(); for (ServiceDescriptor sd : services) { res.add(Utils.toServiceObject(sd)); } return res; } /** * Save the specified {@link ServiceDescriptor} object, only the id/name/description fields * @param service * @param userId * @return */ public Service saveServiceObject(Service service, Long userId) { validateServiceData(service); ServiceDescriptor sdOld = serviceRepository.findOne(service.getId()); if (sdOld != null && !sdOld.getOwnerId().equals(userId.toString())) { throw new SecurityException("Service ID is in use by another user"); } ServiceDescriptor sd = sdOld == null ? Utils.toServiceEntity(service) : sdOld; sd.setDescription(service.getDescription()); sd.setServiceName(service.getName()); sd.setServiceId(service.getId()); sd.setOwnerId(userId.toString()); sd = serviceRepository.save(sd); return Utils.toServiceObject(sd); } /** * Validate service fields * @param service */ private void validateServiceData(Service service) { if (!StringUtils.hasText(service.getId())) { throw new IllegalArgumentException("empty service ID"); } if (!StringUtils.hasText(service.getName())) { throw new IllegalArgumentException("empty service name"); } if (!StringUtils.hasText(service.getDescription())) { throw new IllegalArgumentException("empty service description"); } } /** * Delete the specified service * @param serviceId * @param ownerId * @throws ResourceException */ public void deleteService(String serviceId, String ownerId) throws ResourceException { ServiceDescriptor old = serviceRepository.findOne(serviceId); deleteService(old, ownerId); } /** * read the resource that the client app may request permissions for * @param clientId * @return */ public List<Resource> getAvailableResources(String clientId, Long userId) { if (clientId != null) { // check all the resources List<Resource> list = resourceRepository.findAll(); for (Iterator<Resource> iterator = list.iterator(); iterator.hasNext();) { Resource resource = iterator.next(); // interested only in non-owned resources if (!clientId.equals(resource.getClientId()) && resource.getClientId() != null) { if (!resource.isAccessibleByOthers()) { iterator.remove(); continue; } // check the resource visibility for the current client switch (resource.getVisibility()) { case CLIENT_APP: iterator.remove(); break; case DEVELOPER: ClientDetailsEntity cd = clientDetailsRepository.findByClientId(resource.getClientId()); if (cd == null || !cd.getDeveloperId().equals(userId)) { iterator.remove(); } default: break; } } } return list; } return Collections.emptyList(); } private static class ServiceKey { String id; String service; public ServiceKey(String id, String service) { super(); this.id = id; this.service = service; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((service == null) ? 0 : service.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ServiceKey other = (ServiceKey) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (service == null) { if (other.service != null) return false; } else if (!service.equals(other.service)) return false; return true; } } /** * Add parameter declaration to service * @param serviceId * @param decl * @param ownerId * @throws ResourceException */ public Service addResourceDeclaration(String serviceId, ResourceDeclaration decl, String ownerId) throws ResourceException { validateResourceDeclarationData(decl); ServiceDescriptor sd = serviceRepository.findOne(serviceId); if (sd == null) throw new EntityNotFoundException("Not found: " + serviceId); Service s = Utils.toServiceObject(sd); boolean found = false; for (ResourceDeclaration rd : s.getResource()) { if (rd.getId().equals(decl.getId())) { rd.setDescription(decl.getDescription()); rd.setName(decl.getName()); found = true; break; } } if (!found) { s.getResource().add(decl); } updateService(s, ownerId); return s; } /** * @param decl */ private void validateResourceDeclarationData(ResourceDeclaration decl) { if (!StringUtils.hasText(decl.getId())) { throw new IllegalArgumentException("empty resource parameter ID"); } if (!StringUtils.hasText(decl.getName())) { throw new IllegalArgumentException("empty resource parameter name"); } if (!StringUtils.hasText(decl.getDescription())) { throw new IllegalArgumentException("empty resource parameter description"); } } /** * @param mapping */ private void validateResourceMappingData(ResourceMapping mapping) { if (!StringUtils.hasText(mapping.getId())) { throw new IllegalArgumentException("empty resource mapping ID"); } if (!StringUtils.hasText(mapping.getUri())) { throw new IllegalArgumentException("empty resource mapping uri"); } if (!StringUtils.hasText(mapping.getName())) { throw new IllegalArgumentException("empty resource mapping name"); } if (!StringUtils.hasText(mapping.getDescription())) { throw new IllegalArgumentException("empty resource mapping description"); } } /** * Add parameter declaration to service * @param serviceId * @param mapping * @param ownerId * @throws ResourceException */ public Service addMapping(String serviceId, ResourceMapping mapping, String ownerId) throws ResourceException { validateResourceMappingData(mapping); ServiceDescriptor sd = serviceRepository.findOne(serviceId); if (sd == null) throw new EntityNotFoundException("Not found: " + serviceId); Service s = Utils.toServiceObject(sd); boolean found = false; for (ResourceMapping rm : s.getResourceMapping()) { if (rm.getId().equals(mapping.getId())) { rm.setAccessibleByOthers(mapping.isAccessibleByOthers()); rm.setApprovalRequired(mapping.isAccessibleByOthers()); rm.setAuthority(mapping.getAuthority()); rm.setDescription(mapping.getDescription()); rm.setName(mapping.getName()); rm.setUri(mapping.getUri()); found = true; break; } } if (!found) { s.getResourceMapping().add(mapping); } updateService(s, ownerId); return s; } /** * @param serviceId * @param ownerId */ public void checkServiceOwnership(String serviceId, String ownerId) { ServiceDescriptor sd = serviceRepository.findOne(serviceId); if (sd == null || !sd.getOwnerId().equals(ownerId)) { throw new IllegalArgumentException("Incorrect owner for service"); } } /** * Remove specified resource declaration * @param serviceId * @param id * @param ownerId * @return * @throws ResourceException */ public Object removeResourceDeclaration(String serviceId, String id, String ownerId) throws ResourceException { ServiceDescriptor sd = serviceRepository.findOne(serviceId); if (sd == null) throw new EntityNotFoundException("Not found: " + serviceId); Service s = Utils.toServiceObject(sd); for (Iterator<ResourceDeclaration> iterator = s.getResource().iterator(); iterator.hasNext();) { ResourceDeclaration rd = iterator.next(); if (rd.getId().equals(id)) { iterator.remove(); } } updateService(s, ownerId); return s; } /** * Remove specified resource mapping * @param serviceId * @param id * @param ownerId * @return * @throws ResourceException */ public Object removeMapping(String serviceId, String id, String ownerId) throws ResourceException { ServiceDescriptor sd = serviceRepository.findOne(serviceId); if (sd == null) throw new EntityNotFoundException("Not found: " + serviceId); Service s = Utils.toServiceObject(sd); for (Iterator<ResourceMapping> iterator = s.getResourceMapping().iterator(); iterator.hasNext();) { ResourceMapping rm = iterator.next(); if (rm.getId().equals(id)) { iterator.remove(); } } updateService(s, ownerId); return s; } }