blob: a8cc44dc2afa37449c0c47b8f46223914d55765d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.oodt.xmlps.product;
//OODT imports
import org.apache.oodt.product.ProductException;
import org.apache.oodt.product.QueryHandler;
import org.apache.oodt.xmlps.mapping.DatabaseTable;
import org.apache.oodt.xmlps.mapping.FieldScope;
import org.apache.oodt.xmlps.mapping.Mapping;
import org.apache.oodt.xmlps.mapping.MappingField;
import org.apache.oodt.xmlps.mapping.MappingReader;
import org.apache.oodt.xmlps.mapping.funcs.MappingFunc;
import org.apache.oodt.xmlps.queryparser.Expression;
import org.apache.oodt.xmlps.queryparser.HandlerQueryParser;
import org.apache.oodt.xmlps.structs.CDEResult;
import org.apache.oodt.xmlps.structs.CDEValue;
import org.apache.oodt.xmlps.util.XMLQueryHelper;
import org.apache.oodt.xmlquery.QueryElement;
import org.apache.oodt.xmlquery.XMLQuery;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* <p>
* An XML configurable version of a Product Server that requires no code
* to be written to plug into a local site's relational backend DBMS.
* </p>.
*/
public class XMLPSProductHandler implements QueryHandler {
/* our log stream */
private static final Logger LOG = Logger
.getLogger(XMLPSProductHandler.class.getName());
protected Mapping mapping;
private DBMSExecutor executor;
protected XMLPSProductHandler(String phony) {
/* this is to get around invoking the default constructor in sub-classes */
}
public XMLPSProductHandler() throws InstantiationException {
String MappingFilePath = System
.getProperty("org.apache.oodt.xmlps.xml.mapFilePath");
if (MappingFilePath == null) {
throw new InstantiationException(
"Need to specify path to xml mapping file!");
}
try {
mapping = MappingReader.getMapping(MappingFilePath);
} catch (Exception e) {
throw new InstantiationException(
"Unable to parse mapping xml file: ["
+ MappingFilePath + "]: reason: "
+ e.getMessage());
}
/* load the db properties file */
/*
* if one exists: otherwise, don't bother and just print out the SQL to
* the console.
*/
String dbPropFilePath = System
.getProperty("org.apache.oodt.xmlps.xml.dbPropFilePath");
if (dbPropFilePath != null) {
try {
System.getProperties()
.load(new FileInputStream(dbPropFilePath));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
throw new InstantiationException(e.getMessage());
}
executor = new DBMSExecutor();
}
}
/*
* (non-Javadoc)
*
* @see org.apache.oodt.product.QueryHandler#query(org.apache.oodt.xmlquery.XMLQuery)
*/
public XMLQuery query(XMLQuery query) throws ProductException {
List<QueryElement> whereSet = query.getWhereElementSet();
List<QueryElement> selectSet = query.getSelectElementSet();
try {
translateToDomain(selectSet, true);
translateToDomain(whereSet, false);
} catch (Exception e) {
LOG.severe(e.getMessage());
throw new ProductException(e.getMessage());
}
queryAndPackageResults(query);
return query;
}
public static void main(String[] args) throws Exception {
String usage = "XMLPSProductHandler <query>\n";
if (args.length != 1) {
System.err.println(usage);
System.exit(1);
}
XMLPSProductHandler handler = new XMLPSProductHandler();
XMLQuery q = handler.query(XMLQueryHelper
.getDefaultQueryFromQueryString(args[0]));
System.out.println(q.getXMLDocString());
}
protected List<QueryElement> getElemNamesFromQueryElemSet(
List<QueryElement> origSet) {
if (origSet == null || (origSet != null && origSet.size() == 0))
return Collections.emptyList();
List<QueryElement> newSet = new Vector<QueryElement>();
for (Iterator<QueryElement> i = origSet.iterator(); i.hasNext();) {
QueryElement elem = i.next();
if (elem.getRole().equals(XMLQueryHelper.ROLE_ELEMNAME)
&& !mapping.constantField(elem.getValue())) {
newSet.add(elem);
}
}
return newSet;
}
protected List<QueryElement> getConstElemNamesFromQueryElemSet(
List<QueryElement> origSet) {
if (origSet == null || (origSet != null && origSet.size() == 0))
return Collections.emptyList();
List<QueryElement> newSet = new Vector<QueryElement>();
for (Iterator<QueryElement> i = origSet.iterator(); i.hasNext();) {
QueryElement elem = i.next();
if (elem.getRole().equals(XMLQueryHelper.ROLE_ELEMNAME)
&& mapping.constantField(elem.getValue())) {
newSet.add(elem);
}
}
return newSet;
}
protected void queryAndPackageResults(XMLQuery query) {
Stack<QueryElement> queryStack = HandlerQueryParser
.createQueryStack(query.getWhereElementSet());
Expression parsedQuery = HandlerQueryParser.parse(queryStack,
this.mapping);
List<QueryElement> selectNames = getElemNamesFromQueryElemSet(query
.getSelectElementSet());
String querySelectNames = toSQLSelectColumns(selectNames);
StringBuffer sqlBuf = new StringBuffer("SELECT ");
sqlBuf.append(querySelectNames);
sqlBuf.append(" FROM ");
sqlBuf.append(mapping.getDefaultTable());
sqlBuf.append(" ");
if (mapping.getNumTables() > 0) {
List<QueryElement> whereNames = getElemNamesFromQueryElemSet(query.getWhereElementSet());
Set<DatabaseTable> requiredTables = getRequiredTables(whereNames, selectNames);
for (DatabaseTable tbl : requiredTables) {
sqlBuf.append("INNER JOIN ");
sqlBuf.append(tbl.getName());
sqlBuf.append(" ON ");
sqlBuf.append(tbl.getName());
sqlBuf.append(".");
sqlBuf.append(tbl.getJoinFieldName());
sqlBuf.append(" = ");
sqlBuf.append(tbl.getDefaultTableJoin());
sqlBuf.append(".");
sqlBuf.append(tbl.getDefaultTableJoinFieldName());
sqlBuf.append(" ");
}
}
if(parsedQuery != null){
sqlBuf.append(" WHERE ");
sqlBuf.append(parsedQuery.evaluate());
}
LOG.log(Level.INFO, sqlBuf.toString());
if (executor != null) {
try {
CDEResult res = executor.executeLocalQuery(sqlBuf.toString());
res.setOrderedFields(query.getSelectElementSet());
res.setMapping(mapping);
res.setConstValues(getConstValuesForQuery(query));
query.getResults().add(res);
} catch (SQLException e) {
e.printStackTrace();
LOG.log(Level.WARNING, "Error executing sql: ["
+ sqlBuf.toString() + "]: Message: " + e.getMessage());
}
}
}
private List<CDEValue> getConstValuesForQuery(XMLQuery query) {
List<QueryElement> select = query.getSelectElementSet();
List<QueryElement> constNames = getConstElemNamesFromQueryElemSet(select);
List<CDEValue> constValues = new ArrayList<CDEValue>();
if (constNames != null) {
for (QueryElement qe : constNames) {
MappingField fld = mapping.getFieldByLocalName(qe.getValue());
if (fld != null) {
constValues.add(new CDEValue(fld.getName(), fld.getConstantValue()));
}
}
}
return constValues;
}
private String toSQLSelectColumns(List<QueryElement> elems) {
if (elems == null || (elems != null && elems.size() == 0))
return null;
StringBuilder buf = new StringBuilder();
for (QueryElement qe : elems) {
MappingField fld = this.mapping.getFieldByLocalName(qe.getValue());
if (fld != null) {
buf.append(fld.getLocalName());
buf.append(" as ");
buf.append(fld.getName());
buf.append(",");
}
}
buf.deleteCharAt(buf.length() - 1);
return buf.toString();
}
protected void translateToDomain(List<QueryElement> elemSet,
boolean selectSet) throws Exception {
// go through each query element: use the mapping fields
// to translate the names
for (Iterator<QueryElement> i = elemSet.iterator(); i.hasNext();) {
QueryElement elem = i.next();
if (elem.getRole().equals(XMLQueryHelper.ROLE_ELEMNAME)) {
// do the translation
String elemValue = elem.getValue();
MappingField fld = this.mapping.getFieldByName(elemValue);
// make sure fld is not null
if (fld == null) {
continue;
}
// make sure scope is null, or if it's not null, then it's
// FieldScope.QUERY
if (fld.getScope() != null
&& fld.getScope().equals(FieldScope.RETURN)) {
// skip
continue;
}
// check to see if it has a dbname attr, if not, then the name
// stays
// the same
String newFldName = fld.getLocalName();
elem.setValue(newFldName);
// now translate the domain vocab if there are translate funcs
// present and this isn't the select set
if (!selectSet && fld.getFuncs() != null
&& fld.getFuncs().size() > 0) {
// the next query element should be
// XMLQueryHelper.ROLE_LITERAL
if (!i.hasNext())
break;
QueryElement litElem = i.next();
if (!litElem.getRole().equals(XMLQueryHelper.ROLE_LITERAL)) {
throw new Exception("next query element not "
+ XMLQueryHelper.ROLE_LITERAL + "! role is "
+ litElem.getRole() + " instead!");
}
for (Iterator<MappingFunc> j = fld.getFuncs().iterator(); j
.hasNext();) {
MappingFunc func = j.next();
CDEValue origVal = new CDEValue(fld.getName(),
litElem.getValue());
CDEValue newVal = func.inverseTranslate(origVal);
litElem.setValue(newVal.getVal());
}
}
}
}
}
protected Set<DatabaseTable> getRequiredTables(
List<QueryElement> whereElemNames, List<QueryElement> selectElemNames) {
Set<DatabaseTable> tables = new HashSet<DatabaseTable>();
// add tables from where element set
if (whereElemNames != null) {
for (QueryElement qe : whereElemNames) {
MappingField fld = mapping.getFieldByLocalName(qe.getValue());
if (fld != null) {
DatabaseTable t = mapping.getTableByName(fld.getTableName());
if (t != null && !tables.contains(t) && !t.getName().equals(mapping.getDefaultTable())) {
tables.add(t);
}
}
}
}
// add tables from select element set
if (selectElemNames != null) {
for (QueryElement qe : selectElemNames) {
MappingField fld = mapping.getFieldByLocalName(qe.getValue());
if (fld != null) {
DatabaseTable t = mapping.getTableByName(fld.getTableName());
if (t != null && !tables.contains(t) && !t.getName().equals(mapping.getDefaultTable())) {
tables.add(t);
}
}
}
}
// the tables found may be joined on columns from tables we haven't found
// yet
// add additional required join tables
Set<DatabaseTable> moreTables = new HashSet<DatabaseTable>(tables);
for (DatabaseTable t : tables) {
DatabaseTable join = mapping.getTableByName(t.getDefaultTableJoin());
// recursively add all join tables until we get to either
// (a) the mapping default table (join == null)
// (b) or a table already found (moreTables.contains(join))
while (join != null && !moreTables.contains(join) && !join.getName().equals(mapping.getDefaultTable())) {
moreTables.add(join);
join = mapping.getTableByName(join.getDefaultTableJoin());
}
}
return moreTables;
}
}