001package co.codewizards.cloudstore.rest.client;
002
003import java.security.KeyStore;
004import java.util.Map;
005
006import javax.net.ssl.HostnameVerifier;
007import javax.net.ssl.SSLContext;
008import javax.ws.rs.client.Client;
009import javax.ws.rs.client.ClientBuilder;
010import javax.ws.rs.core.Configuration;
011
012import org.glassfish.jersey.client.ClientConfig;
013import org.glassfish.jersey.client.ClientProperties;
014
015import co.codewizards.cloudstore.core.config.Config;
016import co.codewizards.cloudstore.core.config.ConfigImpl;
017import co.codewizards.cloudstore.rest.client.ssl.HostnameVerifierAllowingAll;
018import co.codewizards.cloudstore.rest.shared.filter.GZIPClientRequestFilter;
019import co.codewizards.cloudstore.rest.shared.interceptor.GZIPReaderInterceptor;
020import co.codewizards.cloudstore.rest.shared.interceptor.GZIPWriterInterceptor;
021
022public class ClientBuilderDefaultValuesDecorator extends ClientBuilder{
023        private static final int DEFAULT_SOCKET_CONNECT_TIMEOUT = 1 * 60 * 1000;
024        private static final int DEFAULT_SOCKET_READ_TIMEOUT = 5 * 60 * 1000;
025
026        /**
027         * The {@code key} for the connection timeout used with {@link Config#getPropertyAsInt(String, int)}.
028         * <p>
029         * The configuration can be overridden by a system property - see {@link Config#SYSTEM_PROPERTY_PREFIX}.
030         */
031        public static final String CONFIG_KEY_SOCKET_CONNECT_TIMEOUT = "socket.connectTimeout"; //$NON-NLS-1$
032
033        /**
034         * The {@code key} for the read timeout used with {@link Config#getPropertyAsInt(String, int)}.
035         * <p>
036         * The configuration can be overridden by a system property - see {@link Config#SYSTEM_PROPERTY_PREFIX}.
037         */
038        public static final String CONFIG_KEY_SOCKET_READ_TIMEOUT = "socket.readTimeout"; //$NON-NLS-1$
039
040        private final ClientBuilder builder;
041
042        public ClientBuilderDefaultValuesDecorator(){
043                this(ClientBuilder.newBuilder());
044        }
045
046        public ClientBuilderDefaultValuesDecorator(ClientBuilder builder){
047                this.builder = builder;
048
049                final ClientConfig clientConfig = new ClientConfig(CloudStoreJaxbContextResolver.class);
050                final Integer socketReadTimeout = ConfigImpl.getInstance().getPropertyAsPositiveOrZeroInt(
051                                CONFIG_KEY_SOCKET_READ_TIMEOUT,
052                                DEFAULT_SOCKET_READ_TIMEOUT);
053
054                final Integer socketConnectTimeout = ConfigImpl.getInstance().getPropertyAsPositiveOrZeroInt(
055                                CONFIG_KEY_SOCKET_CONNECT_TIMEOUT,
056                                DEFAULT_SOCKET_CONNECT_TIMEOUT);
057
058                clientConfig.property(ClientProperties.CONNECT_TIMEOUT, socketConnectTimeout); // must be a java.lang.Integer
059                clientConfig.property(ClientProperties.READ_TIMEOUT, socketReadTimeout); // must be a java.lang.Integer
060                // The following line allows for PUT without entity. We decide whether to use PUT or POST dependent on whether
061                // it is idempotent (=> PUT) or not (=> POST). Jersey allows to use POST with null as entity, but throws an exception
062                // when trying to PUT the same way.
063                clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
064
065
066                this.builder.withConfig(clientConfig)
067                        .register(GZIPReaderInterceptor.class)
068                        .register(GZIPClientRequestFilter.class)
069                        .register(GZIPWriterInterceptor.class)
070                        .hostnameVerifier(new HostnameVerifierAllowingAll());
071        }
072
073        @Override
074        public Client build(){
075                return builder.build();
076        }
077
078        @Override
079        public ClientBuilderDefaultValuesDecorator sslContext(final SSLContext sslContext){
080                builder.sslContext(sslContext);
081                return this;
082        }
083
084        @Override
085        public ClientBuilderDefaultValuesDecorator hostnameVerifier(final HostnameVerifier hostnameVerifier){
086                builder.hostnameVerifier(hostnameVerifier);
087                return this;
088        }
089
090        @Override
091        public Configuration getConfiguration() {
092                return builder.getConfiguration();
093        }
094
095        @Override
096        public ClientBuilder property(String name, Object value) {
097                builder.property(name, value);
098                return this;
099        }
100
101        @Override
102        public ClientBuilder register(Class<?> componentClass) {
103                builder.register(componentClass);
104                return this;
105        }
106
107        @Override
108        public ClientBuilder register(Class<?> componentClass, int priority) {
109                builder.register(componentClass, priority);
110                return this;
111        }
112
113        @Override
114        public ClientBuilder register(Class<?> componentClass, Class<?>... contracts) {
115                builder.register(componentClass, contracts);
116                return this;
117        }
118
119        @Override
120        public ClientBuilder register(Class<?> componentClass, Map<Class<?>, Integer> contracts) {
121                builder.register(componentClass, contracts);
122                return this;
123        }
124
125        @Override
126        public ClientBuilder register(Object component) {
127                builder.register(component);
128                return this;
129        }
130
131        @Override
132        public ClientBuilder register(Object component, int priority) {
133                builder.register(component, priority);
134                return this;
135        }
136
137        @Override
138        public ClientBuilder register(Object component, Class<?>... contracts) {
139                builder.register(component, contracts);
140                return this;
141        }
142
143        @Override
144        public ClientBuilder register(Object component, Map<Class<?>, Integer> contracts) {
145                builder.register(component, contracts);
146                return this;
147        }
148
149        @Override
150        public ClientBuilder withConfig(Configuration config) {
151                builder.withConfig(config);
152                return this;
153        }
154
155        @Override
156        public ClientBuilder keyStore(KeyStore keyStore, char[] password) {
157                builder.keyStore(keyStore, password);
158                return this;
159        }
160
161        @Override
162        public ClientBuilder trustStore(KeyStore trustStore) {
163                builder.trustStore(trustStore);
164                return this;
165        }
166
167}