Safe Query Objects: Statically Typed Objects as Remotely Executable Queries

Preview:

DESCRIPTION

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 - PowerPoint PPT Presentation

Citation preview

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 20 of 22

OpenJava

RemoteQueryJDOMetaclass

Query Class Definition

Execute Method

Compile Time

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.

Page 22 of 22

Disadvantages

• Dynamic queries and data-driven with query definition loaded from DB– Open problem…

• What about creating new tables?

• Updating tables..

Recommended