1 package gdetester.restapi;
3 import com.google.gson.Gson;
4 import java.io.BufferedOutputStream;
5 import java.io.BufferedReader;
6 import java.io.ByteArrayOutputStream;
7 import java.io.FileNotFoundException;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.InputStreamReader;
11 import java.io.OutputStream;
12 import java.lang.reflect.Type;
13 import java.net.HttpURLConnection;
15 import java.nio.ByteBuffer;
16 import java.nio.channels.Channels;
17 import java.nio.channels.ReadableByteChannel;
18 import java.nio.channels.WritableByteChannel;
19 import java.security.KeyManagementException;
20 import java.security.KeyStore;
21 import java.security.KeyStoreException;
22 import java.security.NoSuchAlgorithmException;
23 import java.security.cert.Certificate;
24 import java.security.cert.CertificateException;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28 import javax.net.ssl.HostnameVerifier;
29 import javax.net.ssl.HttpsURLConnection;
30 import javax.net.ssl.SSLContext;
31 import javax.net.ssl.SSLSession;
32 import javax.net.ssl.TrustManagerFactory;
33 import gdetester.restapi.providers.CertificateProvider;
37 * @author Kavoos Bojnourdi
39 public class SimpleRestApi {
44 protected RestContext restContext;
46 private KeyStore keyStore;
47 private TrustManagerFactory tmf;
48 private SSLContext context;
49 private boolean verifyHostName;
50 private HttpURLConnection connection;
53 public SimpleRestApi() {
54 restContext = new RestContext();
58 public SimpleRestApi(RestContext context) {
59 this.restContext = context;
63 public boolean isVerifyHostName() {
64 return verifyHostName;
67 public void setVerifyHostName(boolean verifyHostName) {
68 this.verifyHostName = verifyHostName;
71 protected void setContext(RestContext context) {
72 this.restContext = context;
73 if (context.getBaseResource() != null) {
78 private void initResource() {
82 public RestContext getContext() {
86 protected void setResource(String resource) {
87 restContext.setBaseResource(resource);
91 protected void setResource(String base, String resource) {
92 restContext.setBaseResource(base + resource);
96 public void closeConnection() {
97 if (connection != null) {
98 connection.disconnect();
102 public void setCertificateProvider(CertificateProvider certificateProvider) {
103 restContext.setCertificateProvider(certificateProvider);
110 protected void initAuthentication(HttpURLConnection connection) {
111 if (restContext.getUserName() == null) {
114 String userCredentials = restContext.getUserName() + ":" + restContext.getPassword();
115 String basicAuth = "Basic " + new String(Base64.encode(userCredentials.getBytes()));
116 connection.setRequestProperty("Authorization", basicAuth);
117 connection.setRequestProperty("User-Agent", "Deuterium/1.0");
124 * @throws IOException
126 protected boolean remove(ResponseHandler rh) throws IOException {
127 setUpHttpConnection();
130 connection.setDoInput(true);
131 connection.setDoOutput(false);
132 initAuthentication(connection);
134 connection.setRequestMethod("DELETE");
137 int responseCode = connection.getResponseCode();
138 String resultString = readStringResponse(connection);
141 rh = new DefaultResponseHandler();
143 return rh.checkResponse(responseCode, resultString);
154 * @throws IOException
156 protected boolean putAsJSonData(Object data, ResponseHandler rh) throws IOException {
157 setUpHttpConnection();
159 connection.setRequestMethod("PUT");
160 return writeJsonData(data, connection, rh);
170 * @throws IOException
172 protected boolean putAsJSonData(Object data) throws IOException {
173 return putAsJSonData(data, null);
181 * @throws IOException
183 protected boolean postAsJSonData(Object data, ResponseHandler rh) throws IOException {
184 setUpHttpConnection();
186 connection.setRequestMethod("POST");
187 return writeJsonData(data, connection, rh);
197 * @throws IOException
199 protected boolean postAsJSonData(Object data) throws IOException {
200 return postAsJSonData(data, null);
208 * @throws IOException
210 protected boolean postAsBinaryData(byte[] data, ResponseHandler rh) throws IOException {
211 setUpHttpConnection();
213 connection.setRequestMethod("POST");
214 return sendBinaryData(connection, data, rh);
225 * @throws IOException
227 protected boolean putAsBinaryData(byte[] data, ResponseHandler rh) throws IOException {
228 setUpHttpConnection();
230 connection.setRequestMethod("PUT");
231 return sendBinaryData(connection, data, rh);
241 * @throws IOException
243 protected boolean putAsBinaryData(byte[] data) throws IOException {
244 return putAsBinaryData(data, null);
252 * @throws IOException
254 protected boolean postAsBinaryStream(InputStream in, ResponseHandler rh) throws IOException {
255 setUpHttpConnection();
257 connection.setRequestMethod("POST");
258 return sendBinaryStream(connection, in, rh);
268 * @throws IOException
270 protected boolean postAsBinaryStream(InputStream in) throws IOException {
271 return postAsBinaryStream(in, null);
279 * @throws IOException
281 protected boolean putAsBinaryStream(InputStream in, ResponseHandler rh) throws IOException {
282 setUpHttpConnection();
284 connection.setRequestMethod("PUT");
285 return sendBinaryStream(connection, in, rh);
296 * @throws IOException
298 protected boolean putAsBinaryStream(InputStream in) throws IOException {
299 return putAsBinaryStream(in, null);
306 * @throws IOException
308 protected byte[] getBinaryData(ResponseHandler rh) throws IOException {
309 setUpHttpConnection();
311 connection.setRequestMethod("GET");
312 connection.setDoInput(true);
313 connection.setDoOutput(false);
314 initAuthentication(connection);
316 int responseCode = connection.getResponseCode();
318 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
319 copy(connection.getInputStream(), outputStream);
322 rh = new DefaultResponseHandler();
324 rh.checkResponse(responseCode, connection.getResponseMessage());
326 return outputStream.toByteArray();
334 * @return @throws IOException
336 protected byte[] getBinaryData() throws IOException {
337 return getBinaryData(null);
344 * @throws IOException
346 protected InputStream getBinaryStream(ResponseHandler rh) throws IOException {
347 setUpHttpConnection();
348 connection.setRequestMethod("GET");
349 connection.setDoInput(true);
350 connection.setDoOutput(false);
351 initAuthentication(connection);
353 int responseCode = connection.getResponseCode();
355 rh = new DefaultResponseHandler();
357 rh.checkResponse(responseCode, connection.getResponseMessage());
358 return connection.getInputStream();
363 * @return @throws IOException
365 protected InputStream getBinaryStream() throws IOException {
366 return getBinaryStream(null);
375 * @throws IOException
377 protected <T> T getData(Class<T> classOfT, ResponseHandler rh) throws IOException {
378 setUpHttpConnection();
380 connection.setRequestMethod("GET");
381 connection.setDoInput(true);
382 connection.setDoOutput(false);
383 initAuthentication(connection);
385 String data = readStringResponse(connection);
386 int responseCode = connection.getResponseCode();
388 rh = new DefaultResponseHandler();
390 rh.checkResponse(responseCode, connection.getResponseMessage());
391 T o = gson.fromJson(data, classOfT);
403 * @throws IOException
405 protected <T> T getData(Class<T> classOfT) throws IOException {
406 return getData(classOfT, null);
409 protected <T> List<T> getDataList(Type typeOfT, ResponseHandler rh) throws IOException {
411 setUpHttpConnection();
414 connection.setRequestMethod("GET");
415 connection.setDoInput(true);
416 connection.setDoOutput(false);
417 initAuthentication(connection);
419 int responseCode = connection.getResponseCode();
421 rh = new DefaultResponseHandler();
423 rh.checkResponse(responseCode, connection.getResponseMessage());
425 String data = readStringResponse(connection);
426 T[] o = gson.fromJson(data, typeOfT);
427 List<T> ret = new ArrayList<T>();
428 ret.addAll(Arrays.asList(o));
435 /* Private methods */
436 /* ********************************************************************** */
437 private boolean sendBinaryStream(HttpURLConnection connection, InputStream in, ResponseHandler rh) throws IOException {
438 initAuthentication(connection);
439 connection.setDoInput(true);
440 connection.setDoOutput(true);
441 connection.setChunkedStreamingMode(4096);
442 connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
443 copy(in, connection.getOutputStream());
444 int responseCode = connection.getResponseCode();
445 String response = readStringResponse(connection);
447 rh = new DefaultResponseHandler();
450 return rh.checkResponse(responseCode, response);
454 private void copy(InputStream in, OutputStream out) throws IOException {
455 ReadableByteChannel source = Channels.newChannel(in);
456 WritableByteChannel target = Channels.newChannel(out);
458 ByteBuffer buffer = ByteBuffer.allocate(16 * 1024);
459 while (source.read(buffer) != -1) {
460 buffer.flip(); // Prepare the buffer to be drained
461 while (buffer.hasRemaining()) {
462 target.write(buffer);
464 buffer.clear(); // Empty buffer to get ready for filling
472 private boolean sendBinaryData(HttpURLConnection connection, byte[] data, ResponseHandler rh) throws IOException {
473 initAuthentication(connection);
474 writeData(connection, data);
475 int responseCode = connection.getResponseCode();
476 String response = readStringResponse(connection);
478 rh = new DefaultResponseHandler();
481 return rh.checkResponse(responseCode, response);
484 private void writeData(HttpURLConnection connection, byte[] data) throws IOException {
485 connection.setDoInput(true);
486 connection.setDoOutput(true);
487 connection.setChunkedStreamingMode(4096);
488 connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
489 BufferedOutputStream outputStream = new BufferedOutputStream(connection.getOutputStream());
490 outputStream.write(data);
491 outputStream.flush();
492 outputStream.close();
496 private boolean writeJsonData(Object data, HttpURLConnection connection, ResponseHandler rh) throws IOException {
498 String dataStr = gson.toJson(data);
499 initAuthentication(connection);
500 writeData(connection, dataStr.getBytes("UTF-8"));
501 int responseCode = connection.getResponseCode();
502 String response = readStringResponse(connection);
504 rh = new DefaultResponseHandler();
507 return rh.checkResponse(responseCode, response);
510 private String readStringResponse(HttpURLConnection connection) throws IOException {
511 BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
513 StringBuilder builder = new StringBuilder();
514 while ((inputLine = reader.readLine()) != null) {
515 builder.append(inputLine);
517 String resultString = builder.toString();
522 private void setUpHttpConnection() {
525 String urlString = restContext.getResource();
526 URL url = new URL(urlString);
527 if (url.getProtocol().equals("http")) {
528 connection = (HttpURLConnection) url.openConnection();
531 if (url.getProtocol().equals("https")) {
532 connection = makeHttpsConnection(url);
535 } catch (Exception ex) {
536 throw new RuntimeException(ex);
544 * @throws CertificateException
545 * @throws IOException
546 * @throws KeyManagementException
547 * @throws NoSuchAlgorithmException
548 * @throws KeyStoreException
549 * @throws FileNotFoundException
551 private HttpURLConnection makeHttpsConnection(URL url) throws CertificateException, IOException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
552 if (keyStore == null) {
553 CertificateProvider certificateProvider = restContext.getCertificateProvider();
554 if (certificateProvider == null) {
555 throw new CertificateException("Need a certification provider");
557 Certificate ca = certificateProvider.getCertificate();
559 String keyStoreType = KeyStore.getDefaultType();
560 keyStore = KeyStore.getInstance(keyStoreType);
561 keyStore.load(null, null);
562 keyStore.setCertificateEntry("ca", ca);
564 // Create a TrustManager that trusts the CAs in our KeyStore
565 String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
566 tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
569 // Create an SSLContext that uses our TrustManager
570 context = SSLContext.getInstance("TLS");
571 context.init(null, tmf.getTrustManagers(), null);
574 // Tell the URLConnection to use a SocketFactory from our SSLContext
575 HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
576 urlConnection.setSSLSocketFactory(context.getSocketFactory());
578 if (!verifyHostName) {
579 HostnameVerifier hv = new HostnameVerifier() {
582 public boolean verify(String string, SSLSession ssls) {
586 urlConnection.setHostnameVerifier(hv);
589 return urlConnection;