Skip to content

Commit 8f82a4a

Browse files
Merge remote-tracking branch 'origin/master' into develop
2 parents f9d8ec3 + 8268a4e commit 8f82a4a

File tree

2 files changed

+196
-73
lines changed

2 files changed

+196
-73
lines changed

pom.xml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<axiom-api.version>1.2.20</axiom-api.version>
4242
<jmockit.version>1.46</jmockit.version>
4343
<junit-jupiter.version>5.4.0</junit-jupiter.version>
44-
<lombok.version>1.18.22</lombok.version>
44+
<lombok.version>1.18.30</lombok.version>
4545
<maven-assembly-plugin.version>3.1.1</maven-assembly-plugin.version>
4646
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
4747
<nexus-staging-maven-plugin.version>1.6.13</nexus-staging-maven-plugin.version>
@@ -107,11 +107,6 @@
107107
<artifactId>java_certificado</artifactId>
108108
<version>${java-certificado.version}</version>
109109
</dependency>
110-
<dependency>
111-
<groupId>org.ini4j</groupId>
112-
<artifactId>ini4j</artifactId>
113-
<version>${ini4j.version}</version>
114-
</dependency>
115110
<dependency>
116111
<groupId>org.apache.httpcomponents</groupId>
117112
<artifactId>httpcore</artifactId>

src/main/java/br/com/swconsultoria/nfe/util/WebServiceUtil.java

Lines changed: 195 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@
1010
import br.com.swconsultoria.nfe.dom.enuns.ServicosEnum;
1111
import br.com.swconsultoria.nfe.exception.NfeException;
1212
import lombok.extern.java.Log;
13-
import org.ini4j.Wini;
1413

1514
import java.io.*;
15+
import java.io.InputStreamReader;
16+
import java.nio.charset.StandardCharsets;
1617
import java.util.logging.Logger;
18+
import java.util.Map;
19+
import java.util.HashMap;
20+
import java.util.regex.Matcher;
21+
import java.util.regex.Pattern;
22+
1723

