package br.com.centralit.citcorpore.negocio; import java.io.File; import java.io.FileNotFoundException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import br.com.centralit.citajax.html.DocumentHTML; import br.com.centralit.citcorpore.bean.ScriptsDTO; import br.com.centralit.citcorpore.bean.VersaoDTO; import br.com.centralit.citcorpore.integracao.ScriptsDao; import br.com.centralit.citcorpore.integracao.VersaoDao; import br.com.centralit.citcorpore.util.CITCorporeUtil; import br.com.citframework.dto.IDto; import br.com.citframework.excecao.ServiceException; import br.com.citframework.integracao.PersistenceEngine; import br.com.citframework.integracao.TransactionControler; import br.com.citframework.integracao.TransactionControlerImpl; import br.com.citframework.service.CrudServiceImpl; import br.com.citframework.util.Constantes; import br.com.citframework.util.UtilDatas; import br.com.citframework.util.UtilI18N; public class ScriptsServiceEjb extends CrudServiceImpl implements ScriptsService { private static final Logger LOGGER = Logger.getLogger(ScriptsServiceEjb.class); private ScriptsDao dao; @Override protected ScriptsDao getDao() { if (dao == null) { dao = new ScriptsDao(); } return dao; } private Map<String, String> chaves; @Override public ScriptsDTO buscaScriptPorId(final Integer id) throws Exception { return this.getDao().buscaScriptPorId(id); } @Override public void deletarScript(final IDto model, final DocumentHTML document) throws Exception { final ScriptsDTO scriptsDto = (ScriptsDTO) model; final TransactionControler tc = new TransactionControlerImpl(this.getDao().getAliasDB()); final ScriptsDao scriptsDao = new ScriptsDao(); try { this.validaUpdate(scriptsDto); scriptsDao.setTransactionControler(tc); tc.start(); scriptsDto.setDataFim(UtilDatas.getDataAtual()); scriptsDao.update(scriptsDto); document.alert(this.i18nMessage("MSG07")); tc.commit(); tc.close(); } catch (final Exception e) { this.rollbackTransaction(tc, e); } } @SuppressWarnings("resource") @Override public String executaRotinaScripts() throws Exception { String erro = null; // LEITURA PROGRESSIVA DO XML final String separator = System.getProperty("file.separator"); String diretorio = CITCorporeUtil.CAMINHO_REAL_APP + "XMLs" + separator; File file = new File(diretorio + "historicoDeVersoes.xml"); final SAXBuilder sb = new SAXBuilder(); final Document doc = sb.build(file); final Element historicoDeVersoes = doc.getRootElement(); final List<Element> versoes = historicoDeVersoes.getChildren(); final TransactionControler tc = new TransactionControlerImpl(Constantes.getValue("DATABASE_ALIAS")); final ScriptsDao scriptsDao = new ScriptsDao(); final VersaoDao versaoDao = new VersaoDao(); try { tc.start(); scriptsDao.setTransactionControler(tc); versaoDao.setTransactionControler(tc); /** * Recupera lista com todos os scripts e as ordena em ordem crescente para se realizar uma busca bin�ria * * @author thyen.chang * @since 03/02/2015 - OPERA��O USAIN BOLT */ final ArrayList<ScriptsDTO> listaScripts = new ArrayList<ScriptsDTO>(scriptsDao.listaTodosScripts()); Collections.sort(listaScripts, new ScriptsDTO()); if (versoes != null & !versoes.isEmpty()) { for (final Element versao : versoes) { // limpa o HashMap de chaves this.setChaves(null); VersaoDTO versaoDTO = versaoDao.buscaVersaoPorNome(versao.getText()); if (versaoDTO == null) { versaoDTO = new VersaoDTO(); versaoDTO.setNomeVersao(versao.getText()); versaoDTO = (VersaoDTO) versaoDao.create(versaoDTO); tc.commit(); } diretorio = CITCorporeUtil.CAMINHO_REAL_APP + "scripts_deploy" + separator; final String nomeArquivo = "deploy_versao_" + versaoDTO.getNomeVersao() + "_" + CITCorporeUtil.SGBD_PRINCIPAL + ".sql"; file = new File(diretorio + nomeArquivo); Scanner scanner = null; try { scanner = new Scanner(file, "ISO-8859-1"); scanner = scanner.useDelimiter("\n"); } catch (final FileNotFoundException e) { // VERSAO N�O ENCONTROU SCRIPT continue; } // TIRA COMENTARIOS String sqlQuery = new String(); boolean comentario = false; while (scanner.hasNext()) { String linha = scanner.next(); if (comentario && linha.contains("*/")) { linha = linha.substring(linha.indexOf("*/") + 2); comentario = false; } if (linha.contains("/*")) { final String str = linha; linha = str.substring(0, str.indexOf("/*")); if (linha.contains("*/")) { linha += str.substring(str.indexOf("*/") + 2); } else { comentario = true; sqlQuery += " " + linha + "\n"; } } if (!comentario && !linha.startsWith("--") && !linha.startsWith("//")) { sqlQuery += " " + linha + "\n"; } } scanner.close(); // DIVIDE O SCRIPT USANDO ";" SEGUIDO DE QUEBRA DE LINHA scanner = new Scanner(sqlQuery).useDelimiter(";(\r)?\n"); while (scanner.hasNext()) { String sql = scanner.next(); sql = sql.replaceAll("(\r\n|\n\r|\r|\n)", " "); sql = sql.trim(); if (!sql.isEmpty()) { final String nomeScript = nomeArquivo + "#" + sql.hashCode(); ScriptsDTO scriptsDTO = new ScriptsDTO(); scriptsDTO.setNome(nomeScript); /** * Busca o script via busca bin�ria. * Se n�o o encontrar, o �ndice retornado � negativo * * @author thyen.chang * @since 03/02/2015 - OPERA��O USAIN BOLT */ final int indexScript = Collections.binarySearch(listaScripts, scriptsDTO, new ScriptsDTO()); if (indexScript < 0) { sql = this.preencheChavesPrimarias(sql); scriptsDTO = new ScriptsDTO(); scriptsDTO.setNome(nomeScript); scriptsDTO.setDataInicio(UtilDatas.getDataAtual()); scriptsDTO.setSqlQuery(sql); scriptsDTO.setTipo(ScriptsDTO.TIPO_UPDATE); scriptsDTO.setHistorico("INSTRU��O EXECUTADA PELA ROTINA DO SISTEMA AO INICIALIZAR A APLICA��O. DATA / HORA: " + UtilDatas.getDataHoraAtual()); scriptsDTO.setIdVersao(versaoDTO.getIdVersao()); try { LOGGER.info("Vers�o -> " + versaoDTO.getNomeVersao() + " SQL -> " + scriptsDTO.getSqlQuery()); final int quantidadeRegistrosAfetados = tc.getConnection().createStatement().executeUpdate(sql); scriptsDTO.setDescricao("SUCESSO: " + quantidadeRegistrosAfetados + " REGISTROS AFETADOS!"); } catch (final SQLException e) { scriptsDTO.setDescricao("ERRO: " + e.getLocalizedMessage()); } finally { try { tc.commit(); } catch (final Exception e) { LOGGER.warn(e.getMessage(), e); } LOGGER.info("resultado: " + scriptsDTO.getDescricao()); if (scriptsDTO.getIdScript() == null) { try { scriptsDao.create(scriptsDTO); } catch (final Exception e) { LOGGER.warn(e.getMessage(), e); } } else { try { scriptsDao.update(scriptsDTO); } catch (final Exception e) { LOGGER.warn(e.getMessage(), e); } } tc.commit(); } } } } scanner.close(); } } } catch (final Exception e) { LOGGER.warn(e.getMessage(), e); erro = e.getLocalizedMessage(); } finally { tc.closeQuietly(); } return erro; } @Override public List<String[]> executarScriptConsulta(final ScriptsDTO script) throws Exception { List<String[]> retorno = null; final TransactionControler tc = new TransactionControlerImpl(Constantes.getValue("DATABASE_ALIAS")); tc.start(); final Connection connection = tc.getConnection(); try (Statement statement = connection.createStatement();) { statement.setMaxRows(1024); retorno = new ArrayList<String[]>(); String sql = script.getSqlQuery(); sql = sql.trim(); if (sql.endsWith(";")) { sql = sql.substring(0, sql.length() - 1); } try (ResultSet resultSet = statement.executeQuery(sql);) { final ResultSetMetaData rsmd = resultSet.getMetaData(); final int quantidadeColunas = rsmd.getColumnCount(); boolean primeiro = true; while (resultSet.next()) { if (primeiro) { primeiro = false; final String colunas[] = new String[quantidadeColunas]; for (int i = 1; i <= quantidadeColunas; i++) { colunas[i - 1] = rsmd.getColumnName(i); } retorno.add(colunas); } final String dados[] = new String[quantidadeColunas]; for (int i = 1; i <= quantidadeColunas; i++) { dados[i - 1] = resultSet.getString(i); } retorno.add(dados); } } tc.commit(); tc.close(); } catch (final Exception e) { this.rollbackTransaction(tc, e); throw e; } return retorno; } @SuppressWarnings("resource") @Override public String executarScriptUpdate(final ScriptsDTO script) throws Exception { final String retorno = null; final TransactionControler tc = new TransactionControlerImpl(Constantes.getValue("DATABASE_ALIAS")); tc.start(); final Connection connection = tc.getConnection(); try (Statement statement = connection.createStatement();) { final Scanner scanner = new Scanner(script.getSqlQuery()).useDelimiter(";(\r)?\n"); while (scanner.hasNext()) { String sql = scanner.next(); sql = sql.replaceAll("(\r\n|\n\r|\r|\n)", " "); sql = sql.trim(); if (sql.endsWith(";")) { sql = sql.substring(0, sql.length() - 1); } if (!sql.isEmpty()) { statement.executeUpdate(sql); } } scanner.close(); tc.commit(); tc.close(); } catch (final Exception e) { this.rollbackTransaction(tc, e); } return retorno; } private Map<String, String> getChaves() { if (chaves == null) { chaves = new HashMap<>(); } return chaves; } @Override public boolean haScriptDeVersaoComErro() throws Exception { return this.getDao().haScriptDeVersaoComErro(); } @Override public void marcaErrosScriptsComoCorrigidos() throws Exception { final ScriptsDao scriptsDao = new ScriptsDao(); final TransactionControler tc = new TransactionControlerImpl(Constantes.getValue("DATABASE_ALIAS")); scriptsDao.setTransactionControler(tc); try { tc.start(); scriptsDao.marcaErrosScriptsComoCorrigidos(); tc.commit(); tc.close(); } catch (final Exception e) { this.rollbackTransaction(tc, e); } } public String obterColunaCorrespondenteAChave(final String sql, final String chave) { String coluna = ""; // pega o conteudo dos parenteses final Pattern pattern = Pattern.compile("\\(([^\\)]+)\\)"); final Matcher matcher = pattern.matcher(sql); // se existem dois grupos de parenteses. (colunas e valores) if (matcher.find()) { String colunasString = matcher.group(); if (matcher.find()) { String valoresString = matcher.group(); // remove os parenteses colunasString = colunasString.replaceAll("\\(|\\)", ""); valoresString = valoresString.replaceAll("\\(|\\)", ""); final List<String> colunas = Arrays.asList(colunasString.split(",")); final List<String> valores = Arrays.asList(valoresString.split(",")); int indice = 0; for (final String valor : valores) { if (chave.trim().equalsIgnoreCase(valor.trim())) { break; } indice++; } coluna = colunas.get(indice); coluna = coluna.trim(); } } return coluna; } /** * Retorna o nome da tabela de acordo com o sql(insert) informado * * @author Murilo Gabriel Rodrigues */ private String obterNomeDaTabela(final String sql) { final List<String> palavras = Arrays.asList(sql.split(" |\n|\r")); boolean insert = false; boolean into = false; for (String palavra : palavras) { if (insert & into) { if (palavra.contains(".")) { palavra = palavra.substring(palavra.lastIndexOf(".") + 1); } return palavra.trim(); } if (palavra.trim().equalsIgnoreCase("insert")) { insert = true; } if (insert && palavra.trim().equalsIgnoreCase("into")) { into = true; } } return null; } /** * Faz a leitura da SQL substituindo as chaves pelos pr�ximos valores dispon�veis no banco de dados. Essas chaves * tem o padr�o $id_[texto] Ex.: $id_idusuario01, $id_idusuario20, * $id_texto_qualquer... * * @author Murilo Gabriel Rodrigues */ private String preencheChavesPrimarias(String sql) throws Exception { final Pattern pattern = Pattern.compile("(\\$id_\\w+)\\b"); final Matcher matcher = pattern.matcher(sql); while (matcher.find()) { final String chave = matcher.group(); if (chave != null && !chave.trim().isEmpty()) { String indice = this.getChaves().get(chave); // se a chave ainda n�o foi obtida if (indice == null || indice.trim().isEmpty()) { final String coluna = this.obterColunaCorrespondenteAChave(sql, chave); final String tabela = this.obterNomeDaTabela(sql); if (tabela != null && !tabela.isEmpty() && coluna != null && !coluna.isEmpty()) { final Integer nextKey = PersistenceEngine.getNextKey(this.getDao().getAliasDB(), tabela, coluna); if (nextKey != null && nextKey.intValue() != 0) { indice = nextKey.toString(); this.getChaves().put(chave, indice); } } } if (indice != null && !indice.trim().isEmpty()) { sql = sql.replaceAll("\\" + chave, indice); } } } return sql; } private void setChaves(final Map<String, String> chaves) { this.chaves = chaves; } @Override public boolean temScriptsAtivos(final ScriptsDTO script) throws Exception { return this.getDao().temScriptsAtivos(script); } @Override public String verificaPermissoesUsuarioBanco(final HttpServletRequest request) throws ServiceException { final String resultadoTesteCriacaoTabela = this.getDao().testaPermissaoCriacaoTabela(); final String resultadoTesteInsercaoRegistroTabela = this.getDao().testaPermissaoInsercaoRegistroTabela(); final String resultadoTesteConsultaTabela = this.getDao().testaPermissaoConsultaTabela(); final String resultadoTesteExclusaoRegistroTabela = this.getDao().testaPermissaoExclusaoRegistroTabela(); final String resultadoTesteCriacaoColuna = this.getDao().testaPermissaoCriacaoColuna(); final String resultadoTesteAlteracaoColuna = this.getDao().testaPermissaoAlteracaoColuna(); final String resultadoTesteExclusaoColuna = this.getDao().testaPermissaoExclusaoColuna(); final String resultadoTesteExclusaoTabela = this.getDao().testaPermissaoExclusaoTabela(); final List<String> acoesSemPermissao = new ArrayList<String>(); if (this.resultadoNegativoPermissoes(resultadoTesteCriacaoTabela)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.criacaoTabelas")); } if (this.resultadoNegativoPermissoes(resultadoTesteInsercaoRegistroTabela)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.incersaoRegistrosTabelas")); } if (this.resultadoNegativoPermissoes(resultadoTesteConsultaTabela)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.consultaTabelas")); } if (this.resultadoNegativoPermissoes(resultadoTesteExclusaoRegistroTabela)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.exclusaoRegistrosTabelas")); } if (this.resultadoNegativoPermissoes(resultadoTesteCriacaoColuna)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.criacaoColunasTabelas")); } if (this.resultadoNegativoPermissoes(resultadoTesteAlteracaoColuna)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.alteracaoColunasTabelas")); } if (this.resultadoNegativoPermissoes(resultadoTesteExclusaoColuna)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.exclusaoColunasTabelas")); } if (this.resultadoNegativoPermissoes(resultadoTesteExclusaoTabela)) { acoesSemPermissao.add(UtilI18N.internacionaliza(request, "citcorpore.comum.ExclusaoTabelas")); } final StringBuilder retorno = new StringBuilder(); if (acoesSemPermissao.isEmpty()) { return "sucesso"; } else { retorno.append(UtilI18N.internacionaliza(request, "citcorpore.comum.encontradaFaltaPermissao") + "<br>"); for (final String acao : acoesSemPermissao) { retorno.append("   <b>").append(acao).append("</b>,<br>"); } return retorno.substring(0, retorno.lastIndexOf(",")) + "."; } } private boolean resultadoNegativoPermissoes(final String resultadoTestePermissoes) { return resultadoTestePermissoes != null && !resultadoTestePermissoes.trim().equalsIgnoreCase("sucesso") && (resultadoTestePermissoes.toLowerCase().contains("command denied") || resultadoTestePermissoes.toLowerCase().contains("permission denied") || resultadoTestePermissoes.toLowerCase().contains("permiss�o negada") || resultadoTestePermissoes.toLowerCase().contains("must be owner") || resultadoTestePermissoes.toLowerCase().contains("deve ser o dono") || resultadoTestePermissoes.toLowerCase().contains("insufficient privileges") || resultadoTestePermissoes .toLowerCase().contains("no privileges")); } @Override public List<ScriptsDTO> pesquisaScriptsComFaltaPermissao() throws Exception { final List<ScriptsDTO> scriptsNaoExecutadosManualmente = new ArrayList<>(); final List<ScriptsDTO> scriptsComFaltaPermissao = this.getDao().pesquisaScriptsComFaltaPermissao(); if (scriptsComFaltaPermissao != null && !scriptsComFaltaPermissao.isEmpty()) { for (final ScriptsDTO script : scriptsComFaltaPermissao) { if (!this.scriptFoiExecutado(script)) { scriptsNaoExecutadosManualmente.add(script); } } } return scriptsNaoExecutadosManualmente; } private boolean scriptFoiExecutado(final ScriptsDTO scriptsDTO) throws Exception { boolean scriptFoiExecutado = false; final String sqlLowerCase = scriptsDTO.getSqlQuery().toLowerCase(); Matcher matcher = null; switch (this.obtemTipoSQL(scriptsDTO)) { case ScriptsDTO.TIPO_CRIAR_TABELA: matcher = Pattern.compile("create table").matcher(sqlLowerCase); if (matcher.find()) { final String nomeTabela = sqlLowerCase.substring(matcher.end()).trim().split(" ", 2)[0]; scriptFoiExecutado = this.getDao().verificaExistenciaTabela(nomeTabela); } break; case ScriptsDTO.TIPO_INSERIR_REGISTRO: // verificacao para esse caso atualmente n�o � vi�vel scriptFoiExecutado = true; break; case ScriptsDTO.TIPO_DELETAR_REGISTRO: // verificacao para esse caso atualmente n�o � vi�vel scriptFoiExecutado = true; break; case ScriptsDTO.TIPO_ADICIONAR_COLUNA: String nomeTabela = null; String nomeColuna = null; matcher = Pattern.compile("alter table").matcher(sqlLowerCase); if (matcher.find()) { nomeTabela = sqlLowerCase.substring(matcher.end()).trim().split(" ", 2)[0]; } matcher = Pattern.compile("add column").matcher(sqlLowerCase); if (matcher.find()) { nomeColuna = sqlLowerCase.substring(matcher.end()).trim().split(" ", 2)[0]; } if (nomeTabela != null && nomeColuna != null) { scriptFoiExecutado = this.getDao().verificaExistenciaColuna(nomeTabela, nomeColuna); } break; case ScriptsDTO.TIPO_ADICIONAR_CONSTRAINT: // verificacao para esse caso atualmente n�o � vi�vel scriptFoiExecutado = true; break; case ScriptsDTO.TIPO_ALTERAR_COLUNA: // verificacao para esse caso atualmente n�o � vi�vel scriptFoiExecutado = true; break; case ScriptsDTO.TIPO_DELETAR_COLUNA: // verificacao para esse caso atualmente n�o � vi�vel scriptFoiExecutado = true; break; case ScriptsDTO.TIPO_DELETAR_TABELA: // verificacao para esse caso atualmente n�o � vi�vel scriptFoiExecutado = true; break; } return scriptFoiExecutado; } private int obtemTipoSQL(final ScriptsDTO scriptsDTO) { int tipo = 0; if (scriptsDTO != null && scriptsDTO.getSqlQuery() != null) { if (scriptsDTO.getSqlQuery().trim().toUpperCase().startsWith("CREATE TABLE")) { tipo = ScriptsDTO.TIPO_CRIAR_TABELA; } else if (scriptsDTO.getSqlQuery().trim().toUpperCase().startsWith("INSERT INTO")) { tipo = ScriptsDTO.TIPO_INSERIR_REGISTRO; } else if (scriptsDTO.getSqlQuery().trim().toUpperCase().startsWith("DELETE FROM")) { tipo = ScriptsDTO.TIPO_DELETAR_REGISTRO; } else if (scriptsDTO.getSqlQuery().trim().toUpperCase().startsWith("ALTER TABLE")) { if (scriptsDTO.getSqlQuery().trim().toUpperCase().contains(" ADD CONSTRAINT ")) { tipo = ScriptsDTO.TIPO_ADICIONAR_CONSTRAINT; } else if (scriptsDTO.getSqlQuery().trim().toUpperCase().contains(" ADD ")) { tipo = ScriptsDTO.TIPO_ADICIONAR_COLUNA; } } else if (scriptsDTO.getSqlQuery().trim().toUpperCase().startsWith("ALTER TABLE") && (scriptsDTO.getSqlQuery().trim().toUpperCase().contains("CHANGE COLUMN") || scriptsDTO.getSqlQuery().trim().toUpperCase().contains("RENAME COLUMN"))) { tipo = ScriptsDTO.TIPO_ALTERAR_COLUNA; } else if (scriptsDTO.getSqlQuery().trim().toUpperCase().startsWith("ALTER TABLE") && scriptsDTO.getSqlQuery().trim().toUpperCase().contains("DROP COLUMN")) { tipo = ScriptsDTO.TIPO_DELETAR_COLUNA; } else if (scriptsDTO.getSqlQuery().trim().toUpperCase().startsWith("DROP TABLE")) { tipo = ScriptsDTO.TIPO_DELETAR_TABELA; } } return tipo; } }