diff --git a/.travis.yml b/.travis.yml index b04e191..1848f57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: java jdk: -- oraclejdk8 +- openjdk11 before_install: - chmod +x ./gradlew script: diff --git a/build.gradle b/build.gradle index 34485fe..db8de21 100644 --- a/build.gradle +++ b/build.gradle @@ -91,19 +91,18 @@ configurations { dependencies { compile group: 'com.mashape.unirest', name: 'unirest-java', version:'1.4.9' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version:'4.5.3' + compile group: 'org.apache.httpcomponents', name: 'httpclient', version:'4.5.9' compile group: 'org.json', name: 'json', version:'20160810' - compile group: 'com.google.code.gson', name: 'gson', version:'2.8.0' + compile group: 'com.google.code.gson', name: 'gson', version:'2.8.5' compile group: 'commons-beanutils', name: 'commons-beanutils', version:'1.9.3' - compile group: 'commons-io', name: 'commons-io', version:'2.5' - compile group: 'org.slf4j', name: 'slf4j-api', version:'1.7.25' + compile group: 'commons-io', name: 'commons-io', version:'2.6' + compile group: 'org.slf4j', name: 'slf4j-api', version:'1.7.26' testCompile group: 'junit', name: 'junit', version:'4.12' - testCompile group: 'commons-io', name: 'commons-io', version:'2.5' - testCompile group: 'com.github.tomakehurst', name: 'wiremock', version:'2.8.0' - testCompile group: 'org.slf4j', name: 'slf4j-jdk14', version:'1.7.25' + testCompile group: 'com.github.tomakehurst', name: 'wiremock', version:'2.23.2' + testCompile group: 'org.slf4j', name: 'slf4j-jdk14', version:'1.7.26' - codacy group: 'com.codacy', name: 'codacy-coverage-reporter', version: '1.0.13' + codacy 'com.github.codacy:codacy-coverage-reporter:-SNAPSHOT' } // custom tasks for creating source jar @@ -127,6 +126,7 @@ task sendCoverageToCodacy(type: JavaExec, dependsOn: jacocoTestReport) { main = "com.codacy.CodacyCoverageReporter" classpath = configurations.codacy args = [ + "report", "-l", "Java", "-r", @@ -135,7 +135,7 @@ task sendCoverageToCodacy(type: JavaExec, dependsOn: jacocoTestReport) { } task integrationTest(type: Test) { - testClassesDir = sourceSets.integrationTest.output.classesDir + testClassesDirs = project.sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath // This is not needed, but I like to see which tests have run testLogging { @@ -195,5 +195,5 @@ bintray { } } -integrationTest.mustRunAfter test +integrationTest.mustRunAfter test diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 6ffa237..778aa9b 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 038dd12..82acbe8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Apr 13 17:03:46 CEST 2017 +#Thu Jul 11 10:56:19 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip diff --git a/gradlew b/gradlew index 9aa616c..4453cce 100644 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -154,16 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then cd "$(dirname "$0")" fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/src/main/java/com/sybit/airtable/Table.java b/src/main/java/com/sybit/airtable/Table.java index 7c1e1bb..31bd032 100644 --- a/src/main/java/com/sybit/airtable/Table.java +++ b/src/main/java/com/sybit/airtable/Table.java @@ -26,6 +26,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; /** * Representation Class of Airtable Tables. @@ -197,6 +199,9 @@ public List select(final Query query) throws AirtableException { if (offset != null) { list.addAll(this.select(query, offset)); } + } else if (429 == code) { + randomWait(); + return select(query); } else { HttpResponseExceptionHandler.onResponse(response); list = null; @@ -205,6 +210,17 @@ public List select(final Query query) throws AirtableException { return list; } + /** + * Performs a sleep for random time period between 30 and 35 seconds + */ + private void randomWait() { + try { + TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(30, 36)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + /** * Get List by given offset. * @@ -491,6 +507,9 @@ public T find(final String id) throws AirtableException { if (200 == code) { body = response.getBody(); + } else if (429 == code) { + randomWait(); + return find(id); } else { HttpResponseExceptionHandler.onResponse(response); body = null; @@ -538,6 +557,9 @@ public T create(final T item) throws AirtableException, IllegalAccessException, if (200 == code) { responseBody = response.getBody(); + } else if (429 == code) { + randomWait(); + return create(item); } else { HttpResponseExceptionHandler.onResponse(response); } @@ -586,6 +608,9 @@ public T update(final T item) throws AirtableException, IllegalAccessException, if (200 == code) { responseBody = response.getBody(); + } else if (429 == code) { + randomWait(); + return update(item); } else { HttpResponseExceptionHandler.onResponse(response); } @@ -638,6 +663,9 @@ public boolean destroy(String id) throws AirtableException { if (200 == code) { Delete body = response.getBody(); isDeleted = body.isDeleted(); + } else if (429 == code) { + randomWait(); + return destroy(id); } else { isDeleted = false; HttpResponseExceptionHandler.onResponse(response); diff --git a/src/test/java/com/sybit/airtable/CustomObjectMapperTest.java b/src/test/java/com/sybit/airtable/CustomObjectMapperTest.java index f8b299d..8d840e4 100644 --- a/src/test/java/com/sybit/airtable/CustomObjectMapperTest.java +++ b/src/test/java/com/sybit/airtable/CustomObjectMapperTest.java @@ -12,9 +12,9 @@ import com.sybit.airtable.vo.Attachment; import com.sybit.airtable.vo.Thumbnail; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.commons.collections4.map.HashedMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Before; @@ -25,61 +25,61 @@ * @author fzr */ public class CustomObjectMapperTest { - + private ListConverter listConverter; private MapConverter mapConverter; - + @Before public void before(){ - + this.listConverter = new ListConverter(); this.mapConverter = new MapConverter(); - + } - + @Test public void listClassTest(){ - + listConverter.setListClass(Attachment.class); - assertEquals(listConverter.getListClass(),Attachment.class); + assertEquals(listConverter.getListClass(),Attachment.class); } - - @Test + + @Test public void mapClassTest(){ - + mapConverter.setMapClass(Thumbnail.class); assertEquals(mapConverter.getMapClass(),Thumbnail.class); } - + @Test public void convertListTest(){ - + listConverter.setListClass(Attachment.class); - + Class type = List.class; List value = new ArrayList(); - + LinkedTreeMap ltm = new LinkedTreeMap(); ltm.put("id","id0001"); ltm.put("url","http://test.com"); ltm.put("filename","filename.txt"); ltm.put("size","10"); ltm.put("type","image/jpeg"); - - Map thumbnails = new HashedMap<>(); + + Map thumbnails = new HashMap<>(); Thumbnail tmb = new Thumbnail(); - + tmb.setName("Thumbnail"); tmb.setUrl("http:example.com"); tmb.setWidth(Float.valueOf(10)); tmb.setHeight(Float.valueOf(10)); - + thumbnails.put("small", tmb); - + ltm.put("thumbnails",thumbnails); - + value.add(0, ltm); - + List list = (List) listConverter.convert(type, value); assertNotNull(list); assertNotNull(list.get(0).getId()); @@ -87,32 +87,32 @@ public void convertListTest(){ assertNotNull(list.get(0).getSize()); assertNotNull(list.get(0).getType()); assertNotNull(list.get(0).getUrl()); - assertNotNull(list.get(0).getThumbnails()); - + assertNotNull(list.get(0).getThumbnails()); + } - + @Test public void convertMapTest(){ - + mapConverter.setMapClass(Thumbnail.class); - + Class type = Map.class; - + LinkedTreeMap value = new LinkedTreeMap<>(); LinkedTreeMap innerMap = new LinkedTreeMap<>(); - + innerMap.put("url","http://example.com"); - value.put("small",innerMap); - - + value.put("small",innerMap); + + Map thumb = (Map) mapConverter.convert(type,value); System.out.println(thumb); assertNotNull(thumb); assertNotNull(thumb.get("small")); assertNotNull(thumb.get("small").getUrl()); - - - + + + } - + }