Nouvelle publication

Rechercher

Question
· 13 hr il y a

Web Gateway/Apache configuration to make SOAP Client Requests?

I am having issues trying to send SOAP requests to a Cloud Based AWS Application that lives outside of our network. 

It is using a Basic Authentication, Key, Certificate Authority and Whitelist for Security. 

If I attempt the connection using wget from the command line I am able to connect,

:>wget --bind-address=10.95.129.245 --server-response https://xxxxxxxxxx/xxxxxxx/services/Mirth
--2025-06-06 15:54:51--  https://xxxxxxx/xxxxxxxx/services/Mirth
wget: /ensemble/.netrc:16: unknown token xxxxxxx
wget: /ensemble/.netrc:16: unknown token xxxxxxxx
Resolving xxxxxxx.com (xxxxxxx)... 34.233.89.102, 54.165.234.62
Connecting to hcis-staging.cbord.com (xxxxxxxx)|xxxxxxx|:443... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Cache-control: no-cache="set-cookie"
  Content-Type: text/html; charset=utf-8
  Date: Fri, 06 Jun 2025 19:54:51 GMT
  Server: nginx
  Set-Cookie: AWSELB=D507B3110AAE4C39FED576EDFCA8C486670B04F18A5E3BBF0AE38321B36B528F14A78096B862E1C523ADEB028C4EB54BB3C1A6750FC29A6832764251160DDA704F73127995;PATH=/
  Set-Cookie: AWSELBCORS=D507B3110AAE4C39FED576EDFCA8C486670B04F18A5E3BBF0AE38321B36B528F14A78096B862E1C523ADEB028C4EB54BB3C1A6750FC29A6832764251160DDA704F73127995;PATH=/;SECURE;SAMESITE=None
  Content-Length: 754
  Connection: keep-alive
Length: 754 [text/html]
Saving to: 'Mirth'
 

 

 

however when I attempt from a Business Operation I am getting....

06/06/2025 15:51:49.8039637 *********************
Output from Web client with SOAP action = http://xxxxxxxx/msg/SendMessage
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:s='http://www.w3.org/2001/XMLSchema'>
  <SOAP-ENV:Body><SendMessage xmlns="http://xxxxxxxxx/msg/"><key xsi:type="s:string">xxxxxxxxxxxxxxx</key><encodedMessage xsi:type="s:string">xxxx@EnsLib.HL7.Message</encodedMessage></SendMessage></SOAP-ENV:Body>
</SOAP-ENV:Envelope>

06/06/2025 15:51:54.8081368 *********************
Input to Web client with SOAP action = http://xxxxxxx/msg/SendMessage

ERROR #6059: Unable to open TCP/IP socket to server xxxxxxx:443
string**** SOAP client return error. method=SendMessage, action=http://xxxxxxxx/msg/SendMessage
     ERROR #6059: Unable to open TCP/IP socket to server xxxxxxxxxx:443

Within the Business Operation class, I was able to define the Local Interface it should use.

Class osuwmc.Nutrition.OSU.CBORD.Operation.CBORDHL7Port Extends Ens.BusinessOperation [ ProcedureBlock ]
{

Parameter ADAPTER = "EnsLib.SOAP.OutboundAdapter";

Property LocalInterface As %String(MAXLEN = 255);

Parameter SETTINGS = "LocalInterface:Connection:selector?context={Ens.ContextSearch/TCPLocalInterfaces}";

Method OnInit() As %Status
{
 IF '$IsObject(..Adapter.%Client.HttpRequest) {
	set ..Adapter.%Client.HttpRequest = ##class(%Net.HttpRequest).%New()
 }
 set ..Adapter.%Client.HttpRequest.LocalInterface = $ZStrip($P(..LocalInterface,"("),"*W")

	quit $$$OK
}

Method SendMessage(pRequest As osuwmc.Nutrition.OSU.CBORD.Request.SendMessageRequest, Output pResponse As osuwmc.Nutrition.OSU.CBORD.Response.SendMessageResponse) As %Library.Status
{
 Set ..Adapter.WebServiceClientClass = "CBORDHL7WSService.CBORDHL7Por.....

Do I have to do something special with the Web Gateway and Apache Web Service to allow the connection out?

2 nouveaux commentaires
Discussion (2)3
Connectez-vous ou inscrivez-vous pour continuer
Question
· 14 hr il y a

Shared code execution speed

Let's suppose two different routines use one and the same chunk of code. From the object-oriented POV, a good decision is to have this chunk of code in a separate class and have both routines call it. However, whenever you call code outside of the routine as opposed to calling code in the same routine, some execution speed is lost. For reports churning through millions of transactions this lost speed might be noticeable. Any advice how to optimize specifically speed?
P.S. Whenever someone is talking about the best choice for whatever, I am always tempted to ask: "What are we optimizing?". Optimizing speed here.
P.P.S. I did notice that some classes speed is very different comparing with old style utilities, while doing largely the same, like exporting.

2 nouveaux commentaires
Discussion (2)3
Connectez-vous ou inscrivez-vous pour continuer
Article
· 14 hr il y a 2m de lecture

Converting Oracle Hierarchical Queries to InterSystems IRIS: Generating Date Ranges

If you're migrating from Oracle to InterSystems IRIS—like many of my customers—you may run into Oracle-specific SQL patterns that need translation.

Take this example:

SELECT (TO_DATE('2023-05-12','YYYY-MM-DD') - LEVEL + 1) AS gap_date
FROM dual
CONNECT BY LEVEL <= (TO_DATE('2023-05-12','YYYY-MM-DD') - TO_DATE('2023-05-02','YYYY-MM-DD') + 1);

In Oracle:

  • LEVEL is a pseudo-column used in hierarchical queries (CONNECT BY). It starts at 1 and increments by 1.
  • CONNECT BY LEVEL <= (...) determines how many rows to generate.
  • The difference between the two dates plus one gives 11, so the query produces 11 rows, counting backwards from May 12, 2023 to May 2, 2023.

Breakdown of the result:

LEVEL = 1  → 2023-05-12
LEVEL = 2  → 2023-05-11
...
LEVEL = 11 → 2023-05-02

Now the question is: How do you achieve this in InterSystems IRIS, which doesn’t support CONNECT BY?

One solution is to implement a SQL-style query using ObjectScript that mimics this behavior. Below is a sample CREATE QUERY definition that accepts a STARTDATE and a number of DAYS, and returns the descending list of dates.


✅ InterSystems IRIS: Implementing a Date Gap Query

CREATE QUERY GET_GAP_DATE(IN STARTDATE DATE, IN DAYS INT)
  RESULTS (GAP_DATE DATE)
  PROCEDURE
  LANGUAGE OBJECTSCRIPT

  Execute(INOUT QHandle BINARY(255), IN STARTDATE DATE, IN DAYS INT)
  {
    SET QHandle("start") = STARTDATE
    SET QHandle("days")  = DAYS
    SET QHandle("level") = 1
    RETURN $$$OK
  }

  Fetch(INOUT QHandle BINARY(255), INOUT Row %List, INOUT AtEnd INT)
  {
    IF (QHandle("level") > QHandle("days")) {
      SET Row = ""
      SET AtEnd = 1
    } ELSE {
      SET Row = $ListBuild(QHandle("start") - QHandle("level") + 1)
      SET QHandle("level") = QHandle("level") + 1
    }
    RETURN $$$OK
  }

  Close(INOUT QHandle BINARY(255))
  {
    KILL QHandle
    QUIT $$$OK
  }

You can run the above CREATE QUERY in IRIS System Management Portal, or through a tool like DBeaver or a Python/Jupyter notebook using JDBC/ODBC.


🧪 Example Usage:

To generate the same result as the Oracle query above, use:

SELECT * FROM GET_GAP_DATE(
  TO_DATE('2023-05-12', 'YYYY-MM-DD'),
  TO_DATE('2023-05-12', 'YYYY-MM-DD') - TO_DATE('2023-05-02', 'YYYY-MM-DD') + 1
);

This will output:

GAP_DATE
----------
2023-05-12
2023-05-11
...
2023-05-02
(11 rows)

🔁 Advanced Usage: Join with Other Tables

You can also use this query as a subquery or in joins:

SELECT * 
FROM GET_GAP_DATE(TO_DATE('2023-05-12', 'YYYY-MM-DD'), 11) 
CROSS JOIN dual;

This allows you to integrate date ranges into larger SQL workflows.


Hope this helps anyone tackling Oracle-to-IRIS migration scenarios! If you’ve built alternative solutions or have improvements, I’d love to hear your thoughts.

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Article
· 17 hr il y a 6m de lecture

Diseñar e implementar APIs REST en InterSystems IRIS a partir de especificaciones OpenAPI

​En el artículo anterior, Generación de Especificaciones OpenAPI, vimos qué es OpenAPI, por qué es útil para documentar los servicios REST y cómo generar un archivo de especificación en formato .yaml o .json. También exploramos cómo IRIS permite crear automáticamente esta documentación a partir del código existente, siguiendo el enfoque code-first.

Pero, ¿qué sucede si partimos del archivo OpenAPI en lugar del código? En otras palabras, ¿si primero definiéramos el comportamiento de nuestra API y luego generáramos las clases necesarias para implementarla en IRIS? Este método, conocido como enfoque specification-first, permite diseñar un servicio de manera clara y coherente, incluso antes de escribir la lógica de aplicación.

En este artículo veremos cómo utilizar este enfoque para construir una REST API completa en Intersystems IRIS a partir de una especificación OpenAPI 2.0.

Primer paso: construcción del archivo OpenAPI

El archivo OpenAPI 2.0 es un documento en formato JSON (o YAML) en el que se describen todas las API de la aplicación: las rutas disponibles (endpoints), los métodos HTTP soportados (GET, POST, PUT, DELETE...), los parámetros aceptados, las respuestas esperadas y mucho más.

Para construir correctamente este archivo, es fundamental conocer la estructura definida por el estándar OpenAPI 2.0
Algunos recursos útiles para profundizar son:

A continuación, se muestra un ejemplo sencillo de archivo openapi.json que define una API con un endpoint GET /hello:

{
  "swagger": "2.0",
  "info": {
    "title": "API example",
    "description": "Example of openAPI file",
    "version": "1.0.0"
  },
  "produces": [
    "application/json"
  ],
  "consumes": [
    "application/json"
  ],
  "paths": {
    "/hello": {
      "get": {
        "summary": "Sample greeting",
        "description": "Returns a greeting message",
        "responses": {
          "200": {
            "description": "OK",
            "schema": {
              "type": "string"
            }
          }
        },
        "operationId": "hello"
      }
    }
  }
}

Segundo paso: generación de las clases de la interfaz REST

Una vez creado el archivo de especificación, es posible utilizar una de las herramientas de gestión de APIs de InterSystems IRIS para generar automáticamente las tres clases principales que constituyen un servicio REST:

  • Clase de especificación (.spec)
    Subclase de %REST.Spec, que contiene la especificación OpenAPI 2.0 del servicio REST.
  • Clase de dispatch (.disp)
    Subclase de %CSP.REST, responsable de recibir las solicitudes HTTP y de invocar los métodos apropiados en la clase de implementación.
  • Clase de implementación (.impl)
    Subclase de %REST.Impl, contiene la implementación de la lógica de los métodos REST.

En este artículo se muestra cómo generar el servicio REST utilizando el servicio /api/mgmnt/.

Generación de las clases utilizando el servicio /api/mgmnt

  1. Utilizar Postman (o una herramienta similar) para crear un mensaje de solicitud HTTP como sigue:
    • Para la acción HTTP, seleccionar POST.
    • Para la URL, especificar una URL en el siguiente formato, usando la <baseURL> de tu instancia: https://<baseURL>/api/mgmnt/v2/namespace/myapp Donde namespace es el espacio de nombres en el que se desea crear el servicio REST y myapp es el nombre del paquete en el que se desea crear las clases. Ejemplo: http://localhost:1888/api/mgmnt/v2/myNamespace/Greetings  
    • En el cuerpo de la solicitud, pegar la especificación OpenAPI 2.0 de tu servicio web en formato JSON.
    • Especificar el tipo de contenido del cuerpo como JSON (application/json).
    • Como método de autenticación, usar Basic Auth e introducir como username y password las credenciales de un usuario con permisos de lectura/escritura sobre el espacio de nombres indicado.
  2. Enviar el mensaje de solicitud.
  • Caso de creación del servicio REST: si la llamada tiene éxito, InterSystems IRIS crea las clases .disp, .impl y .spec en el paquete del namespace especificado, y en Postman se recibirá el siguiente mensaje de confirmación:  { "msg": "New application myapp created" }
  • Caso de actualización del servicio REST: si la llamada tiene éxito, se recibirá el mensaje: {"msg": "Application lombardia.GUIConvenzioni.OMRREST updated"} Además, InterSystems IRIS regenerará completamente las clases .disp y .spec en el paquete especificado, y actualizará la clase .impl, conservando el código previamente implementado en ella. Atención: cualquier modificación manual realizada a la clase .disp será sobrescrita cada vez que se actualice la especificación, por lo que no se recomienda modificarla directamente.

Tercer paso: implementación de la lógica REST

Una vez generadas las tres clases (.spec, .disp, .impl), es momento de completar el servicio REST implementando la lógica de las operaciones.

Veamos un ejemplo concreto basado en la especificación mostrada anteriormente (que define un endpoint GET /hello).
Las clases generadas serán:

Clase Greetings.spec

Esta clase contiene la definición OpenAPI en formato JSON. No requiere modificaciones manuales, pero puede ser actualizada regenerándola mediante el servicio /api/mgmnt/ cada vez que se modifique la especificación.

Class Greetings.spec Extends Extends %REST.Spec [ ProcedureBlock ]
{

XData OpenAPI [ MimeType = application/json ]
  "swagger": "2.0",
  "info": {
    "title": "API example",
    "description": "Example of openAPI file",
    "version": "1.0.0"
  },
  ...
};
}

Clase Greetings.disp

Es la clase de dispatch la que conecta las rutas HTTP con los métodos de implementación. No es necesario (ni recomendable) modificarla, ya que se regenera cada vez que se actualiza la especificación.

Class Greetings.disp Extends %CSP.REST [ GeneratedBy = Greetings.spec.cls, ProcedureBlock ]
{

/// The class containing the RESTSpec which generated this class
Parameter SpecificationClass = "Greetings.spec";
/// Ignore any writes done directly by the REST method.
Parameter IgnoreWrites = 1;
/// Default the Content-Type for this application.
Parameter CONTENTTYPE = "application/json";
/// By default convert the input stream to Unicode
Parameter CONVERTINPUTSTREAM = 1;
/// The default response charset is utf-8
Parameter CHARSET = "utf-8";
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
  <Route Url="/hello" Method="GET" Call="hello"/>
</Routes>

ClassMethod hello() As %Status
{
    Try {
        Do ##class(%REST.Impl).%SetContentType("application/json")
        If '##class(%REST.Impl).%CheckAccepts("application/json") Do ##class(%REST.Impl).%ReportRESTError(..#HTTP406NOTACCEPTABLE,$$$ERROR($$$RESTBadAccepts)) Quit
        Set response=##class(Greetings.impl).hello()
        Do ##class(Greetings.impl).%WriteResponse(response)
    } Catch (ex) {
        Do ##class(%REST.Impl).%ReportRESTError(..#HTTP500INTERNALSERVERERROR,ex.AsStatus(),$parameter("Greetings.impl","ExposeServerExceptions"))
    }
    Quit $$$OK
}
}

Como se puede observar, esta clase mapea el endpoint /hello al método hello() presente en la clase Greetings.impl.

Clase Greetings.impl

Esta es la clase en la que se escribe la lógica de aplicación propiamente dicha. Es una subclase de %REST.Impl y se genera con métodos “vacíos” que deben ser implementados.

Class Greetings.impl Extends %REST.Impl [ ProcedureBlock ]
{
/// Returns a greeting message
ClassMethod hello() As %Status
{
  //write here your code..
}
}

Conclusión

Hemos visto cómo, a partir de una especificación OpenAPI 2.0, es posible construir una interfaz REST completa en InterSystems IRIS siguiendo el enfoque specification-first. Con unos pocos pasos, el framework nos proporciona una estructura lista para usar sobre la cual integrar nuestra lógica de negocio, permitiéndonos desarrollar APIs de manera clara, ordenada y escalable.

En el próximo artículo veremos cómo exponer efectivamente el servicio REST a través de una aplicación web de IRIS.

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Article
· 20 hr il y a 3m de lecture

Un coup de poids

image

Tel un coup de grâce, sans laisser aucune chance à l'adversaire, Kubernetes, plateforme open source, offre un univers de possibilités grâce à sa disponibilité (c'est-à-dire la facilité d'accès au support, aux services et aux outils). Cette plateforme permet de gérer les tâches et les services dans des conteneurs, ce qui simplifie grandement la configuration et l'automatisation de ces processus.

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer