Category: java

How to Indent XML String in Java (Pretty)

Hello Guys,

This is a cool way to prettify your XML (String format) in Java Language:

public static String format(String xml, Boolean ommitXmlDeclaration) throws IOException, SAXException, ParserConfigurationException {

DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xml)));

OutputFormat format = new OutputFormat(doc);
format.setIndenting(true);
format.setIndent(2);
format.setOmitXMLDeclaration(ommitXmlDeclaration);
format.setLineWidth(Integer.MAX_VALUE);
Writer outxml = new StringWriter();
XMLSerializer serializer = new XMLSerializer(outxml, format);
serializer.serialize(doc);

return outxml.toString();

}

Spring Batch Partitioner – Case Study with SourceCode – Best Practices

I’m writing this post because i report a bug at Spring Community Jira, this is the link:

https://jira.spring.io/browse/BATCH-2309

I started a sample project which could reproduce the problem to show the community what I was experiencing, but to my surprise I was using the partitioner feature incorrectly. I am writing this post to share what I learned throughout this experience to help those who are going through the same questions.

My Goal: I wanted to use the resource partitioner for parallel processing but was worried to use the primary key of the table (column ID) because my table has gaps (id column is not incremental) and for this reason the partitioner would distribute number of different records for each thread, thus being inefficient in their distribution.

For example:

This is the good example partitioner:

https://github.com/spring-projects/spring-batch/blob/master/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/ColumnRangePartitioner.java

Suppose that my table has the following records: Ids 1, 8, 9,10 11, 12, 13, 14, 15.

min: 1

max: 15

gridSize = number of threads = 2 in this example

target size calculation: int targetSize = (max min) / gridSize + 1;

(15 – 1) / 2 + 1 = 8

In this example:

Thread number 1 will receive to process: 1 to 8

Thread number 2 will receive to process: 9 to 16

The Problem: Thread 1 receives only two records to process (The Id’s 1 and 8) and the thread 2 will receive 7 records to process. At this case the partitioner to split incorrectly number of records between threads.

My Goal: I want to split the number of records equally between all threads.

Where I was going wrong: To achieve my goal I tried to use a query that makes use of rownum and / or ntile oracle feature, the goal was to use the split an id that is sequential, with no gaps in the id column table, so the load would be uniform among the threads. The JdbcPagingItemReader class can not be used with multithreaded characteristics using Oracle ROWNUM because the query is partially executed multiple times in the database and there is no guarantee that all records are processed because a confusion of Ids between threads occurs.

 The correct way: You can use JdbcPagingItemReader using the Primary Key column (may be single or multiple columns) or JdbcCursorItemReader can use both the PK column or  Rownum / NTILE to do division.

Why use JdbcCursorItemReader not cause problems of mistaken IDs or lost records ?

This class executes the query once the database and will use chunk mode to fetch the records as needed. If you use a rownum column in this case will not cause data loss because every query is processed only once in the database.

To illustrate and facilitate understanding, I created a design example set with various possible configurations available here:

springbatchpoc

GitHub Example Project:

https://github.com/victorjabur/PartitionSpringBatch_DataLose_Poc_BATCH-2309

Here are the sql scripts to create the database tables used in this poc:

https://github.com/victorjabur/PartitionSpringBatch_DataLose_Poc_BATCH-2309/tree/master/src/main/resources/sql

  1. JdbcCursorItemReader-OracleNtile – It works
  2. JdbcCursorItemReader-OracleRownum – It works
  3. JdbcPagingItemReader-OracleNtile – It not works, don’t use this. PagingReader does not work with NTile
  4. JdbcPagingItemReader-OracleRownum – It not works, don’t use this. PagingReader does not work with Rownum
  5. JdbcPagingItemReader-TablePrimaryKey – It works, but the records aren’t distributed in an uniform way (same quantity for each thread)

