220 likes | 375 Views
Safe Query Objects: Statically Typed Objects as Remotely Executable Queries. By: William Cook & Siddhartha Rai ICSE 2005 Department of Computer Sciences University of Texas at Austin. Prerequisite #1: OpenJava. Pretends to be simple and universal Metaprogramming system
E N D
Safe Query Objects:Statically Typed Objects as Remotely Executable Queries By: William Cook & Siddhartha Rai ICSE 2005 Department of Computer Sciences University of Texas at Austin
Prerequisite #1: OpenJava • Pretends to be simple and universal Metaprogramming system • Compile time code generation: methods, properties etc. • The source is a kind of “pseudo-code”. • Examples for usefulness: • Generous operator – like “…” in C or Vararg in Java 1.5 • Can check for proper method overriding definitions • Code generation is just text manipulation! • Problems in correctess, performance & documentation • Had potential, but did not fly
Prerequisite #2: JDO • Java Data Objects library for efficient persistence • What’s special? • Stores and retrieves Java objects in a database • Objects are hierarchically structured and use references • Database is typically relational – i.e. flat tables. • JDO layer is absolutely transparent to the programmer • Takes care of object states – dirty, saved etc. • Need to define templates for DB tables as XML metadata. • The core of JDO is the PersistenceManager class
Introduction • Fact: Large Applications require persistence. • Problems: • Code writing & maintenance • String encoding • Runtime checking only • Complex queries must be weaved by hand… • Programmers must learn two languages.
New Idea • Safe Query Objects • Working with relational database using objects. • Represent a query as a statically typed object. • The same principle like in Ararat. • We will see: • Statically typed interface to the dynamically typed functionality in the JDO 1.0 specification.
Instead of SELECT '$' || (RETAIL/100) FROM INVENTORY WHERE WHOLESALE > parameter AND TYPE IN (SELECT TYPECODE, TYPEDESC FROM TYPES WHERE NAME = 'fish' OR NAME = 'meat') Produce this: class PerishablePrices { Integer lowerBound; boolean filter(Inventory item) { return lowerBound == null || item.Wholesale > lowerBound.intValue()) && (item.Type.Name.equals("fish") || item.Type.Name.equals("meat"); } }
JDO Background: The Persistence Manager Interface • Access to persistent objects via instance of the PersistenceManager interface. • Loading individual objects: • getObjectById • Creating a new Query: • newQuery interface javax.jdo.PeristenceManager{ Object getObjectById(Object id); Javax.jdo.Query newQuery(Class class); //methods for transactions not listed }
JDO Background: The Query Interface • Query execution is provided by the Query Interface. interface javax.jdo.Query { void setFilter(String filter); void setOrdering(String ordering); void declareImports(String imports); void declareParameters(String params); void declareVariable(String vars); Object execute(); Object execute(Object arg1); Object executeWithMap(Map parameters); // bookkeeping methods not listed }
JDO Background:Candidate Classes • Candidate classes: • Have structural correspondence to tables in database. • We will use: class Employee { String name; float salary; Department department; Employee manager; } class Department { String name; Collection<Employee> employees; }
JDO Background: Usage Collection<Employee> execute(PersistenceManager pm){ javax.jdo.Query payCheck = pm.newQuery(Employee.class); payCheck.setFilter(“salary > maneger.salary”); Object result = payCheck.execute(); return (Collection<Employee>)result; } The misspelled “maneger” will not be detected until runtime! Not type safe!
Safe Query • Safe query object contains: • Filtering method • Ordering method • Safe Query Class • Subclass of SafeQuery<T> • Instantiates RemoteQueryJDO Candidate Class class PayCheck extends SafeQuery<Employee> instantiates RemoteQueryJDO { boolean filter(Employee emp) { return emp.salary > emp.maneger.salary; } } Compilation Error
Safe query object suggested design • Filtering Method: • Defines the “WHERE” condition in the query. • Must be called filter • Must return a boolean value. • Free of side effects: • Must not modify states • No iterative constructs No automatic checks of proper Design! Not Clear!
Sorted Results: JDO • Queries often specify sort order for the set of query results. • Relational query languages: • ascending/descending order. • Sorting in JDO: • setOrdering method. Collection sortEmployees() { javax.jdo.Query q = pm.newQuery(Employee.class); q.setOrdering(“department.name ascending,” + “ salary descending”); return (Collection) q.execute(); }
Sorted Results: Safe Query • Safe query defines ordermethod • Takes a candidate object • Returns a linked list of sortable values. classSortQuery instantiates RemoteQueryJDO extends SafeQuery<Employee> { Sort order(Employee emp) { returnnew Sort(emp.department.name, Sort.Direction.ASCENDING, new Sort(emp.salary, Sort.Direction.DESCENDING)); } }
Parameterized Queries: JDO • Needed when a query behavior depends upon one or more input value. • JDO approach: • declareParameters method Collection salaryLimitEmployees(double limit){ javax.jdo.Query q = pm.newQuery(Employee.class); q.setFilter(“salary > limit”); q.declareParameters(“Double limit”); Collection r = (Collection)q.execute(new Double(limit)); return r; } What happens if we omit the call to declareParameters?
Parameterized Queries: Safe Query • Query parameters are defined as standard Java function parameters. • Declared as arguments to the query constructor • Stored as member variables of the query object. class SalaryLimit instantiates RemoteQueryJDO extends SafeQuery<Employee> { double limit; /*parameter*/ SalaryLimit(double limit) { this.limit = limit; } boolean filter(Employee employee) { return employee.salary > limit; } }
Dynamic Queries: JDO • Involve filters, parameters or sort orders • Constructed at runtime. Collection search(String namePrefix) { String filter = null; HashMap paramMap = new HashMap(); javax.jdo.Query q = makeQuery(Employee.class); if (namePrefix != null) { q.declareParameters(“String namePrefix”); paramMap.put(“namePrefix”,namePrefix); filter = ”(name.startsWith(namePrefix))”; } q.setFilter(filter); return q.executeWithMap(pramMap); } No Type Safety!
Dynamic Queries: Safe Query class DynQuery instantiates RemoteQueryJDO extends SafeQuery<Employee> { private String namePrefix; // may be null private Double minSalary; // may be null DynQuery (String namePrefix, Double minSalary){ this.namePrefix = namePrefix; this.minSalary = minSalary; } boolean filter(Employee item) { return (namePrefix == null || item.name.startsWith(namePrefix)) && (minSalary == null || item.salary >= minSalary); } }
Implementation • The query translation is encapsulated in the RemoteQueryJDOmetaclass which is applied to the safe query by the OpenJava instantiates keyword. • OpenJava runs the metaclass at compile time, supplying the definition of the of the query class (e.g. PayCheck) as input. • The RemoteQueryJDO metaclass examines the user-defined filter method and generates the corresponding execute method.
OpenJava Compile Time Query Class Definition Execute Method RemoteQueryJDO Metaclass
Advantages • Queries defined using OO language • Static type checking • Syntax errors (at compilation time) • JDO seems more comfortable • Observation: Most queries are either static or dynamic with static tables. • Safe query can help.
Disadvantages • Dynamic queries and data-driven with query definition loaded from DB • Open problem… • What about creating new tables? • Updating tables..