com.jservlet.TcloudClientApplication.java Source code

Java tutorial

Introduction

Here is the source code for com.jservlet.TcloudClientApplication.java

Source

package com.jservlet;

import com.google.common.collect.ImmutableMap;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import feign.RequestInterceptor;
import io.swagger.annotations.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.hateoas.Resources;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import springfox.documentation.builders.*;
import springfox.documentation.service.*;

import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static com.google.common.collect.Lists.newArrayList;

/*import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.messaging.MessageChannel;*/

/**
 * Tcloud Client
 *
 * Javascript OAuth2 SSO Client, login and handle Jason Web Token, see http://localhost:9999/login
 * Swagger UI, Rest API support, see http://localhost:9999/swagger-ui.html
 *
 * OAuth2SsoDefaultConfiguration for OAuth2 Single Sign On (SSO):
 * If the user only has {@code @EnableOAuth2Sso} but not on a WebSecurityConfigurerAdapter then one is
 * added with all paths secured and with an order that puts it ahead of the default HTTP Basic security chain in Spring Boot.
 *
 * @EnableOAuth2Sso  with OAuth2Sso client in config
 * curl -X GET http://localhost:9999/tclouds/list -v -L -u franck:spring -c cookies.txt
 * or
 * @EnableResourceServer with Resource Server in config
 * curl -X GET http://localhost:9999/tclouds/list?access_token=8f142df8-c13f-4297-b841-abbb275e1b46
 *
 * @author Franck Andriano 2016
 */

/*@EnableBinding(TcloudChannels.class)
@IntegrationComponentScan */
//@EnableOAuth2Sso        // @EnableOAuth2Client
@EnableResourceServer // Spring Boot 1.3, security.oauth2 in config!
@EnableFeignClients // Scans for interfaces that declare they are feign clients (via @FeignClient)
@EnableZuulProxy // @EnableDiscoveryClient @EnableCircuitBreaker
@SpringBootApplication // @SpringBootConfiguration @EnableAutoConfiguration
public class TcloudClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(TcloudClientApplication.class, args);
    }

}

@Component
class DiscoveryClientConsole implements CommandLineRunner {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(DiscoveryClientConsole.class);

    private final DiscoveryClient discoveryClient;
    private final LoadBalancerClient loadBalancerClient;

    @Autowired
    public DiscoveryClientConsole(LoadBalancerClient loadBalancerClient, DiscoveryClient discoveryClient) {
        this.loadBalancerClient = loadBalancerClient;
        this.discoveryClient = discoveryClient;
    }

    @Override
    public void run(String... strings) throws Exception {

        // Spring Cloud Commons DiscoveryClient abstraction
        discoveryClient.getInstances("edge-service").forEach((ServiceInstance si) -> {
            logger.warn("[" + si.getServiceId() + "] " + ToStringBuilder.reflectionToString(si));
            logger.warn("[" + si.getServiceId() + "] " + si.getHost() + ":" + si.getPort() + " secure: "
                    + si.isSecure());
        });

        // Spring Cloud Commons LoadBalancerClient
        ServiceInstance edgechoose = loadBalancerClient.choose("edge-service");
        if (edgechoose != null)
            logger.warn("[" + edgechoose.getServiceId() + "] " + "choose: " + edgechoose.getHost() + ":"
                    + edgechoose.getPort() + " secure: " + edgechoose.isSecure());

        // Spring Cloud Commons DiscoveryClient abstraction
        discoveryClient.getInstances("auth-service").forEach((ServiceInstance si) -> {
            logger.warn("[" + si.getServiceId() + "] " + ToStringBuilder.reflectionToString(si));
            logger.warn("[" + si.getServiceId() + "] " + si.getHost() + ":" + si.getPort() + " secure: "
                    + si.isSecure());
        });

        // Spring Cloud Commons LoadBalancerClient
        ServiceInstance authchoose = loadBalancerClient.choose("auth-service");
        if (authchoose != null)
            logger.warn("[" + authchoose.getServiceId() + "] " + "choose: " + authchoose.getHost() + ":"
                    + authchoose.getPort() + " secure: " + authchoose.isSecure());
    }
}

/*
@MessagingGateway
interface TcloudWriter {
  @Gateway(requestChannel = "output")
  void write(String rn);
}
    
interface TcloudChannels {
@Output
MessageChannel output();
}
*/

@FeignClient("edge-service") // by edge-service or tcloud-service
interface TcloudReader {
    // /tcloud-service/tclouds or /tclouds
    @RequestMapping(method = RequestMethod.GET, value = "/tcloud-service/tclouds") // GetMapping signature doesn't work with Feign!?
    Resources<Tcloud> read();