What is Oracle NTile ?
This feature of Oracle Database can create a desired number of containers so that each thread can consume one. For example: I have 1000 records in the database to be divided among 10 threads:

SELECT ID, DESCRIPTION, FLAG_PROCESSED, NTILE(10) OVER (ORDER BY ID)
AS CONTAINER_COLUMN FROM TABLE_SOURCE
WHERE FLAG_PROCESSED = 'N';

With this query, you can use the column “CONTAINER_COLUMN”, values are already pre split into buckets ready to be divided among the various threads.

This is the documentation with more clarified explanation:

https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions101.htm

That’s it.

Any question or suggestion is very welcome.

Credits to this post:

http://alexandreesl.wordpress.com/2014/09/21/spring-batch-construindo-processamento-massivo-de-dados-em-java/
http://www.mkyong.com/spring-batch/spring-batch-partitioning-example/
https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples

Cheers,
Victor Jabur

How to consume a WebService that uses Ws-Security Authentication (UsernameToken) – OWSM – Oracle Service Bus (OSB)

Hi,

The Oracle Service Bus (OSB) allows to enable OWSM authentication, there is many policies that can be applied to the Proxy Service to turn on security authentication. The most basic of this policies is:

oracle / wss_username_token_service_policy

Requiring only a username and password. Once enabled this security, following a tip on how to make a request using a Java Client.

File: MainPost.java – This is a main class to make a request

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;

import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;

public class MainPost {

