CXF SOAP Client Example to Use Plain Text Password Authentication

CXF SOAP client can be configured to support various web authentication strategies via its out WSS4JOutInterceptor. For example it can be configured to support plain text username/password or digest based authentication. This post will show the plain text case. 

First of all, you need to add cxf-rt-ws-security and cxf-rt-frontend-jaxws to your dependencies.

With that you can use the following code to to access a  secured endpoint (which is MyService in this example).


//Example code

createSecureService(MyService.class, "https://example.com/soap/example",1000, 2000, "user", "password");

private <S> S createSecureService(Class<S> serviceClass, String url, long connectionTimeout,
  long receiveTimeout, String username, String password) {
  JaxWsProxyFactoryBean jaxWsFactory = new JaxWsProxyFactoryBean();
  jaxWsFactory.setServiceClass(serviceClass);
  jaxWsFactory.setAddress(url);
  @SuppressWarnings("unchecked")
  S service = (S) jaxWsFactory.create();
  Client client = ClientProxy.getClient(service);
  Endpoint cxfEndpoint = client.getEndpoint();
  Map<String, Object> outProps = new HashMap<String, Object>();
  outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
  outProps.put(WSHandlerConstants.USER, username);
  outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
  outProps.put(WSHandlerConstants.PW_CALLBACK_REF, new CallbackHandler() {
    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
      Arrays.stream(callbacks).filter(WSPasswordCallback.class::isInstance)
      .map(WSPasswordCallback.class::cast)
      .forEach(callback -> callback.setPassword(password));
    }
  });
  WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
  cxfEndpoint.getOutInterceptors().add(wssOut);
  configureClient(connectionTimeout, receiveTimeout, client);
  return service;
}

private void configureClient(long connectionTimeout, long receiveTimeout, Client client) {
  HTTPConduit http = (HTTPConduit) client.getConduit();
  HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
  httpClientPolicy.setConnectionTimeout(connectionTimeout);
  httpClientPolicy.setReceiveTimeout(receiveTimeout);
  http.setClient(httpClientPolicy);
}

Advertisements
Posted in Java | Tagged , , , , | Leave a comment

CXF REST Client Parses Badgefish JSON Data

Badgerfish is one of the JSON conventions supported by CXF. To use it with CXF RS Client, you need to add both cxf-rt-rs-extension-providers and cxf-rt-rs-client to your dependencies. Then you can create a JSON provider and pass it to the web client to make request. The following example calls the D&B Direct API sandbox to retrieve some sample data.

Bean declaration:


@XmlRootElement
public class SampleData{
...
}

Code to map JSON to the bean:


JSONProvider<SampleData> provider = new JSONProvider<>();
provider.setConvention("badgerfish");
//Configure the provider as needed
provider.setSerializeAsArray(true);
provider.setDropRootElement(true);
provider.setUnmarshallAsJaxbElement(true);
provider.setConvertTypesToStrings(true);

WebClient client =
WebClient.create("https://direct.dnb.com", Collections.singletonList(badgerFishJson));
client = client.accept("application/json").path("/V5.0/organizations")
.query("CountryISOAlpha2Code", "US").query("SubjectName", "GORMAN2 MANUFACTURING")
.query("match", true).query("MatchTypeText", "Basic").query("TerritoryName", "CA");
client = client.header("Authorization", "xxxxxx");
SampleData result = client.get(SampleData.class);

Posted in Java | Tagged , , , | Leave a comment

JConsole Connection Failed

It is very annoying when you see JConsole failed to attach to a runtime with simply tells you “The connection to pid did not succeed. Would you like to try again?”. This is a completely useless message.

How to troubleshooting JConsole connection failure? You can start it with option

jconsole -J-Djava.util.logging.config.file="e:\\logging.properties"

And the logging.properties file should look like