1824
/**
1925
* @author Samuel Oliveira
@@ -24,19 +30,129 @@
2430
public class WebServiceUtil {
2531

2632
private final static Logger logger = Logger.getLogger(WebServiceUtil.class.getName());
33+
private static final Pattern sectionPattern = Pattern.compile("^\\[(.+)\\]$");
34+
35+
/**
36+
* Obtém um valor de um Mapa que representa uma seção de um arquivo INI,
37+
* buscando pela {@code targetKey} de forma case-insensitive.
38+
* Este método também normaliza as chaves lidas do mapa (que vêm do arquivo INI)
39+
* que contêm "..", substituindo por ".", antes de realizar a comparação case-insensitive.
40+
*
41+
* @param sectionMap O Mapa ({@code Map<String, String>}) contendo os pares de chave-valor da seção específica.
42+
* Pode ser nulo ou vazio.
43+
* @param targetKey A chave alvo (geralmente esperada em lowercase, vinda de {@code ServicosEnum}, ou "Usar" em PascalCase)
44+
* a ser buscada dentro da seção.
45+
* @param logger O logger para registrar informações de depuração (ex: qual chave está sendo comparada).
46+
* @return O valor da propriedade como String, se uma correspondência case-insensitive for encontrada;
47+
* {@code null} caso contrário, ou se {@code sectionMap} for nulo/vazio, ou se {@code targetKey} for nula.
48+
*/
49+
private static String getIniValueIgnoreCase(Map<String, String> sectionMap, String targetKey, Logger logger) {
50+
if (sectionMap == null || sectionMap.isEmpty() || targetKey == null) {
51+
return null;
52+
}
53+
for (Map.Entry<String, String> entry : sectionMap.entrySet()) {
54+
String keyFromIni = entry.getKey();
55+
String normalizedKeyFromIni = keyFromIni.replace("..", ".");
56+
String normalizedTargetKey = targetKey.replace("..", ".");
57+
if (normalizedTargetKey.equalsIgnoreCase(normalizedKeyFromIni)) {
58+
return entry.getValue();
59+
}
60+
}
61+
return null;
62+
}
63+
64+
/**
65+
* Analisa (parse) um arquivo INI a partir de um {@link InputStream} e o carrega em uma estrutura de dados aninhada de Mapas.
66+
* O método lê o stream linha por linha, identificando seções (ex: {@code [NomeDaSecao]}),
67+
* pares de chave-valor (ex: {@code chave=valor} ou {@code chave:valor}), e linhas de comentário (iniciadas com ';' ou '#').
68+
* Espaços em branco ao redor de nomes de seção, chaves e valores são removidos (trim).
69+
* As seções e chaves são armazenadas preservando o case original do arquivo.
70+
*
71+
* @param inputStream O {@link InputStream} do arquivo INI a ser analisado. O stream é fechado ao final do parsing.
72+
* @return Um {@code Map<String, Map<String, String>>} representando os dados do INI.
73+
* A chave do mapa externo é o nome da seção. O valor é outro mapa contendo
74+
* os pares de chave-valor daquela seção.
75+
* @throws IOException Se ocorrer um erro de I/O durante a leitura do stream.
76+
* @throws NfeException Se forem encontradas linhas malformadas que não se encaixam no padrão esperado
77+
* de seção ou chave-valor (ex: nome de seção vazio em {@code []}, ou uma chave-valor fora de uma seção).
78+
*/
79+
private static Map<String, Map<String, String>> parseIniFile(InputStream inputStream) throws IOException, NfeException {
80+
Map<String, Map<String, String>> iniData = new HashMap<>();
81+
String currentSectionName = null;
82+
Map<String, String> currentSectionMap = null;
83+
84+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
85+
String line;
86+
while ((line = reader.readLine()) != null) {
87+
line = line.trim();
88+
89+
if (line.isEmpty() || line.startsWith(";") || line.startsWith("#")) {
90+
continue; // Skip empty lines and comments
91+
}
92+
93+
Matcher sectionMatcher = sectionPattern.matcher(line);
94+
if (sectionMatcher.matches()) {
95+
// If currentSectionMap is not null and not empty, it means a previous section was being processed.
96+
// It's already in iniData, as we put it there when its name was found.
97+
currentSectionName = sectionMatcher.group(1).trim();
98+
if (currentSectionName.isEmpty()) {
99+
throw new NfeException("Nome da seção inválido (vazio) no arquivo INI.");
100+
}
101+
// Ensure new section map is created, even if previous one with same name existed (though INI typically doesn't repeat sections)
102+
currentSectionMap = new HashMap<>();
103+
iniData.put(currentSectionName, currentSectionMap);
104+
} else {
105+
if (currentSectionName == null) {
106+
// Property outside of any section - not expected for WebServicesNfe.ini
107+
// For now, we can log and ignore, or throw an exception.
108+
// Based on prompt, let's be strict for this specific INI structure.
109+
throw new NfeException("Propriedade encontrada fora de uma seção: " + line);
110+
}
111+
112+
int separatorPos = -1;
113+
int equalsPos = line.indexOf('=');
114+
// According to INI standards, some parsers also accept ':' but '=' is more common.
115+
// The original ini4j might have handled both. For this custom parser, let's stick to '=' for simplicity
116+
// unless ':' is confirmed to be used in WebServicesNfe.ini for key-value.
117+
// A quick check of WebServicesNfe.ini shows only '='.
118+
separatorPos = equalsPos;
119+
120+
if (separatorPos != -1) {
121+
String key = line.substring(0, separatorPos).trim();
122+
String value = line.substring(separatorPos + 1).trim();
123+
if (!key.isEmpty() && currentSectionMap != null) {
124+
currentSectionMap.put(key, value);
125+
} else if (key.isEmpty()){
126+
logger.warning("Linha malformada (chave vazia): " + line);
127+
} else {
128+
// currentSectionMap should not be null here if currentSectionName is set.
129+
// This case implies currentSectionName was set, but currentSectionMap wasn't put in iniData or was null.
130+
// This should ideally not happen if logic is correct.
131+
logger.warning("Tentativa de adicionar propriedade a uma seção nula: " + line);
132+
}
133+
} else {
134+
// Line is not a comment, not a section, and not a valid key-value pair.
135+
logger.warning("Linha malformada ignorada: " + line);
136+
}
137+
}
138+
}
139+
}
140+
return iniData;
141+
}
142+
27143