	public static void main(String[] args) {

		try {

			MyService service = new MyService();
			MyServicePort myServicePort = service.getMySoapPort();

			// This is the block that apply the Ws Security to the request
			BindingProvider bindingProvider = (BindingProvider) myServicePort;
			@SuppressWarnings("rawtypes")
			List<Handler> handlerChain = new ArrayList<Handler>();
			handlerChain.add(new WSSecurityHeaderSOAPHandler("myUsername", "myPassword"));
			bindingProvider.getBinding().setHandlerChain(handlerChain);

			RequestType myRequest = new RequestType();
			myRequest.setId(25);

			ResponseType response = myServicePort.searchSomething(myRequest);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

File: WSSecurityHeaderSOAPHandler.java – This is a handler responsible for creating the header authentication.

import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class WSSecurityHeaderSOAPHandler implements SOAPHandler<SOAPMessageContext> {

 private static final String SOAP_ELEMENT_PASSWORD = "Password";
 private static final String SOAP_ELEMENT_USERNAME = "Username";
 private static final String SOAP_ELEMENT_USERNAME_TOKEN = "UsernameToken";
 private static final String SOAP_ELEMENT_SECURITY = "Security";
 private static final String NAMESPACE_SECURITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
 private static final String PREFIX_SECURITY = "wsse";

 private String usernameText;
 private String passwordText;

 public WSSecurityHeaderSOAPHandler(String usernameText, String passwordText) {
 this.usernameText = usernameText;
 this.passwordText = passwordText;
 }

 public boolean handleMessage(SOAPMessageContext soapMessageContext) {

 Boolean outboundProperty = (Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

 if (outboundProperty.booleanValue()) {

 try {
 SOAPEnvelope soapEnvelope = soapMessageContext.getMessage().getSOAPPart().getEnvelope();

 SOAPHeader header = soapEnvelope.getHeader();
 if (header == null) {
 header = soapEnvelope.addHeader();
 }

 SOAPElement soapElementSecurityHeader = header.addChildElement(SOAP_ELEMENT_SECURITY, PREFIX_SECURITY,
 NAMESPACE_SECURITY);

 SOAPElement soapElementUsernameToken = soapElementSecurityHeader.addChildElement(SOAP_ELEMENT_USERNAME_TOKEN, PREFIX_SECURITY);
 SOAPElement soapElementUsername = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_USERNAME, PREFIX_SECURITY);
 soapElementUsername.addTextNode(this.usernameText);

 SOAPElement soapElementPassword = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_PASSWORD, PREFIX_SECURITY);
 soapElementPassword.addTextNode(this.passwordText);

 } catch (Exception e) {
 throw new RuntimeException("Error on wsSecurityHandler: " + e.getMessage());
 }

 }

 return true;
 }

 @Override
 public void close(MessageContext context) {
 // TODO Auto-generated method stub
 }

 @Override
 public boolean handleFault(SOAPMessageContext context) {
 // TODO Auto-generated method stub
 return true;
 }

 @Override
 public Set<QName> getHeaders() {
 // TODO Auto-generated method stub
 return null;
 }
}

Xml Request: This is the payload request that Java Client request to the server.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
 <soapenv:Header>
 <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
 <wsse:UsernameToken>
 <wsse:Username>myUsername</wsse:Username>
 <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">myPassword</wsse:Password>
 </wsse:UsernameToken>
 </wsse:Security>
 </soapenv:Header>
 <soapenv:Body>
 <searchSomething>
 <Id>25</Id>
 </searchSomething>
 </soapenv:Body>
</soapenv:Envelope>

TDC Florianópolis – 2014

Boa Noite Galera:

Desejo a todos um excelente evento e boas palestras.

Obrigado ao Vinicius Senger e a Yara por promover eventos de tão elevada qualidade para os devs brasileros.

Parabéns !!!

Evento TDC2014

Abraços,
Victor Jabur

Utilitário para geração de TrustStore (JKS) – Java

Olá Pessoal,

Desenvolvi um utilitário que transforma um arquivo zip, contendo “n” certificados de Autoridades Certificadoras para um arquivo JKS.

Para referência segue um link que contém todas as CA’s brasileiras:

http://acraiz.icpbrasil.gov.br/credenciadas/CertificadosAC-ICP-Brasil/ACcompactado.zip

Como seria o processo normal ?

1 – Java Keytool – http://download.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html
É um software que acompanha a máquina virtual Java (jdk), utilizado para diversas finalidades com relação à segurança de aplicações e pode ser usado para gerar o pacote JKS.
Seguem dois comandos exemplo para se trabalhar com arquivos JKS de truststore:

1. Listando todos os certificados contidos em um arquivo JKS:

keytool –list –v –keystore C:\meukeystore.jks

2. Importando um certificado de uma AC para dentro de um JKS pré-existente

keytool –import –trustcacerts –file C:\certificadoAC.cer –alias apelidoentrada –keystore C:\meutruststore.jks

Observação: Caso não exista um jks no diretório especificado em -keystore, será criado um automaticamente.
O arquivo ACcompactado.zip especificado na URL anteriormente, possui atualmente 84 certificados, portanto, deve-se executar o comando (2), 84 vezes, alterando o -alias e o –file. Por ser esta uma forma muito trabalhosa de se gerar um arquivo Trusted JKS, foi criado um utilitário que auxiliará nesta etapa, apresentado no próximo capítulo.

2 – Usando o utilitário – utilitarioTrustJKS.jar
O utilitário desenvolvido basicamente recebe como entrada um arquivo zip com todos os certificados desejados e gera um arquivo trust.jks.
Parâmetros de Entrada:
1 – caminhoZip – Diretório do arquivo zip que contém todos os certificados das AC’s
2 – caminhoSaida – Diretório de saída, onde será gerado o truststore.jks
3 – senhaKestore – Senha do arquivo TrustStore JKS
4 – incluirExpirados (opcional) – valor default => false) – Possui os valores true ou false. Informa se certificados expirados ou não válidos ainda deverão ser incluídos no arquivo JKS gerado.

Exemplo de utilização:

java -jar utilitarioTrustJKS.jar C:\ACcompactado.zip C:\truststore.jks 123456789 true

Link para Download do arquivo Jar:
http://arquivos.victorjabur.com/java/seguranca/utilitarioTrustJKS.jar

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;

public class Main {

