package org.teiid.designer.modelgenerator.xsd.procedures; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.xml.namespace.QName; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.xsd.XSDTypeDefinition; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.query.QueryValidator; import org.teiid.designer.core.types.DatatypeConstants; import org.teiid.designer.core.workspace.ModelWorkspaceException; import org.teiid.designer.metamodels.relational.Column; import org.teiid.designer.metamodels.relational.DirectionKind; import org.teiid.designer.metamodels.relational.NullableType; import org.teiid.designer.metamodels.relational.Procedure; import org.teiid.designer.metamodels.relational.ProcedureParameter; import org.teiid.designer.metamodels.relational.ProcedureResult; import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot; import org.teiid.designer.schema.tools.NameUtil; import org.teiid.designer.transformation.util.TransformationHelper; import org.teiid.designer.transformation.util.TransformationMappingHelper; /** * @since 8.0 */ public class RequestBuilderTraversalContext extends BaseTraversalContext implements TraversalContext { public static final String REQUEST = "request_"; //$NON-NLS-1$ public static final String XML_OUT = "xml_out"; //$NON-NLS-1$ private Procedure procedure; private List<ProcedureParameter> cachedParams = new ArrayList(); private ProcedureResult procedureResult; public RequestBuilderTraversalContext(String procedureName, QName namespace, TraversalContext ctx, ProcedureBuilder builder) { super(procedureName, namespace, ctx, builder); } public RequestBuilderTraversalContext(String procedureName, QName namespace, ProcedureBuilder builder) { super(procedureName, namespace, builder); } @Override public void addColumn(String name, XSDTypeDefinition type) throws ModelerCoreException { if (procedure == null) { procedure = createProcedure(procedureName); } ProcedureParameter param = factory.createProcedureParameter(); procedure.getParameters().add(param); param.setDirection(DirectionKind.IN_LITERAL); String uniqueName = getUniqueName(param, NameUtil.normalizeName(name)); param.setName(uniqueName); param.setNameInSource(uniqueName); param.setNullable(NullableType.NULLABLE_LITERAL); param.setType(datatypeManager.getDatatypeForXsdType(type)); setReachedResultNode(true); cachedParams.add(param); // see RevalidateModelTransformationsAction } Procedure createProcedure(String procedureNameBase) throws ModelWorkspaceException, ModelerCoreException { Procedure procedure = factory.createProcedure(); builder.getSchema().getProcedures().add(procedure); String uniqueName = getUniqueName(procedure, REQUEST + NameUtil.normalizeName(procedureNameBase)); procedure.setName(uniqueName); procedure.setNameInSource(procedureNameBase); builder.addProcedure(procedureNameBase); procedureResult = factory.createProcedureResult(); procedure.setResult(procedureResult); procedureResult.setName(NameUtil.normalizeName(procedureNameBase) + IBuilderConstants.V_FUNC_RESULT); procedureResult.setNameInSource(procedureNameBase); Column resultCol = factory.createColumn(); procedureResult.getColumns().add(resultCol); resultCol.setName(XML_OUT); resultCol .setType(datatypeManager .getBuiltInDatatype(DatatypeConstants.BuiltInNames.XML_LITERAL)); return procedure; } @Override public void createTransformation() { if (null != procedure) { StringBuffer sqlString = new StringBuffer(); sqlString.append(IBuilderConstants.V_FUNC_PREAMBLE); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_SELECT); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_XML_ELEMENT); sqlString.append(IBuilderConstants.V_FUNC_OPEN); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_NAME); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_DOUBLE_QUOTE); sqlString.append(procedureResult.getNameInSource()); sqlString.append(IBuilderConstants.V_FUNC_DOUBLE_QUOTE); sqlString.append(IBuilderConstants.V_FUNC_COMMA); sqlString.append(IBuilderConstants.V_FUNC_SPACE); if(null != getNamespace() || !getNamespace().getNamespaceURI().isEmpty()) { sqlString.append(IBuilderConstants.V_FUNC_XMLNAMESPACES); sqlString.append(IBuilderConstants.V_FUNC_OPEN); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_DEFAULT); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_QUOTE); sqlString.append(getNamespace().getNamespaceURI()); sqlString.append(IBuilderConstants.V_FUNC_QUOTE); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_CLOSE); sqlString.append(IBuilderConstants.V_FUNC_COMMA); } boolean firstTime = true; for (ProcedureParameter param : cachedParams) { if (!firstTime) { sqlString.append(IBuilderConstants.V_FUNC_COMMA); sqlString.append(IBuilderConstants.V_FUNC_SPACE); } sqlString.append(IBuilderConstants.V_FUNC_XML_ELEMENT); sqlString.append(IBuilderConstants.V_FUNC_OPEN); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_NAME); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_DOUBLE_QUOTE); sqlString.append(param.getNameInSource()); sqlString.append(IBuilderConstants.V_FUNC_DOUBLE_QUOTE); sqlString.append(IBuilderConstants.V_FUNC_COMMA); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(param.getName()); sqlString.append(IBuilderConstants.V_FUNC_CLOSE); firstTime = false; } sqlString.append(IBuilderConstants.V_FUNC_CLOSE); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_AS_XML_OUT); sqlString.append(IBuilderConstants.V_FUNC_SPACE); sqlString.append(IBuilderConstants.V_FUNC_POSTSCRIPT); SqlTransformationMappingRoot root = (SqlTransformationMappingRoot) TransformationHelper .getTransformationMappingRoot(procedure); TransformationHelper.setSqlString(root, sqlString.toString(), QueryValidator.SELECT_TRNS, true, this); TransformationMappingHelper.reconcileMappingsOnSqlChange( root, this); } } private String getUniqueName(final EObject eObject, final String proposedName) { CoreArgCheck.isNotNull(eObject); final EStructuralFeature nameFeature = ModelerCore.getModelEditor().getNameFeature(eObject); if (nameFeature != null) { return generateUniqueInternalName( eObject.eContainer() == null ? eObject.eResource().getContents() : eObject.eContainer().eContents(), eObject, nameFeature, proposedName); } return proposedName; } private String generateUniqueInternalName(final EList siblings, final EObject eObject, final EStructuralFeature nameFeature, final String name) { String newName = name; if (siblings != null) { final Set siblingNames = new HashSet(); for (Iterator it = siblings.iterator(); it.hasNext();) { final EObject child = (EObject) it.next(); if (eObject.getClass().equals(child.getClass())) { siblingNames.add(child.eGet(nameFeature)); } } boolean foundUniqueName = false; int index = 1; while (!foundUniqueName) { if (siblingNames.contains(newName)) { newName = name + String.valueOf(index++); } else { foundUniqueName = true; } } } return newName; } }