Acessar arquivos do servidor que o Fluig está hospedado pelo Fluig

Boa tarde pessoal, tudo certo?

Tenho um caso aqui em que preciso de dados de outro serviço, mas esse serviço não tem acesso por API, e comumente ele fornece informação para outros por pastas compartilhadas.

Pensei em, via Samba (meu fluig esta no linux) compartilhar uma pasta minha com esse serviço e ler os dados dessa pasta para pegar os arquivos que ele me enviar, teria alguma forma padrão da plataforma?

Testei manualmente editar um arquivo do proprio volume e devolve erro que o arquivo foi editado externamente, acredito que não seria o ideal manter esse método.

Acredito que via Java (dataset) teria como, mas gostaria de ver se já não existe algo do gênero antes de criar do zero.

O Fluig salva um CRC pra saber se o arquivo foi modificado, então se alterar externamente dá esse problema mesmo.

Nesse Post comentam sobre isso. Que basta editar as propriedades do arquivo, via API mesmo, que o Fluig já recalcula o CRC.

Mas se o seu outro serviço não consegue executar a API terá uma dificuldade com isso.

1 curtida

Bom dia,

Acabei fazendo um dataset usando java.io e java.nio, vou deixar aqui caso alguém tenha utilidade um dia, a formatação é pra XLS e XLSX, não testei com outros arquivos, mas a base de leitura é até a linha 52 ‘newInputStream’, após isso é só formatar como precisar.

Só precisa rever as regras perante o seu ambiente, tem algumas regras do meu servidor ali dentro, ai quem for usar precisa retirar.

dsGetArchiveInServer.js (5,3,KB)

@pietro, Infelizmente o arquivo não ficou acessível. Acho que tá com algum problema de permissão no fórum.

Uma coisa legal desse fórum é que dá pra postar o código direto no post e deixar formatado.

Basta colocar o código entre “cercas” que indicam a linguagem. No caso do JS é só clicar no botão de fences e escrever o código dentro da demarcação.

1 curtida

To ligado, é MD, mas achei que tava ok só o arquivo, foi por praticidade mesmo kkkk.

Segue o código ai, caso alguém queria usar/adaptar.

/**
 * Dataset: ds_le_xls_arquivo
 * Lê um arquivo Excel (XLS/XLSX) do filesystem (somente caminhos sob /opt/).
 *
 * Constraint
 *  - caminho: caminho absoluto do arquivo, ex.: /opt/fluig_bi/testes/planilha.xlsx
 *  
 * Observações:
 *  - Ignora linhas totalmente vazias após o cabeçalho.
 *  - Se ter cabeçalhos vazios, gera nomes "col1", "col2"
 *  - Se ter cabeçalhos repetidos, torna-os únicos adicionando sufixos _2, _3...
 */