    @RequestMapping(method = RequestMethod.GET, value = "/tcloud-service/tclouds")
    Resources<Tcloud> read(@RequestParam(value = "q") String q);

    @RequestMapping(method = RequestMethod.GET, value = "/tcloud-service/tclouds/{id}")
    Resources<Tcloud> read(@PathVariable(value = "id") Long id);

    @RequestMapping(method = RequestMethod.POST, value = "/tcloud-service/tclouds")
    void save(@RequestBody Tcloud tcloud);

    @RequestMapping(method = RequestMethod.PUT, value = "/tcloud-service/tclouds/{id}")
    void update(@PathVariable("id") long id, @RequestBody Tcloud tcloud); // not RequestParam!

    @RequestMapping(method = RequestMethod.DELETE, value = "/tcloud-service/tclouds/{id}") // idem!
    void delete(@PathVariable(value = "id") Long id);
}

@FeignClient("edge-service") // or edge-service / tcloud-service
interface TcloudMessageReader { // or /message
    @RequestMapping(method = RequestMethod.GET, value = "/tcloud-service/message")
    String read();
}

/**
 * Pre-defined custom RequestInterceptor for Feign Requests, uses the provided OAuth2ClientContext and Bearer tokens
 * within Authorization for header injection with current OAuth2ProtectedResourceDetails!
 *
 * See https://github.com/spring-cloud/spring-cloud-netflix/issues/675
 *
 * {@link OAuth2ClientContext oauth2ClientContext} see {@link DefaultOAuth2ClientContext }
 * {@link BaseOAuth2ProtectedResourceDetails resource} see config Oauth2 Resource!
 */
@Configuration
class OAuth2FeignConfig {

    @Bean
    @Autowired
    public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext,
            BaseOAuth2ProtectedResourceDetails resource) {
        return new OAuth2FeignRequestInterceptor(oauth2ClientContext, resource);
    }
}

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "1800");
        response.setHeader("Access-Control-Allow-Headers",
                "origin,accept,x-requested-with,content-type,access-control-request-method,access-control-request-headers,authorization");
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}

@Controller
class TcloudLoginMvc {

    @GetMapping(value = "/")
    public String index() {
        return "redirect:swagger-ui.html";
    }

    @GetMapping("/login")
    ModelAndView login() {
        return new ModelAndView("jssoclient");
    }
}

@Configuration
@EnableWebSecurity
@EnableResourceServer
class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests().antMatchers("/v2/api-docs/**").permitAll()
                .antMatchers("/swagger-ui.html", "/webjars/**", "/swagger-resources/**").permitAll().and()
                .authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin().loginPage("/login")
                .permitAll(); // Override Spring HttpSecurity login form path!
        // @formatter:on
    }
}

/**
 *  Bugs in Swagger-UI... Use static files swagger-ui/dist/ and swagger.json with Swagger Editor!
 *  see http://editor.swagger.io
 */
@Configuration
@EnableSwagger2
class SwaggerConfig {

    @Bean
    public Docket tcloudApi() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("tcloud-api").apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors.any()).paths(PathSelectors.ant("/api/v1/**")).build()
                .securitySchemes(newArrayList(apiKey()));
    }

    // Put Authorization bearer +' '+JWT (Jason Web Token)
    @Bean
    SecurityScheme apiKey() {
        return new ApiKey("Authorization", "api_key", "header");
    }

    private ApiInfo apiInfo() {
        ApiInfo apiInfo = new ApiInfo("Tcloud API Manual",
                "This online API manual for the development of client-side reference :\n"
                        + "- Put Authorization header : Bearer+' '+JWT(Jason Web Token)\n",
                "0.0.1", "Terms of service",
                new Contact("Swagger Tcloud API Team", "https://github.com/javaguru/tcloud-microservices",
                        "support@jservlet.com"),
                "GPL-3.0 license", "https://github.com/javaguru/tcloud-microservices/blob/master/LICENSE");
        return apiInfo;
    }
}

@Api(description = "Tclouds API")
@RestController
@RequestMapping({ "/tclouds", "/api/v1" })
class TcloudApiGateway {

    private final TcloudReader tcloudReader;

    /*  private final TcloudWriter tcloudWriter;*/

    @Autowired
    public TcloudApiGateway(TcloudReader tcloudReader/*, TcloudWriter tcloudWriter*/) {
        this.tcloudReader = tcloudReader;
        /*this.tcloudWriter = tcloudWriter;*/
    }

