Package com.dbxml.labrador.jdbc

Source Code of com.dbxml.labrador.jdbc.JDBCDiscovery

package com.dbxml.labrador.jdbc;

/*
* The dbXML Labrador Software License, Version 1.0
*
*
* Copyright (c) 2003 The dbXML Group, L.L.C.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by The
*        dbXML Group, L.L.C. (http://www.dbxml.com/)."
*    Alternately, this acknowledgment may appear in the software
*    itself, if and wherever such third-party acknowledgments normally
*    appear.
*
* 4. The names "Labrador" and "dbXML Group" must not be used to
*    endorse or promote products derived from this software without
*    prior written permission. For written permission, please contact
*    info@dbxml.com
*
* 5. Products derived from this software may not be called "Labrador",
*    nor may "Labrador" appear in their name, without prior written
*    permission of The dbXML Group, L.L.C..
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE DBXML GROUP, L.L.C. OR ITS
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* $Id: JDBCDiscovery.java,v 1.18 2003/10/29 20:11:16 bradford Exp $
*/

import java.sql.*;

import com.dbxml.labrador.Discovery;
import com.dbxml.labrador.broker.Broker;
import com.dbxml.labrador.configuration.Configuration;
import com.dbxml.labrador.configuration.ConfigurationCallback;
import com.dbxml.labrador.configuration.ConfigurationException;
import com.dbxml.labrador.types.Types;
import com.dbxml.labrador.types.Variant;
import com.dbxml.labrador.util.DOMHelper;
import com.dbxml.labrador.util.SimpleConfigurable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

/**
* JDBCDiscovery is a Discovery implementation for JDBC Statements.  It
* actually does the work of invoking the Statements as well as managing
* pools of cached Statements.
*/

public final class JDBCDiscovery extends SimpleConfigurable implements Discovery {
   private static final String[] EmptyStrings = new String[0];
   private static final ParamInfo[] EmptyParams = new ParamInfo[0];
  
   private static final boolean DoIndent = true;
   private static final String IndentString = "\n                    ";

   private static final String RS_RESULTS = "results";
   private static final String RS_RESULTSET = "resultset";
   private static final String RS_METADATA = "metadata";
   private static final String RS_COLINFO = "colinfo";
   private static final String RS_NAME = "name";
   private static final String RS_TYPE = "type";
   private static final String RS_ROW = "row";
   private static final String RS_COL = "col";
  
   private static final String METHOD = "method";
   private static final String NAME = "name";

   private static final String PARAM = "param";

   private static final String TYPE = "type";

   private static final String STATEMENT = "statement";
   private static final String PROCEDURE = "procedure";

   private static final String VOID = "void";
   private static final String STRING = "string";
   private static final String INT = "int";
   private static final String FLOAT = "float";
   private static final String BOOLEAN = "boolean";
   private static final String DOCUMENT = "document";
   private static final String RESULTSET = "resultset";
  
   private static final String[] TYPES = {
      VOID,
      STRING,
      INT,
      FLOAT,
      BOOLEAN,
      DOCUMENT,
      RESULTSET
   };
  
   private static final String[] STATEMENT_TYPES = {
      VOID,
      RESULTSET
   };
  
   private static final String[] PROCEDURE_TYPES = {
      VOID,
      STRING,
      INT,
      FLOAT,
      BOOLEAN,
      RESULTSET
   };
  
   private static final String[] PARAM_TYPES = {
      STRING,
      INT,
      FLOAT,
      BOOLEAN,
      DOCUMENT
   };
  
   private static final int[] TYPE_MAPPINGS = {
      Types.VOID,
      Types.STRING,
      Types.INT,
      Types.FLOAT,
      Types.BOOLEAN,
      Types.NODE,
      Types.NODE
   };
  
   private static final int[] SQL_MAPPINGS = {
      java.sql.Types.VARCHAR, // VOID
      java.sql.Types.VARCHAR, // STRING
      java.sql.Types.INTEGER, // INT
      java.sql.Types.DOUBLE,  // FLOAT
      java.sql.Types.BOOLEAN, // BOOLEAN
      java.sql.Types.CLOB,    // DOCUMENT
      java.sql.Types.CLOB     // RESULTSET
   };
  
   private Map methods = new HashMap(); // MethodInfo
   private JDBCConnectionPool pool;

   public JDBCDiscovery(JDBCConnectionPool pool) {
      this.pool = pool;
   }