function createDataset(fields, constraints, sortFields) {

    var ds = DatasetBuilder.newDataset();

    try {
        var Files = Packages.java.nio.file.Files;
        var Paths = Packages.java.nio.file.Paths;
        var StandardOpenOption = Packages.java.nio.file.StandardOpenOption;
        var WorkbookFactory = Packages.org.apache.poi.ss.usermodel.WorkbookFactory;
        var DataFormatter = Packages.org.apache.poi.ss.usermodel.DataFormatter;
        var Locale = Packages.java.util.Locale;

        // -------- utils --------
        function getConstraint(name) {
            if (!constraints) return null;
            for (var i = 0; i < constraints.length; i++) {
                if (String(constraints[i].fieldName) === String(name)) {
                    return String(constraints[i].initialValue);
                }
            }
            return null;
        }

        function assert(cond, msg) { if (!cond) throw msg; }

        // -------- ler constraint / validar caminho --------
        var caminho = getConstraint("caminho");
         
        assert(caminho && caminho.length > 0, "Informe a constraint obrigatória 'caminho'.");
        assert(caminho.indexOf("\u0000") < 0, "Caminho inválido.");
        assert(caminho.indexOf("..") < 0, "Caminho não pode conter '..'.");
        assert(caminho.indexOf("/opt/") === 0, "Por segurança, apenas caminhos sob /opt/ são permitidos.");

        var path = Paths.get(caminho);
        assert(Files.exists(path), "Arquivo não encontrado: " + caminho);
        assert(Files.isReadable(path), "Sem permissão de leitura no arquivo: " + caminho);
 
        // -------- abrir workbook --------
        var is = Files.newInputStream(path, StandardOpenOption.READ);
        var wb = null;
        try {
            wb = WorkbookFactory.create(is); // detecta xls/xlsx
        } catch (e) {
            if (is) try { is.close(); } catch (ex) { }
            throw "Falha ao abrir arquivo como Excel (XLS/XLSX). Verifique o formato. Erro: " + e;
        } finally {
            try { if (is) is.close(); } catch (ex2) { }
        }
 
        var sheet = wb.getNumberOfSheets() > 0 ? wb.getSheetAt(0) : null;
        assert(sheet !== null, "Workbook sem abas (sheets).");

        // -------- formatter: converte qualquer tipo de célula em String "como exibido" --------
        var fmt = new DataFormatter(Locale.forLanguageTag("pt-BR"));

        // -------- localizar primeira linha (cabeçalho) --------
        var headerRow = sheet.getRow(sheet.getFirstRowNum());
        assert(headerRow !== null, "Planilha vazia: sem cabeçalho.");

        // extrair cabeçalhos
        var firstCell = headerRow.getFirstCellNum();
        var lastCell = headerRow.getLastCellNum();
        assert(lastCell > firstCell, "Cabeçalho sem colunas.");

        var headers = [];
        var seen = {}; // para evitar nomes duplicados
        var colIndexMap = []; // pos -> nome
 
        for (var c = firstCell; c < lastCell; c++) { 
            var cell = headerRow.getCell(c); 
            var raw = cell ? String(fmt.formatCellValue(cell)).trim() : ""; 
            var base = raw && raw.length ? String(raw) : ("col" + (c - firstCell + 1)); 
            var name = sanitizeColumnName(base); 
            
            // tornar único se repetido
            if (seen[name]) {
                var k = 2;
                while (seen[name + "_" + k]) k++;
                name = name + "_" + k;
            } 
            seen[name] = true;

            headers.push(name);
            colIndexMap.push(name);
        }
        log.info(headers.join(" | "))
        // criar colunas no dataset
        for (var i = 0; i < headers.length; i++) {

            ds.addColumn(headers[i]);
        }

        // -------- iterar linhas de dados --------
        var firstDataRowIdx = sheet.getFirstRowNum() + 1;
        var lastRowIdx = sheet.getLastRowNum();

        for (var r = firstDataRowIdx; r <= lastRowIdx; r++) {
            var row = sheet.getRow(r);
            if (row === null) continue;

            var allEmpty = true;
            var values = java.lang.reflect.Array.newInstance(java.lang.String, headers.length);

            for (var c2 = 0; c2 < headers.length; c2++) {
                var cell2 = row.getCell(c2);
                var val = cell2 ? String(fmt.formatCellValue(cell2)) : "";
                if (val && String(val).trim().length) allEmpty = false;
                values[c2] = val;
            }

            if (allEmpty) continue; // pula linha totalmente vazia
            ds.addRow(values);
        }

        // liberar workbook (POI) — ajuda GC
        try { wb.close(); } catch (ignore) { }


    } catch (error) {
        ds.addColumn('error');
        ds.addRow([error]);
    }
    return ds;
}

function sanitizeColumnName(name) {
    var Normalizer = Packages.java.text.Normalizer;
    try {
        if (name == null) return "null";
        var s = String(name);
        s = String(Normalizer.normalize(s, Normalizer.Form.NFD));
        s = s.replace(/[\u0300-\u036f]/g, "")
             .replace(/[^a-zA-Z0-9_]/g, "_") 
             .replace(/_+/g, "_")            
             .replace(/^_+|_+$/g, "")        
             .toLowerCase();

        return s.length ? s : "col";
    } catch (error) {
        log.error("Erro ao normalizar cabeçalho: " + error);
        var f = String(name || "col")
            .replace(/[^\x00-\x7F]/g, "")
            .replace(/[^a-zA-Z0-9_]/g, "_")
            .replace(/_+/g, "_")
            .replace(/^_+|_+$/g, "")
            .toLowerCase();

        return f.length ? f : "col";
    }
}

1 curtida