Develop applications to access Simple Data Grids
- Develop applications to access Simple Data Grids
- API documentation
- Develop data grid applications with Java APIs
- Develop data grid applications with the REST gateway
- Dynamic map configuration options
Develop applications to access Simple Data Grids
Two different options to program for Simple Data Grids...
- Java client application that uses the ObjectMap API
- Non-Java client application that uses the REST gateway.
You must have an existing Simple Data Grid.
The Dynamic Cache and Session Data grids are associated with WebSphere Application Server applications, and can be used without modification.
API documentation
Simple data grid application walkthrough
- Connect to the catalog service
The catalog server to specify is displayed on the user interface page for the Simple Data Grid...
Data Grid | Simple Data Grid | my_simple_data_grid
To connect to the catalog server...
ClientClusterContext ccc = ObjectGridManagerFactory.getObjectGridManager().connect("myXC10.myhost.com:2809", null, null);
The connect method requires only the catalog server endpoint in the format...
host1:port[,host2:port,...]
The connect method attempts to connect to each appliance in the list until it makes a successful connection. Automatic failover is provided if one of the other appliances does not respond.
- Obtain an ObjectGrid instance.
ObjectGrid grid = ObjectGridManagerFactory.getObjectGridManager().getObjectGrid(ccc, "my_simple_data_grid");
- Set the necessary security credentials.
Create a client security configuration and a credential generator with a user name and password possessing sufficient authority to access the Simple Data Grid.
ClientSecurityConfiguration clientSC = ClientSecurityConfigurationFactory.getClientSecurityConfiguration();
clientSC.setSecurityEnabled(true);
CredentialGenerator credGen = new UserPasswordCredentialGenerator(username,password);
clientSC.setCredentialGenerator(credGen);
return clientSC;
- Get a Session instance
We can get a Session from the obtained ObjectGrid instance. A Session instance is required to get the ObjectMap instance, and perform transaction demarcation.
Session sess = grid.getSession();
- Get an ObjectMap instance.
To use the default map instance, named after the data grid...
ObjectMap map1 = sess.getMap("my_simple_data_grid");
To create a new map that uses creation time eviction and pessimistic locking...
ObjectMap map2 = sess.getMap("my_simple_data_grid.CT.P");
To create a new map that does not have any eviction or locking settings...
ObjectMap map3 = sess.getMap("my_new_map.NONE");
- Use the ObjectMap methods
If there is no explicit transaction demarcation in the application, ObjectMap operations run with auto-commit transactions...
map1.insert(key1, value1);
The keys used can be of an Java type (java.lang.String, Integer, etc). Values can be any serializable object type.
To use the ObjectMap API with explicit transaction demarcation...
sess.begin();
map1.insert(key1, value1);
sess.commit();
Example: Simple data grid application
// SimpleGrid.java // import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.HashSet; import java.util.BitSet; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; import java.util.logging.Logger; import java.io.File; import java.io.PrintWriter; import java.io.FileWriter; import java.io.PrintWriter; import java.io.Serializable; import java.io.IOException; import java.text.DecimalFormat; import java.text.DateFormat; import java.text.SimpleDateFormat; import com.ibm.websphere.objectgrid.ClientClusterContext; import com.ibm.websphere.objectgrid.ConnectException; import com.ibm.websphere.objectgrid.ObjectGrid; import com.ibm.websphere.objectgrid.ObjectMap; import com.ibm.websphere.objectgrid.ObjectGridException; import com.ibm.websphere.objectgrid.ObjectGridManager; import com.ibm.websphere.objectgrid.ObjectGridManagerFactory; import com.ibm.websphere.objectgrid.ObjectGridRuntimeException; import com.ibm.websphere.objectgrid.Session; import com.ibm.websphere.objectgrid.config.BackingMapConfiguration; import com.ibm.websphere.objectgrid.config.ObjectGridConfigFactory; import com.ibm.websphere.objectgrid.config.ObjectGridConfiguration; import com.ibm.websphere.objectgrid.plugins.TransactionCallbackException; import com.ibm.websphere.objectgrid.security.config.ClientSecurityConfiguration; import com.ibm.websphere.objectgrid.security.config.ClientSecurityConfiguration; import com.ibm.websphere.objectgrid.security.config.ClientSecurityConfigurationFactory; import com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator; import com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredentialGenerator; import com.ibm.websphere.objectgrid.server.CatalogServerProperties; public class SimpleGrid { static String gridName = "test"; static String mapName = gridName; static String username="xcadmin"; static String password="xcadmin"; static String hostName="localhost"; static ObjectGrid clientGrid=null; static ConcurrentLinkedQueue<Session> sessions = new ConcurrentLinkedQueue<Session>(); static synchronized public ObjectGrid getObjectGrid() { if (clientGrid == null) { ClientClusterContext ccc = null; try { new java.io.File(System.getProperty("java.io.tmpdir")).mkdirs(); } catch (Throwable t) { t.printStackTrace(); } ObjectGridManager ogm = ObjectGridManagerFactory.getObjectGridManager(); ClientSecurityConfiguration clientSC = getAdminClientConfig(); List<ObjectGridConfiguration> ogConfigs=new ArrayList<ObjectGridConfiguration>(); ObjectGridConfiguration lclGridConfig = ObjectGridConfigFactory.createObjectGridConfiguration(gridName); BackingMapConfiguration bmc = ObjectGridConfigFactory.createBackingMapConfiguration(mapName); bmc.setNumberOfBuckets(0); lclGridConfig.addBackingMapConfiguration(bmc); ogConfigs.add(lclGridConfig); try { ccc = ogm.connect(hostName+":2809", clientSC, null); } catch (Throwable e) { e.printStackTrace(); } if (ccc != null) { HashMap<String,List<ObjectGridConfiguration>> overrideMap = new HashMap<String,List<ObjectGridConfiguration>>(); overrideMap.put(ccc.getClusterName(),ogConfigs); ogm.setOverrideObjectGridConfigurations(overrideMap); try { clientGrid = ogm.getObjectGrid(ccc, gridName); } catch (ObjectGridRuntimeException ogre) { ogre.printStackTrace(); } } } return clientGrid; } // Get session instance // static public Session getSession() throws TransactionCallbackException, ObjectGridException { Session session = sessions.poll(); if (session == null && getObjectGrid()!=null) { session = getObjectGrid().getSession(); } if (session == null) throw new IllegalStateException("unable to initialize connection to objectgrid"); return session; } static public void putSession(Session session) { if (session.isTransactionActive()) { try { session.rollback(); } catch (Exception e) { } } sessions.add(session); } public static ClientSecurityConfiguration getAdminClientConfig() { // Create a ClientSecurityConfiguration object using the specified file ClientSecurityConfiguration clientSC = ClientSecurityConfigurationFactory.getClientSecurityConfiguration(); clientSC.setSecurityEnabled(true); // Create a CredentialGenerator using the passed-in user and password. CredentialGenerator credGen = new UserPasswordCredentialGenerator(username,password); clientSC.setCredentialGenerator(credGen); return clientSC; } public static void main(String args[]) throws Exception { for (int i=0;i<args.length;i++) { if(args[i].startsWith("-username:")) { username = args[i].substring(args[i].indexOf(":")+1); } else if(args[i].startsWith("-password:")) { password = args[i].substring(args[i].indexOf(":")+1); } else if(args[i].startsWith("-gridname:")) { gridName = args[i].substring(args[i].indexOf(":")+1); } else if(args[i].startsWith("-mapname:")) { mapName = args[i].substring(args[i].indexOf(":")+1); } else if(args[i].startsWith("-hostname:")) { hostName = args[i].substring(args[i].indexOf(":")+1); } else { System.out.println("usage: SimpleGrid [optional args]"); System.out.println(" -username:<username>"); System.out.println(" -password:<password>"); System.out.println(" -gridname:<gridname>"); System.out.println(" -mapname:<mapname>"); System.out.println(" -hostname:<hostname>"); System.exit(1); } } System.out.println("--------------------------------------------------------------"); System.out.println("Simple Grid Test"); System.out.println("--------------------------------------------------------------"); System.out.println("username : "+username); System.out.println("password : "+password); System.out.println("gridname : "+gridName); System.out.println("mapname : "+mapName); System.out.println("hostname : "+hostName); System.out.println("--------------------------------------------------------------"); if (getObjectGrid() == null) { System.out.println("ERROR: unable to connect to objectgrid at "+hostName); System.exit(1); } Session session = getSession(); ObjectMap map=session.getMap(mapName); session.begin(); Object data = map.get("TestKey"); if (data!=null) map.remove("TestKey"); map.insert("TestKey","TestValue"); session.commit(); putSession(session); } }
Develop data grid applications with the REST gateway
Use the REST gateway to access Simple Data Grid data from non-Java environments such as...
- DataPower XI50 Appliance
- .NET application
We can also use the REST gateway to access map data from a JVM that cannot host the IBM ORB used by the Java-based ObjectMap API.
Each REST operation to the WebSphere DataPower XC10 appliance begins and ends an independent transaction to the data grid. It is not possible to chain together multiple operations into a single transaction.
When we are using the REST gateway, it is the client responsibility to load balance their requests onto the appliance collective. Use an external load balancer or add additional logic in the HTTP client we are using in the client program.
Communication through the REST gateway always results in a secure configuration, even if you do not have security enabled on the data grid. Configure the user groups to access the data grid to have all access rights to the data grid.
The REST gateway is a separate entity from the WXS REST data service, which implements the Microsoft ADO.NET Data Services interface.
REST gateway: URI format
The REST URI for accessing a simple data grid on the appliance...
/resources/datacaches/[grid_name]/[map_name]/[key]
For grid MyGrid on appliance myxc10.ibm.com, to access key my.data.item...
http://myxc10.ibm.com/resources/datacaches/MyGrid/MyGrid/my.data.item
In the previous example, the MyGrid default map was used in the MyGrid grid. This default map does not have any TTL eviction. Entries placed in the data grid stay in the data grid until they are explicitly removed.
REST gateway: Data format
The REST gateway uses the Content-Type header in HTTP requests to determine the data format of the data stored into the data grid.
To determine the data format of the data stored in the data grid, the REST gateway uses the Content-type header in HTTP requests. If you insert content of type application/xml, when the application does a GET operation for the same cache key, the response body and Content-type are in the equivalent format type. In this example, the response body would be in application/xml format. We can store data of multiple content types in the same data grid.
Content type Use application/xml XML application/json JavaScript data application/octet-stream Serialized objects, general-purpose data
REST operations
Use HTTP POST, GET, and DELETE operations to insert or update, get, and remove data from the data grid.
Operation HTTP Method Response Code Insert or update POST
- 200 CREATED: The data was successfully inserted or updated into the data grid.
- 400 BAD REQUEST: The data insert or update operation did not complete successfully.
Get GET
- 200 OK: The response body and content-type are retrieved from a previous insert or update operation.
- 404 NOT FOUND: The specified key is not present in the data grid.
- 400 BAD REQUEST: The appliance was unable to process the request.
Delete DELETE
- 200 NO CONTENT: The entry was deleted from the data grid.
- 400 BAD REQUEST: The appliance was unable to process the request.
REST gateway example: Insert and get data grid map entries
Use the POST and GET HTTP methods to insert and get data grid map entries.
Example: Insert operation
To insert a key "bob" into the MyGrid grid and MyGrid map:
POST /resources/datacaches/MyGrid/MyGrid/bob
Content-type: application/xml
<mydata>this is some data</mydata>
Example: Get operation
Retrieve key "bob" inserted in the previous example...
GET /resources/datacaches/MyGrid/MyGrid/bob
You must run GET operations on an individual key. We cannot retrieve all map entries
Clear entries
- Delete an individual entry...
DELETE http://myxc10.ibm.com/resources/datacaches/MyGrid/MyGrid/my.data.item
- Clear an entire map in the data grid.
To clear the MyDataMap.LUT map on the MyGrid data grid...
DELETE http://myxc10.ibm.com/resources/datacaches/MyGrid/MyDataMap.LUT
Note that we omit the key portion of the URI.
Create dynamic maps
When you create a Simple Data Grid, a default map with the same name is created by default. We can use map templates to create additional maps as the application requires.
The first operation to a map that matches the map template, but has not yet been created, results in the creation of a new dynamic map. For example, to create a new dynamic map, using last update time, named MyMap.LUT, use the following URI in a GET, DELETE, or POST operation:
http://myxc10.ibm.com/resources/datacaches/MyGrid/MyMap.LUT/a.key
Time to live (TTL) expiration
We can set a TTL value for both last update time (*.LUT) and last access time (*.LAT) maps. The default TTL for both types of maps is one hour.
Example
To set a TTL value for both last update time (*.LUT) and last access time (*.LAT) maps, provide the TTL request parameter with a value in seconds. For example, to set a TTL value of 600 seconds on the a.key key, specify the ttl request parameter when the value is inserted or updated into the data grid using the HTTP POST method:
http://myxc10.ibm.com/resources/datacaches/MyGrid/MyMap.LUT/a.key?ttl=600
Security
To access a data grid through the REST gateway, the user must be authenticated to the WebSphere DataPower XC10 appliance, regardless of whether the data grid has security enabled. The application client must always provide a basic authorization header with the authorized user ID and password in the HTTP headers of the HTTP request. To access data grids through the REST gateway, provide the user ID and password in an authorization header.
To access to a data grid map through the REST gateway, the user or user group must be authenticated and authorized to access the specified data grid in the URI. Even if you do not have security configured on the data grid, configure the user group we are using to communicate through the REST gateway to have all access to the data grid. The application client must provide a basic authorization header with the authorized user ID and password in the HTTP headers of the HTTP request.
Authorization: Basic <base64 encoded string of "userid:password">
Secured data grids
Use the REST gateway in a secured data grid configuration. To access the secured data grids, provide the user ID and password in an authorization header. The user must be authenticated and authorized to access the specified data grid in the URI.
Permission Get Post Delete READ X WRITE X CREATE X X ALL X X X
Transport security
Clients that are using the REST Gateway can use the HTTPS protocol if transport security is required. Using HTTPS instead of HTTP introduces significant additional processing burden on the WebSphere DataPower XC10 appliance to process the request.
REST gateway: HTTP sessions and cookies
Use HTTP sessions and cookies with the REST gateway with Set-Cookie: headers.
The REST gateway code creates an HTTP session when it receives a request from a client that is not currently in session. To prevent unnecessary creation of sessions and to get peak performance, the REST client must remember cookies that are returned from the REST gateway with Set-Cookie: headers and supply those same cookies back to the REST gateway with Cookie: headers on subsequent requests.
Dynamic map configuration options
We can create additional maps in a data grid by having your client application connect to the specially-named map. When this connection occurs, the map is automatically created.
Dynamic map naming
When you create a data grid, a single map is created by default. This map is named the same as the data grid. For example, if you create the myGrid data grid, you automatically get a myGrid map. However, we can also add maps to the data grid. A map is automatically created when the client application connects to a map using the following naming convention:
<map_name>.<template>.<locking_option>
...where...
map_name Required. Name of the map. template Required. Template that defines when entries expire from the map, by defining the TTL behavior. locking_option Locking mechanism used for the map. Include a template name for the map. If you do not specify a locking option, no locking occurs on the map.
Map templates
Map Template Description *.NONE Map with no time to live (TTL) expiration. *.LUT Map in which the entries are expired based on the last update time of the entry. The default TTL is one hour. *.LAT A map in which the entries are expired based on the last access time of the entry. The default TTL is one hour. *.CT A map in which the entries are expired based on the of the creation time of the entry plus the TTL value. The default TTL is one hour.
Locking options
Locking Option Description (blank) No locking mechanism is used. -P The map has pessimistic locking -O The map has optimistic locking