View Javadoc
1   package org.oxerr.vividseats.client.rescu.impl;
2   
3   import java.util.function.Supplier;
4   
5   import org.apache.commons.lang3.ArrayUtils;
6   import org.oxerr.rescu.ext.singleton.RestProxyFactorySingletonImpl;
7   import org.oxerr.vividseats.client.ListingService;
8   import org.oxerr.vividseats.client.VividSeatsClient;
9   import org.oxerr.vividseats.client.rescu.resource.ListingResource;
10  
11  import com.fasterxml.jackson.annotation.JsonInclude.Include;
12  import com.fasterxml.jackson.databind.DeserializationFeature;
13  import com.fasterxml.jackson.databind.ObjectMapper;
14  import com.fasterxml.jackson.databind.SerializationFeature;
15  import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
16  
17  import io.github.poshjosh.ratelimiter.store.BandwidthsStore;
18  import jakarta.ws.rs.HeaderParam;
19  import si.mazi.rescu.ClientConfig;
20  import si.mazi.rescu.IRestProxyFactory;
21  import si.mazi.rescu.Interceptor;
22  import si.mazi.rescu.RestProxyFactoryImpl;
23  import si.mazi.rescu.serialization.jackson.DefaultJacksonObjectMapperFactory;
24  import si.mazi.rescu.serialization.jackson.JacksonObjectMapperFactory;
25  
26  public class ResCUVividSeatsClient implements VividSeatsClient {
27  
28  	private static final String DEFAULT_BASE_URL = "https://brokers.vividseats.com/webservices";
29  
30  	private final String baseUrl;
31  
32  	private final IRestProxyFactory restProxyFactory;
33  
34  	private final ListingService listingService;
35  
36  	/**
37  	 * Constructs a client with the specified token.
38  	 *
39  	 * @param token the token to access the API.
40  	 * @param interceptors the interceptors to intercept the requests.
41  	 */
42  	public ResCUVividSeatsClient(String token, Interceptor... interceptors) {
43  		this(DEFAULT_BASE_URL, token, interceptors);
44  	}
45  
46  	/**
47  	 * Constructs a client with the specified base URL and token.
48  	 *
49  	 * @param baseUrl the base URL of the API.
50  	 * @param token the token to access the API.
51  	 * @param interceptors the interceptors to intercept the requests.
52  	 */
53  	public ResCUVividSeatsClient(String baseUrl, String token, Interceptor... interceptors) {
54  		this(baseUrl, () -> token, interceptors);
55  	}
56  
57  	/**
58  	 * Constructs a client with the specified token.
59  	 *
60  	 * @param token the token to access the API.
61  	 * @param interceptors the interceptors to intercept the requests.
62  	 */
63  	public ResCUVividSeatsClient(Supplier<String> token, Interceptor... interceptors) {
64  		this(DEFAULT_BASE_URL, token, interceptors);
65  	}
66  
67  	/**
68  	 * Constructs a client with the specified base URL and token.
69  	 *
70  	 * @param baseUrl the base URL of the API.
71  	 * @param tokenSupplier the token supplier to access the API.
72  	 * @param interceptors the interceptors to intercept the requests.
73  	 */
74  	public ResCUVividSeatsClient(String baseUrl, Supplier<String> tokenSupplier, Interceptor... interceptors) {
75  		this(baseUrl, tokenSupplier, BandwidthsStore.ofDefaults(), interceptors);
76  	}
77  
78  	/**
79  	 * Constructs a client with the specified base URL, token supplier, bandwidths store and interceptors.
80  	 *
81  	 * @param baseUrl the base URL of the API.
82  	 * @param tokenSupplier the token supplier to access the API.
83  	 * @param bandwidthsStore the bandwidths store to store the bandwidth.
84  	 * @param interceptors the interceptors to intercept the requests.
85  	 */
86  	public ResCUVividSeatsClient(String baseUrl, Supplier<String> tokenSupplier, BandwidthsStore<String> bandwidthsStore, Interceptor... interceptors) {
87  		this.baseUrl = baseUrl;
88  		JacksonObjectMapperFactory jacksonObjectMapperFactory = createJacksonObjectMapperFactory();
89  		var clientConfigV1 = createClientConfigV1(jacksonObjectMapperFactory);
90  		var clientConfig = createClientConfig(jacksonObjectMapperFactory, tokenSupplier);
91  		this.restProxyFactory = new RestProxyFactorySingletonImpl(new RestProxyFactoryImpl());
92  		this.listingService = new ListingServiceImpl(
93  			tokenSupplier,
94  			this.restProxyFactory.createProxy(org.oxerr.vividseats.client.rescu.resource.v1.ListingResource.class, baseUrl, clientConfigV1, interceptors),
95  			createProxy(ListingResource.class, clientConfig, bandwidthsStore, interceptors)
96  		);
97  	}
98  
99  	@Override
100 	public ListingService getListingService() {
101 		return this.listingService;
102 	}
103 
104 	protected <I> I createProxy(Class<I> restInterface, ClientConfig clientConfig, BandwidthsStore<String> bandwidthsStore, Interceptor... interceptors) {
105 		var rateLimiterInterceptor = new RateLimiterInterceptor(bandwidthsStore);
106 		return createProxy(restInterface, clientConfig, ArrayUtils.add(interceptors, rateLimiterInterceptor));
107 	}
108 
109 	protected <I> I createProxy(Class<I> restInterface, ClientConfig clientConfig, Interceptor... interceptors) {
110 		return this.restProxyFactory.createProxy(restInterface, baseUrl, clientConfig, interceptors);
111 	}
112 
113 	protected ClientConfig createClientConfigV1(JacksonObjectMapperFactory jacksonObjectMapperFactory) {
114 		var clientConfig = new ClientConfig();
115 		clientConfig.setJacksonObjectMapperFactory(jacksonObjectMapperFactory);
116 		return clientConfig;
117 	}
118 
119 	protected ClientConfig createClientConfig(JacksonObjectMapperFactory jacksonObjectMapperFactory, Supplier<String> tokenSupplier) {
120 		var clientConfig = new ClientConfig();
121 		clientConfig.addDefaultParam(HeaderParam.class, "Api-token", new Object() {
122 
123 			@Override
124 			public String toString() {
125 				return tokenSupplier.get();
126 			}
127 
128 		});
129 		clientConfig.setJacksonObjectMapperFactory(jacksonObjectMapperFactory);
130 		return clientConfig;
131 	}
132 
133 	protected JacksonObjectMapperFactory createJacksonObjectMapperFactory() {
134 		return new DefaultJacksonObjectMapperFactory() {
135 
136 			@Override
137 			public void configureObjectMapper(ObjectMapper objectMapper) {
138 				super.configureObjectMapper(objectMapper);
139 				objectMapper.registerModule(new JavaTimeModule());
140 				objectMapper.setSerializationInclusion(Include.NON_ABSENT);
141 				objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
142 				objectMapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
143 				objectMapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
144 			}
145 
146 		};
147 	}
148 
149 }