/*
* StreamCruncher: Copyright (c) 2006-2008, Ashwin Jayaprakash. All Rights Reserved.
* Contact: ashwin {dot} jayaprakash {at} gmail {dot} com
* Web: http://www.StreamCruncher.com
*
* This file is part of StreamCruncher.
*
* StreamCruncher 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 3 of the License, or
* (at your option) any later version.
*
* StreamCruncher 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 StreamCruncher. If not, see <http://www.gnu.org/licenses/>.
*/
package streamcruncher.innards.impl.expression;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import ognl.Node;
import ognl.Ognl;
import ognl.OgnlContext;
import streamcruncher.api.artifact.RowSpec;
import streamcruncher.boot.Registry;
import streamcruncher.innards.db.cache.CacheManager;
import streamcruncher.innards.db.cache.CachedData;
import streamcruncher.innards.expression.Constants;
import streamcruncher.innards.impl.query.DDLHelper;
import streamcruncher.util.LoggerManager;
import streamcruncher.util.RowEvaluator;
import streamcruncher.util.sysevent.SystemEvent;
import streamcruncher.util.sysevent.SystemEventBus;
import streamcruncher.util.sysevent.SystemEvent.Priority;
/*
* Author: Ashwin Jayaprakash Date: Jun 17, 2007 Time: 8:32:02 PM
*/
public class OgnlRowEvaluator implements RowEvaluator {
protected final String queryName;
protected final String expressionStr;
protected final OgnlRow ognlRow;
protected final Node ognlExpression;
protected final String[][] subQueryAndAlias;
protected final Map<String, Object> ognlBatchContext;
protected final CacheManager cacheManager;
public OgnlRowEvaluator(String queryName, String expressionStr, RowSpec sourceRowSpec,
Map<String, Object> context, Map<String, String> subQueries)
throws ExpressionEvaluationException {
this.queryName = queryName;
this.expressionStr = expressionStr;
try {
this.ognlRow = new OgnlRow(sourceRowSpec);
this.ognlRow.toggleTestMode();
OgnlContext ognlContext = (OgnlContext) Ognl.createDefaultContext(this.ognlRow);
this.ognlExpression = Ognl.compileExpression(ognlContext, this.ognlRow, expressionStr);
this.ognlRow.toggleTestMode();
}
catch (Exception e) {
throw new ExpressionEvaluationException(e);
}
this.ognlBatchContext = new HashMap<String, Object>();
this.subQueryAndAlias = new String[subQueries == null ? 0 : subQueries.size()][];
if (this.subQueryAndAlias.length > 0) {
int l = 0;
for (String alias : subQueries.keySet()) {
this.subQueryAndAlias[l] = new String[] { subQueries.get(alias), alias };
l++;
}
}
this.cacheManager = Registry.getImplFor(CacheManager.class);
}
public String getExpressionStr() {
return expressionStr;
}
public String getQueryName() {
return queryName;
}
public void batchStart() {
ognlBatchContext.clear();
try {
for (String[] sqlAndAlias : subQueryAndAlias) {
CachedData data = cacheManager.getCachedData(sqlAndAlias[0]);
Object obj = data.getData();
ognlBatchContext.put(sqlAndAlias[1], obj);
}
}
catch (Exception e) {
ExpressionEvaluationException exception = new ExpressionEvaluationException(
"An error occurred while executing the Pre-Filter for the Query: " + queryName,
e);
Logger logger = Registry.getImplFor(LoggerManager.class).getLogger(
OgnlRowEvaluator.class.getName());
logger.log(Level.SEVERE, exception.getMessage(), exception);
SystemEventBus bus = Registry.getImplFor(SystemEventBus.class);
SystemEvent event = new SystemEvent(OgnlRowEvaluator.class.getName(),
RowEvaluator.class.getName(), exception, Priority.SEVERE);
bus.submit(event);
}
}
public ContextHolder rowStart(ContextHolder contextHolder, Object[] row) {
OgnlContextHolder ognlContextHolder = (OgnlContextHolder) contextHolder;
if (ognlContextHolder == null) {
ognlContextHolder = new OgnlContextHolder();
}
Map<String, Object> mapContext = ognlContextHolder.getContext();
// Populate the Context only once for each Row.
if (mapContext.isEmpty()) {
mapContext.put(Constants.VARIABLE_CURRENT_TIMESTAMP, new Timestamp(System
.currentTimeMillis()));
}
ognlRow.setRow(row);
return ognlContextHolder;
}
public Object evaluate(ContextHolder contextHolder) {
Object retVal = null;
try {
OgnlContextHolder holder = (OgnlContextHolder) contextHolder;
Map<String, Object> mapContext = holder.getContext();
for (String[] sqlAndAlias : subQueryAndAlias) {
Object obj = ognlBatchContext.get(sqlAndAlias[1]);
mapContext.put(sqlAndAlias[1], obj);
}
retVal = Ognl.getValue(ognlExpression, mapContext, ognlRow);
}
catch (Exception e) {
ExpressionEvaluationException exception = new ExpressionEvaluationException(
"An error occurred while executing the Pre-Filter for the Query: " + queryName,
e);
Logger logger = Registry.getImplFor(LoggerManager.class).getLogger(
OgnlRowEvaluator.class.getName());
logger.log(Level.SEVERE, exception.getMessage(), exception);
SystemEventBus bus = Registry.getImplFor(SystemEventBus.class);
SystemEvent event = new SystemEvent(OgnlRowEvaluator.class.getName(),
RowEvaluator.class.getName(), exception, Priority.SEVERE);
bus.submit(event);
}
return retVal;
}
public void rowEnd() {
}
public void batchEnd() {
ognlBatchContext.clear();
}
// ----------------
public static class OgnlContextHolder implements ContextHolder {
protected final Map<String, Object> context;
public OgnlContextHolder() {
this.context = new HashMap<String, Object>();
}
public Map<String, Object> getContext() {
return context;
}
public void clear() {
context.clear();
}
public boolean isEmpty() {
return context.isEmpty();
}
}
public static class OgnlRow {
protected final Class[] columnDefs;
protected boolean testMode;
protected Object[] row;
/**
* See {@link DDLHelper#getJavaTypes()}.
*
* @param rowSpec
*/
public OgnlRow(RowSpec rowSpec) {
String[] types = rowSpec.getColumnNativeTypes();
this.columnDefs = new Class[types.length];
for (int i = 0; i < types.length; i++) {
String[] array = types[i].split(RowSpec.INFO_SEPARATOR);
try {
this.columnDefs[i] = Class.forName(array[0]);
}
catch (ClassNotFoundException e) {
String[] javaTypes = { java.lang.Integer.class.getName(),
java.lang.Float.class.getName(), java.lang.Double.class.getName(),
java.lang.Long.class.getName(), java.lang.String.class.getName(),
java.sql.Timestamp.class.getName() };
throw new RuntimeException("The Data type: " + array[0]
+ " is not supported. Supported Types: " + Arrays.asList(javaTypes));
}
}
}
public void toggleTestMode() {
testMode = !testMode;
}
public boolean isTestMode() {
return testMode;
}
public void setRow(Object[] row) {
this.row = row;
}
public void setColumn_$(int index, Object column) {
row[index] = column;
}
public Integer getColumn_$Integer(int index) {
if (testMode) {
return 1;
}
return row[index] == null ? null : ((Number) row[index]).intValue();
}
public Long getColumn_$Long(int index) {
if (testMode) {
return 1L;
}
return row[index] == null ? null : ((Number) row[index]).longValue();
}
public Float getColumn_$Float(int index) {
if (testMode) {
return 1.0F;
}
return row[index] == null ? null : ((Number) row[index]).floatValue();
}
public Double getColumn_$Double(int index) {
if (testMode) {
return 1.0D;
}
return row[index] == null ? null : ((Number) row[index]).doubleValue();
}
public String getColumn_$String(int index) {
if (testMode) {
return "";
}
return (String) row[index];
}
public Timestamp getColumn_$Timestamp(int index) {
if (testMode) {
return new Timestamp(System.currentTimeMillis());
}
return (Timestamp) row[index];
}
public Object getColumn_$(int index) {
if (testMode) {
return new Object();
}
return row[index];
}
}
}