protected List<String> serviceNamesNotFoundInZipkin(List<io.zipkin.Span> spans) { List<String> serviceNamesFoundInAnnotations = spans .stream() .filter(span -> span.annotations != null) .map(span -> span.annotations) .flatMap(Collection::stream) .filter(span -> span.endpoint != null) .map(annotation -> annotation.endpoint) .map(endpoint -> endpoint.serviceName) .distinct() .collect(Collectors.toList()); List<String> serviceNamesFoundInBinaryAnnotations = spans .stream() .filter(span -> span.binaryAnnotations != null) .map(span -> span.binaryAnnotations) .flatMap(Collection::stream) .filter(span -> span.endpoint != null) .map(annotation -> annotation.endpoint) .map(endpoint -> endpoint.serviceName) .distinct() .collect(Collectors.toList()); List<String> names = new ArrayList<>(); names.addAll(serviceNamesFoundInAnnotations); names.addAll(serviceNamesFoundInBinaryAnnotations); return names.contains(getAppName()) ? Collections.emptyList() : names; }
protected List<String> annotationsNotFoundInZipkin(List<io.zipkin.Span> spans) { String binaryAnnotationName = getRequiredBinaryAnnotationName(); Optional<String> names = spans .stream() .filter(span -> span.binaryAnnotations != null) .map(span -> span.binaryAnnotations) .flatMap(Collection::stream) .filter(span -> span.endpoint != null) .map(annotation -> annotation.key) .filter(binaryAnnotationName::equals) .findFirst(); return names.isPresent() ? Collections.emptyList() : Collections.singletonList(binaryAnnotationName); }
/** * Retrieve the attribute of an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributeName the attribute name * @return */ public ListenableFuture<String> getAttributeValueAsString( String entityId, String type, String attributeName) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}/attrs/{attributeName}/value"); addParam(builder, "type", type); HttpHeaders httpHeaders = cloneHttpHeaders(); httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); return adapt( request( HttpMethod.GET, builder.buildAndExpand(entityId, attributeName).toUriString(), httpHeaders, null, String.class)); }
private Ngsi2Client() { // set default headers for Content-Type and Accept to application/JSON httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); }
/** NGSIv2 API Client */ public class Ngsi2Client { private static final Map<String, ?> noParams = Collections.emptyMap(); private AsyncRestTemplate asyncRestTemplate; private HttpHeaders httpHeaders; private String baseURL; private Ngsi2Client() { // set default headers for Content-Type and Accept to application/JSON httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); } /** * Default constructor * * @param asyncRestTemplate AsyncRestTemplate to handle requests * @param baseURL base URL for the NGSIv2 service */ public Ngsi2Client(AsyncRestTemplate asyncRestTemplate, String baseURL) { this(); this.asyncRestTemplate = asyncRestTemplate; this.baseURL = baseURL; // Inject NGSI2 error handler and Java 8 support injectNgsi2ErrorHandler(); injectJava8ObjectMapper(); } /** @return the list of supported operations under /v2 */ public ListenableFuture<Map<String, String>> getV2() { ListenableFuture<ResponseEntity<JsonNode>> responseFuture = request(HttpMethod.GET, baseURL + "v2", null, JsonNode.class); return new ListenableFutureAdapter<Map<String, String>, ResponseEntity<JsonNode>>( responseFuture) { @Override protected Map<String, String> adapt(ResponseEntity<JsonNode> result) throws ExecutionException { Map<String, String> services = new HashMap<>(); result .getBody() .fields() .forEachRemaining(entry -> services.put(entry.getKey(), entry.getValue().textValue())); return services; } }; } /* * Entities requests */ /** * Retrieve a list of Entities (simplified) * * @param ids an optional list of entity IDs (cannot be used with idPatterns) * @param idPattern an optional pattern of entity IDs (cannot be used with ids) * @param types an optional list of types of entity * @param attrs an optional list of attributes to return for all entities * @param offset an optional offset (0 for none) * @param limit an optional limit (0 for none) * @param count true to return the total number of matching entities * @return a pagined list of Entities */ public ListenableFuture<Paginated<Entity>> getEntities( Collection<String> ids, String idPattern, Collection<String> types, Collection<String> attrs, int offset, int limit, boolean count) { return getEntities(ids, idPattern, types, attrs, null, null, null, offset, limit, count); } /** * Retrieve a list of Entities * * @param ids an optional list of entity IDs (cannot be used with idPatterns) * @param idPattern an optional pattern of entity IDs (cannot be used with ids) * @param types an optional list of types of entity * @param attrs an optional list of attributes to return for all entities * @param query an optional Simple Query Language query * @param geoQuery an optional Geo query * @param orderBy an option list of attributes to difine the order of entities * @param offset an optional offset (0 for none) * @param limit an optional limit (0 for none) * @param count true to return the total number of matching entities * @return a pagined list of Entities */ public ListenableFuture<Paginated<Entity>> getEntities( Collection<String> ids, String idPattern, Collection<String> types, Collection<String> attrs, String query, GeoQuery geoQuery, Collection<String> orderBy, int offset, int limit, boolean count) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities"); addParam(builder, "id", ids); addParam(builder, "idPattern", idPattern); addParam(builder, "type", types); addParam(builder, "attrs", attrs); addParam(builder, "query", query); addGeoQueryParams(builder, geoQuery); addParam(builder, "orderBy", orderBy); addPaginationParams(builder, offset, limit); if (count) { addParam(builder, "options", "count"); } return adaptPaginated( request(HttpMethod.GET, builder.toUriString(), null, Entity[].class), offset, limit); } /** * Create a new entity * * @param entity the Entity to add * @return the listener to notify of completion */ public ListenableFuture<Void> addEntity(Entity entity) { return adapt( request( HttpMethod.POST, UriComponentsBuilder.fromHttpUrl(baseURL).path("v2/entities").toUriString(), entity, Void.class)); } /** * Get an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attrs the list of attributes to retreive for this entity, null or empty means all * attributes * @return the entity */ public ListenableFuture<Entity> getEntity( String entityId, String type, Collection<String> attrs) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}"); addParam(builder, "type", type); addParam(builder, "attrs", attrs); return adapt( request( HttpMethod.GET, builder.buildAndExpand(entityId).toUriString(), null, Entity.class)); } /** * Update existing or append some attributes to an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributes the attributes to update or to append * @param append if true, will only allow to append new attributes * @return the listener to notify of completion */ public ListenableFuture<Void> updateEntity( String entityId, String type, Map<String, Attribute> attributes, boolean append) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}"); addParam(builder, "type", type); if (append) { addParam(builder, "options", "append"); } return adapt( request( HttpMethod.POST, builder.buildAndExpand(entityId).toUriString(), attributes, Void.class)); } /** * Replace all the existing attributes of an entity with a new set of attributes * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributes the new set of attributes * @return the listener to notify of completion */ public ListenableFuture<Void> replaceEntity( String entityId, String type, Map<String, Attribute> attributes) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}"); addParam(builder, "type", type); return adapt( request( HttpMethod.PUT, builder.buildAndExpand(entityId).toUriString(), attributes, Void.class)); } /** * Delete an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @return the listener to notify of completion */ public ListenableFuture<Void> deleteEntity(String entityId, String type) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}"); addParam(builder, "type", type); return adapt( request( HttpMethod.DELETE, builder.buildAndExpand(entityId).toUriString(), null, Void.class)); } /* * Attributes requests */ /** * Retrieve the attribute of an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributeName the attribute name * @return */ public ListenableFuture<Attribute> getAttribute( String entityId, String type, String attributeName) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}/attrs/{attributeName}"); addParam(builder, "type", type); return adapt( request( HttpMethod.GET, builder.buildAndExpand(entityId, attributeName).toUriString(), null, Attribute.class)); } /** * Update the attribute of an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributeName the attribute name * @return */ public ListenableFuture<Void> updateAttribute( String entityId, String type, String attributeName, Attribute attribute) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}/attrs/{attributeName}"); addParam(builder, "type", type); return adapt( request( HttpMethod.PUT, builder.buildAndExpand(entityId, attributeName).toUriString(), attribute, Void.class)); } /** * Delete the attribute of an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributeName the attribute name * @return */ public ListenableFuture<Attribute> deleteAttribute( String entityId, String type, String attributeName) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}/attrs/{attributeName}"); addParam(builder, "type", type); return adapt( request( HttpMethod.DELETE, builder.buildAndExpand(entityId, attributeName).toUriString(), null, Attribute.class)); } /* * Attribute values requests */ /** * Retrieve the attribute of an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributeName the attribute name * @return */ public ListenableFuture<Object> getAttributeValue( String entityId, String type, String attributeName) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}/attrs/{attributeName}/value"); addParam(builder, "type", type); return adapt( request( HttpMethod.GET, builder.buildAndExpand(entityId, attributeName).toUriString(), null, Object.class)); } /** * Retrieve the attribute of an entity * * @param entityId the entity ID * @param type optional entity type to avoid ambiguity when multiple entities have the same ID, * null or zero-length for empty * @param attributeName the attribute name * @return */ public ListenableFuture<String> getAttributeValueAsString( String entityId, String type, String attributeName) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/entities/{entityId}/attrs/{attributeName}/value"); addParam(builder, "type", type); HttpHeaders httpHeaders = cloneHttpHeaders(); httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); return adapt( request( HttpMethod.GET, builder.buildAndExpand(entityId, attributeName).toUriString(), httpHeaders, null, String.class)); } /* * Entity Type requests */ /** * Retrieve a list of entity types * * @param offset an optional offset (0 for none) * @param limit an optional limit (0 for none) * @param count true to return the total number of matching entities * @return a pagined list of entity types */ public ListenableFuture<Paginated<EntityType>> getEntityTypes( int offset, int limit, boolean count) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/types"); addPaginationParams(builder, offset, limit); if (count) { addParam(builder, "options", "count"); } return adaptPaginated( request(HttpMethod.GET, builder.toUriString(), null, EntityType[].class), offset, limit); } /** * Retrieve an entity type * * @param entityType the entityType to retrieve * @return an entity type */ public ListenableFuture<EntityType> getEntityType(String entityType) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/types/{entityType}"); return adapt( request( HttpMethod.GET, builder.buildAndExpand(entityType).toUriString(), null, EntityType.class)); } /* * Registrations requests */ /** * Retrieve the list of all Registrations * * @return a list of registrations */ public ListenableFuture<List<Registration>> getRegistrations() { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/registrations"); ListenableFuture<ResponseEntity<Registration[]>> e = request(HttpMethod.GET, builder.toUriString(), null, Registration[].class); return new ListenableFutureAdapter<List<Registration>, ResponseEntity<Registration[]>>(e) { @Override protected List<Registration> adapt(ResponseEntity<Registration[]> result) throws ExecutionException { return new ArrayList<>(Arrays.asList(result.getBody())); } }; } /** * Create a new registration * * @param registration the Registration to add * @return the listener to notify of completion */ public ListenableFuture<Void> addRegistration(Registration registration) { return adapt( request( HttpMethod.POST, UriComponentsBuilder.fromHttpUrl(baseURL).path("v2/registrations").toUriString(), registration, Void.class)); } /** * Retrieve the registration by registration ID * * @param registrationId the registration ID * @return registration */ public ListenableFuture<Registration> getRegistration(String registrationId) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/registrations/{registrationId}"); return adapt( request( HttpMethod.GET, builder.buildAndExpand(registrationId).toUriString(), null, Registration.class)); } /** * Update the registration by registration ID * * @param registrationId the registration ID * @return */ public ListenableFuture<Void> updateRegistration( String registrationId, Registration registration) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/registrations/{registrationId}"); return adapt( request( HttpMethod.PATCH, builder.buildAndExpand(registrationId).toUriString(), registration, Void.class)); } /** * Delete the registration by registration ID * * @param registrationId the registration ID * @return */ public ListenableFuture<Void> deleteRegistration(String registrationId) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/registrations/{registrationId}"); return adapt( request( HttpMethod.DELETE, builder.buildAndExpand(registrationId).toUriString(), null, Void.class)); } /* * Subscriptions requests */ /** * Retrieve the list of all Subscriptions present in the system * * @param offset an optional offset (0 for none) * @param limit an optional limit (0 for none) * @param count true to return the total number of matching entities * @return a pagined list of Subscriptions */ public ListenableFuture<Paginated<Subscription>> getSubscriptions( int offset, int limit, boolean count) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/subscriptions"); addPaginationParams(builder, offset, limit); if (count) { addParam(builder, "options", "count"); } return adaptPaginated( request(HttpMethod.GET, builder.toUriString(), null, Subscription[].class), offset, limit); } /** * Create a new subscription * * @param subscription the Subscription to add * @return subscription Id */ public ListenableFuture<String> addSubscription(Subscription subscription) { ListenableFuture<ResponseEntity<Void>> s = request( HttpMethod.POST, UriComponentsBuilder.fromHttpUrl(baseURL).path("v2/subscriptions").toUriString(), subscription, Void.class); return new ListenableFutureAdapter<String, ResponseEntity<Void>>(s) { @Override protected String adapt(ResponseEntity<Void> result) throws ExecutionException { return extractId(result); } }; } /** * Get a Subscription by subscription ID * * @param subscriptionId the subscription ID * @return the subscription */ public ListenableFuture<Subscription> getSubscription(String subscriptionId) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/subscriptions/{subscriptionId}"); return adapt( request( HttpMethod.GET, builder.buildAndExpand(subscriptionId).toUriString(), null, Subscription.class)); } /** * Update the subscription by subscription ID * * @param subscriptionId the subscription ID * @return */ public ListenableFuture<Void> updateSubscription( String subscriptionId, Subscription subscription) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/subscriptions/{subscriptionId}"); return adapt( request( HttpMethod.PATCH, builder.buildAndExpand(subscriptionId).toUriString(), subscription, Void.class)); } /** * Delete the subscription by subscription ID * * @param subscriptionId the subscription ID * @return */ public ListenableFuture<Void> deleteSubscription(String subscriptionId) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/subscriptions/{subscriptionId}"); return adapt( request( HttpMethod.DELETE, builder.buildAndExpand(subscriptionId).toUriString(), null, Void.class)); } /* * POJ RPC "bulk" Operations */ /** * Update, append or delete multiple entities in a single operation * * @param bulkUpdateRequest a BulkUpdateRequest with an actionType and a list of entities to * update * @return Nothing on success */ public ListenableFuture<Void> bulkUpdate(BulkUpdateRequest bulkUpdateRequest) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/op/update"); return adapt(request(HttpMethod.POST, builder.toUriString(), bulkUpdateRequest, Void.class)); } /** * Query multiple entities in a single operation * * @param bulkQueryRequest defines the list of entities, attributes and scopes to match entities * @param orderBy an optional list of attributes to order the entities (null or empty for none) * @param offset an optional offset (0 for none) * @param limit an optional limit (0 for none) * @param count true to return the total number of matching entities * @return a paginated list of entities */ public ListenableFuture<Paginated<Entity>> bulkQuery( BulkQueryRequest bulkQueryRequest, Collection<String> orderBy, int offset, int limit, boolean count) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/op/query"); addPaginationParams(builder, offset, limit); addParam(builder, "orderBy", orderBy); if (count) { addParam(builder, "options", "count"); } return adaptPaginated( request(HttpMethod.POST, builder.toUriString(), bulkQueryRequest, Entity[].class), offset, limit); } /** * Create, update or delete registrations to multiple entities in a single operation * * @param bulkRegisterRequest defines the list of entities to register * @return a list of registration ids */ public ListenableFuture<String[]> bulkRegister(BulkRegisterRequest bulkRegisterRequest) { return adapt( request( HttpMethod.POST, UriComponentsBuilder.fromHttpUrl(baseURL).path("v2/op/register").toUriString(), bulkRegisterRequest, String[].class)); } /** * Discover registration matching entities and their attributes * * @param bulkQueryRequest defines the list of entities, attributes and scopes to match * registrations * @param offset an optional offset (0 for none) * @param limit an optional limit (0 for none) * @param count true to return the total number of matching entities * @return a paginated list of registration */ public ListenableFuture<Paginated<Registration>> bulkDiscover( BulkQueryRequest bulkQueryRequest, int offset, int limit, boolean count) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL); builder.path("v2/op/discover"); addPaginationParams(builder, offset, limit); if (count) { addParam(builder, "options", "count"); } return adaptPaginated( request(HttpMethod.POST, builder.toUriString(), bulkQueryRequest, Registration[].class), offset, limit); } /** * Default headers * * @return the default headers */ public HttpHeaders getHttpHeaders() { return httpHeaders; } /** Make an HTTP request with default headers */ protected <T, U> ListenableFuture<ResponseEntity<T>> request( HttpMethod method, String uri, U body, Class<T> responseType) { return request(method, uri, getHttpHeaders(), body, responseType); } /** Make an HTTP request with custom headers */ protected <T, U> ListenableFuture<ResponseEntity<T>> request( HttpMethod method, String uri, HttpHeaders httpHeaders, U body, Class<T> responseType) { HttpEntity<U> requestEntity = new HttpEntity<>(body, httpHeaders); return asyncRestTemplate.exchange(uri, method, requestEntity, responseType); } private <T> ListenableFuture<T> adapt( ListenableFuture<ResponseEntity<T>> responseEntityListenableFuture) { return new ListenableFutureAdapter<T, ResponseEntity<T>>(responseEntityListenableFuture) { @Override protected T adapt(ResponseEntity<T> result) throws ExecutionException { return result.getBody(); } }; } private <T> ListenableFuture<Paginated<T>> adaptPaginated( ListenableFuture<ResponseEntity<T[]>> responseEntityListenableFuture, int offset, int limit) { return new ListenableFutureAdapter<Paginated<T>, ResponseEntity<T[]>>( responseEntityListenableFuture) { @Override protected Paginated<T> adapt(ResponseEntity<T[]> result) throws ExecutionException { return new Paginated<>( Arrays.asList(result.getBody()), offset, limit, extractTotalCount(result)); } }; } private void addPaginationParams(UriComponentsBuilder builder, int offset, int limit) { if (offset > 0) { builder.queryParam("offset", offset); } if (limit > 0) { builder.queryParam("limit", limit); } } private void addParam(UriComponentsBuilder builder, String key, String value) { if (!nullOrEmpty(value)) { builder.queryParam(key, value); } } private void addParam( UriComponentsBuilder builder, String key, Collection<? extends CharSequence> value) { if (!nullOrEmpty(value)) { builder.queryParam(key, String.join(",", value)); } } private void addGeoQueryParams(UriComponentsBuilder builder, GeoQuery geoQuery) { if (geoQuery != null) { StringBuilder georel = new StringBuilder(geoQuery.getRelation().name()); if (geoQuery.getRelation() == GeoQuery.Relation.near) { georel.append(';').append(geoQuery.getModifier()); georel.append(':').append(geoQuery.getDistance()); } builder.queryParam("georel", georel.toString()); builder.queryParam("geometry", geoQuery.getGeometry()); builder.queryParam( "coords", geoQuery .getCoordinates() .stream() .map(Coordinate::toString) .collect(Collectors.joining(";"))); } } private boolean nullOrEmpty(Collection i) { return i == null || i.isEmpty(); } private boolean nullOrEmpty(String i) { return i == null || i.isEmpty(); } private int extractTotalCount(ResponseEntity responseEntity) { String total = responseEntity.getHeaders().getFirst("X-Total-Count"); try { return Integer.parseInt(total); } catch (NumberFormatException e) { return 0; } } private String extractId(ResponseEntity responseEntity) { String location = responseEntity.getHeaders().getFirst("Location"); String paths[] = location.split("/"); if (paths != null && paths.length > 0) { return paths[paths.length - 1]; } return ""; } /** @return return a clone HttpHeader from default HttpHeader */ private HttpHeaders cloneHttpHeaders() { HttpHeaders httpHeaders = getHttpHeaders(); HttpHeaders clone = new HttpHeaders(); for (String entry : httpHeaders.keySet()) { clone.put(entry, httpHeaders.get(entry)); } return clone; } /** Inject the Ngsi2ResponseErrorHandler */ protected void injectNgsi2ErrorHandler() { MappingJackson2HttpMessageConverter converter = getMappingJackson2HttpMessageConverter(); if (converter != null) { this.asyncRestTemplate.setErrorHandler( new Ngsi2ResponseErrorHandler(converter.getObjectMapper())); } } /** Inject an ObjectMapper supporting Java8 and JavaTime module by default */ protected void injectJava8ObjectMapper() { MappingJackson2HttpMessageConverter converter = getMappingJackson2HttpMessageConverter(); if (converter != null) { converter .getObjectMapper() .registerModule(new Jdk8Module()) .registerModule(new JavaTimeModule()) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); } } private MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() { for (HttpMessageConverter httpMessageConverter : asyncRestTemplate.getMessageConverters()) { if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) { return (MappingJackson2HttpMessageConverter) httpMessageConverter; } } return null; } }
@RestController @RequestMapping( value = ReConfConstants.CRUD_ROOT, produces = ReConfConstants.MT_APPLICATION_JSON, consumes = { ReConfConstants.MT_TEXT_PLAIN, ReConfConstants.MT_ALL, ReConfConstants.MT_APPLICATION_JSON }) public class UpsertUserService { @Autowired JdbcUserDetailsManager userDetailsManager; private static final List<String> mustBeRoot = Collections.singletonList("must be root to perform this action"); private static final List<String> cannotChangeRootPassword = Collections.singletonList("cannot change root password"); @RequestMapping(value = "/user", method = RequestMethod.PUT) @Transactional public ResponseEntity<Client> doIt(@RequestBody Client client, Authentication authentication) { List<String> errors = DomainValidator.checkForErrors(client); if (!errors.isEmpty()) { return new ResponseEntity<Client>(new Client(client, errors), HttpStatus.BAD_REQUEST); } HttpStatus status = null; List<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority("USER")); if (ApplicationSecurity.isRoot(authentication)) { if (ApplicationSecurity.isRoot(client.getUsername())) { return new ResponseEntity<Client>( new Client(client, cannotChangeRootPassword), HttpStatus.BAD_REQUEST); } status = upsert(client, authorities); } else if (StringUtils.equals(client.getUsername(), authentication.getName())) { if (!userDetailsManager.userExists(client.getUsername())) { return new ResponseEntity<Client>(new Client(client, mustBeRoot), HttpStatus.BAD_REQUEST); } User user = new User(client.getUsername(), client.getPassword(), authorities); userDetailsManager.updateUser(user); status = HttpStatus.OK; } else { return new ResponseEntity<Client>(HttpStatus.FORBIDDEN); } return new ResponseEntity<Client>(new Client(client), status); } private HttpStatus upsert(Client client, List<GrantedAuthority> authorities) { HttpStatus status; User user = new User(client.getUsername(), client.getPassword(), authorities); if (userDetailsManager.userExists(client.getUsername())) { userDetailsManager.updateUser(user); status = HttpStatus.OK; } else { userDetailsManager.createUser(user); status = HttpStatus.CREATED; } return status; } }