   public void setConfig(Configuration config) throws ConfigurationException {
      super.setConfig(config);
     
      config.processChildren(METHOD, new ConfigurationCallback() {
         public void process(Configuration cfg) {
            String name = cfg.getAttribute(NAME);
            if ( name == null || name.length() == 0 ) {
               Broker.printerr("The '"+NAME+"' attribute is required for '"+METHOD+"'");
               System.exit(1);
            }

            boolean storedProc = false;
            List params = new ArrayList();
            String sql = null;
            Integer resultType = null;
           
            Configuration[] cfgs = cfg.getChildren();
            for ( int i = 0; i < cfgs.length; i++ ) {
               String tag = cfgs[i].getName();
               if ( tag.equals(STATEMENT) || tag.equals(PROCEDURE) ) {
                  if ( sql != null ) {
                     Broker.printerr("A '"+STATEMENT+"' or '"+PROCEDURE+"' tag already defined in '"+METHOD+"'");
                     System.exit(1);
                  }

                  storedProc = tag.equals(PROCEDURE);
                  sql = cfgs[i].getValue();
                 
                  String resType = cfgs[i].getAttribute(TYPE);
                  resultType = new Integer(getMappedType(cfgs[i].getAttribute(TYPE)));

            if ( storedProc )
                    checkType(tag, resType, PROCEDURE_TYPES);
            else
                    checkType(tag, resType, STATEMENT_TYPES);
               }
               else if ( tag.equals(PARAM) ) {
                  String paramName = cfgs[i].getAttribute(NAME);
                  String parmType = cfgs[i].getAttribute(TYPE);
                  int paramType = getMappedType(parmType);

                  checkType(PARAM, parmType, PARAM_TYPES);
                 
                  ParamInfo p = new ParamInfo(paramName, paramType);
                  params.add(p);
               }
               else {
                  Broker.printerr("Invalid tag '"+tag+"' in '"+METHOD+"'");
                  System.exit(1);
               }
            }
           
            if ( sql == null ) {
               Broker.printerr("No '"+STATEMENT+"' or '"+PROCEDURE+"' tags defined");
               System.exit(1);
            }
           
            ParamInfo[] p = (ParamInfo[])params.toArray(EmptyParams);
            int res;
        if ( resultType != null )
          res = resultType.intValue();
        else
          res =  Types.VOID;
       
            MethodInfo m = new MethodInfo(name, res, p, sql, storedProc);
           
            methods.put(name, m);
         }
      });
   }
  
   private static void checkType(String tag, String type, String[] types) {
      if ( type == null || type.length() == 0 ) {
         Broker.printerr("'"+TYPE+"' attribute for '"+tag+"' has not been set");
         System.exit(1);
      }
     
      for ( int i = 0; i < types.length; i++ )
         if ( types[i].equalsIgnoreCase(type) )
            return;
        
      Broker.printerr("'"+type+"' is not a valid value for the '"+tag+"' element's '"+TYPE+"' attribute");
      System.exit(1);
   }
  
   private static int getMappedType(String type) {
      for ( int i = 0; i < TYPES.length; i++ )
         if ( TYPES[i].equalsIgnoreCase(type) )
            return TYPE_MAPPINGS[i];
      return Types.UNKNOWN;
   }
  
   private static int getSQLType(int type) {
      for ( int i = 0; i < TYPES.length; i++ )
         if ( TYPE_MAPPINGS[i] == type )
            return SQL_MAPPINGS[i];
      return -1;
   }
  
   public String[] listMethods() {
      return (String[])methods.keySet().toArray(EmptyStrings);
   }

