Package org.springframework.data.rest.shell.commands

Source Code of org.springframework.data.rest.shell.commands.DiscoveryCommands$SslAwareClientHttpRequestFactory

package org.springframework.data.rest.shell.commands;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.hateoas.Link;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.shell.support.util.OsUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

/**
* Commands that discover resources and create local helpers for defined links.
*
* @author Jon Brisbin
*/
@Component
public class DiscoveryCommands implements CommandMarker, ApplicationEventPublisherAware {

  private static final MediaType COMPACT_JSON = MediaType.valueOf("application/x-spring-data-compact+json");
  private static final Logger    LOG          = LoggerFactory.getLogger(DiscoveryCommands.class);
  @Autowired
  private ConfigurationCommands configCmds;
  @Autowired
  private ContextCommands       contextCmds;
  @Autowired
  private SslCommands           sslCmds;
  private SslAwareClientHttpRequestFactory requestFactory = new SslAwareClientHttpRequestFactory();
  @Autowired(required = false)
  private RestTemplate                     client         = new RestTemplate(requestFactory);
  @Autowired(required = false)
  private ObjectMapper                     mapper         = new ObjectMapper();
  private Map<String, String>              resources      = new HashMap<String, String>();
  private ApplicationEventPublisher ctx;

  private static String pad(String s, int len) {
    char[] pad = new char[len - s.length()];
    Arrays.fill(pad, ' ');
    return s + new String(pad);
  }

