public static Link createVerifyPasswordLink(UserClient user) {
   Link verifyPasswordLink =
       linkTo(methodOn(UserClientsResource.class).verifyPassword(null)).withRel("verifyPassword");
   UriTemplate verifyPasswordUriTemplate =
       new UriTemplate(verifyPasswordLink.getHref())
           .with(
               new TemplateVariables(
                   new TemplateVariable("password", TemplateVariable.VariableType.REQUEST_PARAM)));
   return new Link(verifyPasswordUriTemplate, verifyPasswordLink.getRel());
 }
  @Test
  public void usesCustomLinkProvided() {

    Link link = new Link("http://foo:9090", "rel");

    PagedResourcesAssembler<Person> assembler = new PagedResourcesAssembler<Person>(resolver, null);
    PagedResources<Resource<Person>> resources = assembler.toResource(createPage(1), link);

    assertThat(resources.getLink(Link.REL_PREVIOUS).getHref(), startsWith(link.getHref()));
    assertThat(resources.getLink(Link.REL_NEXT).getHref(), startsWith(link.getHref()));
  }
  // Creates a user resource
  @Override
  public UserResource toResource(User user) {
    UserResource userResource = new UserResource();
    userResource.setUserId(user.getUserId());
    userResource.setUserName(user.getUserName());

    // HATEOAS link builder object
    Link link = linkTo(methodOn(UserController.class).getUser(user.getUserId())).withSelfRel();
    userResource.add(link.withSelfRel());

    return userResource;
  }
 private UriTemplate createUriTemplate(String requestParameterName, Link linkName) {
   return new UriTemplate(linkName.getHref())
       .with(
           new TemplateVariables(
               new TemplateVariable(
                   requestParameterName, TemplateVariable.VariableType.REQUEST_PARAM)));
 }
  @RequestMapping(method = RequestMethod.POST)
  ResponseEntity<?> add(@PathVariable String userId, @RequestBody CoinOrder input) {
    this.validateUser(userId);

    return this.accountRepository
        .findByUsername(userId)
        .map(
            account -> {
              CoinOrder result =
                  coinOrderRepository.save(
                      new CoinOrder(account, input.type, input.quantity, input.priceInCents));

              Link forOneBookmark = new CoinOrderResource(result).getLink("self");

              return ResponseEntity.created(URI.create(forOneBookmark.getHref())).build();
            })
        .orElse(ResponseEntity.noContent().build());
  }
  @Test
  public void accessServiceUsingRestTemplate() {

    // Access root resource

    URI uri = URI.create(String.format(SERVICE_URI, port));
    RequestEntity<Void> request = RequestEntity.get(uri).accept(HAL_JSON).build();
    Resource<Object> rootLinks =
        restOperations.exchange(request, new ResourceType<Object>() {}).getBody();
    Links links = new Links(rootLinks.getLinks());

    // Follow stores link

    Link storesLink = links.getLink("stores").expand();
    request = RequestEntity.get(URI.create(storesLink.getHref())).accept(HAL_JSON).build();
    Resources<Store> stores =
        restOperations.exchange(request, new ResourcesType<Store>() {}).getBody();

    stores.getContent().forEach(store -> log.info("{} - {}", store.name, store.address));
  }
  /**
   * Creates the {@link Descriptor}s for pagination parameters.
   *
   * @param type
   * @return
   */
  private List<Descriptor> getPaginationDescriptors(Class<?> type, HttpMethod method) {

    RepositoryInformation information = repositories.getRepositoryInformationFor(type);

    if (!information.isPagingRepository() || !getType(method).equals(Type.SAFE)) {
      return Collections.emptyList();
    }

    Link linkToCollectionResource = entityLinks.linkToCollectionResource(type);
    List<TemplateVariable> variables = linkToCollectionResource.getVariables();
    List<Descriptor> descriptors = new ArrayList<Descriptor>(variables.size());

    ProjectionDefinitionConfiguration projectionConfiguration =
        configuration.projectionConfiguration();

    for (TemplateVariable variable : variables) {

      // Skip projection parameter
      if (projectionConfiguration.getParameterName().equals(variable.getName())) {
        continue;
      }

      ResourceDescription description =
          SimpleResourceDescription.defaultFor(variable.getDescription());

      descriptors.add( //
          descriptor()
              . //
              name(variable.getName())
              . //
              type(Type.SEMANTIC)
              . //
              doc(getDocFor(description))
              . //
              build());
    }

    return descriptors;
  }
 /*
  * (non-Javadoc)
  * @see org.springframework.hateoas.hal.CurieProvider#getNamespacedRelFrom(org.springframework.hateoas.Link)
  */
 @Override
 public String getNamespacedRelFrom(Link link) {
   return getNamespacedRelFor(link.getRel());
 }
  @Override
  public UserClientResource toResource(UserClient user) {
    if (user == null) {
      return null;
    }
    Set<String> perms = new HashSet<>();
    for (GrantedAuthority grantedAuthority : user.getAuthorities()) {
      // strip off the client and team specifics on the authorities
      Matcher matcher = specializedPermissions.matcher(grantedAuthority.getAuthority());
      if (matcher.matches()) {
        perms.add(matcher.replaceAll("$1"));
      } else {
        perms.add(grantedAuthority.getAuthority());
      }
    }

    if (user.isSuperUser()) {
      // give the super user all team permissions (not necessary but nice for the UI)
      user.setTeamRoles(superUserTeamRoleGenerator.allPermissionsOnAllTeams(user.getClient()));
    }

    // add the teams to which this user has access
    Set<TeamResource> teams = new HashSet<>();
    for (UserClientUserClientTeamRole userClientUserClientTeamRole : user.getTeamRoles()) {
      teams.add(roleTeamResourceResourceAssembler.toResource(userClientUserClientTeamRole));
    }

    boolean interruptFlow = false;

    if (user.getNotNowExpirationTime() != null) {
      LocalDateTime dateTime = LocalDateTime.now(DateTimeZone.UTC);
      interruptFlow = dateTime.isBefore(user.getNotNowExpirationTime());
    }

    UserClientResource ret =
        new UserClientResource(
            user.getId(),
            user.getVersion(),
            user.getLogin(),
            user.getFirstName(),
            user.getLastName(),
            user.getEmail(),
            user.isActive(),
            user.isAccountNonExpired(),
            user.isAccountNonLocked(),
            user.isCredentialsNonExpired(),
            user.isEmailValidated(),
            user.isSecretQuestionCreated(),
            clientResourceAssembler.toResource(user.getClient()),
            new ArrayList<>(perms),
            user.isImpersonated(),
            user.getNotNowExpirationTime(),
            user.getPasswordExpireationDateTime(),
            user.getPasswordSavedDateTime(),
            interruptFlow);

    ret.setSecurityQuestionsNotRequiredForReset(user.isSecurityQuestionsNotRequiredForReset());

    ret.add(linkTo(methodOn(UserClientsResource.class).authenticated()).withRel("authenticated"));

    if (!CollectionUtils.isEmpty(teams)) {
      ret.setTeams(teams);
    }

    if (!user.isImpersonated()) {
      // non-impersonation users only
      ret.add(linkTo(methodOn(UserClientsResource.class).getById(user.getId())).withSelfRel());
      ret.add(updateUserClientLink(user));
      ret.add(createVerifyPasswordLink(user));

      Link link =
          linkTo(
                  methodOn(UserClientSecretQuestionResponsesResource.class)
                      .secretQuestionResponses(user.getId(), null, null, null))
              .withRel("secretQuestionResponses");
      ret.add(new Link(createUriTemplate("password", link), link.getRel()));

      Link updateUserClientSecretQuestion =
          linkTo(methodOn(UserClientsResource.class).updateUserClient(user.getId(), null))
              .withRel("updateUserClientSecretQuestionFlag");
      ret.add(
          new Link(
              createUriTemplate("secretQuestionsCreated", updateUserClientSecretQuestion),
              updateUserClientSecretQuestion.getRel()));

      ret.add(
          linkTo(
                  methodOn(UserClientSecretQuestionResponsesResource.class)
                      .secretQuestionAsteriskResponse(user.getId(), null, null))
              .withRel("secretQuestionAsteriskResponses"));
      ret.add(
          linkTo(methodOn(UserClientsResource.class).sendValidationEmail(user.getId()))
              .withRel("sendValidationEmail"));
      ret.add(
          linkTo(methodOn(UserClientsPasswordResource.class).changePassword(null, null, null))
              .withRel("changePassword"));
      ret.add(linkTo(methodOn(UserClientsResource.class).notNow(user.getId())).withRel("notNow"));
    } else {
      // impersonation users
      ret.add(
          new Link(
              UriComponentsBuilder.fromHttpUrl(
                      linkTo(methodOn(UserClientsResource.class).getById(1l))
                          .withSelfRel()
                          .getHref())
                  .replacePath(adminEntryPoint)
                  .build(false)
                  .toUriString(),
              "adminApp"));
    }

    return ret;
  }
  @Override
  public void serialize(List<Link> links, JsonGenerator jgen, SerializerProvider serializerProvider)
      throws IOException {

    try {
      Collection<Link> simpleLinks = new ArrayList<Link>();
      Collection<Affordance> affordances = new ArrayList<Affordance>();
      Collection<Link> templatedLinks = new ArrayList<Link>();
      Collection<Affordance> templatedAffordances = new ArrayList<Affordance>();
      Collection<Affordance> collectionAffordances = new ArrayList<Affordance>();
      Link selfRel = null;
      for (Link link : links) {
        if (link instanceof Affordance) {
          final Affordance affordance = (Affordance) link;
          final List<ActionDescriptor> actionDescriptors = affordance.getActionDescriptors();
          if (!actionDescriptors.isEmpty()) {
            if (affordance.isTemplated()) {
              templatedAffordances.add(affordance);
            } else {
              if (!affordance.isSelfRel()
                  && Cardinality.COLLECTION == affordance.getCardinality()) {
                collectionAffordances.add(affordance);
              } else {
                affordances.add(affordance);
              }
            }
          } else {
            if (affordance.isTemplated()) {
              templatedLinks.add(affordance);
            } else {
              simpleLinks.add(affordance);
            }
          }
        } else if (link.isTemplated()) {
          templatedLinks.add(link);
        } else {
          simpleLinks.add(link);
        }
        if ("self".equals(link.getRel())) {
          selfRel = link;
        }
      }

      for (Affordance templatedAffordance : templatedAffordances) {
        jgen.writeObjectFieldStart(templatedAffordance.getRel());

        jgen.writeStringField("@type", "hydra:IriTemplate");
        jgen.writeStringField("hydra:template", templatedAffordance.getHref());
        final List<ActionDescriptor> actionDescriptors = templatedAffordance.getActionDescriptors();
        ActionDescriptor actionDescriptor = actionDescriptors.get(0);
        jgen.writeArrayFieldStart("hydra:mapping");
        writeHydraVariableMapping(jgen, actionDescriptor, actionDescriptor.getPathVariableNames());
        writeHydraVariableMapping(jgen, actionDescriptor, actionDescriptor.getRequestParamNames());
        jgen.writeEndArray();

        jgen.writeEndObject();
      }
      for (Link templatedLink : templatedLinks) {
        // we only have the template, no access to method params
        jgen.writeObjectFieldStart(templatedLink.getRel());

        jgen.writeStringField("@type", "hydra:IriTemplate");
        jgen.writeStringField("hydra:template", templatedLink.getHref());

        jgen.writeArrayFieldStart("hydra:mapping");
        writeHydraVariableMapping(jgen, null, templatedLink.getVariableNames());
        jgen.writeEndArray();

        jgen.writeEndObject();
      }

      @SuppressWarnings("unchecked")
      Deque<LdContext> contextStack =
          (Deque<LdContext>) serializerProvider.getAttribute(JacksonHydraSerializer.KEY_LD_CONTEXT);
      String currentVocab =
          (contextStack != null && !contextStack.isEmpty()) ? contextStack.peek().vocab : null;

      // related collections
      if (!collectionAffordances.isEmpty()) {
        jgen.writeArrayFieldStart("hydra:collection");

        for (Affordance collectionAffordance : collectionAffordances) {
          jgen.writeStartObject();
          jgen.writeStringField(JsonLdKeywords.AT_TYPE, "hydra:Collection");
          jgen.writeStringField(JsonLdKeywords.AT_ID, collectionAffordance.getHref());
          jgen.writeObjectFieldStart("hydra:manages");
          jgen.writeStringField("hydra:property", collectionAffordance.getRel());
          // a) in the case of </Alice> :knows /bob the subject must be /Alice
          // b) in the case of <> orderedItem /latte-1 the subject is an anonymous resource of type
          // Order
          // c) in the case of </order/1> :seller </store> the object must be the store
          // 1. where is the information *about* the subject or object: the type or @id
          // 2. how to decide if the collection manages items for a subject or object?
          // ad 1.)
          // ad a) self rel of the Resource that has the collection affordance: looking through link
          // list
          //       at serialization time is possible
          // ad b) a candidate is the class given as value of @ExposesResourceFor on the controller
          //       that defines the method which leads us to believe we have a collection:
          //       either a GET /orders handler having a collection return type or the POST /orders.
          //       Works only if the GET or POST has no request mapping path of its own
          //       an alternative is to use {} without type if @ExposesResourceFor is not present
          // ad c) like a
          // ad 2.)
          // we know the affordance is a collection
          // * we could pass information into build(rel), like
          // .rel().reverseRel("schema:seller").build()
          // * we could use build("myReversedTerm") and look at the @context to see if it is
          // reversed,
          //   if so, we know that the manages block must use object not subject. However weird if
          // the
          //   reverse term is never really used in the json-ld
          // * we could have a registry which says if a property is meant to be reversed in a
          // certain context
          //   and use that to find out if we need subject or object, like :seller ->
          if (selfRel != null) {
            // prefer rev over rel, assuming that rev exists to be used by RDF serialization
            if (collectionAffordance.getRev() != null) {
              jgen.writeStringField("hydra:object", selfRel.getHref());
            } else if (collectionAffordance.getRel() != null) {
              jgen.writeStringField("hydra:subject", selfRel.getHref());
            }
          } else {
            // prefer rev over rel, assuming that rev exists to be used by RDF serialization
            if (collectionAffordance.getRev() != null) {
              jgen.writeObjectFieldStart("hydra:object");
              jgen.writeEndObject();
            } else if (collectionAffordance.getRel() != null) {
              jgen.writeObjectFieldStart("hydra:subject");
              jgen.writeEndObject();
            }
          }
          jgen.writeEndObject(); // end manages

          List<ActionDescriptor> actionDescriptors = collectionAffordance.getActionDescriptors();
          if (!actionDescriptors.isEmpty()) {
            jgen.writeArrayFieldStart("hydra:operation");
          }
          writeActionDescriptors(jgen, currentVocab, actionDescriptors);
          if (!actionDescriptors.isEmpty()) {
            jgen.writeEndArray(); // end hydra:operation
          }

          jgen.writeEndObject(); // end collection
        }
        jgen.writeEndArray();
      }

      for (Affordance affordance : affordances) {
        final String rel = affordance.getRel();
        List<ActionDescriptor> actionDescriptors = affordance.getActionDescriptors();

        if (!actionDescriptors.isEmpty()) {
          if (!Link.REL_SELF.equals(rel)) {
            jgen.writeObjectFieldStart(rel); // begin rel
          }
          jgen.writeStringField(JsonLdKeywords.AT_ID, affordance.getHref());
          jgen.writeArrayFieldStart("hydra:operation");
        }

        writeActionDescriptors(jgen, currentVocab, actionDescriptors);

        if (!actionDescriptors.isEmpty()) {
          jgen.writeEndArray(); // end hydra:operation

          if (!Link.REL_SELF.equals(rel)) {
            jgen.writeEndObject(); // end rel
          }
        }
      }

      for (Link simpleLink : simpleLinks) {
        final String rel = simpleLink.getRel();
        if (Link.REL_SELF.equals(rel)) {
          jgen.writeStringField("@id", simpleLink.getHref());
        } else {
          String linkAttributeName = IanaRels.isIanaRel(rel) ? IANA_REL_PREFIX + rel : rel;
          jgen.writeObjectFieldStart(linkAttributeName);
          jgen.writeStringField("@id", simpleLink.getHref());
          jgen.writeEndObject();
        }
      }
    } catch (IntrospectionException e) {
      throw new RuntimeException(e);
    }
  }