    /**
     * Get Rest Principal user through the OAuth2Sso!
     *
    @RequestMapping("/user")
    public Principal user(Principal user) {
    return user;
    }*/

    public Collection<String> fallback() {
        return new ArrayList<>();
    }

    @HystrixCommand(fallbackMethod = "fallback")
    @ApiOperation(value = "Names tcloud data", notes = "Get names Tcloud json")
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success", response = String[].class),
            @ApiResponse(code = 401, message = "Unauthorized") })
    @GetMapping(path = "/names", produces = "application/json")
    public Collection<String> names() {
        return this.tcloudReader.read().getContent().stream().map(Tcloud::getTcloudName)
                .collect(Collectors.toList());
    }

    public Collection<Tcloud> listback() {
        return new ArrayList<Tcloud>();
    }

    @HystrixCommand(fallbackMethod = "listback")
    @ApiOperation(value = "List tcloud data", notes = "Get list Tcloud json")
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success", response = Tcloud[].class),
            @ApiResponse(code = 401, message = "Unauthorized") })
    @GetMapping(path = "/list", produces = "application/json")
    public Collection<Tcloud> list() { // Return a list with ids!
        return this.tcloudReader.read().getContent().stream().collect(Collectors.toList());
    }

    @ApiOperation(value = "Raw tcloud data", notes = "Raw list Tcloud json")
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success", response = Tcloud[].class),
            @ApiResponse(code = 401, message = "Unauthorized"), @ApiResponse(code = 500, message = "Failure") })
    @GetMapping(path = "/raw", produces = "application/json")
    public Object[] raw() { // Return a raw list!
        return this.tcloudReader.read().getContent().stream().sequential().toArray();
    }

    @ApiOperation(value = "Add tcloud data", notes = "Add Tcloud json")
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
            @ApiResponse(code = 401, message = "Unauthorized"), @ApiResponse(code = 500, message = "Failure") })
    @PostMapping(path = "/save")
    public void save(@RequestBody Tcloud tcloud) {
        this.tcloudReader.save(tcloud);
    }

    @ApiOperation(value = "Update tcloud data", notes = "Update Tcloud json")
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
            @ApiResponse(code = 401, message = "Unauthorized"), @ApiResponse(code = 500, message = "Failure") })
    @PutMapping(path = "/update")
    public void update(@RequestParam(value = "id") long id, @RequestBody Tcloud tcloud) {
        this.tcloudReader.update(id, tcloud);
    }

    @ApiOperation(value = "Delete tcloud data", notes = "Delete Tcloud id json")
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
            @ApiResponse(code = 401, message = "Unauthorized"), @ApiResponse(code = 500, message = "Failure") })
    @DeleteMapping(path = "/delete")
    public void delete(@RequestParam(value = "id") Long id) {
        this.tcloudReader.delete(id);
    }

    /* @PostMapping()
     public void write(@RequestBody Tcloud tcloud) {
    this.tcloudWriter.write(tcloud.getTcloudName());
     }*/
}

@Controller
@RequestMapping("/tclouds-service")
class TcloudApiGatewayMvc {

    private final TcloudReader tcloudReader;
    private final TcloudMessageReader tcloudMessageReader;

    @Autowired
    public TcloudApiGatewayMvc(TcloudReader tcloudReader, TcloudMessageReader tcloudMessageReader) {
        this.tcloudReader = tcloudReader;
        this.tcloudMessageReader = tcloudMessageReader;
    }

    public ModelAndView listback() {
        return new ModelAndView("error");
    }

    @HystrixCommand(fallbackMethod = "listback")
    @GetMapping("/names")
    ModelAndView page() {
        ModelAndView model = new ModelAndView("tcloud");

        Resources<Tcloud> tclouds = this.tcloudReader.read();
        List<Object> data = new LinkedList<>();
        tclouds.forEach(tcloud -> data.add(ImmutableMap.<String, Object>builder().put("id", tcloud.getId())
                .put("tcloudName", tcloud.getTcloudName()).build()));

        model.addObject("tclouds", data);
        model.addObject("message", this.tcloudMessageReader.read());

        return model;
    }
}

class Tcloud {

    private Long id;

    private String tcloudName;

    public Tcloud() {
    }

    public Tcloud(String tcloudName) {
        this.tcloudName = tcloudName;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTcloudName() {
        return tcloudName;
    }

    public void setTcloudName(String tcloudName) {
        this.tcloudName = tcloudName;
    }

    @Override
    public String toString() {
        return "Tcloud { id: " + id + ", tcloudName: " + tcloudName + " }";
    }

}