  @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    this.ctx = applicationEventPublisher;
  }

  /**
   * Get the discovered resources.
   *
   * @return
   */
  public Map<String, String> getResources() {
    return resources;
  }

  @CliAvailabilityIndicator({"discover", "list", "follow"})
  public boolean available() {
    return true;
  }

  /**
   * Issue a GET and discover what resources are available by looking in the links property of the JSON.
   *
   * @param path
   *     URI to resource.
   *
   * @return
   *
   * @throws IOException
   */
  @CliCommand(value = "discover", help = "Discover the resources available at a given URI.")
  public String discover(
      @CliOption(key = {"", "rel"},
                 mandatory = false,
                 help = "The URI at which to discover resources.",
                 unspecifiedDefaultValue = "/") PathOrRel path) throws IOException, URISyntaxException {

    URI requestUri;
    if("/".equals(path)) {
      requestUri = configCmds.getBaseUri();
    } else if(path.getPath().startsWith("http")) {
      requestUri = URI.create(path.getPath());
    } else {
      requestUri = UriComponentsBuilder.fromUri(configCmds.getBaseUri()).path(path.getPath()).build().toUri();
    }

    configCmds.setBaseUri(requestUri.toString());

    return list(new PathOrRel(requestUri.toString()), null);
  }

  @CliCommand(value = "list", help = "Discover the resources available at a given URI.")
  public String list(
      @CliOption(key = {"", "rel"},
                 mandatory = false,
                 help = "The URI at which to discover resources.",
                 unspecifiedDefaultValue = "/") PathOrRel path,
      @CliOption(key = "params",
                 mandatory = false,
                 help = "Query parameters to add to the URL.") Map params) {

    URI requestUri;
    if("/".equals(path)) {
      requestUri = configCmds.getBaseUri();
    } else if(path.getPath().startsWith("http")) {
      requestUri = URI.create(path.getPath());
    } else if(resources.containsKey(path)) {
      requestUri = UriComponentsBuilder.fromUriString(resources.get(path))
                                       .build()
                                       .toUri();
    } else if("/".equals(configCmds.getBaseUri().getPath())) {
      requestUri = UriComponentsBuilder.fromUri(configCmds.getBaseUri())
                                       .path(path.getPath())
                                       .build()
                                       .toUri();
    } else {
      requestUri = UriComponentsBuilder.fromUri(configCmds.getBaseUri())
                                       .pathSegment(path.getPath())
                                       .build()
                                       .toUri();
    }

    if(null != params) {
      UriComponentsBuilder urib = UriComponentsBuilder.fromUri(requestUri);
      for(Object key : params.keySet()) {
        urib.queryParam(key.toString(), params.get(key));
      }
      requestUri = urib.build().toUri();
    }

    ExtractLinksHelper elh = new ExtractLinksHelper();
    List<Link> links = client.execute(requestUri, HttpMethod.GET, elh, elh);

    if(links.size() == 0) {
      return "No resources found...";
    }

    StringBuilder sb = new StringBuilder();

    int maxRelLen = 0;
    int maxHrefLen = 0;

    // First get max lengths
    for(Link l : links) {
      if(maxRelLen < l.getRel().length()) {
        maxRelLen = l.getRel().length();
      }
      if(maxHrefLen < l.getHref().length()) {
        maxHrefLen = l.getHref().length();
      }
    }
    maxRelLen += 4;

    sb.append(pad("rel", maxRelLen))
      .append(pad("href", maxHrefLen))
      .append(OsUtils.LINE_SEPARATOR);

    char[] line = new char[maxRelLen + maxHrefLen];
    Arrays.fill(line, '=');
    sb.append(new String(line))
      .append(OsUtils.LINE_SEPARATOR);

    // Now build a table
    for(Link l : links) {
      resources.put(l.getRel(), l.getHref());
      sb.append(pad(l.getRel(), maxRelLen))
        .append(pad(l.getHref(), maxHrefLen))
        .append(OsUtils.LINE_SEPARATOR);
    }

    return sb.toString();
  }

  /**
   * Follow a URI by setting the baseUri to this path, then discovering what resources are available there.
   *
   * @param path
   *     URI to resource.
   *
   * @return
   *
   * @throws IOException
   * @throws URISyntaxException
   */
  @CliCommand(value = "follow",
              help = "Follows a URI path, sets the base to that new path, and discovers what resources are available.")
  public void follow(
      @CliOption(key = {"", "rel"},
                 mandatory = true,
                 help = "The URI to follow.") PathOrRel path) throws IOException, URISyntaxException {
    configCmds.setBaseUri(path.getPath());
  }

  private class ExtractLinksHelper implements RequestCallback, ResponseExtractor<List<Link>> {

    @Override public void doWithRequest(ClientHttpRequest request) throws IOException {
      request.getHeaders().setAll(configCmds.getHeaders().toSingleValueMap());
      if(CollectionUtils.isEmpty(request.getHeaders().getAccept())) {
        if(LOG.isDebugEnabled()) {
          LOG.debug("No 'Accept' header specified, using " + COMPACT_JSON);
        }
        request.getHeaders().setAccept(Arrays.asList(COMPACT_JSON, MediaType.APPLICATION_JSON));
      }
    }

    @Override public List<Link> extractData(ClientHttpResponse response) throws IOException {
      List<Link> links = new ArrayList<Link>();

      MediaType ct = response.getHeaders().getContentType();
      if(null != ct && ct.getSubtype().endsWith("json")) {
        Map m = mapper.readValue(response.getBody(), Map.class);

        Object o = m.get("links");
        if(o instanceof List) {
          for(Object lnk : (List)o) {
            if(lnk instanceof Map) {
              Map lnkmap = (Map)lnk;
              String href = String.format("%s", lnkmap.get("href"));
              String rel = String.format("%s", lnkmap.get("rel"));
              links.add(new Link(href, rel));
            }
          }
        }
      } else if(null != ct && ct.getSubtype().endsWith("uri-list")) {
        BufferedReader rdr = new BufferedReader(new InputStreamReader(response.getBody()));
        String line;
        while(null != (line = rdr.readLine())) {
          links.add(new Link(URI.create(line).toString(), ""));
        }
      }

      if(LOG.isDebugEnabled()) {
        LOG.debug("Returning links: " + links);
      }

      return links;
    }

  }

  private class SslAwareClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
    @Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
      if(connection instanceof HttpsURLConnection) {
        HttpsURLConnection httpsConnection = (HttpsURLConnection)connection;
        if(!sslCmds.getValidate()) {
          httpsConnection.setHostnameVerifier(new HostnameVerifier() {
            @Override public boolean verify(String s, SSLSession sslSession) {
              return true;
            }
          });
          httpsConnection.setSSLSocketFactory(sslCmds.getCustomContext().getSocketFactory());
        }
      }
      super.prepareConnection(connection, httpMethod);
    }
  }

}
TOP

Related Classes of org.springframework.data.rest.shell.commands.DiscoveryCommands$SslAwareClientHttpRequestFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.