//Log level is the level of java.util.logging.Level
//It can be SEVERE, WARNING, INFO, CONFIG, FINE, FINER or FINEST
handlers = java.util.logging.ConsoleHandler
.level = INFO
java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.formatter = \
java.util.logging.SimpleFormatter
javax.management.level = FINEST
javax.management.remote.level = FINER

With this, you will see a separated log dialog popped out when you start Jconsole and it will print out more information about the failure.

Posted in Tool and Debug | Tagged , , | Leave a comment

ActiveMQ Message Expiration

When a message is produced, you can specify its timeToLive in milliseconds. This duration is added to the message every time when the message failed to be consumed. If there is no attempt to consume the message (i.e. consumer detached) within the next TTL duration, the message is considered expired.

There are different strategies to handle expired messages by the broker. The broker can be configured to automatically discard the expired message

<deadLetterStrategy>
    <sharedDeadLetterStrategy processExpired="false" />
</deadLetterStrategy>

or keep it into the DLQ for another configured period of time(the example below uses 5 minutes)

<deadLetterStrategy>
    <sharedDeadLetterStrategy processExpired="true" expiration="300000" />
</deadLetterStrategy>

The sharedDeadLetterStrategy above can be replaced by individualDeadLetterStrategy.

Posted in Java | Tagged , , , , , | Leave a comment

Isn’t our code beautiful?

Are we programmers artists? Everyone has to agree once they see our artworks. Our two secret paint brushes are GIT and Gource.

To see your art own artwork, follow the two steps:

  • install Gource
  • run command “gource” from your local git repo directory or check advanced options (gource –help)

The following screenshot was copied from Google image search result.

capture

Posted in Tool and Debug | Tagged , | Leave a comment

Use SpringBoot to Deploy ActiveMQ Broker to Tomcat 3/3

ActiveMQ supports LeaseDatabaseLocker in its recent releases to increase its reliability when handling database failover. With the previous default database locker, the master broker holds the lock until it initiates a request to release the lock. This is problematic when database fails or the network is disconnected abruptly. In such cases, the master can not properly release the lock anymore therefore neither the master nor the slave, until the brokers are restarted, can own the lock after the database comes back. This is often not desirable in production environment.

LeaseDatabaseLocker is implemented to overcome this weakness. With this, the master essentially creates a row in the activemq_lock table and uses it as a lock. The lock is only effective for a period of time. If it is not renewed/refreshed before expiry, any broker can take over the lock ownership when the database becomes accessible.

The code to configure the LeaseDatabaseLocker looks like

  @Bean
  public PersistenceAdapter persistenceAdapter(DataSource dataSource,
      @Value(&amp;quot;${activemq.broker.name}&amp;quot;) String brokerName) throws Exception {
    JDBCPersistenceAdapter jdbcPersistenceAdapter =
        new JDBCPersistenceAdapter(dataSource, new OpenWireFormat());
    broker.setPersistenceAdapter(jdbcPersistenceAdapter);
    LeaseDatabaseLocker locker = new LeaseDatabaseLocker();
    locker.setDataSource(dataSource);
    locker.setLeaseHolderId(brokerName);
    // TODO: externalize the value into application.properties
    //This value must be greater than the LockKeepAlivePeriod
    locker.setLockAcquireSleepInterval(5000);
    jdbcPersistenceAdapter.setLocker(locker);
    // TODO: externalize the value into application.properties
    jdbcPersistenceAdapter.setLockKeepAlivePeriod(1000);
    broker.start();
    return jdbcPersistenceAdapter;
  }

Notice how the lock holding period and the refresh period are configured by the setLockAcquireSleepInterval() and setLockKeepAlivePeriod() respectively.

Please be aware that you’d better to use DBCP2 connection pool to manage the data source connections for this application. If Tomcat pool manager is used, you may experience database blocking problem. The full configuration can be found from the source code.

You can find the two earlier posts related to this one: part1 and part2.

Posted in Uncategorized | Tagged , , , , , | 2 Comments

