/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.epl.expression.core;
import com.espertech.esper.client.EventPropertyDescriptor;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.PropertyAccessException;
import com.espertech.esper.collection.Pair;
import com.espertech.esper.epl.core.PropertyResolutionDescriptor;
import com.espertech.esper.epl.core.StreamTypeService;
import com.espertech.esper.epl.core.StreamTypesException;
import com.espertech.esper.epl.table.mgmt.TableServiceUtil;
import com.espertech.esper.util.LevenshteinDistance;
public class ExprIdentNodeUtil {
public static Pair<PropertyResolutionDescriptor, String> getTypeFromStream(StreamTypeService streamTypeService, String propertyNameNestable, boolean explicitPropertiesOnly, boolean obtainFragment)
throws ExprValidationPropertyException {
String streamOrProp = null;
String prop = propertyNameNestable;
if (propertyNameNestable.indexOf('.') != -1) {
prop = propertyNameNestable.substring(propertyNameNestable.indexOf('.') + 1);
streamOrProp = propertyNameNestable.substring(0, propertyNameNestable.indexOf('.'));
}
if (explicitPropertiesOnly) {
return getTypeFromStreamExplicitProperties(streamTypeService, prop, streamOrProp, obtainFragment);
}
return getTypeFromStream(streamTypeService, prop, streamOrProp, obtainFragment);
}
protected static Pair<PropertyResolutionDescriptor, String> getTypeFromStream(StreamTypeService streamTypeService, String unresolvedPropertyName, String streamOrPropertyName, boolean obtainFragment)
throws ExprValidationPropertyException {
PropertyResolutionDescriptor propertyInfo = null;
// no stream/property name supplied
if (streamOrPropertyName == null) {
try {
propertyInfo = streamTypeService.resolveByPropertyName(unresolvedPropertyName, obtainFragment);
} catch (StreamTypesException ex) {
throw getSuggestionException(ex);
} catch (PropertyAccessException ex) {
throw new ExprValidationPropertyException("Failed to find property '" + unresolvedPropertyName + "', the property name does not parse (are you sure?): " + ex.getMessage(), ex);
}
// resolves without a stream name, return descriptor and null stream name
return new Pair<PropertyResolutionDescriptor, String>(propertyInfo, propertyInfo.getStreamName());
}
// try to resolve the property name and stream name as it is (ie. stream name as a stream name)
StreamTypesException typeExceptionOne;
try {
propertyInfo = streamTypeService.resolveByStreamAndPropName(streamOrPropertyName, unresolvedPropertyName, obtainFragment);
// resolves with a stream name, return descriptor and stream name
return new Pair<PropertyResolutionDescriptor, String>(propertyInfo, streamOrPropertyName);
} catch (StreamTypesException ex) {
typeExceptionOne = ex;
}
// try to resolve the property name to a nested property 's0.p0'
StreamTypesException typeExceptionTwo;
String propertyNameCandidate = streamOrPropertyName + '.' + unresolvedPropertyName;
try {
propertyInfo = streamTypeService.resolveByPropertyName(propertyNameCandidate, obtainFragment);
// resolves without a stream name, return null for stream name
return new Pair<PropertyResolutionDescriptor, String>(propertyInfo, null);
} catch (StreamTypesException ex) {
typeExceptionTwo = ex;
}
// not resolved yet, perhaps the table name did not match an event type
if (streamTypeService.hasTableTypes() && streamOrPropertyName != null) {
for (int i = 0; i < streamTypeService.getEventTypes().length; i++) {
EventType eventType = streamTypeService.getEventTypes()[i];
String tableName = TableServiceUtil.getTableNameFromEventType(eventType);
if (tableName != null && tableName.equals(streamOrPropertyName)) {
try {
propertyInfo = streamTypeService.resolveByStreamAndPropName(eventType.getName(), unresolvedPropertyName, obtainFragment);
} catch (Exception ex) {
}
if (propertyInfo != null) {
return new Pair<PropertyResolutionDescriptor, String>(propertyInfo, streamOrPropertyName);
}
}
}
}
// see if the stream or property name (the prefix) can be resolved by itself, without suffix
// the property available may be indexed or mapped
try {
PropertyResolutionDescriptor desc = streamTypeService.resolveByPropertyName(streamOrPropertyName, false);
if (desc != null) {
EventPropertyDescriptor d2 = desc.getStreamEventType().getPropertyDescriptor(streamOrPropertyName);
if (d2 != null) {
String text = null;
if (d2.isIndexed()) {
text = "an indexed property and requires an index or enumeration method to access values";
}
if (d2.isMapped()) {
text = "a mapped property and requires keyed access";
}
if (text != null) {
throw new ExprValidationPropertyException("Failed to resolve property '" + propertyNameCandidate + "' (property '" + streamOrPropertyName + "' is " + text + ")");
}
}
}
} catch (StreamTypesException e) {
// need not be handled
}
throw getSuggestionExceptionSecondStep(propertyNameCandidate, typeExceptionOne, typeExceptionTwo);
}
protected static Pair<PropertyResolutionDescriptor, String> getTypeFromStreamExplicitProperties(StreamTypeService streamTypeService, String unresolvedPropertyName, String streamOrPropertyName, boolean obtainFragment)
throws ExprValidationPropertyException {
PropertyResolutionDescriptor propertyInfo;
// no stream/property name supplied
if (streamOrPropertyName == null) {
try {
propertyInfo = streamTypeService.resolveByPropertyNameExplicitProps(unresolvedPropertyName, obtainFragment);
} catch (StreamTypesException ex) {
throw getSuggestionException(ex);
} catch (PropertyAccessException ex) {
throw new ExprValidationPropertyException(ex.getMessage());
}
// resolves without a stream name, return descriptor and null stream name
return new Pair<PropertyResolutionDescriptor, String>(propertyInfo, propertyInfo.getStreamName());
}
// try to resolve the property name and stream name as it is (ie. stream name as a stream name)
StreamTypesException typeExceptionOne;
try {
propertyInfo = streamTypeService.resolveByStreamAndPropNameExplicitProps(streamOrPropertyName, unresolvedPropertyName, obtainFragment);
// resolves with a stream name, return descriptor and stream name
return new Pair<PropertyResolutionDescriptor, String>(propertyInfo, streamOrPropertyName);
} catch (StreamTypesException ex) {
typeExceptionOne = ex;
}
// try to resolve the property name to a nested property 's0.p0'
StreamTypesException typeExceptionTwo;
String propertyNameCandidate = streamOrPropertyName + '.' + unresolvedPropertyName;
try {
propertyInfo = streamTypeService.resolveByPropertyNameExplicitProps(propertyNameCandidate, obtainFragment);
// resolves without a stream name, return null for stream name
return new Pair<PropertyResolutionDescriptor, String>(propertyInfo, null);
} catch (StreamTypesException ex) {
typeExceptionTwo = ex;
}
throw getSuggestionExceptionSecondStep(propertyNameCandidate, typeExceptionOne, typeExceptionTwo);
}
private static ExprValidationPropertyException getSuggestionExceptionSecondStep(String propertyNameCandidate, StreamTypesException typeExceptionOne, StreamTypesException typeExceptionTwo) {
String suggestionOne = getSuggestion(typeExceptionOne);
String suggestionTwo = getSuggestion(typeExceptionTwo);
if (suggestionOne != null) {
return new ExprValidationPropertyException(typeExceptionOne.getMessage() + suggestionOne);
}
if (suggestionTwo != null) {
return new ExprValidationPropertyException(typeExceptionTwo.getMessage() + suggestionTwo);
}
// fail to resolve
return new ExprValidationPropertyException("Failed to resolve property '" + propertyNameCandidate + "' to a stream or nested property in a stream");
}
private static ExprValidationPropertyException getSuggestionException(StreamTypesException ex) {
String suggestion = getSuggestion(ex);
if (suggestion != null) {
return new ExprValidationPropertyException(ex.getMessage() + suggestion);
} else {
return new ExprValidationPropertyException(ex.getMessage());
}
}
private static String getSuggestion(StreamTypesException ex) {
if (ex == null) {
return null;
}
Pair<Integer, String> suggestion = ex.getOptionalSuggestion();
if (suggestion == null) {
return null;
}
if (suggestion.getFirst() > LevenshteinDistance.ACCEPTABLE_DISTANCE) {
return null;
}
return " (did you mean '" + ex.getOptionalSuggestion().getSecond() + "'?)";
}
}