All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gravityrd.recengclient.webshop.GravityClient Maven / Gradle / Ivy

/**
 * The GravityClient and related classes are used to connect to and communicate with the
 * Gravity recommendation engine.
 */
package com.gravityrd.recengclient.webshop;

import com.gravityrd.receng.web.webshop.jsondto.GravityEvent;
import com.gravityrd.receng.web.webshop.jsondto.GravityItem;
import com.gravityrd.receng.web.webshop.jsondto.GravityItemRecommendation;
import com.gravityrd.receng.web.webshop.jsondto.GravityRecEngException;
import com.gravityrd.receng.web.webshop.jsondto.GravityRecommendationContext;
import com.gravityrd.receng.web.webshop.jsondto.GravityScenario;
import com.gravityrd.receng.web.webshop.jsondto.GravityUser;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 * The GravityClient class can be used to send events, item and user information to
 * the recommendation engine and get recommendations.
 * 

* Example usage: *

*
 * 		public GravityClient createGravityClient() {
 * 			GravityClient client = new GravityClient();
 * 			client.setRemoteUrl("https://saas.gravityrd.com/grrec-CustomerID-war/WebshopServlet");
 * 			client.setUserName("sampleUser");
 * 			client.setPassword("samplePasswd");
 * 			return client;
 *        }
 * 		GravityClient client = createGravityClient();
 * 		GravityRecommendationContext context = new GravityRecommendationContext();
 * 		context.numberLimit = 1;
 * 		context.scenarioId = "ITEM_PAGE";
 * 		client.getItemRecommendation("user1", context);
 * 