	private String caminhoZIP = "C:\\ACcompactado.zip";
	private String caminhoSaida = "C:\\truststore.jks";
	private String senhaKeystore = "123456789";
	private Boolean incluirExpirados = false;

	public static void main(String[] args) throws Exception {
		Main main = new Main();
		main.validarParametrosEntrada(args);
		List<X509Certificate> listaCertificadosValidos = main.getListaCertificadosValidos();
		main.gerarJKS(listaCertificadosValidos);
		System.out.println("Arquivo JKS gerado com sucesso - " + listaCertificadosValidos.size() + " certificados incluidos");
	}

	public void validarParametrosEntrada(String[] args){
		if(args.length < 3){
			throw new RuntimeException("O numero minimo de parametros = 3. caminhoZip caminhoSaida senhaKeystore e incluirExpirados (Opcional) ");
		}else{
			String caminhoZip = args[0];
			validacaoLeituraArquivo(new File(caminhoZip));
			this.caminhoZIP = caminhoZip;
			String caminhoSaida = args[1];
			this.caminhoSaida = caminhoSaida;
			String senhaKeystore = args[2];
			this.senhaKeystore = senhaKeystore;
			if(args.length >= 4){
				String incluirExpirados = args[3];
				if(incluirExpirados.equals("true") || incluirExpirados.equals("false")){
					this.incluirExpirados = Boolean.valueOf(incluirExpirados);
				}else{
					throw new RuntimeException("O parametro incluirExpirados (4) deve ser true ou false");
				}
			}
		}
	}
	
	public List<X509Certificate> getListaCertificadosValidos() {
		File arquivoZipEntrada = new File(this.caminhoZIP);
		validacaoLeituraArquivo(arquivoZipEntrada);
		List<X509Certificate> x509CertificateList = new LinkedList<X509Certificate>();
		try {
			InputStream in = new FileInputStream(arquivoZipEntrada);
			ZipInputStream zipInputStream = new ZipInputStream(in);

			ZipEntry zipentry = zipInputStream.getNextEntry();
			while (zipentry != null) {
				byte[] buffer = new byte[(int) zipentry.getSize()];
				int offset = 0;
				int numRead = 0;
				while (offset < buffer.length && (numRead = zipInputStream.read(buffer, offset, buffer.length - offset)) >= 0) {
					offset += numRead;
				}
				InputStream bis = new ByteInputStream(buffer, 0, buffer.length);
				CertificateFactory cf = CertificateFactory.getInstance("X.509");
				X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);
				try {
					cert.checkValidity();
					x509CertificateList.add(cert);
				} catch (CertificateExpiredException e) {
					if(this.incluirExpirados){
						x509CertificateList.add(cert);
						System.out.println("Certificado Expirado - " + zipentry.getName());
					}else{
						System.out.println("Certificado Expirado - " + zipentry.getName() + " - nao sera adicionado no JKS");
					}
				} catch (CertificateNotYetValidException e) {
					if(this.incluirExpirados){
						x509CertificateList.add(cert);
						System.out.println("Certificado não válido ainda - " + zipentry.getName());
					}else{
						System.out.println("Certificado não válido ainda - " + zipentry.getName() + " - nao sera adicionado no JKS");
					}
				}
				zipInputStream.closeEntry();
				zipentry = zipInputStream.getNextEntry();
			}
			zipInputStream.close();
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return x509CertificateList;
	}

	public OutputStream gerarJKS(List<X509Certificate> listaCertificados){
		OutputStream out = null;
		try {
			KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
			keystore.load(null, null);
			int indice = 0;
			for (X509Certificate cert : listaCertificados) {
				keystore.setCertificateEntry("ac_" + indice, cert);
				indice++;
			}
			File jks = new File(this.caminhoSaida);
			String diretorioDestino = jks.getParent();
			new File(diretorioDestino).mkdirs();
			out = new FileOutputStream(this.caminhoSaida);
			keystore.store(out, this.senhaKeystore.toCharArray());
			out.close();
			out.flush();
		} catch (Exception e) {
			throw new RuntimeException("Erro ao gerar o arquivo de Keystore - " + e.getCause() + " - " + e.getMessage());
		}
		return out;
	}
	
