| /** |
| * 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; |
| } |
| |
| } |