Hibernate Fetch Lazy Child Entities with HQL and Native SQL

In one-to-many or many-to-many relationship, we often configure Hibernate to lazily fetch the children collection for performance reasons by reducing the database join operation and the amount of the data been pulled and transmitted from database to application. The application, if needs the child entities, can query the database again. This is the typical n+1 operation in Hibernation. When the data size is small, you won’t notice too much performance problem. However, this can impose some undesired issue with the O(n2) operations as data grows.

Fortunately Hibernate provides a few ways to fetch those lazy entities in much efficient way, with Criteria, HQL or native SQL. You can refer the official document for comprehensive guide.

This post will simply provides two examples, using HQL and native SQL. The entity in the following sections means Java beans mapped by Hibernate with @Entity or xml configuration. The non-entity means plain Java Bean without Hibernate awareness.

Example 1: Using HQL to fetch parents and their children into entities
This example fetches data into a Hibernate aware entity bean Order, which has a set of OrderItems.

  public List<Order> getOrdersByItemName(String accountNumber,String itemName) {      
    Query query = currentSession.createQuery(
        "from Order o " 
        + "join fetch o.orderItems i "
        + "where o.accountNumber = :accountNumber and i.name = :itemName" 
        + "order by o.id asc"
    ).setParameter("accountNumber", accountNumber)
     .setParameter("itemName", itemName)
     .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
    return query.list();
  }

Example 2: Using native HQL to fetch parents and their children into non-entities
This examples converts the query results into a non-entity bean FlattenedOrder. It demonstrates how complicated the native query can go (using SqlServer). It also shows how to map two column values to two user defined Enums OrderSource and ItemSize.

  public List<FlattenedOrder> getFlattenedOrderByItemName(String accountNumber, String itemName) {
    String queryString =
        "select distinct o.orderIdStr as orderId, o.orderSource, o.orderDate,o.expiryDate "
            + "CASE WHEN o.expiryDate <= GETDATE() THEN 0 ELSE DATEDIFF(day, o.orderDate, o.expiryDate) END as daysExpiryIn, "
            + "i.name as itemName, i.size as itemSize, "
            + "(select sum(innerI.quantity) from dbo.OrderItem innerI join dbo.Order innerO on innerI.orderId=innerO.id where innerI.id=i.id) as total, "
            + "from dbo.Order as o "
            + "join OrderItem as i on o.id=j.orderId "
            + "where o.accountNumber=:accountNumber and i.name = : itemName";
	Properties orderSourceParams = new Properties();
    orderSourceParams.put("enumClass", "ca.zl.OrderSource");
    orderSourceParams.put("type", "12"); /*EnumType.STRING type = 12 */
    Type orderSourceEnumType = new TypeLocatorImpl(new TypeResolver()).custom(EnumType.class, orderSourceParams);
    
    Properties orderItemSizeProps = new Properties();
    orderItemSizeProps.put("enumClass", "ca.zl.ItemSize");
    orderItemSizeProps.put("type", "12"); /*EnumType.STRING type = 12 */
    Type  itemSizeEnumType= new TypeLocatorImpl(new TypeResolver()).custom(EnumType.class, orderItemSizeProps);
    
    SQLQuery query = currentSession.createSQLQuery(queryString);
        query.setParameter("accountNumber", accountNumber);
		query.setParameter("itemName", itemName);
        query.addScalar("orderId", new StringType())
        .addScalar("orderSource", orderSourceEnumType)
        .addScalar("orderDate", new DateType())
        .addScalar("expiryDate", new DateType())
        .addScalar("daysExpiryIn", new IntegerType())
        .addScalar("itemName", new StringType())
		.addScalar("itemSize", itemSizeEnumType)
        .addScalar("total", new IntegerType())
        .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
        .setResultTransformer(Transformers.aliasToBean(FlattenedOrder.class));
    return query.list();
Posted in Database, Java | Tagged , , , , , , , , | Leave a comment