28144
/**
29145
* Retorna a URL para consulta de operações do SEFAZ.<br>
30146
*
31147
* <p>
32-
* O método carrega o arquivo <b>WebServicesNfe.ini</b> que contêm as
33-
* URL's de operações do SEFAZ, busca pela seção no arquivo .ini que
148+
* O método carrega o arquivo <b>WebServicesNfe.ini</b> (utilizando um parser customizado)
149+
* que contêm as URL's de operações do SEFAZ, busca pela seção no arquivo .ini que
34150
* corresponda com os argumentos <b>tipo</b>, <b>config</b>, <b>servico</b>
35151
* e retorna essa URL.
36152
* </p>
37153
*
38154
* @param config interface que contêm os dados necessários para a comunicação.
39-
* @param tipoDocumento DocumentoEnum.NFE e ConstantesUtil.NFCE
155+
* @param tipoDocumento {@link DocumentoEnum#NFE} ou {@link DocumentoEnum#NFCE}.
40156
* @param tipoServico é a operação que se deseja fazer.<br>
41157
* Ex.: para consultas status deserviço no ambiente de produção
42158
* use ServicosEnum.NfeStatusServico_4.00
@@ -45,84 +161,96 @@ public class WebServiceUtil {
45161
* @throws NfeException
46162
*
47163
* @see ConfiguracoesNfe
48-
* @see ConstantesUtil
49-
**/
164+
*/
50165
public static String getUrl(ConfiguracoesNfe config, DocumentoEnum tipoDocumento, ServicosEnum tipoServico) throws NfeException {
51-
166+
InputStream is = null;
167+
Map<String, Map<String, String>> iniData;
52168
try {
53-
54-
String secao = tipoDocumento.getTipo() + "_" + config.getEstado() + "_"
55-
+ (config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "H" : "P");
56-
57-
InputStream is;
58169
if (ObjetoUtil.verifica(config.getArquivoWebService()).isPresent()) {
59170
File arquivo = new File(config.getArquivoWebService());
60-
if (!arquivo.exists())
61-
throw new FileNotFoundException("Arquivo WebService" + config.getArquivoWebService() + " não encontrado");
171+
if (!arquivo.exists()) {
172+
throw new FileNotFoundException("Arquivo WebService " + config.getArquivoWebService() + " não encontrado");
173+
}
62174
is = new FileInputStream(arquivo);
63-
log.info("[ARQUIVO INI CUSTOMIZADO]: " + config.getArquivoWebService());
175+
logger.info("[ARQUIVO INI CUSTOMIZADO]: " + config.getArquivoWebService());
64176
} else {
65177
is = WebServiceUtil.class.getResourceAsStream("/WebServicesNfe.ini");
178+
if (is == null) {
179+
throw new NfeException("Arquivo WebServicesNfe.ini não encontrado no classpath.");
180+
}
66181
}
67-
68-
Wini ini = new Wini();
69-
ini.getConfig().setLowerCaseOption(true);
70-
ini.load(is);
71-
is.close();
72-
String url = ini.get(secao, "usar");
73-
74-
//URLS CONSULTA CADASTO
75-
if (tipoServico.equals(ServicosEnum.CONSULTA_CADASTRO) && (
76-
config.getEstado().equals(EstadosEnum.PA) ||
77-
config.getEstado().equals(EstadosEnum.AM) ||
78-
config.getEstado().equals(EstadosEnum.AL) ||
79-
config.getEstado().equals(EstadosEnum.AP) ||
80-
config.getEstado().equals(EstadosEnum.DF) ||
81-
config.getEstado().equals(EstadosEnum.PI) ||
82-
config.getEstado().equals(EstadosEnum.RJ) ||
83-
config.getEstado().equals(EstadosEnum.RO) ||
84-
config.getEstado().equals(EstadosEnum.SE) ||
85-
config.getEstado().equals(EstadosEnum.TO))) {
86-
throw new NfeException("Estado não possui Consulta Cadastro.");
87-
// URLS de ambiente nacional
88-
} else if (tipoServico.equals(ServicosEnum.DISTRIBUICAO_DFE)
89-
|| tipoServico.equals(ServicosEnum.MANIFESTACAO)
90-
|| tipoServico.equals(ServicosEnum.EPEC)) {
91-
secao = config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "NFe_AN_H" : "NFe_AN_P";
92-
} else if (!tipoServico.equals(ServicosEnum.URL_CONSULTANFCE)
93-
&& !tipoServico.equals(ServicosEnum.URL_QRCODE)
94-
&& config.isContigenciaSVC() && tipoDocumento.equals(DocumentoEnum.NFE)) {
95-
// SVC-RS
96-
if (config.getEstado().equals(EstadosEnum.GO) || config.getEstado().equals(EstadosEnum.AM)
97-
|| config.getEstado().equals(EstadosEnum.BA) || config.getEstado().equals(EstadosEnum.CE)
98-
|| config.getEstado().equals(EstadosEnum.MA) || config.getEstado().equals(EstadosEnum.MS)
99-
|| config.getEstado().equals(EstadosEnum.MT) || config.getEstado().equals(EstadosEnum.PA)
100-
|| config.getEstado().equals(EstadosEnum.PE) || config.getEstado().equals(EstadosEnum.PI)
101-
|| config.getEstado().equals(EstadosEnum.PR)) {
102-
secao = tipoDocumento.getTipo() + "_SVRS_"
103-
+ (config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "H" : "P");
104-
// SVC-AN
105-
} else {
106-
secao = tipoDocumento.getTipo() + "_SVC-AN_"
107-
+ (config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "H" : "P");
182+
iniData = parseIniFile(is);
183+
} catch (IOException e) {
184+
throw new NfeException("Erro ao carregar arquivo de configuração WebService: " + e.getMessage(), e);
185+
} finally {
186+
if (is != null) {
187+
try {
188+
is.close();
189+
} catch (IOException e) {
190+
logger.fine("Erro ao fechar InputStream: " + e.getMessage());
108191
}
109-
}else if (!tipoServico.equals(ServicosEnum.URL_CONSULTANFCE)
110-
&& !tipoServico.equals(ServicosEnum.URL_QRCODE) && ObjetoUtil.verifica(url).isPresent()) {
111-
secao = url;
112192
}
193+
}
113194

114-
url = ini.get(secao, tipoServico.getServico().toLowerCase());
115-
116-
ObjetoUtil.verifica(url).orElseThrow(() -> new NfeException(
117-
"WebService de " + tipoServico + " não encontrado para " + config.getEstado().getNome()));
195+
String initialSecaoKey = tipoDocumento.getTipo() + "_" + config.getEstado() + "_"
196+
+ (config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "H" : "P");
118197

119-
log.info("[URL]: " + tipoServico + ": " + url);
198+
String lookupSectionKey = initialSecaoKey;
199+
Map<String, String> initialSectionMap = iniData.get(initialSecaoKey);
200+
// Pass the static logger from the class to the helper method
201+
String usarValue = getIniValueIgnoreCase(initialSectionMap, "Usar", logger);
120202

121-
return url;
203+
String finalUrl = null;
122204

123-
} catch (IOException e) {
124-
throw new NfeException(e.getMessage(),e);
205+
if (tipoServico.equals(ServicosEnum.CONSULTA_CADASTRO) && (
206+
config.getEstado().equals(EstadosEnum.PA) ||
207+
config.getEstado().equals(EstadosEnum.AM) ||
208+
config.getEstado().equals(EstadosEnum.AL) ||
209+
config.getEstado().equals(EstadosEnum.AP) ||
210+
config.getEstado().equals(EstadosEnum.DF) ||
211+
config.getEstado().equals(EstadosEnum.PI) ||
212+
config.getEstado().equals(EstadosEnum.RJ) ||
213+
config.getEstado().equals(EstadosEnum.RO) ||
214+
config.getEstado().equals(EstadosEnum.SE) ||
215+
config.getEstado().equals(EstadosEnum.TO))) {
216+
throw new NfeException("Estado não possui Consulta Cadastro.");
217+
} else if (tipoServico.equals(ServicosEnum.DISTRIBUICAO_DFE) ||
218+
tipoServico.equals(ServicosEnum.MANIFESTACAO) ||
219+
tipoServico.equals(ServicosEnum.EPEC)) {
220+
lookupSectionKey = config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "NFe_AN_H" : "NFe_AN_P";
221+
Map<String, String> nationalSectionMap = iniData.get(lookupSectionKey);
222+
finalUrl = getIniValueIgnoreCase(nationalSectionMap, tipoServico.getServico(), logger);
223+
} else if (!tipoServico.equals(ServicosEnum.URL_CONSULTANFCE) &&
224+
!tipoServico.equals(ServicosEnum.URL_QRCODE) &&
225+
config.isContigenciaSVC() && tipoDocumento.equals(DocumentoEnum.NFE)) {
226+
if (config.getEstado().equals(EstadosEnum.GO) || config.getEstado().equals(EstadosEnum.AM) ||
227+
config.getEstado().equals(EstadosEnum.BA) || config.getEstado().equals(EstadosEnum.CE) ||
228+
config.getEstado().equals(EstadosEnum.MA) || config.getEstado().equals(EstadosEnum.MS) ||
229+
config.getEstado().equals(EstadosEnum.MT) || config.getEstado().equals(EstadosEnum.PA) ||
230+
config.getEstado().equals(EstadosEnum.PE) || config.getEstado().equals(EstadosEnum.PI) ||
231+
config.getEstado().equals(EstadosEnum.PR)) {
232+
lookupSectionKey = tipoDocumento.getTipo() + "_SVRS_" + (config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "H" : "P");
233+
} else {
234+
lookupSectionKey = tipoDocumento.getTipo() + "_SVC-AN_" + (config.getAmbiente().equals(AmbienteEnum.HOMOLOGACAO) ? "H" : "P");
235+
}
236+
Map<String, String> svcSectionMap = iniData.get(lookupSectionKey);
237+
finalUrl = getIniValueIgnoreCase(svcSectionMap, tipoServico.getServico(), logger);
238+
} else if (ObjetoUtil.verifica(usarValue).isPresent() &&
239+
!tipoServico.equals(ServicosEnum.URL_CONSULTANFCE) &&
240+
!tipoServico.equals(ServicosEnum.URL_QRCODE)) {
241+
lookupSectionKey = usarValue;
242+
Map<String, String> usarRedirectedSectionMap = iniData.get(lookupSectionKey);
243+
finalUrl = getIniValueIgnoreCase(usarRedirectedSectionMap, tipoServico.getServico(), logger);
244+
} else {
245+
Map<String, String> currentSectionMap = iniData.get(lookupSectionKey);
246+
finalUrl = getIniValueIgnoreCase(currentSectionMap, tipoServico.getServico(), logger);
125247
}
126248

249+
final String finalLookupSectionKeyForLambda = lookupSectionKey;
250+
ObjetoUtil.verifica(finalUrl).orElseThrow(() -> new NfeException(
251+
"WebService de " + tipoServico + " não encontrado para " + config.getEstado().getNome() + " na seção " + finalLookupSectionKeyForLambda));
252+
253+
logger.info("[URL]: " + tipoServico + ": " + finalUrl);
254+
return finalUrl;
127255
}
128256
}

0 commit comments

Comments
 (0)