/* * 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.designer.metamodels.function.aspects.validation.rules; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.ecore.EObject; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.util.VdbHelper; import org.teiid.designer.core.util.VdbHelper.VdbFolders; import org.teiid.designer.core.validation.ObjectValidationRule; import org.teiid.designer.core.validation.ValidationContext; import org.teiid.designer.core.validation.ValidationProblem; import org.teiid.designer.core.validation.ValidationProblemImpl; import org.teiid.designer.core.validation.ValidationResult; import org.teiid.designer.core.validation.ValidationResultImpl; import org.teiid.designer.core.validation.rules.CoreValidationRulesUtil; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.extension.ExtensionPlugin; import org.teiid.designer.extension.definition.ModelObjectExtensionAssistant; import org.teiid.designer.metamodels.core.Annotation; import org.teiid.designer.metamodels.function.FunctionPlugin; import org.teiid.designer.metamodels.function.PushDownType; import org.teiid.designer.metamodels.function.ReturnParameter; import org.teiid.designer.metamodels.function.ScalarFunction; import org.teiid.designer.metamodels.function.aspects.validation.FunctionEntityAspect; import org.teiid.designer.metamodels.function.extension.FunctionModelExtensionConstants; /** * ScalarFunctionRule * * @since 8.0 */ public class ScalarFunctionRule implements ObjectValidationRule { /* * @See org.teiid.designer.core.validation.ObjectValidationRule#validate(org.eclipse.emf.ecore.EObject, org.teiid.designer.core.validation.ValidationContext) */ @Override public void validate(EObject eObject, ValidationContext context) { CoreArgCheck.isInstanceOf(ScalarFunction.class, eObject); // create a validationResult to add problems to ValidationResult result = new ValidationResultImpl(eObject); ScalarFunction sFunction = (ScalarFunction) eObject; // Validate the name ... // (Not done with the StringNameRule, since it looks at siblings ... validateName(sFunction,result); // validate the return parameter validateReturnParameter(sFunction.getReturnParameter(), result); // validate invocation class String invocationClass = sFunction.getInvocationClass(); if(CoreStringUtil.isEmpty(invocationClass) && !sFunction.getPushDown().equals(PushDownType.REQUIRED_LITERAL)) { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR ,FunctionPlugin.Util.getString("ScalarFunctionRule.Invocation_class_must_be_specified_on_a_scalar_function._1")); //$NON-NLS-1$ result.addProblem(problem); } else { validateJavaIdentifier(invocationClass, FunctionPlugin.Util.getString("ScalarFunctionRule.Invocation_class_3"), true, result); //$NON-NLS-1$ } // validate invocation method String invocationMethod = sFunction.getInvocationMethod(); if(CoreStringUtil.isEmpty(invocationMethod) && !sFunction.getPushDown().equals(PushDownType.REQUIRED_LITERAL)) { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR ,FunctionPlugin.Util.getString("ScalarFunctionRule.Invocation_method_must_be_specified_on_a_scalar_function._2")); //$NON-NLS-1$ result.addProblem(problem); } else { validateJavaIdentifier(invocationMethod, FunctionPlugin.Util.getString("ScalarFunctionRule.Invocation_Method_4"), false, result); //$NON-NLS-1$ } // validate jarPath property validateUdfJarPath(sFunction,result); // validate function category String category = sFunction.getCategory(); if (CoreStringUtil.isEmpty(category)) { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR , FunctionPlugin.Util.getString("ScalarFunctionRule.Category_can_not_be_null_or_empty")); //$NON-NLS-1$ result.addProblem(problem); } else { validateLength(category, FunctionPlugin.Util.getString("ScalarFunctionRule.Category_5"), result); //$NON-NLS-1$ } // validate function description try { Annotation annotation = ModelerCore.getModelEditor().getAnnotation(sFunction, false); if(annotation != null) { validateLength(annotation.getDescription(), FunctionPlugin.Util.getString("ScalarFunctionRule.Description_1"), result); //$NON-NLS-1$ } } catch(ModelerCoreException e) { ModelerCore.Util.log(IStatus.ERROR,e,FunctionPlugin.Util.getString("ScalarFunctionRule.Error_trying_to_lookup_model_annotation_for_the_function_{0}._2", sFunction.getName())); //$NON-NLS-1$ } // add the result to the context context.addResult(result); } /** * @param sFunction * @param result */ private void validateName(ScalarFunction sFunction, ValidationResult result) { // Get the name ... final String name = sFunction.getName(); final char[] validChars = null; CoreValidationRulesUtil.validateStringNameChars(result, name, validChars); } private final void validateReturnParameter(ReturnParameter rParam, ValidationResult result) { // if null already validated by multiplycity rule if(rParam != null) { String paramType = rParam.getType(); if(CoreStringUtil.isEmpty(paramType)) { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR ,FunctionPlugin.Util.getString("ScalarFunctionRule.Type_should_be_specified_on_the_return_parameter_of_a_scalar_function._7")); //$NON-NLS-1$ result.addProblem(problem); } validateJavaIdentifier(paramType, FunctionPlugin.Util.getString("ScalarFunctionRule.Return_Parameter_8"), true, result); //$NON-NLS-1$ } } /** * Check that specified string is valid Java identifier. If not, create problems on the validation result. * @param identifier String to check * @param strName String to use in exception message * @param allowMultiple True if multiple identifiers are allowed, as in a class name */ private final void validateJavaIdentifier(String identifier, String strName, boolean allowMultiple, ValidationResult result) { // First check first character if(!CoreStringUtil.isEmpty(identifier)) { char firstChar = identifier.charAt(0); if(! Character.isJavaIdentifierStart(firstChar)) { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR , strName+FunctionPlugin.Util.getString("ScalarFunctionRule._has_invalid_first_character___10")+firstChar); //$NON-NLS-1$ result.addProblem(problem); } // Then check the rest of the characters for(int i=1; i<identifier.length(); i++) { char ch = identifier.charAt(i); if(! Character.isJavaIdentifierPart(ch)) { if(! allowMultiple || ! (ch == '.')) { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR , strName+FunctionPlugin.Util.getString("ScalarFunctionRule._has_invalid_character___11")+firstChar); //$NON-NLS-1$ result.addProblem(problem); } } } if(identifier.charAt(identifier.length()-1) == '.') { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR ,strName+FunctionPlugin.Util.getString("ScalarFunctionRule._cannot_end_with_a___.___13")); //$NON-NLS-1$ result.addProblem(problem); } } } /** * Check that specified string is no longer than maxLength. If string is longer, problem gets added * to the validation result. * @param string String to check for length * @param strName Name of string to use in exception message */ private final void validateLength(String string, String strName, ValidationResult result) { if(string!= null && string.length() > FunctionEntityAspect.MAX_ENTITY_NAME_LENGTH) { ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR , strName+FunctionPlugin.Util.getString("ScalarFunctionRule._exceeds_maximum_length_of___9")+FunctionEntityAspect.MAX_ENTITY_NAME_LENGTH); //$NON-NLS-1$ result.addProblem(problem); } } /** * Validate the udfJarPath property. * - the path must be set * - the specified jar must be located in the workspace project * @param scalarFunc the Scalar Function to validate * @param result the ValidationResult */ private final void validateUdfJarPath(ScalarFunction scalarFunc, ValidationResult result) { String udfJarPath = getUdfJarPath(scalarFunc); if(udfJarPath!=null) { if (CoreStringUtil.isEmpty(udfJarPath.trim())) { String message = FunctionPlugin.Util.getString("ScalarFunctionRule.udfJarPathNotSet"); //$NON-NLS-1$ ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR ,message); result.addProblem(problem); } else { final ModelResource resrc = ModelerCore.getModelWorkspace().findModelResource(scalarFunc); IProject project = resrc.getModelProject().getProject(); IContainer libFolder = VdbHelper.getFolder(project, VdbFolders.UDF.getReadFolder()); boolean found = VdbHelper.isFileInFolder(libFolder, udfJarPath); if(!found) { String message = FunctionPlugin.Util.getString("ScalarFunctionRule.udfJarNotFound",udfJarPath); //$NON-NLS-1$ ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR ,message); result.addProblem(problem); } } } } /** * Get the Udf jarPath property from the supplied ScalarFunction * @param scalarFunc the supplied ScalarFunction * @return the Udf jarPath property value */ private static String getUdfJarPath(final ScalarFunction scalarFunc) { String udfJarPath = null; ModelObjectExtensionAssistant assistant = (ModelObjectExtensionAssistant)ExtensionPlugin.getInstance().getRegistry().getModelExtensionAssistant(FunctionModelExtensionConstants.NAMESPACE_PROVIDER.getNamespacePrefix()); if(assistant!=null) { try { udfJarPath = assistant.getPropertyValue(scalarFunc, FunctionModelExtensionConstants.PropertyIds.UDF_JAR_PATH); } catch (Exception ex) { ModelerCore.Util.log(IStatus.ERROR,ex,FunctionPlugin.Util.getString("FunctionUtil.ErrorGettingJarPath", scalarFunc.getName())); //$NON-NLS-1$ } } return udfJarPath; } }