/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
package net.ontopia.persistence.proxy;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.ontopia.utils.OntopiaRuntimeException;
import net.ontopia.utils.PropertyUtils;
import net.ontopia.utils.StringUtils;
import net.ontopia.xml.DefaultXMLReaderFactory;
import net.ontopia.xml.Slf4jSaxErrorHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* INTERNAL: Class that is able to read named query definitions from an XML representation.
*/
public class QueryDeclarations {
// Define a logging category.
static Logger log = LoggerFactory.getLogger(QueryDeclarations.class.getName());
class QueriesHandler extends DefaultHandler {
protected QueryDescriptor qdesc;
protected List<Class<?>> params;
protected List<QueryDescriptor.SelectField> selects;
protected String indname;
protected Map<String, Class<?>> indics;
protected Class getClassByName(String class_name) {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return Class.forName(class_name, true, classLoader);
} catch (ClassNotFoundException e) {
log.error("Cannot find class " + e.getMessage());
throw new OntopiaRuntimeException(e);
}
}
public void startElement (String uri, String name, String qName, Attributes atts) throws SAXException {
if (name.equals("query")) {
// Get query name
String query_name = atts.getValue("name");
if (query_name == null)
throw new OntopiaRuntimeException("query.name must be specified: " + query_name);
// Get query result type
String type = atts.getValue("type");
if (type == null)
throw new OntopiaRuntimeException("query.type must be specified: " + type);
// Get query identity lookup
boolean lookup_identities = PropertyUtils.isTrue(atts.getValue("lookup"), true);
// Create query descriptor
qdesc = new QueryDescriptor(query_name, type, lookup_identities);
selects = new ArrayList<QueryDescriptor.SelectField>();
params = new ArrayList<Class<?>>();
// Get fetch size
String fetchSize = atts.getValue("fetchSize");
if (fetchSize != null) {
try {
qdesc.setFetchSize(Integer.parseInt(fetchSize));
} catch (NumberFormatException e) {
throw new SAXException(e);
}
}
}
else if (name.equals("select")) {
// Get class type
String klass = atts.getValue("class");
if (klass != null) {
selects.add(new QueryDescriptor.SelectField(getClassByName(klass),
QueryDescriptor.SelectField.SELECT_CLASS));
} else {
// Get class indicator
String indicator = atts.getValue("class-indicator");
if (indicator != null) {
selects.add(new QueryDescriptor.SelectField(getIndicator(indicator),
QueryDescriptor.SelectField.SELECT_INDICATOR));
} else {
throw new OntopiaRuntimeException("select.<valuetype> must be specified.");
}
}
}
else if (name.equals("param")) {
// Add parameter class
params.add(getClassByName(atts.getValue("class")));
}
else if (name.equals("statement")) {
// Get statement platform
String platform = atts.getValue("platform");
if (platform == null)
throw new OntopiaRuntimeException("statement.platform must be specified: " + platform);
String[] platforms = StringUtils.split(platform, ",");
// Get query statement
String query = atts.getValue("query");
if (query == null)
throw new OntopiaRuntimeException("statement.query must be specified: " + query);
// Add query statement
qdesc.addStatement(platforms, query);
}
else if (name.equals("class-indicator")) {
// Get indicator name
indname = atts.getValue("name");
if (indname == null)
throw new OntopiaRuntimeException("class-indicator.name must be specified: " + indname);
indics = new HashMap<String, Class<?>>();
}
else if (name.equals("indicator")) {
// Get indicator token
String token = atts.getValue("token");
if (token == null)
throw new OntopiaRuntimeException("indicator.token must be specified: " + token);
// Get indicator class
Class klass = getClassByName(atts.getValue("class"));
// Put indicator on map
indics.put(token, klass);
}
else if (name.equals("queries")) {
// Ignore
}
else {
log.warn("Unknown element: " + name);
}
}
public void endElement (String uri, String name, String qName) throws SAXException {
if (name.equals("query")) {
// Set query selects
qdesc.setSelects(selects);
// Set query parameters
qdesc.setParameters(params);
// Register query with query declaration manager
addQuery(qdesc);
// Reset handler fields
qdesc = null;
selects = null;
params = null;
}
else if (name.equals("class-indicator")) {
// Register class indicator with query declaration manager
addIndicator(indname, indics);
// Reset handler fields
indname = null;
indics = null;
}
}
}
protected Map<String, QueryDescriptor> queries = new HashMap<String, QueryDescriptor>();
protected Map<String, Map<String, Class<?>>> indicators = new HashMap<String, Map<String, Class<?>>>();
public QueryDeclarations(InputStream istream) {
loadQueries(istream);
}
/**
* INTERNAL: Gets the query descriptor by name.
*/
public QueryDescriptor getQueryDescriptor(String name) {
return queries.get(name);
}
/**
* INTERNAL: Adds the query descriptor.
*/
public void addQuery(QueryDescriptor qdesc) {
String name = qdesc.getName();
if (name == null)
throw new OntopiaRuntimeException("Cannot add query descriptor without a name: " + qdesc);
queries.put(name, qdesc);
}
/**
* INTERNAL: Looks up the class indicator map by name.
*/
public Map<String, Class<?>> getIndicator(String name) {
if (!indicators.containsKey(name))
throw new OntopiaRuntimeException("No indicator with the name: " + name);
return indicators.get(name);
}
/**
* INTERNAL: Adds the class indicator map by name. The indicator map
* is keyed by strings and has Class object values.
*/
public void addIndicator(String name, Map<String, Class<?>> indicator) {
indicators.put(name, indicator);
}
protected void loadQueries(InputSource isource) {
// Read queries file.
ContentHandler handler = new QueriesHandler();
try {
XMLReader parser = DefaultXMLReaderFactory.createXMLReader();
parser.setContentHandler(handler);
parser.setErrorHandler(new Slf4jSaxErrorHandler(log));
parser.parse(isource);
} catch (Exception e) {
throw new OntopiaRuntimeException(e);
}
}
public void loadQueries(InputStream stream) {
loadQueries(new InputSource(stream));
}
}