/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ejb.plugins.cmp.jdbc;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Collections;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import org.jboss.ejb.plugins.cmp.ejbql.Catalog;
import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge;
import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractEntityBridge;
/**
* @author <a href="mailto:alex@jboss.org">Alex Loubyansky and others</a>
*/
import org.jboss.logging.Logger;
public final class QueryParameter
{
public static List createParameters(int argNum, JDBCFieldBridge field)
{
List parameters;
JDBCType type = field.getJDBCType();
if(type instanceof JDBCTypeComplex)
{
JDBCTypeComplexProperty[] props = ((JDBCTypeComplex)type).getProperties();
parameters = new ArrayList(props.length);
for(int i = 0; i < props.length; i++)
{
QueryParameter param = new QueryParameter(
argNum,
false,
null,
props[i],
props[i].getJDBCType());
parameters.add(param);
}
}
else
{
QueryParameter param = new QueryParameter(argNum, type);
parameters = Collections.singletonList(param);
}
return parameters;
}
public static List createParameters(int argNum, JDBCAbstractEntityBridge entity)
{
List parameters = new ArrayList();
JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
for(int i = 0; i < pkFields.length; ++i)
{
JDBCFieldBridge pkField = pkFields[i];
JDBCType type = pkField.getJDBCType();
if(type instanceof JDBCTypeComplex)
{
JDBCTypeComplexProperty[] props =
((JDBCTypeComplex)type).getProperties();
for(int j = 0; j < props.length; j++)
{
QueryParameter param = new QueryParameter(
argNum,
false,
pkField,
props[j],
props[j].getJDBCType());
parameters.add(param);
}
}
else
{
QueryParameter param = new QueryParameter(
argNum,
false,
pkField,
null,
type.getJDBCTypes()[0]);
param.type = type;
parameters.add(param);
}
}
return parameters;
}
public static List createPrimaryKeyParameters(int argNum, JDBCAbstractEntityBridge entity)
{
List parameters = new ArrayList();
JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
for(int i = 0; i < pkFields.length; ++i)
{
JDBCFieldBridge pkField = pkFields[i];
JDBCType type = pkField.getJDBCType();
if(type instanceof JDBCTypeComplex)
{
JDBCTypeComplexProperty[] props = ((JDBCTypeComplex)type).getProperties();
for(int j = 0; j < props.length; j++)
{
QueryParameter param = new QueryParameter(
argNum,
true,
pkField,
props[j],
props[j].getJDBCType());
parameters.add(param);
}
}
else
{
QueryParameter param = new QueryParameter(
argNum,
true,
pkField,
null,
type.getJDBCTypes()[0]);
param.type = type;
parameters.add(param);
}
}
return parameters;
}
private int argNum;
private final boolean isPrimaryKeyParameter;
private JDBCFieldBridge field;
private JDBCTypeComplexProperty property;
private String parameterString;
private int jdbcType;
private JDBCType type;
public QueryParameter(
JDBCEntityPersistenceStore manager,
Method method,
String parameterString)
{
// Method parameter will never be a primary key object, but always
// a complete entity.
this.isPrimaryKeyParameter = false;
this.parameterString = parameterString;
if(parameterString == null || parameterString.length() == 0)
{
throw new IllegalArgumentException("Parameter string is empty");
}
StringTokenizer tok = new StringTokenizer(parameterString, ".");
// get the argument number
try
{
argNum = Integer.parseInt(tok.nextToken());
}
catch(NumberFormatException e)
{
throw new IllegalArgumentException("The parameter must begin with a number");
}
// get the argument type
if(argNum > method.getParameterTypes().length)
{
throw new IllegalArgumentException("The parameter index is " + argNum +
" but the query method only has " +
method.getParameterTypes().length + "parameter(s)");
}
Class argType = method.getParameterTypes()[argNum];
// get the jdbc type object
JDBCType type;
// if this is an entity parameter
if(EJBObject.class.isAssignableFrom(argType) ||
EJBLocalObject.class.isAssignableFrom(argType))
{
// get the field name
// check more tokens
if(!tok.hasMoreTokens())
{
throw new IllegalArgumentException("When the parameter is an ejb a field name must be supplied.");
}
String fieldName = tok.nextToken();
// get the field from the entity
field = getCMPField(manager, argType, fieldName);
if(!field.isPrimaryKeyMember())
{
throw new IllegalArgumentException("The specified field must be a primay key field");
}
// get the jdbc type object
type = field.getJDBCType();
}
else
{
// get jdbc type from type manager
type = manager.getJDBCTypeFactory().getJDBCType(argType);
}
if(type instanceof JDBCTypeSimple)
{
if(tok.hasMoreTokens())
{
throw new IllegalArgumentException("Parameter is NOT a known " +
"dependent value class, so a properties cannot supplied.");
}
jdbcType = type.getJDBCTypes()[0];
this.type = type;
}
else
{
if(!tok.hasMoreTokens())
{
throw new IllegalArgumentException("Parmeter is a known " +
"dependent value class, so a property must be supplied");
}
// build the propertyName
StringBuffer propertyName = new StringBuffer(parameterString.length());
propertyName.append(tok.nextToken());
while(tok.hasMoreTokens())
{
propertyName.append('.').append(tok.nextToken());
}
property = ((JDBCTypeComplex)type).getProperty(propertyName.toString());
jdbcType = property.getJDBCType();
}
}
public QueryParameter(int argNum, JDBCType type)
{
this.argNum = argNum;
this.type = type;
this.jdbcType = type.getJDBCTypes()[0];
this.isPrimaryKeyParameter = false;
initToString();
}
public QueryParameter(
int argNum,
boolean isPrimaryKeyParameter,
JDBCFieldBridge field,
JDBCTypeComplexProperty property,
int jdbcType)
{
this.argNum = argNum;
this.isPrimaryKeyParameter = isPrimaryKeyParameter;
this.field = field;
this.property = property;
this.jdbcType = jdbcType;
initToString();
}
private void initToString()
{
StringBuffer parameterBuf = new StringBuffer();
parameterBuf.append(argNum);
if(field != null)
{
parameterBuf.append('.').append(field.getFieldName());
}
if(property != null)
{
parameterBuf.append('.').append(property.getPropertyName());
}
parameterString = parameterBuf.toString();
}
public void set(Logger log, PreparedStatement ps, int index, Object[] args)
throws Exception
{
Object arg = args[argNum];
JDBCParameterSetter param;
if(field != null)
{
if(!isPrimaryKeyParameter)
{
if(arg instanceof EJBObject)
{
arg = ((EJBObject)arg).getPrimaryKey();
}
else if(arg instanceof EJBLocalObject)
{
arg = ((EJBLocalObject)arg).getPrimaryKey();
}
else
{
throw new IllegalArgumentException("Expected an instanc of " +
"EJBObject or EJBLocalObject, but got an instance of " +
arg.getClass().getName());
}
}
arg = field.getPrimaryKeyValue(arg);
// use mapper
final JDBCType jdbcType = field.getJDBCType();
arg = jdbcType.getColumnValue(0, arg);
param = jdbcType.getParameterSetter()[0];
}
else if(property != null)
{
arg = property.getColumnValue(arg);
param = property.getParameterSetter();
}
else
{
if(type != null)
{
arg = type.getColumnValue(0, arg);
param = type.getParameterSetter()[0];
}
else
{
param = JDBCUtil.getParameterSetter(jdbcType, arg == null ? null : arg.getClass());
}
}
param.set(ps, index, jdbcType, arg, log);
//JDBCUtil.setParameter(log, ps, index, jdbcType, arg);
}
private static JDBCFieldBridge getCMPField(
JDBCEntityPersistenceStore manager,
Class intf,
String fieldName)
{
Catalog catalog = manager.getCatalog();
JDBCAbstractEntityBridge entityBridge = (JDBCAbstractEntityBridge)catalog.getEntityByInterface(intf);
if(entityBridge == null)
{
throw new IllegalArgumentException("Entity not found in application " +
"catalog with interface=" + intf.getName());
}
JDBCFieldBridge cmpField = (JDBCFieldBridge)entityBridge.getFieldByName(fieldName);
if(cmpField == null)
{
throw new IllegalArgumentException("cmpField not found:" +
" cmpFieldName=" + fieldName +
" entityName=" + entityBridge.getEntityName());
}
return cmpField;
}
public String toString()
{
return parameterString;
}
}