Page 1 of 22 Safe Query Objects: Statically Typed Objects as Remotely Executable Queries By: William...
Transcript of Page 1 of 22 Safe Query Objects: Statically Typed Objects as Remotely Executable Queries By: William...
Page 1 of 22
Safe Query Objects:Statically Typed Objects as Remotely Executable Queries
By: William Cook & Siddhartha RaiICSE 2005Department of Computer SciencesUniversity of Texas at Austin
Page 2 of 22
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
Page 3 of 22
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
Page 4 of 22
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.
Page 5 of 22
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.
Page 6 of 22
Instead of
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");
}}
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");
}}
Produce this:
SELECT '$' || (RETAIL/100) FROM INVENTORYWHERE WHOLESALE > parameter AND TYPE IN (SELECT TYPECODE,
TYPEDESC FROM TYPES WHERENAME = 'fish' OR NAME = 'meat')
SELECT '$' || (RETAIL/100) FROM INVENTORYWHERE WHOLESALE > parameter AND TYPE IN (SELECT TYPECODE,
TYPEDESC FROM TYPES WHERENAME = 'fish' OR NAME = 'meat')
Page 7 of 22
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}
interface javax.jdo.PeristenceManager{Object getObjectById(Object id);Javax.jdo.Query newQuery(Class class);// methods for transactions not listed}
Page 8 of 22
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
}
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
}
Page 9 of 22
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 Employee { String name; float salary; Department department; Employee manager;} class Department {
String name; Collection<Employee> employees;}
class Department { String name; Collection<Employee> employees;}
Page 10 of 22
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;}
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!
Page 11 of 22
Safe Query• Safe query object contains:
– Filtering method– Ordering method
• Safe Query Class– Subclass of SafeQuery<T>– Instantiates RemoteQueryJDO
class PayCheck extends SafeQuery<Employee> instantiates RemoteQueryJDO { boolean filter(Employee emp) {
return emp.salary > emp.maneger.salary; }}
class PayCheck extends SafeQuery<Employee> instantiates RemoteQueryJDO { boolean filter(Employee emp) {
return emp.salary > emp.maneger.salary; }}
Candidate Class
Compilation Error
Page 12 of 22
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 automaticchecks of proper
Design!
Not Clear!
Page 13 of 22
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();}
Collection sortEmployees() { javax.jdo.Query q = pm.newQuery(Employee.class); q.setOrdering(“department.name ascending,”
+ “ salary descending”); return (Collection) q.execute();}
Page 14 of 22
Sorted Results: Safe Query
• Safe query defines order method– Takes a candidate object– Returns a linked list of sortable values.
class SortQuery instantiates RemoteQueryJDOextends SafeQuery<Employee> {
Sort order(Employee emp) { return new Sort(emp.department.name,
Sort.Direction.ASCENDING,new Sort(emp.salary,Sort.Direction.DESCENDING));
}}
class SortQuery instantiates RemoteQueryJDOextends SafeQuery<Employee> {
Sort order(Employee emp) { return new Sort(emp.department.name,
Sort.Direction.ASCENDING,new Sort(emp.salary,Sort.Direction.DESCENDING));
}}
Page 15 of 22
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;}
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?
Page 16 of 22
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 RemoteQueryJDOextends SafeQuery<Employee> {
double limit; /*parameter*/ SalaryLimit(double limit) {
this.limit = limit; } boolean filter(Employee employee) {
return employee.salary > limit; }}
class SalaryLimit instantiates RemoteQueryJDOextends SafeQuery<Employee> {
double limit; /*parameter*/ SalaryLimit(double limit) {
this.limit = limit; } boolean filter(Employee employee) {
return employee.salary > limit; }}
Page 17 of 22
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);}
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!
Page 18 of 22
Dynamic Queries: Safe Query
class DynQuery instantiates RemoteQueryJDO extends SafeQuery<Employee> {
private String namePrefix; // may be nullprivate Double minSalary; // may be nullDynQuery (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);}
}
class DynQuery instantiates RemoteQueryJDO extends SafeQuery<Employee> {
private String namePrefix; // may be nullprivate Double minSalary; // may be nullDynQuery (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);}
}
Page 19 of 22
Implementation• The query translation is encapsulated in the RemoteQueryJDO metaclass 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.
Page 21 of 22
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.