	public void validacaoLeituraArquivo(File arquivo) {
		if (!arquivo.exists()) {
			throw new RuntimeException("Arquivo Inexistente - " + arquivo.getAbsolutePath());
		}
		if (!arquivo.canRead()) {
			throw new RuntimeException("Sem permissão de Leitura do Arquivo - " + arquivo.getAbsolutePath());
		}
	}
}

Abraços,
Victor Jabur

How to access server MBean properties at weblogic 11g using Java – JMX

Hi,

If you want to get any property of Admin or Managed Server (Weblogic) using Java, then this post will help you.

The Oracle Enterprise Manager have a useful tool for explore MBean (System MBean Browser).

As you can see in the picture bellow:

Do you can to capture any server property desired with these java code:

1 – Reading a property if the application is deployed at server (local connection)

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.InitialContext;

String serverName = System.getProperty("weblogic.Name");
InitialContext ctx = new InitialContext();
MBeanServer server = (MBeanServer)ctx.lookup("java:comp/env/jmx/runtime");
ObjectName objName = new ObjectName("com.bea:Name=" + serverName + ",Type=Server");
String pathJKS = (String) server.getAttribute(objName, "CustomTrustKeyStoreFileName");

2 – Reading a property if the application is remote (remote connection)

import java.util.Hashtable;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;

  public static void main(String [] args) throws Exception{
    String serverName = "AdminServer";
    String hostName = "192.168.1.192";
    String username = "weblogic";
    String password = "welcome1";
    int port = 10000;
    String protocol = "t3";
    String jndiroot = "/jndi/";
    String mserver = "weblogic.management.mbeanservers.domainruntime";
    JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostName, port, jndiroot + mserver);
    Hashtable h = new Hashtable();
    h.put(Context.SECURITY_PRINCIPAL, username);
    h.put(Context.SECURITY_CREDENTIALS, password);
    h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");
    JMXConnector connector = JMXConnectorFactory.connect(serviceURL, h);
    ObjectName objName = new ObjectName("com.bea:Name=" + serverName + ",Type=Server");
    String pathJKS = (String) connector.getMBeanServerConnection().getAttribute(objName, "CustomTrustKeyStoreFileName");
    System.out.println(pathJKS);
  }

In the cases above, i’m reading a property that is called “CustomTrustKeyStoreFileName”, that’s a string path of the Trusted Keystore. But many and many properties could be read, for example:

  • CustomIdentityKeyStoreFileName
  • ListenPort
  • UploadDirectoryName

That’s it.

Victor Jabur

How to capture programmatically (Java – Adf Faces) an attribute from payload task (Human Task Form)

Hi Guys,

This is an useful code that capture the value of an attribute inside of payload from Human Task generated automatically from bpel.

Here is a list of attributes that exists in your human task form.

With this code, you can capture the value of any attribute.

You can to call this method this way: getValueAttributeFromHumanTask(“numeroPedido”)


import oracle.adf.model.BindingContext;
import oracle.adf.view.rich.context.AdfFacesContext;
import oracle.binding.AttributeBinding;
import oracle.binding.BindingContainer;
import oracle.bpel.services.datacontrol.data.DataObject;

public String getValueAttributeFromHumanTask(String attributeName){
    String response = "";
    BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
    AttributeBinding attr = (AttributeBinding)bindings.getControlBinding(attributeName);
    DataObject data = null;
    if(attr != null){
        data = (DataObject)attr.getInputValue();
    }
    if(data != null){
        response = data.getValue();
    }
    return response;
}