├── .travis.yml ├── src ├── main │ ├── resources │ │ └── props.properties │ ├── java │ │ └── threescale │ │ │ └── v3 │ │ │ └── api │ │ │ ├── package.html │ │ │ ├── impl │ │ │ ├── package.html │ │ │ ├── ParameterEncoder.java │ │ │ ├── ServerAccessorDriver.java │ │ │ └── ServiceApiDriver.java │ │ │ ├── example │ │ │ ├── package.html │ │ │ ├── TestKeys.java │ │ │ ├── Example.java │ │ │ └── AllCallsExample.java │ │ │ ├── ParameterMapType.java │ │ │ ├── ServerError.java │ │ │ ├── HttpResponse.java │ │ │ ├── ServerAccessor.java │ │ │ ├── ReportResponse.java │ │ │ ├── ServiceApi.java │ │ │ ├── UsageReport.java │ │ │ ├── ParameterMap.java │ │ │ └── AuthorizeResponse.java │ └── javadoc │ │ └── overview.html └── test │ └── java │ └── threescale │ └── v3 │ └── api │ ├── impl │ ├── ServiceAccessorDriverTest.java │ └── ParameterEncoderTest.java │ ├── ServiceApiDriverIntegrationTest.java │ └── ServiceApiDriverTest.java ├── .gitignore ├── LICENSE ├── release.sh ├── pom.xml └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | -------------------------------------------------------------------------------- /src/main/resources/props.properties: -------------------------------------------------------------------------------- 1 | MAVEN_PROJECT_VERSION=${project.version} -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/package.html: -------------------------------------------------------------------------------- 1 | Threescale Service API. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | *.iml 3 | .idea 4 | .classpath 5 | .project 6 | .settings 7 | /target/ 8 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/impl/package.html: -------------------------------------------------------------------------------- 1 | Implementation Classes 2 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/example/package.html: -------------------------------------------------------------------------------- 1 | 2 | Sample code for using the ServiceApi 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/ParameterMapType.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | /** 4 | * Enum for the type that can be stored in a ParameterMap. 5 | */ 6 | public enum ParameterMapType { 7 | STRING, MAP, ARRAY, LONG; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/ServerError.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | /** 4 | * Encapulates error information for a server operation. 5 | */ 6 | public class ServerError extends Exception { 7 | 8 | private static final long serialVersionUID = -5900004126517852322L; 9 | 10 | public ServerError(String reason) { 11 | super(reason); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/javadoc/overview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

This jar provides some interface classes for the 3Scale Service Api. Specifically it supports 4 | Authrep, Authorize and Report.

5 | 6 |

To use the code you create a ServiceApi object, build a ParameterMap with the values for the api call then call the 7 | appropriate method for the operation.

8 | 9 |

Each method call returns a response object that gives success or failure information.

10 | 11 |

See @see threescale.v3.api.example.Example for more details

12 | 13 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/example/TestKeys.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.example; 2 | 3 | /** 4 | * Edit this interface and replace the values with your live values to test the calls to the backend. 5 | */ 6 | public interface TestKeys { 7 | static String my_provider_key = ""; 8 | 9 | //App Id 10 | static String app_id = ""; 11 | static String app_key = ""; 12 | static String app_id_service_id = ""; 13 | 14 | //API Key 15 | static String user_key = ""; 16 | static String user_key_service_id = ""; 17 | 18 | // OAuth 19 | static String oauth_service_id = ""; 20 | static String oauth_app_id = ""; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/HttpResponse.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | /** 4 | * Returns the result of an Http GET / POST 5 | */ 6 | public class HttpResponse { 7 | 8 | private int status; 9 | private String body; 10 | 11 | /** 12 | * construct an HtmlResponse from the Http Status and Body Content 13 | * 14 | * @param status Http Status 15 | * @param body Http Body 16 | */ 17 | public HttpResponse(int status, String body) { 18 | this.status = status; 19 | this.body = body; 20 | } 21 | 22 | /** 23 | * Return the content 24 | * 25 | * @return body 26 | */ 27 | public String getBody() { 28 | return body; 29 | } 30 | 31 | /** 32 | * Get the Status. 33 | * 34 | * @return status. 35 | */ 36 | public int getStatus() { 37 | return status; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010 3scale networks S.L. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/ServerAccessor.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | /** 4 | * Interface to HTML operation between this client and the 3Scale Server 5 | */ 6 | public interface ServerAccessor { 7 | String X_3SCALE_USER_CLIENT_HEADER = "X-3scale-User-Agent"; 8 | String MAVEN_PROJECT_VERSION = "MAVEN_PROJECT_VERSION"; 9 | String X_3SCALE_USER_CLIENT_HEADER_JAVA_PLUGIN = "plugin-java-v"; 10 | 11 | /** 12 | * Perform and HTML GET with the provided URL 13 | * 14 | * @param url The URL and parameters to be sent 15 | * @return Status and content as a HtmlResponse 16 | * @throws ServerError If there are problems connection tp the server. 17 | */ 18 | public HttpResponse get(String url) throws ServerError; 19 | 20 | /** 21 | * Perform and HTML POST with the provided URL and form data 22 | * 23 | * @param url The URl to contact 24 | * @param data The data to be sent 25 | * @return Status and content as a HtmlResponse 26 | * @throws ServerError If there are problems connection tp the server. 27 | */ 28 | public HttpResponse post(String url, String data) throws ServerError; 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/threescale/v3/api/impl/ServiceAccessorDriverTest.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.impl; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import threescale.v3.api.HttpResponse; 10 | import threescale.v3.api.ServerAccessor; 11 | import threescale.v3.api.ServerError; 12 | 13 | /** 14 | * Unit Test class for the Service Api. 15 | */ 16 | 17 | public class ServiceAccessorDriverTest { 18 | private ServerAccessorDriver underTest = new ServerAccessorDriver();; 19 | 20 | 21 | @Before 22 | public void setup() { 23 | 24 | } 25 | 26 | @Test 27 | public void testClientHeader() { 28 | String actualClientHeader = underTest.getPluginHeaderValue(); 29 | Assert.assertNotNull(actualClientHeader); 30 | Assert.assertTrue(actualClientHeader.startsWith(ServerAccessor.X_3SCALE_USER_CLIENT_HEADER_JAVA_PLUGIN)); 31 | } 32 | 33 | //@Test 34 | public void testGet() throws ServerError { 35 | String testUrl = "http://requestb.in/1k27m9c1"; //inspect the headers at http://requestb.in/1k27m9c1?inspect 36 | 37 | HttpResponse response = underTest.get(testUrl); 38 | int status = response.getStatus(); 39 | assertEquals(status, 200); 40 | } 41 | 42 | //@Test 43 | public void testPost() throws ServerError { 44 | String testUrl = "http://requestb.in/1k27m9c1"; //inspect the headers at http://requestb.in/1k27m9c1?inspect 45 | 46 | HttpResponse response = underTest.post(testUrl, ""); 47 | int status = response.getStatus(); 48 | assertEquals(status, 200); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "" 3 | echo "######################################" 4 | echo " Releasing 3scale Java Plugin" 5 | echo "######################################" 6 | echo "" 7 | 8 | BRANCH=`git rev-parse --abbrev-ref HEAD` 9 | 10 | echo "** Current Branch: $BRANCH **" 11 | echo "" 12 | 13 | RELEASE_VERSION=$1 14 | DEV_VERSION=$2 15 | GPG_PASSPHRASE=$3 16 | 17 | if [ "x$RELEASE_VERSION" = "x" ] 18 | then 19 | read -p "Release Version: " RELEASE_VERSION 20 | fi 21 | 22 | if [ "x$DEV_VERSION" = "x" ] 23 | then 24 | read -p "New Development Version: " DEV_VERSION 25 | fi 26 | 27 | if [ "x$GPG_PASSPHRASE" = "x" ] 28 | then 29 | read -p "GPG Passphrase: " GPG_PASSPHRASE 30 | fi 31 | 32 | echo "######################################" 33 | echo "Release Version: $RELEASE_VERSION" 34 | echo "Dev Version: $DEV_VERSION" 35 | echo "######################################" 36 | 37 | rm -rf ~/.m2/repository/io/3scale 38 | mvn clean install 39 | STATUS=$? 40 | if [ $STATUS -eq 0 ]; then 41 | echo "Build success!" 42 | else 43 | echo "Build failed!" 44 | exit 1 45 | fi 46 | 47 | mvn versions:set -DnewVersion=$RELEASE_VERSION 48 | find . -name '*.versionsBackup' -exec rm -f {} \; 49 | git add . 50 | git commit -m "Prepare for release $RELEASE_VERSION" 51 | git push origin $BRANCH 52 | 53 | mvn clean install 54 | 55 | git tag -a -m "Tagging release $RELEASE_VERSION" v$RELEASE_VERSION 56 | git push origin v$RELEASE_VERSION 57 | 58 | mvn clean deploy -Prelease -Dgpg.passphrase=$GPG_PASSPHRASE 59 | 60 | mvn versions:set -DnewVersion=$DEV_VERSION 61 | find . -name '*.versionsBackup' -exec rm -f {} \; 62 | git add . 63 | git commit -m "Update to next development version: $DEV_VERSION" 64 | git push origin $BRANCH 65 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/example/Example.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.example; 2 | 3 | import threescale.v3.api.AuthorizeResponse; 4 | import threescale.v3.api.ParameterMap; 5 | import threescale.v3.api.ServerError; 6 | import threescale.v3.api.ServiceApi; 7 | import threescale.v3.api.impl.ServiceApiDriver; 8 | 9 | /** 10 | * Simple Example of using the API 11 | */ 12 | public class Example { 13 | 14 | public void performAuthRep() { 15 | 16 | ServiceApi serviceApi = new ServiceApiDriver("my_provider_key"); // Create the API object 17 | 18 | ParameterMap params = new ParameterMap(); // Create top level ParameterMap 19 | params.add("app_id", "appid"); // Set the Users App Id 20 | 21 | ParameterMap usage = new ParameterMap(); // Create 1st Level PM for usage 22 | usage.add("hits", "3"); // Add number of hits metric 23 | params.add("usage", usage); // Add 1st level to top level as "usage" 24 | 25 | try { 26 | final AuthorizeResponse response = serviceApi.authrep(params); // Perform the AuthRep and get the response 27 | 28 | if (response.success()) { // Check if the AuthRep succeeded 29 | // Perform your calls there 30 | } else { 31 | // Handle failure here 32 | } 33 | } catch (ServerError serverError) { 34 | // Thrown if there is a communications error with the server. 35 | serverError.printStackTrace(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/ReportResponse.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | import nu.xom.*; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * The response information from a Report operations. 9 | * success is true if the report succeeded. 10 | * success is false if it failed and the Error Code and Error Message fields will be populated. 11 | */ 12 | public class ReportResponse { 13 | private String errorCode = ""; 14 | private String errorMessage = ""; 15 | private boolean status = false; 16 | 17 | /** 18 | * Create a ReportResponse from an HTML POST 19 | * 20 | * @param response 21 | * @throws ServerError 22 | */ 23 | public ReportResponse(HttpResponse response) throws ServerError { 24 | if (response.getStatus() == 200 || response.getStatus() == 202) { 25 | status = true; 26 | } else { 27 | status = false; 28 | parseResponse(response); 29 | } 30 | } 31 | 32 | private void parseResponse(HttpResponse response) throws ServerError { 33 | try { 34 | Builder parser = new Builder(); 35 | Document doc = parser.build(response.getBody(), null); 36 | Element root = doc.getRootElement(); 37 | 38 | Attribute codeEl = root.getAttribute("code"); 39 | errorCode = codeEl.getValue(); 40 | errorMessage = root.getValue(); 41 | return; 42 | } catch (ParsingException ex) { 43 | throw new ServerError("The xml received was invalid: " + response.getBody()); 44 | } catch (IOException ex) { 45 | throw new ServerError("Unable process the XML"); 46 | } 47 | } 48 | 49 | /** 50 | * Return the Error Code 51 | * 52 | * @return error code 53 | */ 54 | public String getErrorCode() { 55 | return errorCode; 56 | } 57 | 58 | /** 59 | * Return the Error Message 60 | * 61 | * @return message 62 | */ 63 | public String getErrorMessage() { 64 | return errorMessage; 65 | } 66 | 67 | /** 68 | * Return success / failure 69 | * 70 | * @return true = success, false = failure 71 | */ 72 | public boolean success() { 73 | return status; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/ServiceApi.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | /** 4 | * Service API interface. 5 | */ 6 | public interface ServiceApi { 7 | String DEFAULT_HOST = "su1.3scale.net"; 8 | 9 | /** 10 | * Performs and AuthRep operation 11 | * 12 | * @param metrics The app_id and metrics for this authrep 13 | * @return Information about the success/failure of the operation and the current metrics 14 | * @throws ServerError Thrown if there is an error communicating with the 3Scale server 15 | */ 16 | public AuthorizeResponse authrep(ParameterMap metrics) throws ServerError; 17 | public AuthorizeResponse authrep(String serviceToken, String serviceId, ParameterMap metrics) 18 | throws ServerError; 19 | 20 | /** 21 | * Performs an Authorize 22 | * 23 | * @param parameters App_id etc for the authorize 24 | * @return Information about the success/failure of the operation 25 | * @throws ServerError Thrown if there is an error communicating with the 3Scale server 26 | */ 27 | public AuthorizeResponse authorize(ParameterMap parameters) throws ServerError; 28 | public AuthorizeResponse authorize(String serviceToken, String serviceId, ParameterMap parameters) 29 | throws ServerError; 30 | 31 | /** 32 | * Perform an Authorize using OAuth. 33 | * 34 | * @param params Parameters for the authorize 35 | * @return Information about the success/failure of the operation 36 | * @throws ServerError Thrown if there is an error communicating with the 3Scale server 37 | */ 38 | public AuthorizeResponse oauth_authorize(ParameterMap params) throws ServerError; 39 | public AuthorizeResponse oauth_authorize(String serviceToken, String serviceId, ParameterMap params) 40 | throws ServerError; 41 | 42 | /** 43 | * Report a set of metrics. Note: report differs from the rest of these methods in that a serviceId is 44 | * an argument. The reason for this is that it does not accept a root level ParameterMap argument, which is 45 | * normally how the serviceId would be passed. Instead, the root level ParameterMap is created by the 46 | * implementation, and so the serviceId cannot be included in it. 47 | * 48 | * @param transactions The metrics to be reported 49 | * @return Information about the success/failure of the operation 50 | * @throws ServerError Thrown if there is an error communicating with the 3Scale server 51 | */ 52 | public ReportResponse report(String serviceId, ParameterMap... transactions) throws ServerError; 53 | public ReportResponse report(String serviceToken, String serviceId, ParameterMap... transactions) throws ServerError; 54 | 55 | /** 56 | * Get the URL of the 3scale server 57 | * 58 | * @return Server url 59 | */ 60 | public String getHost(); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/UsageReport.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | /** 4 | * Usage information for an AuthRep or Authorize 5 | */ 6 | public class UsageReport { 7 | 8 | private String metric = ""; 9 | private String period = ""; 10 | private String periodStart = ""; 11 | private String periodEnd = ""; 12 | private String currentValue = ""; 13 | private String maxValue = ""; 14 | private boolean hasExceeded = false; 15 | 16 | /** 17 | * Create a UsageReport 18 | * 19 | * @param metric 20 | * @param period 21 | * @param periodStart 22 | * @param periodEnd 23 | * @param currentValue 24 | * @param maxValue 25 | * @param hasExceeded 26 | */ 27 | public UsageReport(String metric, String period, String periodStart, String periodEnd, String currentValue, String maxValue, String hasExceeded) { 28 | this.metric = metric; 29 | this.period = period; 30 | this.periodStart = periodStart; 31 | this.periodEnd = periodEnd; 32 | this.currentValue = currentValue; 33 | this.maxValue = maxValue; 34 | setHasExceeded(hasExceeded); 35 | } 36 | 37 | private void setHasExceeded(String hasExceeded) { 38 | if (hasExceeded.toLowerCase().equals("true")) { 39 | this.hasExceeded = true; 40 | } else { 41 | this.hasExceeded = false; 42 | } 43 | } 44 | 45 | /** 46 | * Get the Name of the Metric 47 | * 48 | * @return name 49 | */ 50 | public String getMetric() { 51 | return metric; 52 | } 53 | 54 | /** 55 | * Get the period of the metric 56 | * 57 | * @return 58 | */ 59 | public String getPeriod() { 60 | return period; 61 | } 62 | 63 | /** 64 | * Get the current value of the metric 65 | * 66 | * @return 67 | */ 68 | public String getCurrentValue() { 69 | return currentValue; 70 | } 71 | 72 | /** 73 | * Get the maximum value of the metric 74 | * 75 | * @return 76 | */ 77 | public String getMaxValue() { 78 | return maxValue; 79 | } 80 | 81 | /** 82 | * Get the start of period as a String 83 | * 84 | * @return YYYY-MM-DD HH:mm:SS +NNNN Year-Month-Day Hour:Minute:second Offset from UTC 85 | */ 86 | public String getPeriodStart() { 87 | return periodStart; 88 | } 89 | 90 | /** 91 | * Get the end of period as a String 92 | * 93 | * @return YYYY-MM-DD HH:mm:SS +NNNN Year-Month-Day Hour:Minute:second Offset from UTC 94 | */ 95 | public String getPeriodEnd() { 96 | return periodEnd; 97 | } 98 | 99 | /** 100 | * Returns the hasExceeded flag 101 | * 102 | * @return true if the metrics have been exceeded. 103 | */ 104 | public boolean hasExceeded() { 105 | return hasExceeded; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/threescale/v3/api/impl/ParameterEncoderTest.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.impl; 2 | 3 | import org.joda.time.DateTime; 4 | import org.joda.time.DateTimeZone; 5 | import org.joda.time.format.DateTimeFormat; 6 | import org.joda.time.format.DateTimeFormatter; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import threescale.v3.api.ParameterMap; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | /** 15 | * JUnit Test class 16 | */ 17 | public class ParameterEncoderTest { 18 | 19 | private ParameterEncoder encoder; 20 | DateTimeFormatter fmt; 21 | 22 | @Before 23 | public void setup() { 24 | encoder = new ParameterEncoder(); 25 | fmt = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss Z"); 26 | } 27 | 28 | @Test 29 | public void testEncodeOneParameter() throws Exception { 30 | ParameterMap param = new ParameterMap(); 31 | param.add("provider_key", "123abc"); 32 | 33 | assertEquals("provider_key=123abc", encoder.encode(param)); 34 | } 35 | 36 | @Test 37 | public void testEncodeTwoParameters() throws Exception { 38 | ParameterMap param = new ParameterMap(); 39 | param.add("provider_key", "123abc"); 40 | param.add("app_id", "3456aaa"); 41 | 42 | assertEquals("provider_key=123abc&app_id=3456aaa", encoder.encode(param)); 43 | } 44 | 45 | @Test 46 | public void testEncodeTwoParametersAndOneMap() throws Exception { 47 | ParameterMap param = new ParameterMap(); 48 | param.add("provider_key", "123abc"); 49 | param.add("app_id", "3456aaa"); 50 | 51 | ParameterMap usage = new ParameterMap(); 52 | usage.add("hits", "111"); 53 | param.add("usage", usage); 54 | 55 | assertEquals("provider_key=123abc&app_id=3456aaa&usage%5Bhits%5D=111", encoder.encode(param)); 56 | } 57 | 58 | @Test 59 | public void testEncodeTwoParametersAndTwoMap() throws Exception { 60 | ParameterMap param = new ParameterMap(); 61 | param.add("provider_key", "123abc"); 62 | param.add("app_id", "3456aaa"); 63 | 64 | ParameterMap usage = new ParameterMap(); 65 | usage.add("hits", "111"); 66 | usage.add("timestamp", fmt.print(new DateTime(2010, 4, 27, 15, 0, DateTimeZone.UTC))); 67 | param.add("usage", usage); 68 | 69 | 70 | assertEquals( 71 | "provider_key=123abc&app_id=3456aaa&usage%5Bhits%5D=111&usage%5Btimestamp%5D=2010-04-27%2015%3A00%3A00%20+0000", 72 | encoder.encode(param)); 73 | } 74 | 75 | @Test 76 | public void testEncodingAnArray() throws Exception { 77 | final String expected = 78 | "provider_key=1234abcd&" 79 | + "transactions%5B0%5D%5Bapp_id%5D=foo&" 80 | + "transactions%5B0%5D%5Btimestamp%5D=2010-04-27%2015%3A42%3A17%200200&" 81 | + "transactions%5B0%5D%5Busage%5D%5Bhits%5D=1&" 82 | + "transactions%5B1%5D%5Bapp_id%5D=bar&" 83 | + "transactions%5B1%5D%5Btimestamp%5D=2010-04-27%2015%3A55%3A12%200200&" 84 | + "transactions%5B1%5D%5Busage%5D%5Bhits%5D=1"; 85 | 86 | ParameterMap app1 = new ParameterMap(); 87 | app1.add("app_id", "foo"); 88 | app1.add("timestamp", "2010-04-27 15:42:17 0200"); 89 | 90 | ParameterMap usage1 = new ParameterMap(); 91 | usage1.add("hits", "1"); 92 | app1.add("usage", usage1); 93 | 94 | ParameterMap app2 = new ParameterMap(); 95 | app2.add("app_id", "bar"); 96 | app2.add("timestamp", "2010-04-27 15:55:12 0200"); 97 | 98 | ParameterMap usage2 = new ParameterMap(); 99 | usage2.add("hits", "1"); 100 | app2.add("usage", usage2); 101 | 102 | ParameterMap[] transactions = new ParameterMap[2]; 103 | transactions[0] = app1; 104 | transactions[1] = app2; 105 | 106 | ParameterMap params = new ParameterMap(); 107 | params.add("provider_key", "1234abcd"); 108 | params.add("transactions", transactions); 109 | 110 | assertEquals(expected, encoder.encode(params)); 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/ParameterMap.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.LinkedHashMap; 6 | import java.util.Set; 7 | 8 | /** 9 | * Hold a set of parameter and metrics for an AuthRep, Authorize, OAuth Authorize or Report. 10 | *

11 | * Each item consists of a name/value pair, where the value can be a String, An Array of ParameterMaps or another Parameter Map. 12 | *

13 | *

14 | * E.g. For an AuthRep: 15 | *

16 | * 17 | * ParameterMap params = new ParameterMap();
18 | * params.add("app_id", "app_1234");
19 | * ParameterMap usage = new ParameterMap();
20 | * usage.add("hits", "3");
21 | * params.add("usage", usage);
22 | * AuthorizeResponse response = serviceApi.authrep(params);
23 | *
24 | *

25 | * An example for a report might be: 26 | *

27 | * 28 | * ParameterMap params = new ParameterMap();
29 | * params.add("app_id", "foo");
30 | * params.add("timestamp", fmt.print(new DateTime(2010, 4, 27, 15, 0)));
31 | * ParameterMap usage = new ParameterMap();
32 | * usage.add("hits", "1");
33 | * params.add("usage", usage);
34 | * ReportResponse response = serviceApi.report(params);
35 | *
36 | */ 37 | public class ParameterMap { 38 | 39 | private HashMap data; 40 | 41 | /** 42 | * Construct and empty ParameterMap 43 | */ 44 | public ParameterMap() { 45 | // Note: use a linked hash map for more predictable serialization of the parameters (mostly for testing) 46 | data = new LinkedHashMap(); 47 | } 48 | 49 | /** 50 | * Add a string value 51 | * 52 | * @param key 53 | * @param value 54 | */ 55 | public void add(String key, String value) { 56 | data.put(key, value); 57 | } 58 | 59 | /** 60 | * Add another ParameterMap 61 | * 62 | * @param key 63 | * @param map 64 | */ 65 | public void add(String key, ParameterMap map) { 66 | data.put(key, map); 67 | } 68 | 69 | /** 70 | * Add an array of parameter maps 71 | * 72 | * @param key 73 | * @param array 74 | */ 75 | public void add(String key, ParameterMap[] array) { 76 | data.put(key, array); 77 | } 78 | 79 | /** 80 | * Return the keys in a ParameterMap 81 | * 82 | * @return 83 | */ 84 | public Set getKeys() { 85 | return data.keySet(); 86 | } 87 | 88 | /** 89 | * Get the type of data item associated with the key 90 | * 91 | * @param key 92 | * @return STRING, MAP, ARRAY 93 | */ 94 | public ParameterMapType getType(String key) { 95 | Class clazz = data.get(key).getClass(); 96 | if (clazz == String.class) { 97 | return ParameterMapType.STRING; 98 | } 99 | if (clazz == ParameterMap[].class) { 100 | return ParameterMapType.ARRAY; 101 | } 102 | if (clazz == ParameterMap.class) { 103 | return ParameterMapType.MAP; 104 | } 105 | if (clazz == Long.class) { 106 | return ParameterMapType.LONG; 107 | } 108 | throw new RuntimeException("Unknown object in parameters"); 109 | } 110 | 111 | /** 112 | * Get the String associated with a key 113 | * 114 | * @param key 115 | * @return 116 | */ 117 | public String getStringValue(String key) { 118 | switch (getType(key)) { 119 | case ARRAY: 120 | return Arrays.toString((ParameterMap[]) data.get(key)); 121 | case LONG: 122 | return Long.toString((Long) data.get(key)); 123 | case MAP: 124 | return ((ParameterMap) data.get(key)).toString(); // 125 | case STRING: 126 | return (String) data.get(key); 127 | } 128 | return null; 129 | } 130 | 131 | /** 132 | * Get the map associated with a key 133 | * 134 | * @param key 135 | * @return 136 | */ 137 | public ParameterMap getMapValue(String key) { 138 | return (ParameterMap) data.get(key); 139 | } 140 | 141 | /** 142 | * Get the array associated with a key. 143 | * 144 | * @param key 145 | * @return 146 | */ 147 | public ParameterMap[] getArrayValue(String key) { 148 | return (ParameterMap[]) data.get(key); 149 | } 150 | public long getLongValue(String key) { 151 | return (Long) data.get(key); 152 | } 153 | public void setLongValue(String key, long value) { 154 | data.put(key, value); 155 | } 156 | 157 | /** 158 | * Return the number of elements in the map. 159 | * 160 | * @return 161 | */ 162 | public int size() { 163 | return data.size(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/impl/ParameterEncoder.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.impl; 2 | 3 | import threescale.v3.api.ParameterMap; 4 | 5 | /** 6 | * Encodes a ParameterMap as a string suitable for sending as part of an HTML request. 7 | */ 8 | public class ParameterEncoder { 9 | 10 | /** 11 | * Takes the parameter map and returns an encoded string. 12 | * 13 | * @param params Parameter map to encode 14 | * @return Encoded string 15 | */ 16 | public String encode(ParameterMap params) { 17 | StringBuilder result = new StringBuilder(); 18 | 19 | int index = 0; 20 | for (String mapKey : params.getKeys()) { 21 | if (index != 0) result.append("&"); 22 | switch (params.getType(mapKey)) { 23 | case STRING: 24 | result.append(emitNormalValue(mapKey, params.getStringValue(mapKey))); 25 | break; 26 | case MAP: 27 | result.append(emitNormalMap(mapKey, params.getMapValue(mapKey))); 28 | break; 29 | case ARRAY: 30 | result.append(emitNormalArray(mapKey, params.getArrayValue(mapKey))); 31 | break; 32 | case LONG: 33 | result.append(emitNormalValue(mapKey, Long.toString(params.getLongValue(mapKey)))); 34 | break; 35 | default: 36 | break; 37 | } 38 | index++; 39 | } 40 | 41 | return substituteCharacters(result.toString()); 42 | } 43 | 44 | private String emitNormalArray(String mapKey, ParameterMap[] mapValue) { 45 | StringBuilder b = new StringBuilder(); 46 | int index = 0; 47 | 48 | for (ParameterMap arrayMap : mapValue) { 49 | if (index != 0) b.append("&"); 50 | b.append(emitArray(mapKey, arrayMap, index)); 51 | index++; 52 | } 53 | return b.toString(); 54 | } 55 | 56 | private String emitArray(String mapKey, ParameterMap arrayMap, int arrayIndex) { 57 | StringBuilder b = new StringBuilder(); 58 | int index = 0; 59 | 60 | for (String key : arrayMap.getKeys()) { 61 | switch (arrayMap.getType(key)) { 62 | case STRING: 63 | if (index != 0) b.append("&"); 64 | b.append(mapKey).append("[").append(arrayIndex).append("]"); 65 | b.append("[").append(key).append("]=").append(arrayMap.getStringValue(key)); 66 | index++; 67 | break; 68 | case MAP: 69 | ParameterMap map = arrayMap.getMapValue(key); 70 | for (String itemKey : map.getKeys()) { 71 | if (index != 0) b.append("&"); 72 | b.append(emitArrayValue(mapKey, key, itemKey, map.getStringValue(itemKey), arrayIndex)); 73 | index++; 74 | } 75 | break; 76 | case ARRAY: 77 | // TODO does ARRAY need to be handled? 78 | break; 79 | case LONG: 80 | break; 81 | default: 82 | break; 83 | } 84 | } 85 | return b.toString(); 86 | } 87 | 88 | private String emitArrayValue(String mapKey, String key, String itemKey, String stringValue, int index) { 89 | StringBuilder b = new StringBuilder(); 90 | b.append(mapKey).append("[").append(index).append("]"); 91 | b.append("[").append(key).append("]"); 92 | b.append("[").append(itemKey).append("]=").append(stringValue); 93 | return b.toString(); 94 | } 95 | 96 | private String emitNormalMap(String mapKey, ParameterMap mapValue) { 97 | StringBuilder b = new StringBuilder(); 98 | int index = 0; 99 | for (String key : mapValue.getKeys()) { 100 | if (index != 0) b.append("&"); 101 | switch (mapValue.getType(key)) { 102 | case LONG: 103 | b.append(emitMapValue(mapKey, key, Long.toString(mapValue.getLongValue(key)))); 104 | break; 105 | case STRING: 106 | b.append(emitMapValue(mapKey, key, mapValue.getStringValue(key))); 107 | break; 108 | case MAP: 109 | // TODO does MAP need to be handled? 110 | break; 111 | case ARRAY: 112 | // TODO does ARRAY need to be handled? 113 | break; 114 | } 115 | index++; 116 | } 117 | return b.toString(); 118 | } 119 | 120 | private String emitMapValue(String mapKey, String key, String stringValue) { 121 | StringBuilder b = new StringBuilder(); 122 | b.append(mapKey).append("[").append(key).append("]=").append(stringValue); 123 | return b.toString(); 124 | } 125 | 126 | private String emitNormalValue(String key, String value) { 127 | StringBuilder b = new StringBuilder(); 128 | b.append(key).append("=").append(value); 129 | return b.toString(); 130 | } 131 | 132 | private String substituteCharacters(String input) { 133 | return input.replace(" ", "%20").replace("[", "%5B").replace("]", "%5D").replace("#", "%23").replace(":", "%3A"); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/test/java/threescale/v3/api/ServiceApiDriverIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import org.joda.time.format.DateTimeFormat; 6 | import org.joda.time.format.DateTimeFormatter; 7 | import org.junit.Before; 8 | 9 | import threescale.v3.api.example.TestKeys; 10 | import threescale.v3.api.impl.ServiceApiDriver; 11 | 12 | /** 13 | * Integration Test class for the ServiceApiDriver. Currently only tests 14 | * the authrep and report methods and assumes your service uses a user_key 15 | * Assumes your API has 2 methods getHello and getGoodbye, with getHello 16 | * mapped under Hits 17 | * Set your 3 data items (TestKeys.my_provider_key, TestKeys.user_key_service_id, 18 | * TestKeys.user_key) before running 19 | * Optional: rename the methods below to your own (necessary if your methods are named/configured differently) 20 | * Run each test individually and examine the Metrics before and after on your 21 | * Services overview page in the admin site 22 | 23 | 24 | TODO add tests for the other ServiceApiDriver methods and test the other authentication methods 25 | */ 26 | 27 | public class ServiceApiDriverIntegrationTest { 28 | private final String provider_key = TestKeys.my_provider_key; 29 | 30 | private ServiceApi serviceApi; 31 | // private ServerAccessor htmlServer; 32 | 33 | DateTimeFormatter fmt; 34 | ParameterMap params; 35 | 36 | @Before 37 | public void setup() { 38 | serviceApi = new ServiceApiDriver(provider_key); 39 | 40 | fmt = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss Z"); 41 | 42 | params = new ParameterMap(); 43 | params.add("service_id", TestKeys.user_key_service_id); 44 | params.add("user_key", TestKeys.user_key); 45 | 46 | } 47 | 48 | //@Test 49 | // URL Pattern: [usage][hits]=1 50 | // Expected: OK results in Hits incrementing by 1 51 | public void testAuthrepNullUsageAndUserKey() throws ServerError { 52 | 53 | AuthorizeResponse auresp = serviceApi.authrep(params); 54 | reportResult(auresp); 55 | } 56 | 57 | 58 | 59 | //@Test 60 | // URL Pattern: [usage][hits]=1 61 | // Expected: OK results in Hits incrementing by 1 62 | public void testAuthrepEmptyUsageAndUserKey() throws ServerError { 63 | 64 | ParameterMap usage = new ParameterMap(); 65 | params.add("usage", usage); 66 | 67 | AuthorizeResponse auresp = serviceApi.authrep(params); 68 | reportResult(auresp); 69 | } 70 | 71 | 72 | //@Test 73 | // URL Pattern: [usage][getHello]=2 74 | // EXPECTED: Success; hits +2 75 | public void testAuthrepUsageWithNestedMethodAndUserKey() throws ServerError { 76 | ParameterMap usage = new ParameterMap(); 77 | usage.add("getHello", "2"); 78 | params.add("usage", usage); 79 | 80 | AuthorizeResponse auresp = serviceApi.authrep(params); 81 | reportResult(auresp); 82 | 83 | } 84 | 85 | //@Test 86 | // URL Pattern: [usage][hits]=3&[usage][getHello]=2 87 | // EXPECTED: Success; hits +5 88 | public void testAuthrepUsageWithNestedMethodAndHitsAndUserKey() throws ServerError { 89 | 90 | ParameterMap usage = new ParameterMap(); 91 | usage.add("getHello", "2"); 92 | usage.add("hits", "3"); 93 | params.add("usage", usage); 94 | 95 | AuthorizeResponse auresp = serviceApi.authrep(params); 96 | reportResult(auresp); 97 | 98 | } 99 | 100 | 101 | //@Test 102 | // URL Pattern: [usage][getGoodbye]=4 103 | // EXPECTED: Success; hits unchanged, getGoodbye +4 104 | public void testAuthrepUsageWithNonNestedMethodAndUserKey() throws ServerError { 105 | 106 | ParameterMap usage = new ParameterMap(); 107 | usage.add("getGoodbye", "4"); 108 | params.add("usage", usage); 109 | 110 | AuthorizeResponse auresp = serviceApi.authrep(params); 111 | reportResult(auresp); 112 | 113 | } 114 | 115 | //@Test 116 | // URL Pattern: [usage][hits]=1 117 | // Expected: OK results in Hits incrementing by 1 118 | public void test_successful_report() throws ServerError { 119 | 120 | 121 | ParameterMap usage = new ParameterMap(); 122 | usage.add("hits", "1"); 123 | params.add("usage", usage); 124 | 125 | ReportResponse response = serviceApi.report(TestKeys.user_key_service_id, params); 126 | 127 | assertTrue(response.success()); 128 | } 129 | 130 | 131 | //@Test 132 | // Expected: success 133 | public void testAuthorizeWithEternityPeriod() throws ServerError { 134 | 135 | AuthorizeResponse response = serviceApi.authorize(params); 136 | 137 | assertTrue(response.success()); 138 | 139 | } 140 | 141 | 142 | //@Test 143 | // URL http://requestb.in/1k27m9c1 144 | // In order to visually examine the request headers in a POST 145 | // 146 | public void testPostToRequestBin() throws ServerError { 147 | 148 | AuthorizeResponse auresp = serviceApi.authrep(params); 149 | reportResult(auresp); 150 | } 151 | 152 | 153 | 154 | //@Test 155 | // URL http://requestb.in/1k27m9c1 156 | // In order to visually examine the request headers in a GET 157 | // 158 | public void testGetToRequestBin() throws ServerError { 159 | //String url = "http://requestb.in/1k27m9c1; 160 | 161 | ServiceApiDriver localServiceApiDriver = new ServiceApiDriver("provider_key", "http://requestb.in"); 162 | 163 | localServiceApiDriver.authorize(new ParameterMap()); 164 | 165 | //reportResult(auresp); 166 | } 167 | 168 | 169 | 170 | 171 | 172 | 173 | //******************************************************************* 174 | private void reportResult(AuthorizeResponse auresp){ 175 | boolean success = auresp.success(); 176 | if (success){ 177 | System.out.println("Success"); 178 | } 179 | else{ 180 | System.out.println("Fail: "+auresp.getReason()); 181 | } 182 | 183 | }; 184 | 185 | } 186 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/impl/ServerAccessorDriver.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.impl; 2 | 3 | import threescale.v3.api.HttpResponse; 4 | import threescale.v3.api.ServerAccessor; 5 | import threescale.v3.api.ServerError; 6 | 7 | import java.io.*; 8 | import java.net.HttpURLConnection; 9 | import java.net.MalformedURLException; 10 | import java.net.URL; 11 | 12 | import java.util.Properties; 13 | /** 14 | * Performs GET's and POST's against the live 3Scale Server 15 | */ 16 | public class ServerAccessorDriver implements ServerAccessor { 17 | 18 | private Properties props; 19 | private String pluginHeaderValue; 20 | private String defaultVersion = "3.1"; 21 | public ServerAccessorDriver() { 22 | 23 | 24 | props = new Properties(); 25 | try { 26 | InputStream in = ServerAccessorDriver.class.getClassLoader().getResourceAsStream("props.properties"); 27 | if (in == null) { 28 | System.out.println("props.properties not found"); 29 | } 30 | else{ 31 | props.load(in); 32 | defaultVersion = props.getProperty(MAVEN_PROJECT_VERSION); 33 | } 34 | 35 | 36 | } catch (Exception e) { 37 | System.out.println(e); 38 | } 39 | pluginHeaderValue = X_3SCALE_USER_CLIENT_HEADER_JAVA_PLUGIN+defaultVersion; 40 | 41 | } 42 | 43 | /** 44 | * @param urlParams url + parameter string 45 | * @return Http Response 46 | * @throws ServerError 47 | * @see ServerAccessor 48 | */ 49 | public HttpResponse get(final String urlParams) throws ServerError { 50 | HttpURLConnection connection = null; 51 | URL url; 52 | 53 | try { 54 | url = new URL(urlParams); 55 | } catch (MalformedURLException ex) { 56 | throw new RuntimeException(ex); 57 | } 58 | 59 | try { 60 | connection = (HttpURLConnection) url.openConnection(); 61 | connection.setRequestMethod("GET"); 62 | connection.setDoOutput(true); 63 | connection.setReadTimeout(10000); 64 | connection.setRequestProperty("Accept-Charset", "UTF-8"); 65 | connection.setRequestProperty(X_3SCALE_USER_CLIENT_HEADER, pluginHeaderValue); 66 | 67 | connection.connect(); 68 | 69 | 70 | return new HttpResponse(connection.getResponseCode(), getBody(connection.getInputStream())); 71 | 72 | } catch (IOException ex) { 73 | try { 74 | return new HttpResponse(connection.getResponseCode(), getBody(connection.getErrorStream())); 75 | } catch (IOException e) { 76 | throw new ServerError(e.getMessage()); 77 | } catch (NullPointerException npe) { 78 | throw new ServerError("NullPointerException thrown ServerAccessorDriver::get, urlParams were "+urlParams); 79 | } 80 | } catch (NullPointerException npe) { 81 | throw new ServerError("NullPointerException thrown ServerAccessorDriver::get, urlParams were "+urlParams); 82 | } finally { 83 | if (connection != null) { 84 | connection.disconnect(); 85 | } 86 | } 87 | } 88 | 89 | private String getBody(InputStream content) throws IOException { 90 | BufferedReader rd; 91 | StringBuilder sb; 92 | String line; 93 | rd = new BufferedReader(new InputStreamReader(content)); 94 | sb = new StringBuilder(); 95 | 96 | while ((line = rd.readLine()) != null) { 97 | sb.append(line + '\n'); 98 | } 99 | return sb.toString(); 100 | } 101 | 102 | /** 103 | * @param urlParams url to access 104 | * @param data The data to be sent 105 | * @return Response from the server 106 | * @throws ServerError 107 | * @see ServerAccessor 108 | */ 109 | public HttpResponse post(final String urlParams,final String data) throws ServerError { 110 | HttpURLConnection connection = null; 111 | OutputStreamWriter wr; 112 | URL url; 113 | 114 | try { 115 | url = new URL(urlParams); 116 | } catch (MalformedURLException ex) { 117 | throw new RuntimeException(ex); 118 | } 119 | try { 120 | connection = (HttpURLConnection) url.openConnection(); 121 | connection.setRequestMethod("POST"); 122 | connection.setDoOutput(true); 123 | connection.setReadTimeout(10000); 124 | connection.setRequestProperty("Accept", "*/*"); 125 | connection.setRequestProperty("Accept-Charset", "UTF-8"); 126 | connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 127 | connection.setRequestProperty(X_3SCALE_USER_CLIENT_HEADER, pluginHeaderValue); 128 | 129 | 130 | connection.connect(); 131 | wr = new OutputStreamWriter(connection.getOutputStream()); 132 | wr.write(data); 133 | wr.flush(); 134 | 135 | return new HttpResponse(connection.getResponseCode(), getBody(connection.getInputStream())); 136 | } catch (IOException ex) { 137 | try { 138 | return new HttpResponse(connection.getResponseCode(), 139 | (connection.getErrorStream() == null) ? getBody(connection.getInputStream()) : getBody(connection.getErrorStream())); 140 | } catch (IOException e) { 141 | throw new ServerError(e.getMessage()); 142 | } catch (NullPointerException npe) { 143 | throw new ServerError("NullPointerException thrown ServerAccessorDriver::post, urlParams were "+urlParams+", data was "+data); 144 | } 145 | } catch (NullPointerException npe) { 146 | throw new ServerError("NullPointerException thrown ServerAccessorDriver::post, urlParams were "+urlParams+", data was "+data); 147 | }finally { 148 | if (connection != null) { 149 | connection.disconnect(); 150 | } 151 | } 152 | } 153 | 154 | public String getPluginHeaderValue() { 155 | return pluginHeaderValue; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | net.3scale 5 | 3scale-api 6 | 3.0.5-SNAPSHOT 7 | 8 | 3scale Java API 9 | 10 | This API is used to encapsulate the communication with the 3scale backend server for validating and 11 | reporting transactions between the user and the provider of a service 12 | 13 | https://www.3scale.net/ 14 | 15 | 16 | 17 | MIT 18 | http://creativecommons.org/licenses/MIT/ 19 | 20 | 21 | 22 | 23 | 24 | Andrew Mackenzie 25 | andrew@3scale.net 26 | 3scale 27 | http://www.3scale.net 28 | 29 | 30 | 31 | 32 | GitHub 33 | https://github.com/3scale/3scale_ws_api_for_java/issues 34 | 35 | 36 | 37 | https://github.com/3scale/3scale_ws_api_for_java 38 | scm:git:git@github.com:3scale/3scale_ws_api_for_java.git 39 | scm:git:git@github.com:3scale/3scale_ws_api_for_java.git 40 | 41 | 42 | 43 | 1.6 44 | 1.6 45 | UTF-8 46 | 47 | 48 | 49 | 50 | 51 | central 52 | Central Repository 53 | http://repo.maven.apache.org/maven2 54 | 55 | true 56 | 57 | 58 | false 59 | 60 | 61 | 62 | snapshots-repo 63 | https://oss.sonatype.org/content/repositories/snapshots 64 | 65 | false 66 | 67 | 68 | true 69 | 70 | 71 | 72 | jboss-public-repository-group 73 | JBoss Public Repository Group 74 | http://repository.jboss.org/nexus/content/groups/public 75 | default 76 | 77 | true 78 | never 79 | 80 | 81 | true 82 | daily 83 | 84 | 85 | 86 | 87 | 88 | 89 | ossrh 90 | https://oss.sonatype.org/content/repositories/snapshots 91 | 92 | 93 | 94 | 95 | 96 | xom 97 | xom 98 | 1.2.5 99 | 100 | 101 | 102 | 103 | joda-time 104 | joda-time 105 | 2.3 106 | test 107 | 108 | 109 | org.hamcrest 110 | hamcrest-core 111 | 1.2 112 | test 113 | 114 | 115 | org.jmock 116 | jmock-junit4 117 | 2.6.0 118 | test 119 | 120 | 121 | junit 122 | junit 123 | 4.13.1 124 | test 125 | 126 | 127 | 128 | 129 | 130 | 131 | true 132 | src/main/resources 133 | 134 | 135 | 136 | 137 | org.apache.maven.plugins 138 | maven-compiler-plugin 139 | 3.1 140 | 141 | ${maven.compile.source} 142 | ${maven.compile.source} 143 | 144 | 145 | 146 | org.apache.maven.plugins 147 | maven-javadoc-plugin 148 | 2.9.1 149 | 150 | 151 | attach-javadocs 152 | 153 | jar 154 | 155 | 156 | 157 | 158 | 159 | org.apache.maven.plugins 160 | maven-source-plugin 161 | 3.0.1 162 | 163 | 164 | attach-sources 165 | 166 | jar-no-fork 167 | 168 | 169 | 170 | 171 | 172 | org.apache.maven.plugins 173 | maven-surefire-plugin 174 | 2.16 175 | 176 | 177 | org.apache.maven.plugins 178 | maven-surefire-report-plugin 179 | 2.16 180 | 181 | 182 | 183 | 184 | 185 | 186 | release 187 | 188 | 189 | 190 | org.sonatype.plugins 191 | nexus-staging-maven-plugin 192 | 1.6.7 193 | true 194 | 195 | ossrh 196 | https://oss.sonatype.org/ 197 | true 198 | 199 | 200 | 201 | org.apache.maven.plugins 202 | maven-gpg-plugin 203 | 1.6 204 | 205 | 206 | sign-artifacts 207 | verify 208 | 209 | sign 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | java8 219 | 220 | [1.8,) 221 | 222 | 223 | 224 | 225 | org.apache.maven.plugins 226 | maven-javadoc-plugin 227 | 228 | -Xdoclint:none 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/example/AllCallsExample.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.example; 2 | 3 | import threescale.v3.api.*; 4 | import threescale.v3.api.impl.*; 5 | 6 | 7 | /** 8 | * Simple Example of using the API 9 | */ 10 | public class AllCallsExample implements TestKeys { 11 | 12 | public static void main(String[] args) { 13 | 14 | runUserKey(); 15 | runAppId(); 16 | runOAuth(); 17 | } 18 | 19 | /** 20 | * Example code for calls on user key (API key) mode 21 | */ 22 | private static void runUserKey() { 23 | ServiceApi serviceApi = new ServiceApiDriver(my_provider_key); // Create the API object 24 | 25 | ParameterMap params = new ParameterMap(); 26 | params.add("user_key", user_key); // Add keys for authrep or authorize 27 | params.add("service_id", user_key_service_id); 28 | 29 | ParameterMap usage = new ParameterMap(); // Add a metric 30 | usage.add("hits", "1"); 31 | 32 | params.add("usage", usage); 33 | 34 | AuthorizeResponse response = null; 35 | // the 'preferred way': authrep 36 | try { 37 | response = serviceApi.authrep(params); 38 | System.out.println("AuthRep on User Key Success: " + response.success()); 39 | if (response.success() == false) { 40 | System.out.println("Error: " + response.getErrorCode()); 41 | System.out.println("Reason: " + response.getReason()); 42 | } 43 | System.out.println("Plan: " + response.getPlan()); 44 | } catch (ServerError serverError) { 45 | serverError.printStackTrace(); 46 | } 47 | 48 | // the '2 steps way': authorize + report 49 | try { 50 | response = serviceApi.authorize(params); 51 | System.out.println("Authorize on User Key Success: " + response.success()); 52 | if (response.success() == false) { 53 | System.out.println("Error: " + response.getErrorCode()); 54 | System.out.println("Reason: " + response.getReason()); 55 | } else { 56 | 57 | // the API call got authorized, let's do a report 58 | ParameterMap transaction = new ParameterMap(); 59 | transaction.add("user_key", user_key); 60 | 61 | ParameterMap transaction_usage = new ParameterMap(); 62 | transaction_usage.add("hits", "1"); 63 | transaction.add("usage", transaction_usage); 64 | 65 | try { 66 | final ReportResponse report_response = serviceApi.report(user_key_service_id, transaction); 67 | 68 | if (report_response.success()) { 69 | System.out.println("Report on User Key was successful"); 70 | } else { 71 | System.out.println("Report on User Key failed"); 72 | } 73 | } catch (ServerError serverError) { 74 | serverError.printStackTrace(); 75 | } 76 | 77 | } 78 | System.out.println("Plan: " + response.getPlan()); 79 | 80 | } catch (ServerError serverError) { 81 | serverError.printStackTrace(); 82 | } 83 | } 84 | 85 | /** 86 | * Example code for calls on App Id mode 87 | */ 88 | private static void runAppId() { 89 | ServiceApi serviceApi = new ServiceApiDriver(my_provider_key); // Create the API object 90 | 91 | ParameterMap params = new ParameterMap(); 92 | params.add("app_id", app_id); // Add app_id for authrep or authorize 93 | params.add("app_key", app_key); // Add key for authrep or authorize 94 | params.add("service_id", app_id_service_id); 95 | 96 | ParameterMap usage = new ParameterMap(); // Add a metric 97 | usage.add("hits", "1"); 98 | 99 | params.add("usage", usage); 100 | 101 | AuthorizeResponse response = null; 102 | // the 'preferred way': authrep 103 | try { 104 | response = serviceApi.authrep(params); 105 | System.out.println("AuthRep on App Id Success: " + response.success()); 106 | if (response.success() == false) { 107 | System.out.println("Error: " + response.getErrorCode()); 108 | System.out.println("Reason: " + response.getReason()); 109 | } 110 | System.out.println("Plan: " + response.getPlan()); 111 | } catch (ServerError serverError) { 112 | serverError.printStackTrace(); 113 | } 114 | 115 | // the '2 steps way': authorize + report 116 | try { 117 | response = serviceApi.authorize(params); 118 | System.out.println("Authorize on App Id Success: " + response.success()); 119 | if (response.success() == false) { 120 | System.out.println("Error: " + response.getErrorCode()); 121 | System.out.println("Reason: " + response.getReason()); 122 | } else { 123 | 124 | // the API call got authorized, let's do a report 125 | ParameterMap transaction = new ParameterMap(); 126 | transaction.add("app_id", app_id); 127 | 128 | ParameterMap transaction_usage = new ParameterMap(); 129 | transaction_usage.add("hits", "1"); 130 | transaction.add("usage", transaction_usage); 131 | 132 | try { 133 | final ReportResponse report_response = serviceApi.report(app_id_service_id, transaction); 134 | 135 | if (report_response.success()) { 136 | System.out.println("Report on App Id was successful"); 137 | } else { 138 | System.out.println("Report on App Id failed"); 139 | } 140 | } catch (ServerError serverError) { 141 | serverError.printStackTrace(); 142 | } 143 | 144 | } 145 | System.out.println("Plan: " + response.getPlan()); 146 | 147 | } catch (ServerError serverError) { 148 | serverError.printStackTrace(); 149 | } 150 | } 151 | 152 | /** 153 | * Example code for an OAuth authorize 154 | */ 155 | private static void runOAuth() { 156 | ServiceApi serviceApi = new ServiceApiDriver(my_provider_key); // Create the API object 157 | 158 | ParameterMap params = new ParameterMap(); 159 | params.add("app_id", oauth_app_id); 160 | params.add("service_id", oauth_service_id); 161 | 162 | // for OAuth only the '2 steps way' is available 163 | try { 164 | AuthorizeResponse response = serviceApi.oauth_authorize(params); // Perform OAuth authorize 165 | System.out.println("Authorize on OAuth Success: " + response.success()); 166 | if (response.success() == false) { 167 | System.out.println("Error: " + response.getErrorCode()); 168 | System.out.println("Reason: " + response.getReason()); 169 | } else { 170 | 171 | // you check the client's secret returned 172 | System.out.println("OAuth Client Secret: " + response.getClientSecret()); 173 | 174 | // the API call got authorized, let's do a report 175 | ParameterMap transaction = new ParameterMap(); 176 | transaction.add("app_id", oauth_app_id); 177 | 178 | ParameterMap transaction_usage = new ParameterMap(); 179 | transaction_usage.add("hits", "1"); 180 | transaction.add("usage", transaction_usage); 181 | 182 | try { 183 | final ReportResponse report_response = serviceApi.report(oauth_service_id, transaction); 184 | 185 | if (report_response.success()) { 186 | System.out.println("Report on OAuth was successful"); 187 | } else { 188 | System.out.println("Report on OAuth failed"); 189 | } 190 | } catch (ServerError serverError) { 191 | serverError.printStackTrace(); 192 | } 193 | 194 | } 195 | System.out.println("Plan: " + response.getPlan()); 196 | } catch (ServerError serverError) { 197 | serverError.printStackTrace(); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/AuthorizeResponse.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | import nu.xom.*; 4 | 5 | import java.io.IOException; 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * Provides information about the success or failure of an Authorize operation. 10 | *

11 | * The success response sets: 12 | * the Status (true = success false = exceeded/failed) 13 | * the Reason if failed. 14 | * the Plan 15 | * the ClientSecret 16 | * the redirect URL 17 | * the Usage reports 18 | *

19 | * The failure response sets: 20 | * the ErrorCode 21 | * Reason. 22 | */ 23 | public class AuthorizeResponse { 24 | 25 | private boolean status = false; 26 | private String plan = ""; 27 | private String clientSecret = ""; 28 | private UsageReport[] usageReports = new UsageReport[0]; 29 | private String reason = ""; 30 | private String errorCode = ""; 31 | private String redirectUrl = ""; 32 | 33 | /** 34 | * Build an AuthorizeResponse using the status and content of an html get. 35 | * 36 | * @param httpStatus Status value from the GET 37 | * @param httpContent Contents of the GET 38 | * @throws ServerError If the received XML is invalid, or cannot process the XML 39 | */ 40 | public AuthorizeResponse(int httpStatus, String httpContent) throws ServerError { 41 | if (httpStatus == 200 || httpStatus == 409) { 42 | createAuthorizedOKOrExceeded(httpContent); 43 | } else { 44 | createAuthorizationFailed(httpContent); 45 | } 46 | } 47 | 48 | /** 49 | * Create a failure response. 50 | * 51 | * @param httpContent 52 | * @throws ServerError 53 | */ 54 | private void createAuthorizationFailed(String httpContent) throws ServerError { 55 | try { 56 | Builder parser = new Builder(); 57 | Document doc = parser.build(httpContent, null); 58 | Element root = doc.getRootElement(); 59 | 60 | final Attribute codeEl = root.getAttribute("code"); 61 | setErrorCode(codeEl.getValue()); 62 | setReason(root.getValue()); 63 | setStatus("false"); 64 | 65 | } catch (ParsingException ex) { 66 | throw new ServerError("The xml received was invalid: " + httpContent); 67 | } catch (IOException ex) { 68 | throw new ServerError("Error processing the XML"); 69 | } 70 | } 71 | 72 | /** 73 | * Creates a success response 74 | * 75 | * @param httpContent 76 | * @throws ServerError 77 | */ 78 | private void createAuthorizedOKOrExceeded(String httpContent) throws ServerError { 79 | try { 80 | Builder parser = new Builder(); 81 | Document doc = parser.build(httpContent, null); 82 | Element root = doc.getRootElement(); 83 | 84 | Element authorizedEl = root.getFirstChildElement("authorized"); 85 | setStatus(authorizedEl.getValue()); 86 | if (success() == false) { 87 | Element reasonEl = root.getFirstChildElement("reason"); 88 | if (reasonEl != null) { 89 | setReason(reasonEl.getValue()); 90 | } 91 | } 92 | 93 | Element planEl = root.getFirstChildElement("plan"); 94 | setPlan(planEl.getValue()); 95 | 96 | Element applicationEl = root.getFirstChildElement("application"); 97 | if (applicationEl != null) { 98 | Element keyEl = applicationEl.getFirstChildElement("key"); 99 | if (keyEl != null) { 100 | setClientSecret(keyEl.getValue()); 101 | } 102 | 103 | Element redirectUrlEl = applicationEl.getFirstChildElement("redirect_url"); 104 | if (redirectUrlEl != null) { 105 | setRedirectUrl(redirectUrlEl.getValue()); 106 | } 107 | } else { 108 | clientSecret = ""; 109 | redirectUrl = ""; 110 | } 111 | ArrayList reports = new ArrayList(); 112 | Element usageReportsEl = root.getFirstChildElement("usage_reports"); 113 | if (usageReportsEl != null) { 114 | Elements usageReports = usageReportsEl.getChildElements("usage_report"); 115 | for (int upindex = 0; upindex < usageReports.size(); upindex++) { 116 | processUsageReport(reports, usageReports.get(upindex)); 117 | } 118 | } 119 | setUsageReports(reports); 120 | return; 121 | } catch (ParsingException ex) { 122 | throw new ServerError("The xml received was invalid: " + httpContent); 123 | } catch (IOException ex) { 124 | throw new ServerError("Error processing the XML"); 125 | } 126 | } 127 | 128 | /** 129 | * Parse and build a usage report. 130 | * 131 | * @param reports 132 | * @param usageEl 133 | */ 134 | private void processUsageReport(ArrayList reports, Element usageEl) { 135 | final Attribute metricEl = usageEl.getAttribute("metric"); 136 | final Attribute periodEl = usageEl.getAttribute("period"); 137 | final Attribute exceededEl = usageEl.getAttribute("exceeded"); 138 | final Element periodStartEl = usageEl.getFirstChildElement("period_start"); 139 | final Element periodEndEl = usageEl.getFirstChildElement("period_end"); 140 | final Element currentValue = usageEl.getFirstChildElement("current_value"); 141 | final Element maxValue = usageEl.getFirstChildElement("max_value"); 142 | 143 | reports.add(new UsageReport(getValueOrBlank(metricEl), getValueOrBlank(periodEl), 144 | getValueOrBlank(periodStartEl), getValueOrBlank(periodEndEl), 145 | getValueOrBlank(currentValue), getValueOrBlank(maxValue), 146 | (exceededEl == null) ? "false" : exceededEl.getValue() 147 | )); 148 | } 149 | 150 | 151 | /** 152 | * Get the name of the Plan 153 | * 154 | * @return Plan name 155 | */ 156 | public String getPlan() { 157 | return plan; 158 | } 159 | 160 | private void setPlan(String plan) { 161 | this.plan = plan; 162 | } 163 | 164 | /** 165 | * Get the ClientSecret 166 | * 167 | * @return app key 168 | */ 169 | public String getClientSecret() { 170 | return clientSecret; 171 | } 172 | 173 | private void setClientSecret(String clientSecret) { 174 | this.clientSecret = clientSecret; 175 | } 176 | 177 | /** 178 | * Get the redirect url 179 | * 180 | * @return redirect url 181 | */ 182 | public String getRedirectUrl() { 183 | return redirectUrl; 184 | } 185 | 186 | /** 187 | * Get the usage reports for this authoize 188 | * 189 | * @return 190 | */ 191 | public UsageReport[] getUsageReports() { 192 | return usageReports; 193 | } 194 | 195 | private void setUsageReports(ArrayList reports) { 196 | usageReports = new UsageReport[reports.size()]; 197 | usageReports = reports.toArray(new UsageReport[0]); 198 | } 199 | 200 | /** 201 | * Get the status 202 | * 203 | * @return true / false 204 | */ 205 | public boolean success() { 206 | return status; 207 | } 208 | 209 | /** 210 | * Get the error code 211 | * 212 | * @return error code 213 | */ 214 | public String getErrorCode() { 215 | return errorCode; 216 | } 217 | 218 | private void setErrorCode(String code) { 219 | errorCode = code; 220 | } 221 | 222 | /** 223 | * Get the reason for the failure 224 | * 225 | * @return reason 226 | */ 227 | public String getReason() { 228 | return reason; 229 | } 230 | 231 | private void setStatus(String status) { 232 | if (status.toLowerCase().equals("true")) { 233 | this.status = true; 234 | } else { 235 | this.status = false; 236 | } 237 | } 238 | 239 | private void setReason(String reason) { 240 | this.reason = reason; 241 | } 242 | 243 | private void setRedirectUrl(String url) { 244 | this.redirectUrl = url; 245 | } 246 | 247 | private String getValueOrBlank(Attribute attr) { 248 | if (attr == null) { 249 | return ""; 250 | } else { 251 | return attr.getValue(); 252 | } 253 | } 254 | 255 | private String getValueOrBlank(Element element) { 256 | if (element == null) { 257 | return ""; 258 | } else { 259 | return element.getValue(); 260 | } 261 | } 262 | 263 | 264 | } 265 | -------------------------------------------------------------------------------- /src/main/java/threescale/v3/api/impl/ServiceApiDriver.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api.impl; 2 | 3 | import threescale.v3.api.*; 4 | 5 | /** 6 | * Concrete implementation of the ServiceApi. 7 | * 8 | * @see ServiceApi 9 | */ 10 | public class ServiceApiDriver implements ServiceApi { 11 | 12 | /** 13 | * Creates a Service Api with default settings. This will communicate with the 3scale 14 | * platform SaaS default server. 15 | */ 16 | public static ServiceApi createApi() { 17 | return ServiceApiDriver.createApi(ServiceApi.DEFAULT_HOST, 443, true); 18 | } 19 | 20 | /** 21 | * Creates a Service Api for the given host. Use this method when connecting to an on-premise 22 | * instance of the 3scale platform. 23 | */ 24 | public static ServiceApi createApi(String host, int port, boolean useHttps) { 25 | ServiceApiDriver driver = new ServiceApiDriver(); 26 | driver.host = host + ":" + port; 27 | driver.useHttps = useHttps; 28 | return driver; 29 | } 30 | 31 | private String provider_key = null; 32 | private String host = DEFAULT_HOST; 33 | private boolean useHttps = false; 34 | // private String redirect_url = "http://localhost:8080/oauth/oauth_redirect"; 35 | 36 | private ServerAccessor server = null; 37 | 38 | public ServiceApiDriver() { 39 | this.server = new ServerAccessorDriver(); 40 | } 41 | 42 | /** 43 | * @deprecated Instead of using a provider_key, use service tokens. See static constructor methods: createApi(). 44 | */ 45 | @Deprecated 46 | public ServiceApiDriver(String provider_key) { 47 | this.provider_key = provider_key; 48 | this.server = new ServerAccessorDriver(); 49 | } 50 | 51 | /** 52 | * @deprecated Instead of using a provider_key, use service tokens. See static constructor methods: createApi(). 53 | */ 54 | @Deprecated 55 | public ServiceApiDriver(String provider_key, boolean useHttps) { 56 | this.provider_key = provider_key; 57 | this.useHttps = useHttps; 58 | this.server = new ServerAccessorDriver(); 59 | } 60 | 61 | /** 62 | * @deprecated Instead of using a provider_key, use service tokens. See static constructor methods: createApi(). 63 | */ 64 | @Deprecated 65 | public ServiceApiDriver(String provider_key, String host) { 66 | this.provider_key = provider_key; 67 | this.host = host; 68 | this.server = new ServerAccessorDriver(); 69 | } 70 | 71 | /** 72 | * @deprecated Instead of using a provider_key, use service tokens. See static constructor methods: createApi(). 73 | */ 74 | @Deprecated 75 | public ServiceApiDriver(String provider_key, String host, boolean useHttps) { 76 | this.provider_key = provider_key; 77 | this.host = host; 78 | this.useHttps = useHttps; 79 | this.server = new ServerAccessorDriver(); 80 | } 81 | 82 | /* (non-Javadoc) 83 | * @see threescale.v3.api.ServiceApi#authrep(threescale.v3.api.ParameterMap) 84 | */ 85 | public AuthorizeResponse authrep(ParameterMap metrics) throws ServerError { 86 | if (this.provider_key != null) { 87 | metrics.add("provider_key", provider_key); 88 | } 89 | 90 | ParameterMap usage = metrics.getMapValue("usage"); 91 | 92 | if (usage == null || usage.size()==0) { 93 | if (usage == null) { 94 | usage = new ParameterMap(); 95 | metrics.add("usage", usage); 96 | } 97 | usage.add("hits", "1"); 98 | } 99 | String urlParams = encodeAsString(metrics); 100 | 101 | final String s = getFullHostUrl() + "/transactions/authrep.xml?" + urlParams; 102 | // System.out.println("Actual: " + s); 103 | 104 | HttpResponse response = server.get(s); 105 | if (response.getStatus() == 500) { 106 | throw new ServerError(response.getBody()); 107 | } 108 | return convertXmlToAuthorizeResponse(response); 109 | } 110 | 111 | /* (non-Javadoc) 112 | * @see threescale.v3.api.ServiceApi#authrep(java.lang.String, java.lang.String, threescale.v3.api.ParameterMap) 113 | */ 114 | public AuthorizeResponse authrep(String serviceToken, String serviceId, ParameterMap metrics) throws ServerError { 115 | if (serviceToken != null) { 116 | metrics.add("service_token", serviceToken); 117 | } 118 | if (serviceId != null) { 119 | metrics.add("service_id", serviceId); 120 | } 121 | return authrep(metrics); 122 | } 123 | 124 | /* (non-Javadoc) 125 | * @see threescale.v3.api.ServiceApi#report(java.lang.String, java.lang.String, threescale.v3.api.ParameterMap[]) 126 | */ 127 | public ReportResponse report(String serviceToken, String serviceId, ParameterMap... transactions) 128 | throws ServerError { 129 | if (transactions == null || transactions.length == 0) 130 | throw new IllegalArgumentException("No transactions provided"); 131 | 132 | ParameterMap params = new ParameterMap(); 133 | if (this.provider_key != null) { 134 | params.add("provider_key", provider_key); 135 | } 136 | if (serviceToken != null) { 137 | params.add("service_token", serviceToken); 138 | } 139 | if (serviceId != null) { 140 | params.add("service_id", serviceId); 141 | } 142 | params.add("transactions", transactions); 143 | 144 | HttpResponse response = server.post(getFullHostUrl() + "/transactions.xml", encodeAsString(params)); 145 | if (response.getStatus() == 500) { 146 | throw new ServerError(response.getBody()); 147 | } 148 | return new ReportResponse(response); 149 | } 150 | 151 | @Override 152 | public ReportResponse report(String serviceId, ParameterMap... transactions) throws ServerError { 153 | return this.report(null, serviceId, transactions); 154 | } 155 | 156 | /* (non-Javadoc) 157 | * @see threescale.v3.api.ServiceApi#authorize(threescale.v3.api.ParameterMap) 158 | */ 159 | public AuthorizeResponse authorize(ParameterMap parameters) throws ServerError { 160 | if (this.provider_key != null) { 161 | parameters.add("provider_key", provider_key); 162 | } 163 | String urlParams = encodeAsString(parameters); 164 | 165 | final String s = getFullHostUrl() + "/transactions/authorize.xml?" + urlParams; 166 | HttpResponse response = server.get(s); 167 | if (response.getStatus() == 500) { 168 | throw new ServerError(response.getBody()); 169 | } 170 | return convertXmlToAuthorizeResponse(response); 171 | } 172 | 173 | @Override 174 | public AuthorizeResponse authorize(String serviceToken, String serviceId, ParameterMap parameters) 175 | throws ServerError { 176 | if (serviceToken != null) { 177 | parameters.add("service_token", serviceToken); 178 | } 179 | if (serviceId != null) { 180 | parameters.add("service_id", serviceId); 181 | } 182 | return authorize(parameters); 183 | } 184 | 185 | public String getHost() { 186 | return host; 187 | } 188 | 189 | /* (non-Javadoc) 190 | * @see threescale.v3.api.ServiceApi#oauth_authorize(threescale.v3.api.ParameterMap) 191 | */ 192 | public AuthorizeResponse oauth_authorize(ParameterMap params) throws ServerError { 193 | if (this.provider_key != null) { 194 | params.add("provider_key", provider_key); 195 | } 196 | 197 | String urlParams = encodeAsString(params); 198 | 199 | final String s = getFullHostUrl() + "/transactions/oauth_authorize.xml?" + urlParams; 200 | // System.out.println("Actual: " + s); 201 | 202 | HttpResponse response = server.get(s); 203 | if (response.getStatus() == 500) { 204 | throw new ServerError(response.getBody()); 205 | } 206 | return convertXmlToAuthorizeResponse(response); 207 | } 208 | 209 | /* (non-Javadoc) 210 | * @see threescale.v3.api.ServiceApi#oauth_authorize(java.lang.String, java.lang.String, threescale.v3.api.ParameterMap) 211 | */ 212 | public AuthorizeResponse oauth_authorize(String serviceToken, String serviceId, ParameterMap params) 213 | throws ServerError { 214 | if (serviceToken != null) { 215 | params.add("service_token", serviceToken); 216 | } 217 | if (serviceId != null) { 218 | params.add("service_id", serviceId); 219 | } 220 | return oauth_authorize(params); 221 | } 222 | 223 | private String getFullHostUrl() { 224 | 225 | return useHttps ? "https://" + getHost() : "http://" + getHost(); 226 | } 227 | 228 | 229 | public String encodeAsString(ParameterMap params) { 230 | ParameterEncoder encoder = new ParameterEncoder(); 231 | return encoder.encode(params); 232 | } 233 | 234 | 235 | private AuthorizeResponse convertXmlToAuthorizeResponse(HttpResponse res) throws ServerError { 236 | return new AuthorizeResponse(res.getStatus(), res.getBody()); 237 | } 238 | 239 | 240 | public ServiceApiDriver setServer(ServerAccessor server) { 241 | this.server = server; 242 | return this; 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://secure.travis-ci.org/3scale/3scale_ws_api_for_java.png?branch=master)](http://travis-ci.org/3scale/3scale_ws_api_for_java) 2 | 3 | 3scale is an API Infrastructure service which handles API Keys, Rate Limiting, Analytics, Billing Payments and Developer Management. Includes a configurable API dashboard and developer portal CMS. More product stuff at http://www.3scale.net/, support information at http://support.3scale.net/. 4 | 5 | Plugin Versions 6 | =============== 7 | 8 | This is the version 3 of the plugin, if you were using this plugin before March 8th 2013, you are using the old [version 2](https://github.com/3scale/3scale_ws_api_for_java/tree/v2) of it, but we strongly recommend you to port your code to this new simpler version. 9 | 10 | Synopsis 11 | ======== 12 | 13 | This plugin supports the 3 main calls to the 3scale backend: 14 | 15 | - *authrep* grants access to your API and reports the traffic on it in one call. 16 | - *authorize* grants access to your API. 17 | - *report* reports traffic on your API. 18 | 19 | 3scale supports 3 authentication modes: App Id, User Key and OAuth. The first two are similar on their calls to the backend, they support *authrep*. OAuth differs in its usage two calls are required: first *authorize* then *report*. 20 | 21 | Install 22 | ======= 23 | 24 | This is a [Maven](http://maven.apache.org/) project, to add it to your project you can use one of the following options: 25 | - add a dependency to this artifact inside your `pom.xml` like below (specify the version you need): 26 | ``` 27 | 28 | net.3scale 29 | 3scale-api 30 | 3.0.4 31 | 32 | ``` 33 | and run `mvn install` inside your project. 34 | 35 | - download the [JAR file](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22net.3scale%22%20AND%20a%3A%223scale-api%22) for the version you want to use and install it to your repository using the instructions described here: http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html 36 | 37 | 38 | Usage on App Id auth mode 39 | ========================= 40 | 41 | On App Id mode you call *authrep* to: grant access to your API, and also report the traffic on it at the same time. 42 | 43 | ```java 44 | // import the 3scale library into your code 45 | import threescale.v3.api.*; 46 | import threescale.v3.api.impl.*; 47 | 48 | // ... somewhere inside your code 49 | 50 | // Create the API object with default settings. This will communicate with the 3scale platform SaaS default server. 51 | ServiceApi serviceApi = ServiceApiDriver.createApi(); 52 | 53 | // When connecting to an on-premise instance of the 3scale platform, create the API object for a given host and port: 54 | // ServiceApi serviceApi = ServiceApiDriver.createApi("backend.example.com", 80, true); 55 | 56 | 57 | ParameterMap params = new ParameterMap(); // the parameters of your call 58 | params.add("app_id", "your_app_id"); // Add app_id of your application for authorization 59 | params.add("app_key", "your_app_key"); // Add app_key of your application for authorization 60 | 61 | String serviceToken = ...; // Your 3scale service token 62 | String serviceId = ...; // The service id of your application 63 | 64 | ParameterMap usage = new ParameterMap(); // Add a metric to the call 65 | usage.add("hits", "1"); 66 | params.add("usage", usage); // metrics belong inside the usage parameter 67 | 68 | AuthorizeResponse response = null; 69 | // the 'preferred way' of calling the backend: authrep 70 | try { 71 | response = serviceApi.authrep(serviceToken, serviceId, params); 72 | System.out.println("AuthRep on App Id Success: " + response.success()); 73 | if (response.success() == true) { 74 | // your api access got authorized and the traffic added to 3scale backend 75 | System.out.println("Plan: " + response.getPlan()); 76 | } else { 77 | // your api access did not authorized, check why 78 | System.out.println("Error: " + response.getErrorCode()); 79 | System.out.println("Reason: " + response.getReason()); 80 | } 81 | } catch (ServerError serverError) { 82 | serverError.printStackTrace(); 83 | } 84 | ``` 85 | 86 | Usage on API Key auth mode 87 | ========================== 88 | 89 | On API Key mode you call *authrep* to: grant access to your API, and also report the traffic on it at the same time. 90 | 91 | ```java 92 | // import the 3scale library into your code 93 | import threescale.v3.api.*; 94 | import threescale.v3.api.impl.*; 95 | 96 | // ... somewhere inside your code 97 | 98 | // Create the API object with default settings. This will communicate with the 3scale platform SaaS default server. 99 | ServiceApi serviceApi = ServiceApiDriver.createApi(); 100 | 101 | // When connecting to an on-premise instance of the 3scale platform, create the API object for a given host and port: 102 | //ServiceApi serviceApi = ServiceApiDriver.createApi("backend.example.com", 80, true); 103 | 104 | ParameterMap params = new ParameterMap(); // the parameters of your call 105 | params.add("user_key", "your_user_key"); // Add the user key of your application for authorization 106 | 107 | String serviceToken = ...; // Your 3scale service token 108 | String serviceId = ...; // The service id for your user key 109 | 110 | ParameterMap usage = new ParameterMap(); // Add a metric to the call 111 | usage.add("hits", "1"); 112 | params.add("usage", usage); // metrics belong inside the usage parameter 113 | 114 | AuthorizeResponse response = null; 115 | // the 'preferred way' of calling the backend: authrep 116 | try { 117 | response = serviceApi.authrep(serviceToken, serviceId, params); 118 | System.out.println("AuthRep on User Key Success: " + response.success()); 119 | if (response.success() == true) { 120 | // your api access got authorized and the traffic added to 3scale backend 121 | System.out.println("Plan: " + response.getPlan()); 122 | } else { 123 | // your api access did not authorized, check why 124 | System.out.println("Error: " + response.getErrorCode()); 125 | System.out.println("Reason: " + response.getReason()); 126 | } 127 | } catch (ServerError serverError) { 128 | serverError.printStackTrace(); 129 | } 130 | ``` 131 | 132 | Usage on OAuth auth mode 133 | ========================== 134 | 135 | On OAuth you have to make two calls, first *authorize* to grant access to your API and then *report* the traffic on it. 136 | 137 | ```java 138 | // import the 3scale library into your code 139 | import threescale.v3.api.*; 140 | import threescale.v3.api.impl.*; 141 | 142 | // ... somewhere inside your code 143 | 144 | // Create the API object with default settings. This will communicate with the 3scale platform SaaS default server. 145 | ServiceApi serviceApi = ServiceApiDriver.createApi(); 146 | 147 | // When connecting to an on-premise instance of the 3scale platform, create the API object for a given host and port: 148 | //ServiceApi serviceApi = ServiceApiDriver.createApi("backend.example.com", 80, true); 149 | 150 | ParameterMap params = new ParameterMap(); // the parameters of your call 151 | params.add("app_id", "your_oauth_app_id"); // Add the app_id of your application for authorization 152 | 153 | String serviceToken = ...; // Your 3scale service token 154 | String serviceId = ...; // The service id of your application 155 | 156 | ParameterMap usage = new ParameterMap(); // Add a metric to the call 157 | usage.add("hits", "1"); 158 | params.add("usage", usage); // metrics belong inside the usage parameter 159 | 160 | // for OAuth only the '2 steps way' (authorize + report) is available 161 | try { 162 | AuthorizeResponse response = serviceApi.oauth_authorize(serviceToken, serviceId, params); // Perform OAuth authorize 163 | System.out.println("Authorize on OAuth Success: " + response.success()); 164 | if (response.success() == true) { 165 | 166 | // your api access got authorized 167 | 168 | // you check the client's secret returned by the backend 169 | System.out.println("OAuth Client Secret: " + response.getClientSecret()); 170 | 171 | // let's do a report 172 | ParameterMap transaction = new ParameterMap(); 173 | transaction.add("app_id", "your_oauth_app_id"); 174 | 175 | ParameterMap transaction_usage = new ParameterMap(); 176 | transaction_usage.add("hits", "1"); 177 | transaction.add("usage", transaction_usage); 178 | 179 | try { 180 | final ReportResponse report_response = serviceApi.report("your_oauth_service_id", transaction); 181 | 182 | if (report_response.success()) { 183 | System.out.println("Report on OAuth was successful"); 184 | } else { 185 | System.out.println("Report on OAuth failed"); 186 | } 187 | } catch (ServerError serverError) { 188 | serverError.printStackTrace(); 189 | } 190 | } else { 191 | // your api access did not got authorized, check why 192 | System.out.println("Error: " + response.getErrorCode()); 193 | System.out.println("Reason: " + response.getReason()); 194 | } 195 | } catch (ServerError serverError) { 196 | serverError.printStackTrace(); 197 | } 198 | ``` 199 | 200 | To test 201 | ======= 202 | 203 | To test the plugin with your real data: 204 | - edit the interface [TestKeys](https://github.com/3scale/3scale_ws_api_for_java/blob/master/src/main/java/threescale/v3/api/example/TestKeys.java) and put in there your provider key as well as service ids and apps auth fields 205 | - run [AllCallsExample](https://github.com/3scale/3scale_ws_api_for_java/blob/master/src/main/java/threescale/v3/api/example/AllCallsExample.java) class 206 | -------------------------------------------------------------------------------- /src/test/java/threescale/v3/api/ServiceApiDriverTest.java: -------------------------------------------------------------------------------- 1 | package threescale.v3.api; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import org.hamcrest.Description; 11 | import org.hamcrest.TypeSafeMatcher; 12 | import org.jmock.Expectations; 13 | import org.jmock.integration.junit4.JUnitRuleMockery; 14 | import org.joda.time.DateTime; 15 | import org.joda.time.DateTimeZone; 16 | import org.joda.time.format.DateTimeFormat; 17 | import org.joda.time.format.DateTimeFormatter; 18 | import org.junit.Before; 19 | import org.junit.Rule; 20 | import org.junit.Test; 21 | 22 | import threescale.v3.api.impl.ServiceApiDriver; 23 | 24 | /** 25 | * Test class for the Service Api. 26 | */ 27 | 28 | public class ServiceApiDriverTest { 29 | 30 | @Rule 31 | public JUnitRuleMockery context = new JUnitRuleMockery(); 32 | 33 | private final String host = ServiceApi.DEFAULT_HOST; 34 | private final String provider_key = "1234abcd"; 35 | 36 | private ServiceApi serviceApi; 37 | private ServerAccessor htmlServer; 38 | 39 | DateTimeFormatter fmt; 40 | 41 | @Before 42 | public void setup() { 43 | htmlServer = context.mock(ServerAccessor.class); 44 | serviceApi = new ServiceApiDriver(provider_key).setServer(htmlServer); 45 | 46 | fmt = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss Z"); 47 | } 48 | 49 | @Test 50 | public void test_default_host() { 51 | serviceApi = new ServiceApiDriver(); 52 | 53 | assertEquals("su1.3scale.net", serviceApi.getHost()); 54 | } 55 | 56 | @Test 57 | public void test_custom_host() { 58 | serviceApi = new ServiceApiDriver("1234abcd", "example.com"); 59 | 60 | assertEquals("example.com", serviceApi.getHost()); 61 | } 62 | 63 | @Test 64 | public void test_authrep_usage_is_encoded() throws ServerError { 65 | assertAuthrepUrlWithParams("usage%5Bmethod%5D=666"); 66 | 67 | ParameterMap params = new ParameterMap(); 68 | ParameterMap usage = new ParameterMap(); 69 | usage.add("method", "666"); 70 | params.add("usage", usage); 71 | 72 | serviceApi.authrep(params); 73 | } 74 | 75 | @Test 76 | public void test_authrep_usage_values_are_encoded() throws ServerError { 77 | 78 | assertAuthrepUrlWithParams("usage%5Bhits%5D=%230"); 79 | 80 | ParameterMap params = new ParameterMap(); 81 | ParameterMap usage = new ParameterMap(); 82 | usage.add("hits", "#0"); 83 | params.add("usage", usage); 84 | 85 | serviceApi.authrep(params); 86 | } 87 | 88 | @Test 89 | public void test_authrep_usage_defaults_to_hits_1() throws ServerError { 90 | 91 | assertAuthrepUrlWithParams("usage%5Bhits%5D=1&app_id=appid"); 92 | 93 | ParameterMap params = new ParameterMap(); 94 | params.add("app_id", "appid"); 95 | 96 | serviceApi.authrep(params); 97 | } 98 | 99 | @Test 100 | public void test_authrep_supports_app_id_app_key_auth_mode() throws ServerError { 101 | assertAuthrepUrlWithParams("usage%5Bhits%5D=1&app_key=appkey&app_id=appid"); 102 | 103 | ParameterMap params = new ParameterMap(); 104 | params.add("app_id", "appid"); 105 | params.add("app_key", "appkey"); 106 | serviceApi.authrep(params); 107 | } 108 | 109 | @Test 110 | public void test_successful_authrep_with_app_keys() throws ServerError { 111 | final String body = "" + 112 | "true" + 113 | "Ultimate" + 114 | ""; 115 | 116 | context.checking(new UrlWithParamsExpectations() {{ 117 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/authrep.xml?provider_key=1234abcd&usage%5Bhits%5D=1&app_key=toosecret&app_id=foo")); 118 | will(returnValue(new HttpResponse(200, body))); 119 | }}); 120 | 121 | ParameterMap params = new ParameterMap(); 122 | params.add("app_id", "foo"); 123 | params.add("app_key", "toosecret"); 124 | 125 | AuthorizeResponse response = serviceApi.authrep(params); 126 | assertTrue(response.success()); 127 | } 128 | 129 | 130 | @Test 131 | public void test_successful_authorize() throws ServerError { 132 | final String body = "" + 133 | "true" + 134 | "Ultimate" + 135 | "" + 136 | " " + 137 | " 2010-04-26 00:00:00 +0000" + 138 | " 2010-04-27 00:00:00 +0000" + 139 | " 10023" + 140 | " 50000" + 141 | " " + 142 | 143 | " " + 144 | " 2010-04-01 00:00:00 +0000" + 145 | " 2010-05-01 00:00:00 +0000" + 146 | " 999872" + 147 | " 150000" + 148 | " " + 149 | " " + 150 | ""; 151 | 152 | context.checking(new UrlWithParamsExpectations() {{ 153 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/authorize.xml?provider_key=1234abcd&app_id=foo")); 154 | will(returnValue(new HttpResponse(200, body))); 155 | }}); 156 | 157 | ParameterMap params = new ParameterMap(); 158 | params.add("app_id", "foo"); 159 | AuthorizeResponse response = serviceApi.authorize(params); 160 | 161 | assertTrue(response.success()); 162 | assertEquals("Ultimate", response.getPlan()); 163 | assertEquals(2, response.getUsageReports().length); 164 | 165 | assertEquals("day", response.getUsageReports()[0].getPeriod()); 166 | assertEquals(fmt.print(new DateTime(2010, 4, 26, 00, 00, DateTimeZone.UTC)), response.getUsageReports()[0].getPeriodStart()); 167 | assertEquals(fmt.print(new DateTime(2010, 4, 27, 00, 00, DateTimeZone.UTC)), response.getUsageReports()[0].getPeriodEnd()); 168 | assertEquals("10023", response.getUsageReports()[0].getCurrentValue()); 169 | assertEquals("50000", response.getUsageReports()[0].getMaxValue()); 170 | 171 | assertEquals("month", response.getUsageReports()[1].getPeriod()); 172 | assertEquals(fmt.print(new DateTime(2010, 4, 1, 0, 0, DateTimeZone.UTC)), response.getUsageReports()[1].getPeriodStart()); 173 | assertEquals(fmt.print(new DateTime(2010, 5, 1, 0, 0, DateTimeZone.UTC)), response.getUsageReports()[1].getPeriodEnd()); 174 | assertEquals("999872", response.getUsageReports()[1].getCurrentValue()); 175 | assertEquals("150000", response.getUsageReports()[1].getMaxValue()); 176 | } 177 | 178 | @Test 179 | public void test_successful_authorize_with_app_keys() throws ServerError { 180 | final String body = "" + 181 | "true" + 182 | "Ultimate" + 183 | ""; 184 | 185 | context.checking(new UrlWithParamsExpectations() {{ 186 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/authorize.xml?provider_key=1234abcd&app_key=toosecret&app_id=foo")); 187 | will(returnValue(new HttpResponse(200, body))); 188 | }}); 189 | 190 | ParameterMap params = new ParameterMap(); 191 | params.add("app_id", "foo"); 192 | params.add("app_key", "toosecret"); 193 | 194 | AuthorizeResponse response = serviceApi.authorize(params); 195 | assertTrue(response.success()); 196 | } 197 | 198 | @Test 199 | public void test_authorize_with_exceeded_usage_limits() throws ServerError { 200 | final String body = "" + 201 | "false" + 202 | "usage limits are exceeded" + 203 | 204 | "Ultimate" + 205 | 206 | "" + 207 | " " + 208 | " 2010-04-26 00:00:00 +0000" + 209 | " 2010-04-27 00:00:00 +0000" + 210 | " 50002" + 211 | " 50000" + 212 | "" + 213 | 214 | "" + 215 | " 2010-04-01 00:00:00 +0000" + 216 | " 2010-05-01 00:00:00 +0000" + 217 | " 999872" + 218 | " 150000" + 219 | "" + 220 | "" + 221 | ""; 222 | 223 | 224 | context.checking(new UrlWithParamsExpectations() {{ 225 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/authorize.xml?provider_key=1234abcd&app_id=foo")); 226 | will(returnValue(new HttpResponse(409, body))); 227 | }}); 228 | 229 | ParameterMap params = new ParameterMap(); 230 | params.add("app_id", "foo"); 231 | AuthorizeResponse response = serviceApi.authorize(params); 232 | 233 | assertFalse(response.success()); 234 | assertTrue("usage limits are exceeded".equals(response.getReason())); 235 | assertTrue(response.getUsageReports()[0].hasExceeded()); 236 | } 237 | 238 | @Test 239 | public void test_authorize_with_invalid_app_id() throws ServerError { 240 | final String body = "application with id=\"foo\" was not found"; 241 | 242 | context.checking(new UrlWithParamsExpectations() {{ 243 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/authorize.xml?provider_key=1234abcd&app_id=foo")); 244 | will(returnValue(new HttpResponse(403, body))); 245 | }}); 246 | 247 | ParameterMap params = new ParameterMap(); 248 | params.add("app_id", "foo"); 249 | AuthorizeResponse response = serviceApi.authorize(params); 250 | 251 | assertFalse(response.success()); 252 | assertTrue("application_not_found".equals(response.getErrorCode())); 253 | assertTrue("application with id=\"foo\" was not found".equals(response.getReason())); 254 | } 255 | 256 | 257 | @Test 258 | public void test_authorize_metric_period_eternity() throws ServerError { 259 | final String body = "" + 260 | "true" + 261 | " Per hit" + 262 | " " + 263 | " " + 264 | " 0" + 265 | " 0" + 266 | " " + 267 | " " + 268 | ""; 269 | 270 | 271 | context.checking(new UrlWithParamsExpectations() {{ 272 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/authorize.xml?provider_key=1234abcd&app_id=foo")); 273 | will(returnValue(new HttpResponse(200, body))); 274 | }}); 275 | 276 | ParameterMap params = new ParameterMap(); 277 | params.add("app_id", "foo"); 278 | AuthorizeResponse response = serviceApi.authorize(params); 279 | 280 | assertTrue(response.success()); 281 | 282 | assertEquals("Per hit", response.getPlan()); 283 | assertEquals(1, response.getUsageReports().length); 284 | 285 | assertEquals("0", response.getUsageReports()[0].getCurrentValue()); 286 | assertEquals("0", response.getUsageReports()[0].getMaxValue()); 287 | 288 | assertEquals("", response.getUsageReports()[0].getPeriodStart()); 289 | assertEquals("", response.getUsageReports()[0].getPeriodEnd()); 290 | 291 | } 292 | 293 | @Test(expected = ServerError.class) 294 | public void test_authorize_with_server_error() throws ServerError { 295 | context.checking(new UrlWithParamsExpectations() {{ 296 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/authorize.xml?provider_key=1234abcd&app_id=foo")); 297 | will(returnValue(new HttpResponse(500, "OMG! WTF!"))); 298 | }}); 299 | 300 | // FakeWeb.register_uri(:get, "http://#{@host}/transactions/authorize.xml?provider_key=1234abcd&app_id=foo", :status => ['500', 'Internal Server Error'], :body => 'OMG! WTF!') 301 | ParameterMap params = new ParameterMap(); 302 | params.add("app_id", "foo"); 303 | 304 | serviceApi.authorize(params); 305 | } 306 | 307 | @Test 308 | public void test_successful_oauth_authorize() throws ServerError { 309 | final String body = "" + 310 | "true" + 311 | "" + 312 | " 94bd2de3" + 313 | " 883bdb8dbc3b6b77dbcf26845560fdbb" + 314 | " http://localhost:8080/oauth/oauth_redirect" + 315 | "" + 316 | "Ultimate" + 317 | "" + 318 | " " + 319 | " 2012-01-30 00:00:00 +0000" + 320 | " 2012-02-06 00:00:00 +0000" + 321 | " 5000" + 322 | " 1" + 323 | " " + 324 | " " + 325 | " 2012-02-03 00:00:00 +0000" + 326 | " 2012-02-03 00:00:00 +0000" + 327 | " 0" + 328 | " 0" + 329 | " " + 330 | "" + 331 | ""; 332 | 333 | context.checking(new UrlWithParamsExpectations() {{ 334 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/oauth_authorize.xml?redirect_url=http%3A//localhost%3A8080/oauth/oauth_redirect&provider_key=1234abcd&app_id=foo")); 335 | will(returnValue(new HttpResponse(200, body))); 336 | }}); 337 | 338 | ParameterMap params = new ParameterMap(); 339 | params.add("app_id", "foo"); 340 | params.add("redirect_url", "http://localhost:8080/oauth/oauth_redirect"); 341 | 342 | AuthorizeResponse response = serviceApi.oauth_authorize(params); 343 | assertTrue(response.success()); 344 | 345 | assertEquals("883bdb8dbc3b6b77dbcf26845560fdbb", response.getClientSecret()); 346 | assertEquals("http://localhost:8080/oauth/oauth_redirect", response.getRedirectUrl()); 347 | 348 | assertEquals("Ultimate", response.getPlan()); 349 | assertEquals(2, response.getUsageReports().length); 350 | 351 | assertEquals("week", response.getUsageReports()[0].getPeriod()); 352 | assertEquals(fmt.print(new DateTime(2012, 1, 30, 0, 0, DateTimeZone.UTC)), response.getUsageReports()[0].getPeriodStart()); 353 | assertEquals(fmt.print(new DateTime(2012, 02, 06, 0, 0, DateTimeZone.UTC)), response.getUsageReports()[0].getPeriodEnd()); 354 | assertEquals("1", response.getUsageReports()[0].getCurrentValue()); 355 | assertEquals("5000", response.getUsageReports()[0].getMaxValue()); 356 | 357 | assertEquals("minute", response.getUsageReports()[1].getPeriod()); 358 | assertEquals(fmt.print(new DateTime(2012, 2, 03, 0, 0, DateTimeZone.UTC)), response.getUsageReports()[1].getPeriodStart()); 359 | assertEquals(fmt.print(new DateTime(2012, 2, 03, 0, 0, DateTimeZone.UTC)), response.getUsageReports()[1].getPeriodEnd()); 360 | assertEquals("0", response.getUsageReports()[1].getCurrentValue()); 361 | assertEquals("0", response.getUsageReports()[1].getMaxValue()); 362 | } 363 | 364 | @Test 365 | public void test_oauth_authorize_with_exceeded_usage_limits() throws ServerError { 366 | final String body = "" + 367 | "false" + 368 | "usage limits are exceeded" + 369 | "" + 370 | " 94bd2de3" + 371 | " 883bdb8dbc3b6b77dbcf26845560fdbb" + 372 | " http://localhost:8080/oauth/oauth_redirect" + 373 | "" + 374 | "Ultimate" + 375 | "" + 376 | " " + 377 | " 2010-04-26 00:00:00 +0000" + 378 | " 2010-04-27 00:00:00 +0000" + 379 | " 50002" + 380 | " 50000" + 381 | " " + 382 | 383 | " " + 384 | " 2010-04-01 00:00:00 +0000" + 385 | " 2010-05-01 00:00:00 +0000" + 386 | " 999872" + 387 | " 150000" + 388 | " " + 389 | "" + 390 | ""; 391 | 392 | context.checking(new UrlWithParamsExpectations() {{ 393 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/oauth_authorize.xml?provider_key=1234abcd&app_id=foo")); 394 | will(returnValue(new HttpResponse(409, body))); 395 | }}); 396 | 397 | 398 | ParameterMap params = new ParameterMap(); 399 | params.add("app_id", "foo"); 400 | AuthorizeResponse response = serviceApi.oauth_authorize(params); 401 | 402 | assertFalse(response.success()); 403 | assertEquals("usage limits are exceeded", response.getReason()); 404 | assertTrue(response.getUsageReports()[0].hasExceeded()); 405 | } 406 | 407 | @Test 408 | public void test_oauth_authorize_with_invalid_app_id() throws ServerError { 409 | final String body = "application with id=\"foo\" was not found"; 410 | 411 | context.checking(new UrlWithParamsExpectations() {{ 412 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/oauth_authorize.xml?provider_key=1234abcd&app_id=foo")); 413 | will(returnValue(new HttpResponse(403, body))); 414 | }}); 415 | 416 | ParameterMap params = new ParameterMap(); 417 | params.add("app_id", "foo"); 418 | 419 | AuthorizeResponse response = serviceApi.oauth_authorize(params); 420 | 421 | assertFalse(response.success()); 422 | assertEquals("application_not_found", response.getErrorCode()); 423 | assertEquals("application with id=\"foo\" was not found", response.getReason()); 424 | } 425 | 426 | @Test(expected = ServerError.class) 427 | public void test_oath_authorize_with_server_error() throws ServerError { 428 | 429 | context.checking(new UrlWithParamsExpectations() {{ 430 | oneOf(htmlServer).get(withUrl("http://" + host + "/transactions/oauth_authorize.xml?provider_key=1234abcd&app_id=foo")); 431 | will(returnValue(new HttpResponse(500, "OMG! WTF!"))); 432 | }}); 433 | 434 | ParameterMap params = new ParameterMap(); 435 | params.add("app_id", "foo"); 436 | 437 | serviceApi.oauth_authorize(params); 438 | } 439 | 440 | @Test(expected = IllegalArgumentException.class) 441 | public void test_report_raises_an_exception_if_no_transactions_given() throws ServerError { 442 | serviceApi.report(null); 443 | } 444 | 445 | @Test 446 | public void test_successful_report() throws ServerError { 447 | 448 | context.checking(new UrlWithParamsExpectations() {{ 449 | oneOf(htmlServer).post(with("http://" + host + "/transactions.xml"), with(any(String.class))); 450 | will(returnValue(new HttpResponse(202, ""))); 451 | }}); 452 | 453 | ParameterMap params = new ParameterMap(); 454 | params.add("app_id", "foo"); 455 | params.add("timestamp", fmt.print(new DateTime(2010, 4, 27, 15, 0))); 456 | 457 | ParameterMap usage = new ParameterMap(); 458 | usage.add("hits", "1"); 459 | params.add("usage", usage); 460 | 461 | ReportResponse response = serviceApi.report(null, params); 462 | 463 | assertTrue(response.success()); 464 | } 465 | 466 | @Test 467 | public void test_report_encodes_transactions() throws ServerError { 468 | 469 | final String urlParams = 470 | "transactions%5B0%5D%5Btimestamp%5D=2010-04-27%2015%3A42%3A17%200200" + 471 | "&transactions%5B0%5D%5Busage%5D%5Bmetric2%5D=2" + 472 | "&transactions%5B0%5D%5Busage%5D%5Bhits%5D=1" + 473 | "&transactions%5B0%5D%5Bapp_id%5D=foo" + 474 | "&transactions%5B1%5D%5Btimestamp%5D=2010-04-27%2015%3A55%3A12%200200" + 475 | "&transactions%5B1%5D%5Busage%5D%5Bhits%5D=1" + 476 | "&transactions%5B1%5D%5Bapp_id%5D=bar" + 477 | "&provider_key=1234abcd"; 478 | 479 | context.checking(new UrlWithParamsExpectations() {{ 480 | oneOf(htmlServer).post(with("http://" + host + "/transactions.xml"), withParams(urlParams)); 481 | will(returnValue(new HttpResponse(200, ""))); 482 | }}); 483 | 484 | 485 | ParameterMap app1 = new ParameterMap(); 486 | app1.add("app_id", "foo"); 487 | app1.add("timestamp", "2010-04-27 15:42:17 0200"); 488 | 489 | ParameterMap usage1 = new ParameterMap(); 490 | usage1.add("hits", "1"); 491 | usage1.add("metric2", "2"); 492 | app1.add("usage", usage1); 493 | 494 | ParameterMap app2 = new ParameterMap(); 495 | app2.add("app_id", "bar"); 496 | app2.add("timestamp", "2010-04-27 15:55:12 0200"); 497 | 498 | ParameterMap usage2 = new ParameterMap(); 499 | usage2.add("hits", "1"); 500 | app2.add("usage", usage2); 501 | 502 | serviceApi.report(null, app1, app2); 503 | } 504 | 505 | @Test 506 | public void test_failed_report() throws ServerError { 507 | final String error_body = "provider key \"foo\" is invalid"; 508 | 509 | context.checking(new UrlWithParamsExpectations() {{ 510 | oneOf(htmlServer).post(with("http://" + host + "/transactions.xml"), with(any(String.class))); 511 | will(returnValue(new HttpResponse(403, error_body))); 512 | }}); 513 | 514 | ParameterMap params = new ParameterMap(); 515 | params.add("app_id", "abc"); 516 | ParameterMap usage = new ParameterMap(); 517 | usage.add("hits", "1"); 518 | params.add("usage", usage); 519 | 520 | ReportResponse response = serviceApi.report(null, params); 521 | 522 | assertFalse(response.success()); 523 | assertEquals("provider_key_invalid", response.getErrorCode()); 524 | assertEquals("provider key \"foo\" is invalid", response.getErrorMessage()); 525 | } 526 | 527 | @Test(expected = ServerError.class) 528 | public void test_report_with_server_error() throws ServerError { 529 | 530 | context.checking(new UrlWithParamsExpectations() {{ 531 | oneOf(htmlServer).post(with("http://" + host + "/transactions.xml"), with(any(String.class))); 532 | will(returnValue(new HttpResponse(500, "OMG! WTF!"))); 533 | }}); 534 | 535 | ParameterMap params = new ParameterMap(); 536 | params.add("app_id", "foo"); 537 | ParameterMap usage = new ParameterMap(); 538 | usage.add("hits", "1"); 539 | params.add("usage", usage); 540 | serviceApi.report(null, params); 541 | } 542 | 543 | 544 | private void assertAuthrepUrlWithParams(final String params) throws ServerError { 545 | final String authrep_url = "http://" + host + "/transactions/authrep.xml?" + params + "&provider_key=" + provider_key; 546 | 547 | final String body = "" + 548 | "true" + 549 | "Ultimate" + 550 | ""; 551 | //System.out.println("Expect: "+ authrep_url); 552 | context.checking(new UrlWithParamsExpectations() { 553 | { 554 | oneOf(htmlServer).get(withUrl(authrep_url)); 555 | will(returnValue(new HttpResponse(200, body))); 556 | } 557 | }); 558 | } 559 | 560 | private static class UrlWithParamsExpectations extends Expectations { 561 | 562 | protected String withUrl(String url) { 563 | currentBuilder().addParameterMatcher(new UrlWithParamsMatcher(url)); 564 | return url; 565 | } 566 | 567 | protected String withParams(String params) { 568 | currentBuilder().addParameterMatcher(new ParamsMatcher(params)); 569 | return params; 570 | } 571 | 572 | } 573 | 574 | private static class UrlWithParamsMatcher extends TypeSafeMatcher { 575 | 576 | private final String expectedUrl; 577 | 578 | public UrlWithParamsMatcher(String expectedUrl) { 579 | this.expectedUrl = expectedUrl; 580 | } 581 | 582 | @Override 583 | public boolean matchesSafely(String actualUrl) { 584 | // Match the first part of the URL (scheme, host, port, etc) 585 | String expectedUrlHead = expectedUrl.substring(0, expectedUrl.indexOf("?")); 586 | String actualUrlHead = actualUrl.substring(0, actualUrl.indexOf("?")); 587 | 588 | // Match the params (order then compare) 589 | String expectedParams = expectedUrl.substring(expectedUrl.indexOf("?") + 1); 590 | String[] expectedParamsSplit = expectedParams.split("&"); 591 | Arrays.sort(expectedParamsSplit); 592 | String actualParams = actualUrl.substring(actualUrl.indexOf("?") + 1); 593 | String[] actualParamsSplit = actualParams.split("&"); 594 | Arrays.sort(actualParamsSplit); 595 | 596 | List expected = Arrays.asList(expectedParamsSplit); 597 | List actual = Arrays.asList(actualParamsSplit); 598 | 599 | return expected.equals(actual) && expectedUrlHead.equals(actualUrlHead); 600 | } 601 | 602 | @Override 603 | public void describeTo(Description description) { 604 | description.appendText("a url matching '" + this.expectedUrl + "'"); 605 | } 606 | } 607 | 608 | private static class ParamsMatcher extends TypeSafeMatcher { 609 | 610 | private final String expectedParams; 611 | 612 | public ParamsMatcher(String expectedParams) { 613 | this.expectedParams = expectedParams; 614 | } 615 | 616 | @Override 617 | public boolean matchesSafely(String actualParams) { 618 | String[] expectedParamsSplit = expectedParams.split("&"); 619 | Arrays.sort(expectedParamsSplit); 620 | String[] actualParamsSplit = actualParams.split("&"); 621 | Arrays.sort(actualParamsSplit); 622 | 623 | List expected = Arrays.asList(expectedParamsSplit); 624 | List actual = Arrays.asList(actualParamsSplit); 625 | 626 | return expected.equals(actual); 627 | } 628 | 629 | @Override 630 | public void describeTo(Description description) { 631 | description.appendText("params matching '" + this.expectedParams + "'"); 632 | } 633 | } 634 | 635 | } 636 | --------------------------------------------------------------------------------