/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.query.ui.builder.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.I18nUtil; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.query.IQueryFactory; import org.teiid.designer.query.IQueryService; import org.teiid.designer.query.sql.lang.IExpression; import org.teiid.designer.query.sql.lang.ILanguageObject; import org.teiid.designer.query.sql.symbol.IConstant; import org.teiid.designer.query.sql.symbol.IFunction; import org.teiid.designer.udf.IFunctionForm; import org.teiid.designer.udf.IFunctionLibrary; import org.teiid.designer.udf.UdfManager; import org.teiid.query.ui.builder.util.BuilderUtils; /** * FunctionEditorModel * * @since 8.0 */ public class FunctionEditorModel extends AbstractLanguageObjectEditorModel { // ///////////////////////////////////////////////////////////////////////////////////////////// // CONSTANTS // ///////////////////////////////////////////////////////////////////////////////////////////// private static final String PREFIX = I18nUtil.getPropertyPrefix(FunctionEditorModel.class); private static final String NONE = Util.getString(PREFIX + "none"); //$NON-NLS-1$ public static final String CATEGORY = "CATEGORY"; //$NON-NLS-1$ public static final String SELECTED_FUNCTION = "SELECTED_FUNCTION"; //$NON-NLS-1$ // ///////////////////////////////////////////////////////////////////////////////////////////// // FIELDS // ///////////////////////////////////////////////////////////////////////////////////////////// private List argNames; // the current function's argument names private List argValues; // the current function's argument values private String[] categories; private String category; private String[] functions; // collection of function names valid for current category private IFunctionForm[] functionForms; private static String defaultCategory; /** The function library. All information about functions is obtained from here. */ private IFunctionLibrary funcLib; private IFunctionForm selectedFunctionForm; // ///////////////////////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS // ///////////////////////////////////////////////////////////////////////////////////////////// public FunctionEditorModel() { super(IFunction.class); getCategories(); } // ///////////////////////////////////////////////////////////////////////////////////////////// // METHODS // ///////////////////////////////////////////////////////////////////////////////////////////// /* (non-Javadoc) * @see org.teiid.query.ui.builder.model.AbstractLanguageObjectEditorModel#clear() */ @Override public void clear() { argNames = null; argValues = null; selectedFunctionForm = null; super.clear(); } private IFunctionForm findFunctionForm( String theFunctionName ) { IFunctionForm result = null; if (functionForms != null) { for (int i = 0; i < functionForms.length; i++) { if (functionForms[i].getDisplayString().equals(theFunctionName)) { result = functionForms[i]; break; } } } return result; } public String[] getCategories() { // not sure if users can dynamically add categories. // make this construct categories each time this method is called categories = null; funcLib = UdfManager.getInstance().getFunctionLibrary(); //new FunctionLibrary(SystemFunctionManager.getSystemFunctions(), //new FunctionTree(new UDFSource(Collections.EMPTY_LIST))); List list = funcLib.getFunctionCategories(); if ((list != null) && !list.isEmpty()) { Object[] temp = list.toArray(); if ((temp != null) && (temp.length > 0)) { categories = new String[temp.length]; for (int i = 0; i < categories.length; i++) { categories[i] = temp[i].toString(); } } } // no categories found. shouldn't happen. if (categories == null) { categories = new String[1]; categories[0] = NONE; } defaultCategory = categories[0]; // set default to first category return categories; } public String getCategory() { return category; } public String getDefaultCategory() { return defaultCategory; } /** * Gets the current value. * * @return the current <code>Function</code> * @throws IllegalStateException if the current value is not complete */ public IFunction getFunction() { return (IFunction)getLanguageObject(); } /* (non-Javadoc) * @see org.teiid.query.ui.builder.model.AbstractLanguageObjectEditorModel#getLanguageObject() */ @Override public ILanguageObject getLanguageObject() { // return null if not complete if (!isComplete()) { return null; } int numArgs = argValues.size(); List<IExpression> args = new ArrayList<IExpression>(); for (int i = 0; i < numArgs; i++) { args.add((IExpression)argValues.get(i)); } IQueryService service = ModelerCore.getTeiidQueryService(); IQueryFactory factory = service.createQueryFactory(); return factory.createFunction(selectedFunctionForm.getName(), args); } /** * Gets the appropriate value for the function argument trying to use the given value. * * @param theFunctionName the function name * @param theArgName the argument name * @param theProposedValue the proposed value */ private Object getFunctionArgValue( String theFunctionName, String theArgName, Object theProposedValue ) { Object result = theProposedValue; if (BuilderUtils.isConversionTypeArg(theFunctionName, theArgName)) { if ((theProposedValue instanceof IConstant) && BuilderUtils.isConversionTypeConstant(theProposedValue)) { result = theProposedValue; } else { result = BuilderUtils.createConversionTypeConstant(); } } return result; } public String[] getFunctions() { return functions; } public List getFunctionArgNames() { return argNames; } public String getFunctionDescription() { return (selectedFunctionForm == null) ? null : selectedFunctionForm.getDescription(); } public String getFunctionName() { return (selectedFunctionForm == null) ? null : selectedFunctionForm.getDisplayString(); } public List getFunctionArgValues() { return argValues; } /* (non-Javadoc) * @see org.teiid.query.ui.builder.model.AbstractLanguageObjectEditorModel#isComplete() */ @Override public boolean isComplete() { return (selectedFunctionForm != null); } public boolean isValid() { boolean result = isComplete(); if (result) { // make sure argNames have values for (int size = argValues.size(), i = 0; i < size; i++) { if (argValues.get(i) == null) { result = false; break; } } } return result; } public void setCategory( String theCategory ) { // only set category if not null and valid if ((theCategory != null)) { boolean changeCategory = true; if (category == null ) { changeCategory = true; } else if((category.toUpperCase() != null) && category.equals(theCategory.toUpperCase()) ) { changeCategory = false; } if (changeCategory) { category = theCategory; // get corresponding functions for category functions = null; functionForms = null; selectedFunctionForm = null; @SuppressWarnings("deprecation") List<IFunctionForm> forms = funcLib.getFunctionForms(category); if ((forms != null) && !forms.isEmpty()) { // Create a SET of display strings to eliminate duplicate Method signatures Set<String> filteredDisplayStrings = new HashSet<String>(); for( IFunctionForm iForm : forms ) { String displayString = iForm.getDisplayString(); filteredDisplayStrings.add(displayString); } List<String> filteredList = new ArrayList<String>(filteredDisplayStrings); // SORT the list Collections.sort(filteredList); // Set the functions list functions = filteredList.toArray(new String[filteredList.size()]); // Still create an array of IFunctionForms int size = forms.size(); functionForms = new IFunctionForm[size]; for (int i = 0; i < size; i++) { functionForms[i] = (IFunctionForm) forms.get(i); } } else { functionForms = new IFunctionForm[1]; functions = new String[1]; functions[0] = NONE; } fireModelChanged(CATEGORY); } } } private void setFunction( IFunction theFunction ) { notifyListeners = false; if (theFunction == null) { clear(); } else { IExpression[] newArgValues = theFunction.getArgs(); IFunctionForm functionForm = funcLib.findFunctionForm(theFunction.getName(), newArgValues.length); if( functionForm != null ) { setCategory(functionForm.getCategory()); setFunctionName(functionForm.getDisplayString()); } // set current arg values argValues = Arrays.asList(newArgValues); } notifyListeners = true; fireModelChanged(LanguageObjectEditorModelEvent.SAVED); } /** * Sets the function argument at the given index. * * @param theValue * @param theIndex * @throws IllegalArgumentException if the argument value array is null * @throws ArrayIndexOutOfBoundsException if the index is invalid */ public void setFunctionArgValue( IExpression theValue, int theIndex ) { CoreArgCheck.isNotNull(argValues); argValues.set(theIndex, theValue); } public void setFunctionName( String theName ) { IFunctionForm functionForm = findFunctionForm(theName); CoreArgCheck.isNotNull(functionForm); if ((selectedFunctionForm == null) || !selectedFunctionForm.equals(functionForm)) { selectedFunctionForm = functionForm; // set new function arguments List prevArgValues = argValues; int prevNumArgs = (prevArgValues == null) ? 0 : prevArgValues.size(); argNames = selectedFunctionForm.getArgNames(); argValues = new ArrayList(argNames.size()); // reuse prior arg values if possible String functionName = selectedFunctionForm.getName(); for (int numArgs = argNames.size(), i = 0; i < numArgs; i++) { // set value String argName = (String)argNames.get(i); Object value = null; if (i < prevNumArgs) { Object arg = prevArgValues.get(i); if (!BuilderUtils.isConversionTypeConstant(arg) && !BuilderUtils.isConversionTypeArg(functionName, argName)) { // keep value when both old/new argNames are not conversion type constants value = getFunctionArgValue(functionName, argName, arg); } else if (BuilderUtils.isConversionTypeConstant(arg) && BuilderUtils.isConversionTypeArg(functionName, argName)) { // keep value when both old/new argNames are conversion type constants value = getFunctionArgValue(functionName, argName, arg); } } // if value is not set yet get undefined value or conversion type constant if (value == null) { value = getFunctionArgValue(functionName, argName, null); } argValues.add(value); } fireModelChanged(SELECTED_FUNCTION); } } /* (non-Javadoc) * @see org.teiid.query.ui.builder.model.AbstractLanguageObjectEditorModel#setLanguageObject(org.teiid.query.sql.LanguageObject) */ @Override public void setLanguageObject( ILanguageObject theLangObj ) { super.setLanguageObject(theLangObj); setFunction((IFunction)theLangObj); } }