/*
* 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.metadata;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import org.jboss.deployment.DeploymentException;
import org.jboss.metadata.MetaData;
import org.w3c.dom.Element;
public final class JDBCFunctionMappingMetaData
{
private final String functionName;
private String[] sqlChunks;
private int[] parameters;
public JDBCFunctionMappingMetaData(String functionName, String[] sqlChunks, int[] parameters)
{
this.functionName = functionName;
this.sqlChunks = sqlChunks;
this.parameters = parameters;
}
public JDBCFunctionMappingMetaData(Element element) throws DeploymentException
{
functionName = MetaData.getUniqueChildContent(element, "function-name");
String sql = MetaData.getUniqueChildContent(element, "function-sql");
initFromString(sql);
}
public JDBCFunctionMappingMetaData(String functionName, String sql) throws DeploymentException
{
this.functionName = functionName;
initFromString(sql);
}
private void initFromString(String sql) throws DeploymentException
{
ArrayList chunkList = new ArrayList();
ArrayList parameterList = new ArrayList();
// add a dummy chunk so we can be assured that the sql started with chunk before a number
if(sql.charAt(0) == '?')
{
chunkList.add("");
}
// break the sql into chunks and parameters
StringBuffer chunk = new StringBuffer();
StringReader reader = new StringReader(sql);
try
{
for(int c = reader.read(); c >= 0; c = reader.read())
{
if(c != '?')
{
chunk.append((char)c);
}
else
{
chunkList.add(chunk.toString());
chunk = new StringBuffer();
// read the number
StringBuffer number = new StringBuffer();
for(int digit = reader.read(); digit >= 0; digit = reader.read())
{
if(Character.isDigit((char)digit))
{
number.append((char)digit);
}
else
{
if(digit >= 0)
{
chunk.append((char)digit);
}
break;
}
}
if(number.length() == 0)
{
throw new DeploymentException("Invalid parameter in function-sql: " + sql);
}
Integer parameter;
try
{
parameter = new Integer(number.toString());
}
catch(NumberFormatException e)
{
throw new DeploymentException("Invalid parameter number in function-sql: number=" + number + " sql=" + sql);
}
parameterList.add(parameter);
}
}
}
catch(IOException e)
{
// will never happen because io is in memory, but required by the interface
throw new DeploymentException("Error parsing function-sql: " + sql);
}
chunkList.add(chunk.toString());
// save out the chunks
sqlChunks = new String[chunkList.size()];
chunkList.toArray(sqlChunks);
// save out the parameter order
parameters = new int[parameterList.size()];
for(int i = 0; i < parameters.length; i++)
{
parameters[i] = ((Integer)parameterList.get(i)).intValue() - 1;
}
}
public String getFunctionName()
{
return functionName;
}
public StringBuffer getFunctionSql(Object[] args, StringBuffer buf)
{
for(int i = 0; i < sqlChunks.length; i++)
{
if(i < parameters.length)
{
// the logic is that if there is a parameter
// than append its chunck unless the parameter is null
// FIXME: I am not sure it's ok for any kind of template.
Object arg = args[parameters[i]];
if(arg != null)
{
buf.append(sqlChunks[i]);
buf.append(arg);
}
}
else
{
// this is tail
buf.append(sqlChunks[i]);
}
}
return buf;
}
}