   public int getParamCount(String method) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null )
         return info.params.length;
      else
         return 0;
   }

   public String[] listParams(String name) {
      MethodInfo info = (MethodInfo)methods.get(name);
      if ( info != null )
         return info.paramNames;
      else
         return null;
   }

   public int getReturnType(String method) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null )
         return info.type;
      else
         return Types.UNKNOWN;
   }

   public boolean isReturnArray(String method) {
      return false; // Won't happen in JDBC-land
   }

   public int getParamType(String method, int index) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null && index < info.params.length )
         return info.params[index].type;
      else
         return Types.UNKNOWN;
   }

   public boolean isParamArray(String method, int index) {
      return false; // Won't happen in JDBC-land
   }

   public Object invoke(String name, Object[] params) throws Throwable {
      MethodInfo method = (MethodInfo)methods.get(name);
      if ( method != null )
         return method.invoke(params);
      else
         throw new Exception("Method '" + name + "' Not Found");
   }
     
   private void indent(Document doc, Element elem, int size) {
      if ( DoIndent ) {
         String s = IndentString.substring(0, size+1);
         elem.appendChild(doc.createTextNode(s));
      }
   }
  
   private Document buildResultSet(Statement s) throws Throwable {
      /** @todo Might want to modify this to return String */
     
      Document doc = DOMHelper.newDocument();
      Element rootElem = doc.createElement(RS_RESULTS);
      doc.appendChild(rootElem);
     
      do {
         ResultSet rs = s.getResultSet();
         Element rsElem = doc.createElement(RS_RESULTSET);
         indent(doc, rootElem, 3);
         rootElem.appendChild(rsElem);
         indent(doc, rootElem, 0);
        
         // Meta Data
         ResultSetMetaData rsmd = rs.getMetaData();
         int colCount = rsmd.getColumnCount();
         Element meta = doc.createElement(RS_METADATA);
         indent(doc, rsElem, 6);
         rsElem.appendChild(meta);
        
         for ( int i = 0; i < colCount; i++ ) {
            Element col = doc.createElement(RS_COLINFO);
            indent(doc, meta, 9);
            meta.appendChild(col);
            col.setAttribute(RS_NAME, rsmd.getColumnName(i+1));
            col.setAttribute(RS_TYPE, rsmd.getColumnTypeName(i+1));
         }
         indent(doc, meta, 6);
        
         // Rows
         while ( rs.next() ) {
            Element row = doc.createElement(RS_ROW);
            indent(doc, rsElem, 6);
            rsElem.appendChild(row);
           
            for ( int i = 0; i < colCount; i++ ) {
               Element col = doc.createElement(RS_COL);
               indent(doc, row, 9);
               row.appendChild(col);
               Text t = doc.createTextNode(rs.getString(i+1));
               col.appendChild(t);
            }
            indent(doc, row, 6);
         }
         indent(doc, rsElem, 3);
         rs.close();
      }
      while ( s.getMoreResults() );
     
      return doc;
   }
     

   /**
    * ParamInfo encapsulates parameter type and name information
    */

   private class ParamInfo {
      public String name;
      public int type;

      public ParamInfo(String name, int type) {
         this.name = name;
         this.type = type;
      }
   }


   /**
    * MethodInfo encapsulates Method result, name, and parameter information
    */

   private class MethodInfo extends ParamInfo {
      public ParamInfo[] params;
      public String[] paramNames;
      public String sql;
      public boolean storedProc;
      public Map statements = new WeakHashMap();

      public MethodInfo(String name, int type, ParamInfo[] params, String sql, boolean storedProc) {
         super(name, type);
         this.params = params;
         this.sql = sql;
         this.storedProc = storedProc;
         calcParamNames();
      }

      public void calcParamNames() {
         paramNames = new String[params.length];
         for ( int i = 0; i < paramNames.length; i++ )
            paramNames[i] = params[i].name;
      }
     
      private Object invoke(Variant[] args) throws Throwable {
         JDBCConnection conn = null;
         PreparedStatement ps = null;
         try {
            conn = pool.getConnection();
            ps = (PreparedStatement)statements.get(conn);
            if ( ps == null ) {
               if ( storedProc ) {
                  CallableStatement cs = conn.prepareCall(sql);
                  if ( type != Types.VOID )
                     cs.registerOutParameter(1, getSQLType(type));
                  ps = cs;
               }
               else
                  ps = conn.prepareStatement(sql);
            }

        int offset;
        if ( storedProc && type != Types.VOID )
          offset = 2;
        else
          offset = 1;
           
            for ( int i = 0; i < params.length; i++ ) {
               switch ( params[i].type ) {
                  case Types.STRING:
                     ps.setString(i+offset, args[i].getString());
                     break;
                  case Types.INT:
                     ps.setLong(i+offset, args[i].getLong());
                     break;
                  case Types.FLOAT:
                     ps.setDouble(i+offset, args[i].getDouble());
                     break;
                  case Types.BOOLEAN:
                     ps.setBoolean(i+offset, args[i].getBoolean());
                     break;
                  case Types.NODE:
                     ps.setString(i+offset, args[i].getString());
                     break;
               }
            }
           
            Object result = null;
            boolean hasResults = ps.execute();
           
            if ( storedProc ) {
               CallableStatement cs = (CallableStatement)ps;
               switch ( type ) {
                  case Types.STRING:
                     result = cs.getString(1);
                     break;
                  case Types.INT:
                     result = new Long(cs.getLong(1));
                     break;
                  case Types.FLOAT:
                     result = new Double(cs.getDouble(1));
                     break;
                  case Types.BOOLEAN:
                     result = new Boolean(cs.getBoolean(1));
                     break;
                  case Types.NODE:
                     result = buildResultSet(cs);
                     break;
               }
            }
            else if ( type == Types.NODE && hasResults )
               result = buildResultSet(ps);
           
            return result;
         }
         catch ( SQLException e ) {
            try {
               if ( ps != null )
                  ps.close();
               if ( conn != null )
                  conn.close();
            }
            catch ( Exception ex ) {
               /** @todo Hmmmm */
            }
            throw e;
         }
      }
     
      public Object invoke(Object[] params) throws Throwable {
         Variant[] v = new Variant[params.length];
         for ( int i = 0; i < v.length; i++ )
            v[i] = new Variant(params[i]);
         return invoke(v);
      }
   }
}
TOP

Related Classes of com.dbxml.labrador.jdbc.JDBCDiscovery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.