/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.core.content.index.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.ReadableDateTime;
import com.enonic.cms.core.content.index.queryexpression.ArrayExpr;
import com.enonic.cms.core.content.index.queryexpression.FunctionExpr;
import com.enonic.cms.core.content.index.queryexpression.QueryParserException;
import com.enonic.cms.core.content.index.queryexpression.ValueExpr;
import com.enonic.cms.core.search.query.IndexValueConverter;
/**
* This class defines the query functions.
*/
public final class QueryFunctions
{
private static Object executeMethod( String name, Object[] args )
throws QueryParserException
{
Class[] types = new Class[args.length];
for ( int i = 0; i < args.length; i++ )
{
types[i] = args[i].getClass();
}
Method method;
try
{
method = findMethod( name, types );
}
catch ( Exception e )
{
throw new QueryParserException( "Function " + name + "() not found" );
}
try
{
return method.invoke( null, args );
}
catch ( InvocationTargetException e )
{
Throwable ex = e.getTargetException();
if ( ex instanceof QueryParserException )
{
throw (QueryParserException) ex;
}
else
{
throw new QueryParserException( "Error invoking " + name + "(): " + ex.getMessage() );
}
}
catch ( Exception e )
{
throw new QueryParserException( "Failed to invoke " + name + "()" );
}
}
public static ValueExpr executeFunction( FunctionExpr expr )
throws QueryParserException
{
String name = expr.getName();
ArrayExpr args = expr.getArguments();
return executeFunction( name, args.getValues() );
}
private static ValueExpr executeFunction( String name, ValueExpr[] args )
throws QueryParserException
{
Object[] values = new Object[args.length];
for ( int i = 0; i < args.length; i++ )
{
values[i] = args[i].getValue();
}
Object ret = executeMethod( name, values );
if ( ret instanceof Number )
{
return new ValueExpr( ( (Number) ret ).doubleValue() );
}
else if ( ret instanceof ReadableDateTime )
{
return new ValueExpr( (ReadableDateTime) ret );
}
else if ( ret != null )
{
return new ValueExpr( ret.toString() );
}
else
{
return new ValueExpr( 0 );
}
}
private static Method findMethod( String name, Class[] types )
throws Exception
{
String prefix = null;
String local = name;
int pos = name.indexOf( ':' );
if ( pos > 0 )
{
prefix = name.substring( 0, pos );
local = name.substring( pos + 1 );
}
else if ( pos == 0 )
{
local = name.substring( 1 );
}
return findMethod( prefix, local, types );
}
private static Method findMethod( String prefix, String local, Class[] types )
throws Exception
{
if ( prefix == null )
{
return findInternalMethod( local, types );
}
else
{
return findExternalMethod( prefix, local, types );
}
}
private static Method findInternalMethod( String name, Class[] types )
throws Exception
{
return findMethod( QueryFunctions.class, name, types );
}
private static Method findExternalMethod( String prefix, String local, Class[] types )
throws Exception
{
Class clz = Class.forName( prefix );
return findMethod( clz, local, types );
}
private static Method findMethod( Class clz, String name, Class[] types )
throws Exception
{
return clz.getMethod( name, types );
}
/**
* Built in now() function.
*
* @return A <code>Date</code> object that holds the current date and time.
*/
public static DateTime now()
{
return new DateTime();
}
/**
* Built in today() function.
*
* @return A <code>Date</code> object that holds the current date and time.
*/
public static DateMidnight today()
{
// We use DateMidnight to later recognise that user have not specified time
return new DateMidnight();
}
public static DateMidnight todayOffset( BigDecimal offset )
{
// We use DateMidnight to later recognise that user have not specified time
int offsetInDays = offset.intValue();
if ( offsetInDays >= 0 )
{
return new DateMidnight().plusDays( offsetInDays );
}
else
{
return new DateMidnight().minusDays( offsetInDays * ( -1 ) );
}
}
public static DateMidnight todayOffset( Double offset )
{
return todayOffset( new BigDecimal( offset ) );
}
/**
* Built in date() function.
*
* @param value The date to parse.
* @return A <code>Date</code> object that holds the date, parsed from the input <code>value</code>.
*/
public static ReadableDateTime date( String value )
{
return IndexValueConverter.toDate( value );
}
}