*/ public final class GravityClient { private static final ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally /** * The version info of the client. */ @SuppressWarnings("FieldCanBeLocal") private final String VERSION = "1.2.0"; /** * The URL of the server side interface. It has no default value, must be specified. */ private String remoteUrl; /** * The timeout for the operations in millisecs. The default value is 3000 millisecs. */ private int readTimeout = 3000; /** * The user name for the http authenticated connection. Leave it blank in case of * connection without authentication. */ private String userName; /** * The password for the http authenticated connection. Leave it blank in case of * connection without authentication. */ private String password; /** * Query the list of available recommendation scenarios for the backend * @return array of scenarios * @throws GravityRecEngException cannot process answer * @throws IOException cannot connect to server */ public GravityScenario[] getScenarioInformation() throws GravityRecEngException, IOException { return (GravityScenario[]) sendRequest("scenarioInfo", null, null, true, GravityScenario[].class); } public String getRemoteUrl() { return remoteUrl; } /** * Set the URL of the server side interface. It has no default value, must be specified. * @param remoteUrl the server url provided by Gravity integration team */ public void setRemoteUrl(String remoteUrl) { this.remoteUrl = remoteUrl; } public String getUserName() { return userName; } /** * Set the user name for the http authenticated connection. Leave it blank in case of * connection without authentication. * @param userName user authentication name provided by Gravity */ public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } /** * Set the password for the http authenticated connection. Leave it blank in case of * connection without authentication. * @param password user authentication password provided by Gravity */ public void setPassword(String password) { this.password = password; } public int getReadTimeout() { return readTimeout; } /** * Set the timeout for the operations in millisecs. The default value is 3000 millisecs. * @param readTimeout wait up to this millisecond for the request answers */ public void setReadTimeout(int readTimeout) { this.readTimeout = readTimeout; } /** * Adds events to the recommendation engine. * * @param events The events to add. * @param async true if the call is asynchronous. An asynchronous call * returns immediately after an input data checking, * a synchronous call returns only after the data is saved to database. * @throws IOException if cannot connect * @throws GravityRecEngException if cannot process the answer files */ public void addEvents(GravityEvent[] events, boolean async) throws GravityRecEngException, IOException { HashMap queryStringParams = new HashMap<>(); queryStringParams.put("async", Boolean.toString(async)); sendRequest("addEvents", queryStringParams, events, false, null); } private Object sendRequest(String methodName, Map queryStringParams, Object requestBody, boolean hasAnswer, Class answerClass) throws GravityRecEngException, IOException { URL myUrl = new URL(remoteUrl + "/" + methodName + getRequestQueryString(methodName, queryStringParams)); HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection(); connection.setRequestMethod("POST"); connection.addRequestProperty("X-Gravity-RecEng-JavaClient-Webshop-Version", VERSION); connection.setReadTimeout(readTimeout); connection.setConnectTimeout(readTimeout); connection.setDoOutput(true); Authenticator.setDefault(new UserPasswordAuthenticator(userName, password)); String json = mapper.writeValueAsString(requestBody); OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream()); wr.write(json); wr.close(); if (connection.getResponseCode() == 500) { try { throw mapper.readValue(getBodyAsString(connection.getErrorStream()), GravityRecEngException.class); } catch (Exception e) { throw new IllegalStateException(getBodyAsString(connection.getErrorStream()), e); } } connection.getInputStream(); if (hasAnswer) { try { return mapper.readValue(getBodyAsString(connection.getInputStream()), answerClass); } catch (Exception e) { throw new IllegalStateException(getBodyAsString(connection.getInputStream()), e); } } else { return null; } } private String getRequestQueryString(String methodName, Map queryStringParams) throws UnsupportedEncodingException { StringBuilder queryString = new StringBuilder(); if (queryStringParams != null) { for (Entry pair : queryStringParams.entrySet()) { queryString.append(URLEncoder.encode(pair.getKey(), "UTF-8")).append("="); queryString.append(URLEncoder.encode(pair.getValue(), "UTF-8")).append("&"); } } if (queryString.length() > 0) { queryString.deleteCharAt(queryString.length() - 1); queryString.insert(0, "&"); } return "?method=" + URLEncoder.encode(methodName, "UTF-8") + queryString.toString(); } private String getBodyAsString(InputStream input) throws IOException { StringBuilder sb = new StringBuilder(); char[] buffer = new char[2048]; int readChars; BufferedReader reader = new BufferedReader(new InputStreamReader(input, Charset.forName("UTF-8"))); while ((readChars = reader.read(buffer)) != -1) { sb.append(buffer, 0, readChars); } return sb.toString(); } /** * Adds users to the recommendation engine. The existing users will be updated. * If a user already exists with the specified userId, * the entire user will be replaced with the new user specified here. * * @param users The user to add. * @param async true if the call is asynchronous. An asynchronous call * returns immediately after an input data checking, * a synchronous call returns only after the data is saved to database. * @throws IOException if cannot connect * @throws GravityRecEngException if cannot process the answer files */ public void addUsers(GravityUser[] users, boolean async) throws GravityRecEngException, IOException { HashMap queryStringParams = new HashMap<>(); queryStringParams.put("async", Boolean.toString(async)); sendRequest("addUsers", queryStringParams, users, false, null); } /** * Adds items to the recommendation engine. * If an item already exists with the specified itemId, * the entire item along with its NameValue pairs will be replaced to the new item specified here. * * @param items The items to add * @param async true if the call is asynchronous. An asynchronous call * returns immediately after an input data checking, * a synchronous call returns only after the data is saved to * @throws IOException if cannot connect * @throws GravityRecEngException if cannot process the answer filesdatabase. */ public void addItems(GravityItem[] items, boolean async) throws GravityRecEngException, IOException { HashMap queryStringParams = new HashMap<>(); queryStringParams.put("async", Boolean.toString(async)); sendRequest("addItems", queryStringParams, items, false, null); } /** * Returns a list of recommended items, based on the given context parameters. * * @param userId The identifier of the logged in user. If no user is logged in, null should be specified. * @param cookieId It should be a permanent identifier for the end users computer, preserving its value across browser sessions. * It should be always specified. * @param context Additional information which describes the actual scenario. * @return An object containing the recommended items and other information about the recommendation. * @throws IOException if cannot connect * @throws GravityRecEngException if cannot process the answer files */ public GravityItemRecommendation getItemRecommendation(String userId, String cookieId, GravityRecommendationContext context) throws GravityRecEngException, IOException { HashMap queryStringParams = new HashMap<>(); if (userId != null) { queryStringParams.put("userId", userId); } if (cookieId != null) { queryStringParams.put("cookieId", cookieId); } return (GravityItemRecommendation) sendRequest("getItemRecommendation", queryStringParams, context, true, GravityItemRecommendation.class); } /** * Given the userId and the cookieId, we can request recommendations for multiple scenarios (described by the context). * This function returns lists of recommended items for each of the given scenarios in an array. * * @param userId The identifier of the logged in user. If no user is logged in, null should be specified. * @param cookieId It should be a permanent identifier for the end users computer, preserving its value across browser sessions. * It should be always specified. * @param context Additional Array of information which describes the actual scenarios. * @return An Array containing the recommended items for each scenario with other information about the recommendation. * @throws IOException if cannot connect * @throws GravityRecEngException if cannot process the answer files */ public GravityItemRecommendation[] getItemRecommendationBulk(String userId, String cookieId, GravityRecommendationContext[] context) throws GravityRecEngException, IOException { HashMap queryStringParams = new HashMap<>(); if (userId != null) { queryStringParams.put("userId", userId); } if (cookieId != null) { queryStringParams.put("cookieId", cookieId); } return (GravityItemRecommendation[]) sendRequest("getItemRecommendationBulk", queryStringParams, context, true, GravityItemRecommendation[].class); } /** * Simple test function to test without side effects whether the service is alive. * @param name a test string * @return "Hello " + name* @throws IOException if cannot connect * @throws IOException if cannot connect * @throws GravityRecEngException if cannot process the answer files */ public String test(String name) throws GravityRecEngException, IOException { HashMap queryStringParams = new HashMap<>(); queryStringParams.put("name", name); return (String) sendRequest("test", queryStringParams, name, true, String.class); } /** * Simple test function to test throwing an exception. * @throws IOException if cannot connect * @throws GravityRecEngException if cannot process the answer files */ public void testException() throws GravityRecEngException, IOException { sendRequest("testException", null, null, true, null); } private static class UserPasswordAuthenticator extends Authenticator { private final String username, password; public UserPasswordAuthenticator(String user, String pwd) { username = user; password = pwd; } @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password.toCharArray()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy