新しい投稿

検索

記事
· 6 hr 前 18m read

Usando Python no InterSystems Iris

Olá,

Neste artigo vamos ver o uso do python como linguagem de programação no InterSystems Iris. Para tal vamos usar como referência a versão Community 2025.1 que está disponível para ser baixada em https://download.intersystems.com mediante o login no ambiente. Para maiores informações sobre o download e instalação do Iris veja o link da comunidade https://community.intersystems.com/post/how-download-and-install-intersystems-iris

Uma vez instalado o íris agora precisamos ter o python disponível no nosso ambiente. Temos vários tutoriais explicando a instalação e configuração do python no Iris. Uma boa fonte de referência é o link da documentação oficial da InterSystems em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_epython

Uma vez instalado e configurado o python no Iris podemos fazer um primeiro teste: abrir o shell do python via terminal do Iris. Para isso vamos abrir uma janela de terminal do Iris e executar o comando Do $$SYSTEM.Python.Shell():

Fig. 1 – Tela do shell python no Iris

Se você estiver com seu ambiente configurado corretamente você verá a tela acima. A partir daí podemos então executar comandos, como por exemplo, ver a versão do python. Para isso vamos usar o módulo sys:

Fig. 2 – Tela do shell python no Iris

Pronto. Temos o Iris e o python prontos para trabalhar. Agora podemos criar, por exemplo, uma classe Iris e nela programar alguns métodos utilizando python. Vamos ver um exemplo:

Class Demo.Pessoa Extends %Persistent
{

Property nome As %String;

Method MeuNome() [ Language = objectscript ]
{
              write ..nome
}

Method MeuNomePython() [ Language = python ]
{
              print(self.nome)
}


}

 A classe acima te uma propriedade (nome) e dois métodos, um em objectscript e outro em python, apenas para comparação. Chamando estes métodos temos o resultado na tela abaixo:

 

Fig. 3 – Chamada de método no Iris

 

 

Veja então que podemos ter na mesma classe métodos codificados em objectscript e em python. E de um deles podemos chamar o outro. Veja o exemplo a seguir. Vamos criar um novo método GetChave e do método MeuNomePython vamos fazer uma chamada e recuperar a informação:


Method MeuNomePython() [ Language = python ]
{
              chave=self.GetChave()
              print(self.nome)
              print(chave)
}

Method GetChave() As %Integer [ Language = objectscript ]
{
              Return $Get(^Chave)
}

Vamos criar uma global com o valor que desejamos que seja recuperado:

Fig. 4 – Criação de global no Iris

 

Pronto. Com a global criada vamos agora chamar o nosso método:

Fig. 5 – Chamada de método no Iris

 

Veja que agora nosso método em python faz uma chamada a outro método, este codificado em objectscript. O inverso também é válido.

Python tem diversas bibliotecas úteis, como por exemplo:

  • iris – Permite interação com o banco de dados e  ambiente Iris
  • matplot – Visualização de dados e criação de gráficos
  • numpy -  Provê suporte a arrays e estrutura de dados
  • scikit-learn – Permite criar e implementar models de aprendizado de máquina
  • pandas – É utilizada para manipulação e análise de dados

Uma outra funcionalidade presente no Iris com python é a possibilidade de acessar dados via SQL, ou seja, podemos ter os dados armazenados em tabelas no Iris e código em python consumindo estes dados. Vamos ver um exemplo de código que lê uma tabela Iris e gera um arquivo XLS utilizando a biblioteca iris e pandas:

ClassMethod tabela() As %Status [ Language = python ]
{

              import iris
              import pandas as pd
             
              rs = iris.sql.exec("select * from demo.alunos")
              df = rs.dataframe()

              # Salvar o DataFrame como um arquivo XLS
              caminho_arquivo = 'c:\\temp\\dados.xlsx'
              df.to_excel(caminho_arquivo, index=False)
             
              return True
}

Como visto, utilizamos no código as bibliotecas iris e pandas. Então criamos um recordset (rs) com o comando SQL desejado e depois disso um dataframe pandas (df) a partir deste recordset. A partir do dataframe exportamos os dados da tabela para um arquivo Excel no caminho especificado (df.to_excel). Veja que com pouquíssimas linhas montamos um código extremamente útil. Aqui o uso das bibliotecas python foi fundamental. Elas já nos forneceram o suporte ao dataframe (pandas) e a partir daí a sua manipulação (to_excel). Executando nosso código temos então a tabela excel gerada a partir dos dados da tabela:

Fig. 6 – Chamada de método no Iris

 

Fig. 7 – Planilha gerada pelo método

 

 

Python tem diversas bibliotecas prontas para uso, com diversas funcionalidades, assim como muito código em comunidades que podem ser utilizados nas aplicações.

Uma delas, que mencionamos acima, é a scikit-learn, que permite o uso de diversos mecanismos de regressão, permitindo a criação de métodos de predição baseado em informações, como por exemplo, uma regressão linear. Podemos ver um exemplo de código de regressão abaixo:

 ClassMethod CalcularRegressaoLinear() As %String [ Language = python ]
{
    import iris
    import json

    import pandas as pd
    from sklearn.linear_model import LinearRegression
    from sklearn.metrics import mean_absolute_error
    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt
    matplotlib.use("Agg")
    
    rs = iris.sql.exec("select venda as x, temperatura as y from estat.fabrica")
    df = rs.dataframe()
    
    print(df)
    
    # Reformatando x1 para uma matriz 2D exigida pelo scikit-learn
    X = df[['x']]
    y = df['y']

    # Inicializa e ajusta o modelo de regressão linear
    model = LinearRegression()
    model.fit(X, y)

    # Extrai os coeficientes da regressão
    coeficiente_angular = model.coef_[0]
    intercepto = model.intercept_
    r_quadrado = model.score(X, y)
    
    # Calcula Y_pred baseado no X
    Y_pred = model.predict(X)
            
    # Calcula MAE
    MAE = mean_absolute_error(y, Y_pred)

    # Previsão para a linha de regressão
    x_pred = np.linspace(df['x'].min(), df['x'].max(), 100).reshape(-1, 1)
    y_pred = model.predict(x_pred)

    # Geração do gráfico de regressão
    plt.figure(figsize=(8, 6))
    plt.scatter(df['x'], df['y'], color='blue', label='Dados Originais')
    plt.plot(df['x'], df['y'], color='black', label='Linha dos Dados Originais')
    plt.scatter(df['x'], Y_pred, color='green', label='Dados Previstos')
    plt.plot(x_pred, y_pred, color='red', label='Linha da Regressão')
    plt.scatter(0, intercepto, color="purple", zorder=5, label="Ponto do intercepto")
    plt.title('Regressão Linear')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.legend()
    plt.grid(True)

    # Salvando o gráfico como imagem
    caminho_arquivo = 'c:\\temp\\RegressaoLinear.png'
    plt.savefig(caminho_arquivo, dpi=300, bbox_inches='tight')
    plt.close()
        
    # Formata os resultados em JSON
    resultado = {
        'coeficiente_angular': coeficiente_angular,
        'intercepto': intercepto,
        'r_quadrado': r_quadrado,
        'MAE': MAE
    }

    return json.dumps(resultado)
}

 

O código lê uma tabela em Iris via SQL, cria um dataframe pandas baseado nos dados da tabela e calcula uma regressão linear, gerando um gráfico com a reta da regressão, além de trazer indicadores da regressão. Tudo isso a partir da biblioteca scikit-learn.

O artigo da comunidade https://pt.community.intersystems.com/post/usando-o-python-no-intersystems-iris-%E2%80%93-calculando-uma-regress%C3%A3o-linear-simples traz mais informações sobre o uso do scikit-learn para calcular regressão linear.

O Iris também permite o armazenamento dados vetoriais, o que abre inúmeras possibilidades. A biblioteca langchain_iris traz mecanismos que auxiliam no armazenamento e recuperação de informações em base de dados vetoriais.

O código a seguir pega um arquivo PDF e gera uma base de dados vetorial com os embeddings gerados para futura recuperação de dados:

 

ClassMethod Ingest(collectionName As %String, filePath As %String) As %String [ Language = python ]
{

    import json
    from langchain_iris import IRISVector
    from langchain_openai import OpenAIEmbeddings
    from langchain_community.document_loaders import PyPDFLoader

    try:
        apiKey = <chatgpt_api_key>
        loader = PyPDFLoader(filePath)
        splits = loader.load_and_split()
        vectorstore = IRISVector.from_documents(
            documents=splits,
            embedding=OpenAIEmbeddings(openai_api_key=apiKey),
            dimension=1536,
            collection_name=collectionName,
        )
        return json.dumps({"status": True})
    except Exception as err:
        return json.dumps({"error": str(err)})
}

 

Ao ler o arquivo PDF, o mesmo é “quebrado” em pedaços (splits) e esses pedaços são armazenados na forma de embeddings no Iris. Embeddings são vetores que representam aquele split.

Fig. 8 – Tabela com coluna do tipo vetor no Iris

 

 

Uma vez feita a ingestão do arquivo podemos agora recuperar informações e passar para a LLM gerar um texto de retorno baseado em uma pergunta formulada. A pergunta é convertida em vetores e é feita a busca no banco de dados. Os dados recuperados são então enviados a LLM que formata uma resposta. No exemplo usamos o ChatGPT:

Fig.9 – Chamada de método no Iris

 

Abaixo o código da busca realizada:

ClassMethod Retrieve(collectionName As %String, question As %String, sessionId As %String = "") [ Language = python ]
{
    import json
    import iris
    from langchain_iris import IRISVector
    from langchain_community.chat_message_histories import ChatMessageHistory
    from langchain_core.chat_history import BaseChatMessageHistory
    from langchain_core.runnables.history import RunnableWithMessageHistory
    from langchain_openai import ChatOpenAI, OpenAIEmbeddings    

    from langchain.chains import create_history_aware_retriever
    from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
    from langchain.chains import create_retrieval_chain
    from langchain.chains.combine_documents import create_stuff_documents_chain

    
    try:
        
        apiKey = <chatgpt_api_key>
        model = "gpt-3.5-turbo"
        llm = ChatOpenAI(model= model, temperature=0, api_key=apiKey)
        embeddings = OpenAIEmbeddings(openai_api_key=apiKey)

        vectorstore = IRISVector(
            embedding_function=OpenAIEmbeddings(openai_api_key=apiKey),
            dimension=1536,
            collection_name=collectionName,
        )

        retriever = vectorstore.as_retriever()

        contextualize_q_system_prompt = """Dado um histórico de bate-papo e a última pergunta do usuário \
        que pode fazer referência ao contexto no histórico do bate-papo, formule uma pergunta independente \
        que pode ser entendido sem o histórico de bate-papo. NÃO responda à pergunta, \
        apenas reformule-o se necessário e devolva-o como está."""
        
        contextualize_q_prompt = ChatPromptTemplate.from_messages(
            [
                ("system", contextualize_q_system_prompt),
                MessagesPlaceholder("chat_history"),
                ("human", "{input}"),
            ]
        )
        history_aware_retriever = create_history_aware_retriever(
            llm, retriever, contextualize_q_prompt
        )

        qa_system_prompt = """
                            Você é um assistente inteligente que responde perguntas com base em dados recuperados de uma base. Dependendo da natureza dos dados, você deve escolher o melhor formato de resposta:

                            1. **Texto:** Se os dados contêm principalmente informações descritivas ou narrativas, responda em formato de texto.
                           
                            2. **Tabela:** Se os dados contêm informações estruturadas (ex: listas, valores, métricas, comparações diretas), responda em formato HTML com o seguinte estilo:
                               - Bordas de 1px sólidas e de cor #dddddd.
                               - O cabeçalho deve ter um fundo cinza escuro (#2C3E50) e texto em branco.
                               - As células devem ter padding de 8px.
                               - As linhas pares devem ter um fundo cinza claro (#f9f9f9).
                               - As linhas devem mudar de cor ao passar o mouse sobre elas, usando a cor #f1f1f1.
                               - O texto nas células deve estar centralizado.

                            3. **Lista:** Se os dados contêm informações estruturadas (ex: listas, valores, métricas, comparações diretas), responda em formato HTML com o seguinte estilo:
                               - Bordas de 1px sólidas e de cor #dddddd.
                               - O cabeçalho deve ter um fundo cinza escuro (#2C3E50) e texto em branco.
                               - As células devem ter padding de 8px.
                               - As linhas pares devem ter um fundo cinza claro (#f9f9f9).
                               - As linhas devem mudar de cor ao passar o mouse sobre elas, usando a cor #f1f1f1.
                               - O texto nas células deve estar centralizado.
                                                        
                            4. **Gráfico:** Se os dados contêm informações que são mais bem visualizadas em um gráfico (ex: tendências, distribuições, comparações entre categorias), gere um gráfico apropriado. Inclua um título, rótulos de eixo e uma legenda quando necessário. Responda utilizando um link do quickchart.io.
                                                        
                            Contexto: {context}
                            Pergunta: {input}
                            """
        
        qa_prompt = ChatPromptTemplate.from_messages(
            [
                ("system", qa_system_prompt),
                MessagesPlaceholder("chat_history"),
                ("human", "{input}"),
            ]
        )

        question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
        rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)

        def get_session_history(sessionId: str) -> BaseChatMessageHistory:
            rs = iris.sql.exec("SELECT * FROM (SELECT TOP 5 pergunta, resposta, ID FROM Vector.ChatHistory WHERE sessionId = ? ORDER BY ID DESC) SUB ORDER BY ID ASC", sessionId)
            history = ChatMessageHistory()
            for row in rs:
                history.add_user_message(row[0])
                history.add_ai_message(row[1])
            return history

        def save_session_history(sessionId: str, pergunta: str, resposta: str):
            iris.sql.exec("INSERT INTO Vector.ChatHistory (sessionId, pergunta, resposta) VALUES (?, ?, ?) ", sessionId, pergunta, resposta)

        conversational_rag_chain = RunnableWithMessageHistory(
            rag_chain,
            get_session_history,
            input_messages_key="input",
            history_messages_key="chat_history",
            output_messages_key="answer",
        )

        ai_msg_1 = conversational_rag_chain.invoke(
            {"input": question, "chat_history": get_session_history(sessionId).messages},
            config={
                "configurable": {"session_id": sessionId}
            },
        )
        
        save_session_history(sessionId, question, str(ai_msg_1['answer']))
        return str(ai_msg_1['answer'])
    except Exception as err:
        return str(err)
}

 

Aqui neste código entram vários aspectos que devem ser considerados neste tipo de código como o contexto da conversa, o prompt da LLM, embeddings e pesquisa vetorial.

E podemos ainda ter uma interface para realizar as chamadasao método, o que dá uma aparência mais sofisticada para a consulta. No exemplo temos uma página web acessando uma api REST que chama o método de consulta:

 

Fig. 10 – Tela de aplicação web chamando API REST no Iris

 

Estes são exemplos de uso do python no Iris. Mas o universo de bibliotecas disponíveis é muito maior. Podemos utilizar bibliotecas de reconhecimento de imagem, OCR, biometria, estatística e muito mais.

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください
お知らせ
· 8 hr 前

Videos for InterSystems Developers, May 2025 Recap

Hello and welcome to the May 2025 Developer Community YouTube Recap.
InterSystems Global Summit
"Code to Care" videos
How Project BEST Transforms FDA Adverse Event Reporting with FHIR
By Don Woodlock, Head of Global Healthcare Solutions, InterSystems
Streamlining Electronic Prior Authorizations with FHIR
By Don Woodlock, Head of Global Healthcare Solutions, InterSystems
More from InterSystems developers
Prompt the frontend UI for InterSystems IRIS with Lovable
By Evgeny Shvarov, Senior Manager of Developer and Startup Programs, InterSystems
SMART on FHIR: Introduction & FHIR Server Setup
By Tani Frankel, Sales Engineer Manager, InterSystems
SMART on FHIR: OAuthServer
By Tani Frankel, Sales Engineer Manager, InterSystems
SMART on FHIR: FHIR Server - OAuth Config
By Tani Frankel, Sales Engineer Manager, InterSystems
ディスカッション (0)1
続けるにはログインするか新規登録を行ってください
記事
· 17 hr 前 6m read

Persistencia de sesión Oauth con token OpenID en cookie

¿Conoces a Google? Seguro que si 😄 a menudo hacemos login en webs con nuestra cuenta de Gmail por la comodidad de simplemente hacer click! sin tener que escribir email ni contraseña, esto es posible porque nuestro navegador guarda un token de acceso que nos identifica y, en este caso Google, comparte un acceso para poder consultar información de nosotros como el correo electrónico.

🔐 Existen unas pautas o proceso para hacer esta identificación de forma segura, lo que se conoce como Oauth.

En este artículo no voy a explicar cómo funciona Oauth, te mostraré cómo hacer para persistir la sesión en el Oauth de IRIS sin tener que introducir usuario y contraseña cada vez que entras y de paso cómo saltar la pantalla de aceptación de permisos.

Aquí tienes una imagen marcando el flujo que vamos a crear.

¡¡Vamos al lío!!

Como primer paso puedes montar todo un sistema de Oauth en IRIS con el proyecto https://github.com/intersystems-ib/workshop-iris-oauth2, en el archivo Readme tienes los pasos para hacerlo funcionar con Docker.

Abre desde VS code el área de trabajo del proyecto.

 

 

Crea una clase que extienda de %OAuth2.Server.Authenticate, en nuestro caso la hemos llamado cysnet.oauth.server.Authenticate.

 

 

Configura Oauth para usar la clase personalizada y añade las siguientes dos métodos.

 

Y aquí la joya de la corona, crea dos métodos en la clase personalizada.

ClassMethod LoginFromCookie(authorizationCode As %String) As %Status [ Internal, ServerOnly = 1 ]
{
    #dim sc As %Status = $$$OK
    Set currentNS = $NAMESPACE
    Try {
        // Get cookie with jwt access token
        Set cookieToken = %request.GetCookie("access_token")
        If cookieToken '= "" {
            ZNspace "%SYS"
            // Get valid access token from cookie
            Set accessToken = ##class(OAuth2.Server.AccessToken).OpenByToken(cookieToken,.sc)
            If $$$ISOK(sc) && $ISOBJECT(accessToken) {
                // Get current access token
                Set currentToken = ##class(OAuth2.Server.AccessToken).OpenByCode(authorizationCode,.sc)
                If $$$ISOK(sc) && $ISOBJECT(currentToken) {
                    // Get oauth client
                    Set client = ##class(OAuth2.Server.Client).Open(currentToken.ClientId,.sc)
                    If $$$ISOK(sc) && $ISOBJECT(client) {
                        // Skip login page
                        Set currentToken.Username = accessToken.Username
                        #dim propertiesNew As %OAuth2.Server.Properties = currentToken.Properties
                        Set key=""
                        For {
                            Set value=accessToken.Properties.ResponseProperties.GetNext(.key)
                            If key="" Quit
                            Do ..SetTokenProperty(.propertiesNew,key,value)
                        }
                        Do ##class(OAuth2.Server.Auth).AddClaimValues(currentToken, currentToken.ClientId, accessToken.Username)
                        Set currentToken.Properties = propertiesNew
                        Set currentToken.Stage = "permission"
                        Do currentToken.Save()
                        // Skip permissions page
                        Set url = %request.URL_"?AuthorizationCode="_authorizationCode_"&Accept=Aceptar"
                        Set %response.Redirect = url
                    } Else {
                        Set sc = $$$ERROR($$$GeneralError, "Error getting oauth client")
                    }
                } Else {
                    Set sc = $$$ERROR($$$GeneralError, "Error getting current token")
                }
            } Else {
                Set sc = $$$ERROR($$$GeneralError, "Error getting cookie token")
                // Clear cookie access_token
                Set %response.Headers("Set-Cookie") = "access_token=; Path=/; Max-Age=0"
            }
            ZNspace currentNS
        } Else {
            Set sc = $$$ERROR($$$GeneralError, "Error cookie access_token missing")
        }
        
    } Catch ex {
        ZNspace currentNS
        If $$$ISOK(sc) {
            Set sc = ex.AsStatus()
        }
    }
    
    Quit sc
}

ClassMethod SetTokenProperty(Output properties As %OAuth2.Server.Properties, Name, Value, Type = "string") [ Internal, ServerOnly = 1 ]
{
    // Add claims and more
    Set tClaim = ##class(%OAuth2.Server.Claim).%New()
    Do properties.ResponseProperties.SetAt(Value,Name)
    Do properties.IntrospectionClaims.SetAt(tClaim,Name)
    Do properties.UserinfoClaims.SetAt(tClaim,Name)
    Do properties.JWTClaims.SetAt(tClaim,Name)
    Do properties.IDTokenClaims.SetAt(tClaim,Name)
    Do properties.SetClaimValue(Name,Value,Type)
    Quit $$$OK
}

 

Sobrescribe el método DisplayLogin

ClassMethod DisplayLogin(authorizationCode As %String, scope As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties, loginCount As %Integer = 1) As %Status
{
	Set sc = ..LoginFromCookie(authorizationCode)
	If $$$ISOK(sc) {
		Quit sc
	} Else {
		$$$LOGERROR($system.Status.GetErrorText(sc))
	}

	Quit ..DisplayLogin(authorizationCode, scope, properties, loginCount)
}

 

Veamos paso por paso que hace el método LoginFromCookie, supongamos que ya hemos hecho login con anterioridad y tenemos el token JWT de OpenID en una cookie llamada access_token.

  1. Obtiene la cookie access_token.
    Set cookieToken = %request.GetCookie("access_token")
  2. Cambia al namespace %SYS para usar los métodos de las librerías de Oauth.
    ZNspace "%SYS"
  3. Obtiene el token con la cookie, este método elimina los tokens expirados, nos vale para saber que el token es válido y no ha sido modificado.
    Set accessToken = ##class(OAuth2.Server.AccessToken).OpenByToken(cookieToken,.sc)
  4. Obtiene el token recién creado para el cliente de Oauth que solicita el login de usuario.
    Set currentToken = ##class(OAuth2.Server.AccessToken).OpenByCode(authorizationCode,.sc)
  5. Obtiene el cliente de Oauth.
    Set client = ##class(OAuth2.Server.Client).Open(currentToken.ClientId,.sc)
  6. Replica el usuario y las propiedades en el token nuevo.
    Set currentToken.Username = accessToken.Username
    #dim propertiesNew As %OAuth2.Server.Properties = currentToken.Properties
    Set key=""
    For {
    	Set value=accessToken.Properties.ResponseProperties.GetNext(.key)
    	If key="" Quit
    	Do ..SetTokenProperty(.propertiesNew,key,value)
    }
    Do ##class(OAuth2.Server.Auth).AddClaimValues(currentToken, currentToken.ClientId, accessToken.Username)
    Set currentToken.Properties = propertiesNew
  7. Salta el login y guarda los cambios del token.
    Set currentToken.Stage = "permission"
    Do currentToken.Save()
      En este punto podríamos llamar al método DisplayPermissions si queremos mostrar la pantalla de aceptación de permisos.  
  8. Saltar pantalla de permisos y enviar el código de autorización al callback del cliente de oauth
    Set url = %request.URL_"?AuthorizationCode="_authorizationCode_"&Accept=Aceptar"
    Set %response.Redirect = url

 

Otros apuntes

Nos ha pasado en otros entornos con versiones anteriores a la actual de IRIS que la redirección no funciona, una posible solución a esto es devolver un javascript que lo haga:

&html<<script type="text/javascript">
    window.location.href="#(url)#";
</script>>

 

Respecto a la pantalla de permisos lo ideal sería almacenar en una persistencia: Cliente de OAuth, Usuario y Scopes aceptados, y no mostrar la pantalla si los permisos fueron aceptados con anterioridad.

 

Este es mi primer post publicado, espero haberlo hecho de manera clara y que sea de utilidad para llevar el Oauth de IRIS al siguiente nivel.

Si has llegado hasta aquí agradecerte de corazón el tiempo de leer este post y si tienes alguna duda puedes hacérmela llegar en los comentarios.

Un saludo, Miguelio, Cysnet.

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください
質問
· 2025年6月6日

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件の新着コメント
ディスカッション (2)3
続けるにはログインするか新規登録を行ってください
質問
· 2025年6月6日

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.

4件の新着コメント
ディスカッション (4)3
続けるにはログインするか新規登録を行ってください