Ampliar el ejemplo escribiendo su propio convertidor de enlace

Puede ampliar la capacidad de conversión de la herramienta de conversión de WebSphere ESB mediante la creación de clases Java de convertidor de enlace personalizadas.

Un convertidor de enlace definido por el usuario es una clase Java que la herramienta de conversión de WebSphere ESB puede utilizar para convertir un enlace de exportación o un enlace de importación de WebSphere ESB en recursos de IBM Integration Bus.

Para implementar un convertidor de enlace, debe realizar los pasos siguientes cuando cree una clase de convertidor de enlace:

  1. Vaya a la carpeta plugins:

  2. Añada las últimas versiones de los archivos .jar que necesita para implementar la clase de convertidor:
    1. En la perspectiva Java, seleccione el proyecto Java que contiene el convertidor.
    2. Pulse el botón derecho del ratón en Propiedades.
    3. Seleccione Vía de construcción Java > Bibliotecas > Añadir JAR externos...
    4. Añada com.ibm.ws.sca.scdl.mq.jar
    5. Añada com.ibm.ws.sca.scdl.eis.jar
    6. Añada javax.wsdl.jar
    7. Añada org.eclipse.core.jobs.jar
    8. Añada org.eclipse.equinox.common.jar

  3. Importe las siguientes clases Java:
    import java.io.ByteArrayInputStream;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    
    import javax.wsdl.Operation;
    import javax.wsdl.PortType;
    
    import org.eclipse.core.resources.IFile;
    import org.eclipse.core.resources.IProject;		
    		
  4. Añada las siguientes importaciones. La herramienta de conversión de WebSphere ESB necesita estas clases Java para poder utilizar su clase de convertidor y ampliar su funcionalidad.
    import com.ibm.etools.mft.conversion.esb.extensionpoint.AbstractBindingConverter;
    import com.ibm.etools.mft.conversion.esb.extensionpoint.Nodes;
    			
  5. Identifique los nodos de flujo de mensajes que necesita para convertir una exportación o una importación. Para ver una lista de los nodos disponibles, consulte Nodos incorporados.

  6. Importe las clases Java que son necesarias para crear los nodos de flujo de mensajes que ha identificado. Para obtener más información, consulte API Java de IBM Integration Bus. Por ejemplo, para un enlace MQ de exportación, debe importar las siguientes clases:
    import com.ibm.broker.config.appdev.MessageMSLMap;
    import com.ibm.broker.config.appdev.Terminal;
    import com.ibm.broker.config.appdev.nodes.MQInputNode;
    import com.ibm.broker.config.appdev.nodes.MQOutputNode;
    import com.ibm.broker.config.appdev.nodes.MappingMSLNode;
    import com.ibm.broker.config.appdev.nodes.PassthroughNode;
    import com.ibm.broker.config.appdev.nodes.ResetContentDescriptorNode;
    import com.ibm.broker.config.appdev.nodes.RouteToLabelNode;
    			
  7. Importe las clases Java que son necesarias para obtener información sobre la exportación o la importación. Por ejemplo, para un enlace MQ de exportación, debe importar las siguientes clases:
    import com.ibm.msl.mapping.api.MapGenerator;
    import com.ibm.wsspi.sca.scdl.mq.MQConnection;
    import com.ibm.wsspi.sca.scdl.mq.MQExportBinding;
    import com.ibm.wsspi.sca.scdl.mq.MQExportMethodBinding;
    import com.ibm.wsspi.sca.scdl.mq.MQReceiveQueue;
    import com.ibm.wsspi.sca.scdl.mq.MQSendQueue;
    import com.ibm.wsspi.sca.scdl.mq.RequestType1;
    import com.ibm.wsspi.sca.scdl.mq.ResponseType1;
    import com.ibm.wsspi.sca.scdl.mqbase.MQConfiguration;
    			
  8. Declare cualquier constante que pueda necesitar.

  9. Implemente la función getConvertedTo para que devuelva el nombre que desea utilizar en IBM Integration Bus para un tipo de enlace de exportación o de enlace de importación. Por ejemplo, el código de ejemplo para un enlace de exportación MQ es el siguiente:
    	@Override
    	public String getConvertedTo() {
    		return "Nodo MQImport";
    	}
    			

    Este valor se utiliza para llenar la columna Convertir a de la tabla de convertidores de enlace de exportación e importación en la sección Configurar opciones de conversión global de la herramienta de conversión de WebSphere ESB.

  10. Implemente la función getType para que devuelva la clase Java de WebSphere ESB para un tipo de enlace de exportación o de enlace de importación. Por ejemplo, el código de ejemplo para un enlace de exportación MQ es el siguiente:
    	@Override
    	public String getType() {
    		return "com.ibm.wsspi.sca.scdl.mq.impl.MQExportBindingImpl";
    	}
    			
  11. Implemente el método convert para recrear un enlace de exportación o un enlace de importación en IBM Integration Bus.
    @Override
    public Nodes convert(ConverterContext converterContext) throws Exception {
    				
    // Crear el contenedor para los nodos de flujo de mensajes que se crean para recrear el enlace de exportación o el enlace de importación en IBM Integration Bus.
    Nodes nodes = createNodes(converterContext);
    		
    // Obtener el nombre predeterminado para el enlace de exportación o el enlace de importación.
    // Este nombre se utiliza posteriormente para crear nombres exclusivos para los nodos de flujo de mensajes que se crean.
    String nodeName = getProposedIIBNodeNameFromSourcePrimitive(converterContext);
    
    // Obtener los objetos de enlace de exportación o importación de WebSphere ESB.
    // Por ejemplo, para un enlace de exportación MQ, los objetos de WebSphere ESB se obtienen de la siguiente manera:
    MQExportBinding mqExportBinding = (MQExportBinding)converterContext.sourceBinding;	
    RequestType1 mqExportRequest = mqExportBinding.getRequest();
    ResponseType1 mqExportResponse = mqExportBinding.getResponse();		
    		
    // Crear el nodo de entrada.
    // Por ejemplo, para un enlace de exportación MQ, el nodo de entrada se crea de la siguiente manera:
    MQInputNode mqInputNode = (MQInputNode)createNode(converterContext.targetFlow,nodeName+EXPORT_REQUEST,ROLE_ENTRY,MQInputNode.class,nodes);
    
    // Sólo para enlaces de exportación:
    // Establecer el dominio de mensajes en BLOB para que la correlación de selector de función
    // pueda actualizar el entorno local sin necesidad de conocer el tipo de mensaje específico.
    // La conversión del manejador de datos establecerá luego el tipo de mensaje adecuadamente.
    // Por ejemplo, para un enlace de exportación MQ, el dominio se establece de la siguiente manera:
    mqInputNode.setMessageDomainProperty("BLOB");
    
    // Para manejar la conversión de los terminales de anomalías, cree una tarea a realizar en el nodo de entrada. La herramienta de conversión de WebSphere ESB deja los terminales de anomalías sin conectar.
    // Por ejemplo, el código para crear una tarea a realizar para un nodo MQInput es el siguiente:
    createToDoTask(converterContext.flowFile,"Los terminales de anomalías para los nodos MQInput y MQOuput resultantes de la " +
    			   " conversión del enlace de exportación MQ "+nodeName+" han quedado sin conectar.  Determine el manejo de " +
    			   " errores necesario y conecte los terminales de anomalías adecuadamente.");
    		
    // Configurar las propiedades del nodo de entrada.
    
    // Crear el nodo de salida.
    // Nota: Este nodo es necesario cuando el enlace de exportación o importación tiene una interfaz con operaciones de solicitud-respuesta.
    // Para el estilo de invocación asíncrona, el nodo de salida puede estar ubicado en el mismo flujo de mensajes que el nodo de entrada o no.
    // Por ejemplo, puede crear un nodo de salida para un enlace de exportación MQ de la siguiente manera:
    MQOutputNode mqOutputNode = (MQOutputNode)createNode(converterContext.targetFlow,nodeName+EXPORT_RESPONSE,ROLE_EXIT,MQOutputNode.class,nodes);
    mqOutputNode.setRequest(false);
    		
    // Configurar las propiedades del nodo de salida. 
    				
    // Obtener enlaces de método; colocarlos en una correlación que se obtiene del nombre de método nativo.
    // Comprobar si algún enlace de método altera temporalmente el manejador de datos de entrada o salida.
    // Comprobar también si la correlación de nombre de método nativo con nombre de operación es en realidad una correlación de identidad.
    List methodBindingList = mqExportBinding.getMethodBinding();
    Map<String,MQExportMethodBinding> methodBindings = new HashMap<String,MQExportMethodBinding>();
    boolean identityMap = true;
    for( Iterator i = methodBindingList.iterator(); i.hasNext(); )
    	{
    		MQExportMethodBinding mb = (MQExportMethodBinding)i.next();
    		String nativeMethod = mb.getNativeMethod();
    		if( nativeMethod != null ) {
    			methodBindings.put(nativeMethod,mb);
    			if( !nativeMethod.equals(mb.getMethod()) )
    				identityMap = false;
    		}
    		if( mb.getInputDataBindingType() != null )
    			createToDoTask(converterContext.flowFile,"La operación "+mb.getMethod()+" del enlace de
    			 			   exportación MQ "+nodeName+" altera temporalmente el manejador de datos de entrada con "+mb.getInputDataBindingType());
    		if( mb.getOutputDataBindingType() != null )
    			createToDoTask(converterContext.flowFile,"La operación "+mb.getMethod()+" del enlace de
    		 			   	   exportación MQ "+nodeName+" altera temporalmente el manejador de datos de salida con "+mb.getInputDataBindingType());
    	}		
    
    // Sólo para enlaces de exportación: Convertir el selector de función.
    //
    // La selección de función es un proceso de dos pasos:
    // 1) el selector de función resuelve el "nombre de método nativo"
    // 2) el enlace de método correlaciona el "nombre de método nativo" con un nombre de operación.
    // Si no hay ningún enlace de método coincidente, se presupone que el nombre de operación es el nombre de método nativo.
    //
    // Hay cinco selectores de función incorporados identificados por nombre:
    // Operación individual - el nombre de método nativo es el nombre de la operación individual en la interfaz.
    // Manejar mensaje - el nombre de método nativo es "handleMessage".
    // Función de destino - el nombre de método nativo es el valor de la cabecera de mensaje MQ llamada "TargetFunctionName".
    // Formato de cuerpo - el nombre de método nativo es el valor de la serie de formato del cuerpo del mensaje MQ.
    // Tipo de mensaje - el nombre de método nativo es el valor de la cabecera de tipo de mensaje MQ.	
    
    // En preparación para la conversión del selector de función, obtener
    // la lista de operaciones en la interfaz de la exportación.
    String portTypeName = converterContext.portType.getPortType().toString();
    PortType portType = conversionContext.indexer.wsdlPortTypes.get(portTypeName);
    if( portType == null )
    		throw new IllegalArgumentException("Para la exportación "+nodeName+": No se ha podido localizar el Tipo de puerto WSDL para "+portTypeName);
    	List operations = portType.getOperations();
    		
    // En este ejemplo, cada selector de función soportado se representa mediante un nodo Mapping conectado a un nodo RouteToLabel.
    // Crear el nodo de correlación (Mapping).
    MappingMSLNode fsMappingNode = (MappingMSLNode)createNode(converterContext.targetFlow,nodeName+EXPORT_FUNCTION_SELECTOR,"FS",MappingMSLNode.class,nodes);
    
    // Conectar el nodo de entrada al nodo Mapping del selector de función.
    // Por ejemplo, para un enlace de exportación MQ Input, utilice el código siguiente:
    converterContext.targetFlow.connect(mqInputNode.OUTPUT_TERMINAL_OUT,fsMappingNode.INPUT_TERMINAL_IN);
    
    // El archivo de correlaciones define los elementos de mensaje de entrada y salida y las acciones
    // que se realizan para actualizar el mensaje de entrada, para que el nodo RouteToLabel pueda direccionar
    // cada mensaje a la Etiqueta correcta y, desde allí, al subflujo de solicitudes específico de la operación.
    String mapFileName = nodeName+EXPORT_FS_MAPPING;
    String mappingContent = null;
    		
    // Este serie define el inicio común del archivo de correlaciones para todos los selectores de función soportados.
    String mappingPrefix = 		
    "<?xml version=\"1.0\" encoding=\"UTF-8\"?><mappingRoot domainID=\"com.ibm.msl.mapping.xml\" domainIDExtension=\"mb\" mainMap=\"true\" targetNamespace=\"default\" version=\"8.0.4.0\" xmlns=\"http://www.ibm.com/2008/ccl/Mapping\" xmlns:map=\"default\">" +
    "<input path=\"jar:file://!com/ibm/etools/mft/map/xsds/predefined/BlobMessage.xsd\"/>" +
    "<output path=\"jar:file://!com/ibm/etools/mft/map/xsds/predefined/BlobMessage.xsd\"/>" +
    "<generation engine=\"xquery\"/>" +
            
    // Especificar el nombre del archivo .map
    "<mappingDeclaration name=\""+mapFileName+"\">" +
    
    // Especificar el ámbito de la entrada para el nodo Mapping: BLOB de carga útil de mensaje, conjunto de mensajes, propiedades de mensaje, MQMD y MQRFH2
    // MQMD y MQRFH2 pueden ser orígenes del nombre de función nativa para algunos selectores de función.
    // LocalEnvironment se presupone que está vacío después del nodo de entrada y, por lo tanto, no es una entrada para esta correlación.
    "<input path=\"mb:msg(BLOB,assembly,BLOB,Properties,MQMD,MQRFH2)\"/>" +
    
    // Especificar el ámbito de la salida para la correlación: BLOB de carga útil de mensaje, conjunto de mensajes, propiedades de mensaje, LocalEnvironment
    // LocalEnvironment es el destino para el nombre de etiqueta de direccionamiento.       
    "<output path=\"mb:msg(BLOB,assembly,BLOB,LocalEnvironment,Properties)\">" +
    
    // Mover la carga útil de mensaje y las propiedades sin cambios.
    "<move><input path=\"BLOB\"/><output path=\"BLOB\"/></move>" +
    "<move><input path=\"Properties\"/><output path=\"Properties\"/></move>";
    		
    // Esta serie define el final común del archivo de correlaciones para todos los selectores de función.
    String mappingSuffix = "</mappingDeclaration></mappingRoot>";
    		 
    // Cada selector de función especifica la parte de la correlación que establece el
    // nombre de etiqueta de destino de direccionamiento basado en el mensaje de entrada.
    String fsName = mqExportRequest.getFunctionSelector();	
    	if( fsName.equals(FS_SINGLE_OPERATION) ) {
    			
    // Establecer el nombre de operación individual y el nombre de etiqueta de destino.
    // Una implementación alternativa para este caso sería ignorar la etiqueta y conectar
    // el nodo de entrada directamente al subflujo de operación. 
    
    // Si el selector de función es operación individual y la interfaz tiene
    // más de una operación, se emite un error.
    if( operations.size() > 1 )
    		throw new IllegalArgumentException("Para la exportación "+nodeName+": El selector de función Operación individual no puede manejar portType con > 1 operación ("+operations.size()+")");
    
    // Obtener el nombre de la operación individual.
    String operationName = ((Operation)operations.get(0)).getName();
    			
    // Establecer el nombre de etiqueta de destino en el entorno local.
    mappingContent =  
    	"<assign value=\""+operationName+"\">" +
    	"<output path=\"LocalEnvironment/Destination/RouterList/DestinationData/labelName\"/>" +
    	"</assign>";
    			
    // El selector de función "handleMessage" es muy similar, salvo que puede
    // haber más de una operación en la interfaz, la operación a la que se llama
    // es la que tiene un enlace de método con un nombre de método nativo de
    // "handleMessage".
    	} else if( fsName.equals(FS_HANDLE_MESSAGE) ) {
    			
    // Obtener el nombre de la operación para el nombre de método nativo "handleMessage".
    MQExportMethodBinding mb = methodBindings.get("handleMessage");
    if( mb == null ) throw new IllegalArgumentException("Para la exportación "+nodeName+": no hay ningún enlace de método para handleMessage");
    			
    // Crear el contenido del archivo de correlaciones.
    // Establecer el nombre de etiqueta de destino en el entorno local.
    mappingContent =  
    	"<assign value=\""+mb.getMethod()+"\">" +
    	"<output path=\"LocalEnvironment/Destination/RouterList/DestinationData/labelName\"/>" +
    	"</assign>";
    			
    // Otros selectores de función requieren conversión manual.
    	} else {
    // Si el selector de función es una correlación de identidad (es decir, cada nombre de método
    // nativo es idéntico a su correspondiente nombre de operación), el valor se puede mover
    // directamente de la cabecera de mensaje MQ al nombre de etiqueta de destino.
    //
    // Por ejemplo, para el selector de función "Función de destino", lo siguiente movería el
    // nombre de método nativo de la carpeta usr MQRFH2 al labelName de destino.
    //
    // <move>
    // <input path="MQRFH2/usr/TargetFunctionName"/>
    // <output path="LocalEnvironment/Destination/RouterList/DestinationData/labelName"/>
    // </move>
    //
    // Esto requiere que el hijo "any" de la carpeta MQRFH2/usr se convierta al siguiente tipo de esquema:
    //
    // <?xml version="1.0" encoding="UTF-8"?>
    // <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    // <xsd:element name="TargetFunctionName" type="xsd:string"/>
    // </xsd:schema>
    //
    // De lo contrario, la correlación podría crearse utilizando elementos if en la correlación equivalentes a:
    // IF MQRFH2/usr/TargetFunctionName == nativemethod1 THEN labelName = operation1
    // IF MQRFH2/usr/TargetFunctionName == nativemethod2 THEN labelName = operation2
    
    // Por ejemplo, el código para un enlace de exportación MQ es el siguiente:
    createToDoTask(converterContext.flowFile,"El selector de función de tipo "+fsName+"
    	 			    del enlace de exportación MQ "+nodeName+" se debe convertir manualmente");			
    }
    		
    // Si el selector de función se ha podido resolver en una correlación, crear el
    // archivo de correlaciones y establecerlo en el nodo Mapping.
    if( mappingContent != null ) {
    		mappingContent = mappingPrefix + mappingContent + mappingSuffix;
    			
    // Crear el archivo de correlaciones como un recurso en el proyecto convertido.
    IProject targetProject = converterContext.moduleConverter.getTargetProject();
    IFile mappingFile = targetProject.getFile(mapFileName+".map");
    	if( mappingFile.exists() )
    		throw new IllegalArgumentException("Para la exportación "+nodeName+": El archivo de correlaciones "+mapFileName+" .map ya existe");
    	mappingFile.create(new ByteArrayInputStream(mappingContent.getBytes("UTF-8")),true,null);
    
    // Establecer el archivo de correlaciones en el nodo Mapping.
    	MessageMSLMap fsMessageMap = new MessageMSLMap(mapFileName);
    fsMappingNode.setMappingExpression(fsMessageMap);
    }
    
    // Crear un nodo RouteToLabel (direccionar a etiqueta). Este reenvía el mensaje al flujo de solicitudes para la operación.
    RouteToLabelNode routeToLabelNode = (RouteToLabelNode)createNode(converterContext.targetFlow,nodeName+EXPORT_ROUTE,ROLE_MAIN,RouteToLabelNode.class,nodes);
    
    // Convertir el manejador de datos del cuerpo.
    // Este es el valor predeterminado para todas las operaciones, y se puede alterar temporalmente en enlaces de método.
    Object dbRef = mqExportRequest.getBodyDataBindingReferenceName();
    String dataBindingName = dbRef == null ? "" : dbRef.toString();
    
    // Manejar el manejador de datos XML incorporado.
    if( dataBindingName.equals(DH_XML) ) {
    	
    	// Para el manejador de datos XML, utilizamos un nodo ResetContentDescriptor para establecer el dominio de mensajes en XMLNSC.
    	ResetContentDescriptorNode dataHandlerNode = (ResetContentDescriptorNode)createNode(converterContext.targetFlow,nodeName+EXPORT_DATA_HANDLER,"DH",ResetContentDescriptorNode.class,nodes);			
    	dataHandlerNode.setMessageDomain("XMLNSC");
    	dataHandlerNode.setResetMessageDomain(true);
    			
    	// Conectar el nodo de manejador de datos entre el nodo de correlación del selector de función y el nodo direccionar a etiqueta.
    	converterContext.targetFlow.connect(fsMappingNode.OUTPUT_TERMINAL_OUT,dataHandlerNode.INPUT_TERMINAL_IN);
    	converterContext.targetFlow.connect(dataHandlerNode.OUTPUT_TERMINAL_OUT,routeToLabelNode.INPUT_TERMINAL_IN);		
    	} else {
    	
    		// Para otros manejadores de datos, utilizamos un nodo Passthrough para representar el manejador
    		// de datos, que se tendrá que convertir manualmente.
    		PassthroughNode dataHandlerNode = (PassthroughNode)createNode(converterContext.targetFlow,nodeName+EXPORT_DATA_HANDLER,"DH",PassthroughNode.class,nodes);
    		createToDoTask(converterContext.flowFile,"El manejador de datos de tipo "+dataBindingName+"
    	 			   	  del enlace de exportación MQ "+nodeName+" se debe convertir manualmente");
    			
    		// Conectar el nodo de manejador de datos entre el nodo de correlación del selector de función y el nodo direccionar a etiqueta.
    		converterContext.targetFlow.connect(fsMappingNode.OUTPUT_TERMINAL_OUT,dataHandlerNode.INPUT_TERMINAL_IN);
    		converterContext.targetFlow.connect(dataHandlerNode.OUTPUT_TERMINAL_OUT,routeToLabelNode.INPUT_TERMINAL_IN);		
    	}
    		
    	// Es posible que el mensaje de respuesta utilice un manejador de datos diferente, que
    	// no esté soportado por este convertidor.
    	Object responsedbRef = mqExportResponse.getBodyDataBindingReferenceName();
    	String responseDataBindingName = responsedbRef == null ? "" : responsedbRef.toString();
    	if( !responseDataBindingName.equals(dataBindingName) )
    		createToDoTask(converterContext.flowFile,"El manejador de datos de respuesta del enlace de
    	 			   	   exportación MQ "+nodeName+" es distinto al de la solicitud y se debe convertir manualmente.");			
    
    	// Conversión completa.
    		
    	return nodes;
    }
    	
  12. Implemente la función getInputTerminal para que devuelva el objeto de terminal de entrada. Por ejemplo, para un enlace de exportación MQ:
    public Terminal getInputTerminal(String sourceTerminalName, Nodes nodes) {
    // Recuperar el nodo y correlacionarlo a su terminal de entrada.
    return ((MQOutputNode)nodes.getNode(ROLE_EXIT)).INPUT_TERMINAL_IN;
    	}
    	
  13. Implemente la función getOutputTerminal para que devuelva el objeto de terminal de salida. Por ejemplo, para un enlace de exportación MQ:
    public Terminal getOutputTerminal(String sourceTerminalName, Nodes nodes) {
    // Recuperar el nodo y correlacionarlo a su terminal de salida.
    return ((MQInputNode)nodes.getNode(ROLE_ENTRY)).OUTPUT_TERMINAL_OUT;				
    	}
    }
    	

Para obtener más información sobre el ejemplo de convertidor de enlace de exportación MQ definido por el usuario, consulte Convertidor de enlace de exportación MQ definido por el usuario.

Para obtener más información sobre la herramienta de conversión de WebSphere ESB, consulte Ejecutar la herramienta de conversión de WebSphere ESB.

Volver a la página inicial del ejemplo