|
OverviewThis section discusses client applications that use the JavaSpace API to read Entry data from a space and, if the data is not found in the space, require the space to read from a different datasource, which can be a database or any other type of external application. The CacheLoader Interface provides the connection to the datasource.
This section also includes client applications that use ExternalEntry when accessing the space. This is mostly relevant for C++ , C# , JMS and JDBC applications that use ExternalEntry objects implicitly.
The GigaSpaces JavaSpaces API provides two different ways of specifying the Entry to read: by template or by SQLQuery.
Although the following sections discuss Entry classes, POJO classes are also supported when using JavaSpaces API. All Entry or POJO classes should have getter/setters methods and gs.xml or annotations describing the meta data required (index list , primary key , type).
Matching by TemplateThis section discusses how to read object data from the space or data source using template input. A template is an object, passed as a parameter in the read method, whose attributes can be fixed or null ("wild card"). The space or data source is searched until an object whose values match those of the template is found. For a multiple object read operation, the search attempts to match the required number of objects.
Reading a Single Entry Using a Null-Valued TemplateThis section describes how to read or take a single Entry object using a null-valued template. A null-valued template is a an Entry object whose field values are all null. Any object from the template class or its sub-classes that is stored in the space matches this template and is a candidate to be returned back to the client.
The figure above illustrates how a client application reads a single Entry from the space that matches a given template where the actual data is loaded from a database or other external application.
CacheLoader.load ImplementationThe CacheLoader Interface method load is called by the space and has the following signature: IGSEntry loadedObject = load (IGSEntry template) The original template object can be extracted from the passed IGSEntry using: Object originalTemplate = getConverter.toObject(IGSEntry)
The data from the individual properties of the Entry object can now be extracted and a JDBC Query can be created. The JDBC call constructs the result loaded object that should be converted to IGSEntry using the following conversion call: getConverter().toIGSEntry(loadedObject); Sample CodeClient application: JavaSpaces API Person person1 = space.read(new Person(), null, timeout); CacheLoader implementation: load method: MyCacheLoader extends AbstractCacheLoader { public Object load(Object key) { Object values[] = null; Object loaded_object = null; try { Object myObject = getObject((IGSEntry) key); int keyValue = 0; if (myObject instanceof Person) { Person person = null; // This is the template we got - must have ID person = (Person) myObject; keyValue = person.getId().intValue(); // Constructing the query Connection con = getConnection(); PreparedStatement stP = con.prepareStatement( "select * from " + tableNames.get(((IGSEntry) key) .getClassName()) + " where ID = ? "); stP.setInt(1, keyValue); ResultSet rs = stP.executeQuery(); int sz = rs.getMetaData().getColumnCount(); values = new Object[sz]; while (rs.next()) { for (int i = 0; i < sz; i++) { values[i] = rs.getObject(i + 1); } // here we construct the loaded Person object loaded_object = new Person(String.valueOf(values[0]), String.valueOf(values[1]), Integer. valueOf(String .valueOf(values[2]))); break; } rs.close(); rs.close(); con.close(); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } return getConvertor().toIGSEntry(loaded_object); } Reading a Single Entry Object for a Non Null-Valued TemplateThis section describes how to read a single Entry object using a non null-valued template. A non null-valued template is an Entry object one of whose field values are non-null and has a specific value. Any object from the template class or its sub-classes that is stored in the space and whose value for this field matches the given template is a candidate to be returned back to the client. Null field values in the template are ignored in the search.
The figure illustrates how a client application reads or takes a single Entry from the space that that matches a given template where the actual data is loaded from a database or other external application.
CacheIteratorFactory.iterator ImplementationThe CacheIteratorFactory.iterator method is called by the space and has the following signature: Iterator iterator = CacheIteratorFactory.iterator (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery by: SQLQuery sqlQuery = CacheQuery.getQuery(); The SQL Query can now be used to retrieve the data sought using the JDBC API. CacheLoader.loadAll ImplementationThe CacheLoader Interface load method is called by the space and has the following signature: Map persons = loadAll (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery by: SQLQuery sqlQuery = CacheQuery.getQuery() The SQL Query can now be used to retrieve the data sought using the JDBC API. Iterator Method vs. loadAll MethodThe following considerations apply when choosing between implementing the CacheIteratorFactory interface or the CacheLoader.loadAll method for the CacheLoader:
The following table shows when each method is used according to the client API call:
Sample CodeIn client application: JavaSpaces API Using Entry objects: Person person = (Person)space.read(new Person("john","doe", null), null, timeout); CacheLoader implementation: implements CacheIteratorFactory: public class MyCacheLoaderImpl extends AbstractCacheLoader implements CacheLoader,CacheIteratorFactory { public CacheIterator iterator(CacheQuery cacheQuery) { Object query = cacheQuery.getQuery(); String classname = null; System.out.println(" ********* iterator Called ********* "); String querystr = null; // null template PreparedStatement stP = null; Connection con = null; try { con = getConnection(); } catch (SQLException e) { throw new RuntimeException(e); } if (query instanceof IGSEntry) { IGSEntry igsentry = (IGSEntry) query; classname = igsentry.getClassName(); if (classname.equals("java.lang.Object")) { System.out.println("HERE YOU CAN LOAD DATA INTO THE SPACE WHEN IT IS STARTED!"); } if (!tableNames.containsKey(igsentry.getClassName())) { System.out.println("Do not have mapping for class " + igsentry.getClassName()); return null; } querystr = "select * from " + tableNames.get(igsentry.getClassName()); try { con.prepareStatement(querystr); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("IGSEntry " + querystr); } // null template or SQLQuery used else if (query instanceof SQLQuery) { SQLQuery sqlquery = (SQLQuery) query; classname = sqlquery.getClassName(); if (!tableNames.containsKey(sqlquery.getClassName())) { System.out.println("Do not have mapping for class " + sqlquery.getClassName()); } try { stP = buildQuery(cacheQuery, con); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (UnusableEntryException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } ResultSet rs = null; try { System.out.println("***** Iterator Query:" ); rs = stP.executeQuery(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } return new CacheLoaderIterator(con, rs, classname); } return null; }; // The CacheLoaderIterator used by the CacheIteratorFactory.iterator public class CacheLoaderIterator implements CacheIterator { String className = null; ResultSet result = null; Connection con = null; public CacheLoaderIterator(Connection con , ResultSet result, String className) { this.result = result; this.className = className; this.con = con; } public boolean hasNext() { try { return result.next(); } catch (SQLException e) { e.printStackTrace(); return true; } } public Object next() { try { Object obj = null; if (className.equals(Person.class.getName())) { Integer id = new Integer(result.getInt(3)); obj = new Person(result.getString(1), result.getString(2), id); } IGSEntry value = getConvertor().toIGSEntry(obj); return value; } catch (Exception e) { return null; } } public void remove() { throw new NotImplementedException(); } public void close() { try { result.close(); con.close(); } catch (SQLException e) { e.printStackTrace(); } } } } CacheLoader implementation: method loadAll: public class MyCacheLoaderImpl extends AbstractCacheLoader implements CacheLoader{ public Map loadAll(Collection keys) { System.out.println(" ********* loadAll Called ********* "); HashMap map = new HashMap(); Iterator keyIter = keys.iterator(); PreparedStatement stP = null; Connection con = null; try { con = getConnection(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } while (keyIter.hasNext()) { CacheQuery exprationEntry = (CacheQuery) keyIter.next(); Object query = exprationEntry.getQuery(); String querystr = null; // null template if (query instanceof IGSEntry) { IGSEntry igsentry = (IGSEntry) query; if (!tableNames.containsKey(igsentry.getClassName())) { System.out.println("Do not have mapping for class " + igsentry.getClassName()); if (igsentry.getClassName().equals("java.lang.Object")) { System.out.println("HERE YOU CAN LOAD DATA INTO THE SPACE WHEN IT IS STARTED!"); } // return empty map - indicates no objects loaded from database return map; } querystr = "select * from " + tableNames.get(igsentry.getClassName()); try { stP = con.prepareStatement(querystr); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // non null template or SQLQuery used if (query instanceof SQLQuery) { SQLQuery sqlquery = (SQLQuery) query; if (!tableNames.containsKey(sqlquery.getClassName())) { System.out.println("Do not have mapping for class " + sqlquery.getClassName()); // return empty map - indicates no objects loaded from // database return map; } try { stP = buildQuery(exprationEntry , con); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnusableEntryException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { System.out.println("********* loadAll - Query Constructed:" + querystr); ResultSet rs = stP.executeQuery(); IGSEntry value = null; while (rs.next()) { Integer id = new Integer(rs.getInt(3)); Person person = new Person(rs.getString(1), rs.getString(2), id); value = getConvertor().toIGSEntry(person); map.put(value, value); } rs.close(); con.close(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } return map; } } The buildQuery method constructs the SQL query string and fills up the JDBC PreparedStatement with appropriate values. The SQL query string includes ? for each value where the ExternalEntry extracted from the CacheQuery will include the actual values. See below example for such implementation. private PreparedStatement buildQuery(CacheQuery query, Connection connection) throws SQLException, UnusableEntryException { SQLQuery _qry = (SQLQuery)query.getQuery(); String sql = "select * from "+ tableNames.get(_qry.getClassName())+ " where " + _qry.getQuery(); System.out.println(" ********* buildQuery:" + sql); PreparedStatement statement = connection.prepareStatement(sql); ExternalEntry ee = null; ee = ((IGSEntry)query).getExternalEntry(null); Object[] fieldValues = ee.getFieldsValues(); Object[] rangeValues = ee.getRangeValues(); int lastpos =1; for( int i =0; fieldValues != null && i < fieldValues.length; i++) { if (fieldValues[i] != null) { System.out.println("Setting value into position "+ lastpos+ " Value:" + fieldValues[i]); statement.setObject(lastpos, fieldValues[i]); lastpos++; } } for(int i=0 ; rangeValues!= null && i < rangeValues.length; i++) { if (rangeValues[i] != null) { System.out.println("Setting range value position "+ lastpos+ " Value:" + rangeValues[i]); statement.setObject(lastpos, rangeValues[i]); lastpos++; } } return statement ; }
Reading Multiple Entry ObjectsThis section describes how to read multiple Entry objects using any template.
The figure illustrates how a client application reads or takes a fixed number of Entries from the space that match a given template where the actual data is loaded from a database or other external application.
CacheIteratorFactory.iterator ImplementationThe CacheIteratorFactory.iterator method is called by the space and has the following signature: Iterator iterator = CacheIteratorFactory.iterator (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery by: SQLQuery sqlQuery = CacheQuery.getQuery() The SQL Query can now be used to retrieve the data sought using the JDBC API. CacheLoader.loadAll ImplementationThe CacheLoader Interface method load is called by the space and has the following signature: Map persons = loadAll (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery by: SQLQuery sqlQuery = CacheQuery.getQuery() The SQL Query can now be used to retrieve the data sought using the JDBC API.
Sample Codeclient application: IJSpace API: Entry[] persons = space.readMultiple(new person("john","doe", null), null, maxEntries); Matching by SQL QueryFor the IJSpace methods read (), {{take (), readMultiple (), takeMultiple () with a NO_WAIT timeout value, a SQLQuery object may be used in the first argument instead of a valued template. Using SQLQuery makes it possible to create more flexible database queries. Two types of read operations are described.
Understanding How a Query is HandledWhen using the GigaSpaces JavaSpaces API with the SQLQuery or GigaSpaces JDBC API, the executed query is disassembled into smaller partial queries when delegated into the CacheLoader. The space assembles the partial results and returns them to the client. Condition with OR OperationAn SQL query with multiple conditions that includes the OR operation is broken down into its different subconditions, where each subcondition is sent to the CacheStore.loadAll or CacheIteratorFactory.iterator separately. SQLQuery person_template = new SQLQuery("person" , "firstName='john' OR age>30 OR lastName='doe'"); Entry [] result = space.readMultiple(person_template , null , 10); will invoke the CacheIteratorFactory.iterator 3 times – each with a CacheQuery that encapsulates an SQLQuery with:
Condition with AND OperationAn SQL Query that includes conditions with the same field name using AND will not be broken down , but will invoke the CacheStore.loadAll or CacheIteratorFactory.iterator with SQLQuery that includes the condition with the AND operation, for example the code: SQLQuery person_template = new SQLQuery("person" , "age>30 AND age<40 or lastName='doe'"); Entry [] result = space.readMultiple(person_template , null , 10); will invoke the CacheIteratorFactory.iterator 2 times – each with a CacheQuery that will encapsulate SQLQuery with:
Reading a Single Object Using SQLQueryThis section describes how to read a single Entry object using an SQLQuery.
The figure illustrates how a client application reads or takes a single Entry from the space that satisfies an SQL Query where the actual data is loaded from a database or other external application.
CacheIteratorFactory.iterator ImplementationThe CacheIteratorFactory.iterator method is called by the space and has the following signature: Iterator iterator = CacheIteratorFactory.iterator (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery in the following way: SQLQuery sqlQuery = CacheQuery.getQuery() The SQL Query can now be used to retrieve the data sought using the JDBC API. CacheLoader.loadAll ImplementationThe CacheLoader Interface method load is called by the space and has the following signature: Map persons = loadAll (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery in the following way: SQLQuery sqlQuery = CacheQuery.getQuery() The SQL Query can now be used to retrieve the data sought using the JDBC API. Sample CodeIn client application: JavaSpaces API Using SQLQuery object: Person person1 = (Person)space.read(SQLQuery, null, NO_WAIT);
Reading Multiple Objects Using SQLQuery
The figure above illustrates how a client application reads or takes a fixed number of multiple Entries from the space that satisfy an SQL Query where the actual data is loaded from a database or other external application.
CacheIteratorFactory.iterator ImplementationThe CacheIteratorFactory.iterator method is called by the space and has the following signature: Iterator iterator = CacheIteratorFactory.iterator (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery in the following way: SQLQuery sqlQuery = CacheQuery.getQuery() CacheLoader.loadAll ImplementationThe CacheLoader Interface method load is called by the space and has the following signature: Map persons = loadAll (Map<CacheQuery>) The SQLQuery is extracted from the CacheQuery by: SQLQuery sqlQuery = CacheQuery.getQuery()
|
Wiki Content Tree
Your Feedback Needed!
We need your help to improve this wiki site. If you have any suggestions or corrections, write to us at techw@gigaspaces.com. Please provide a link to the wiki page you are referring to.

Add Comment