Wednesday, December 19, 2018

Jersy REST Service

Create Maven web project.




Add pom.xml dependencies.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>hacka2018</groupId>
  <artifactId>hacka-mnl</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>hacka-mnl Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
    <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.27</version>
</dependency>
    <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-server</artifactId>
    <version>2.27</version>
</dependency>
    <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-common</artifactId>
    <version>2.27</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.27</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.27</version>
</dependency>
    
    <dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>2.27</version>
</dependency>
    <!--dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-cdi2-se</artifactId>
    <version>2.27</version>
</dependency-->
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>project</artifactId>
    <version>2.27</version>
    <type>pom</type>
</dependency>

  </dependencies>
  <build>
    <finalName>hacka-mnl</finalName>
  </build>
</project>



Setup web.xml


<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Account Manager Service</display-name>
   
 <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>com.hacka.manila</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>

</web-app>



Create sample class.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * 
 * @author robinsonmago
 * url : http://localhost:8080/hacka-mnl/rest/account-officer/notify-logon
 *
 */

@Path("/account-officer")
public class FinastraActMgr {

  @GET
  @Path("/notify-logon")
  @Produces(MediaType.APPLICATION_JSON)
  public String notifyLogon(){
  CustomerStatusMgr.getInstance();
  CustomerStatusMgr.logon();
      return "{updateStatus:S}";
  }//end method
  
  
  @GET
  @Path("/notify-logout")
  @Produces(MediaType.APPLICATION_JSON)
  public String notifyLogoout(){
  CustomerStatusMgr.getInstance();
  CustomerStatusMgr.logout();
      return "{updateStatus:S}";
  }//end method
  
  


}//end class





Create a server.



Add server dependencies.






Start the server and access the URL.

http://localhost:8080/hacka-mnl/rest/account-officer/notify-logon

Tuesday, December 11, 2018

[Java] Read MQ Using Message Acknowledgment

Sample code to read Websphere MQ and using acknowledgment to automatically remove the message from queue. If the client did not acknowledge, the message will be retained in the queue.


import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;
import com.ibm.mq.jms.MQQueue;
import com.ibm.mq.jms.MQQueueConnection;
import com.ibm.mq.jms.MQQueueConnectionFactory;
import com.ibm.mq.jms.MQQueueReceiver;
import com.ibm.mq.jms.MQQueueSession;
import com.ibm.msg.client.wmq.WMQConstants;

public class MQReader {
 private MQQueueConnection connection;

 private void read() {
  MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
  try {
   cf.setHostName("Hostname");
   cf.setPort(1414);
   cf.setQueueManager("QMGR");
   cf.setChannel("MyChannel");
   cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE,             

   WMQConstants.WMQ_CM_CLIENT);
   connection = (MQQueueConnection)          
   cf.createQueueConnection("MyUsername","MyPassword");
   MQQueueSession session = (MQQueueSession)     
   connection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
   MQQueue localQueue = (MQQueue)    
   session.createQueue("queue:///MY.QUEUE");

   connection.start();
   MQQueueReceiver queueReceiver = (MQQueueReceiver)     
   session.createReceiver(localQueue);

   while(true) {
    TextMessage msg = (TextMessage) queueReceiver.receive();
    System.out.println(i +". Message is - " + msg.getText());
    msg.acknowledge();
   }


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

}//end method


 public static void main(String[] args) {
  new MQReader().read();
 }


}//end class

Monday, October 29, 2018

[Java] Testing Heap Memory

I tried to test heap code provided by stackify.com. I used Java VisualVM to monitor heap memory and Swing application from Oracle site to make it easier to execute the test. 
The visualVM can be found in the Java installation folder/bin directory. Double-click visualvm.exe file to run the application.


This is the class that I created with code lifted from stackify.com and Oracle site.



import java.util.ArrayList;
import java.util.Random;

public class MemoryTester extends javax.swing.JFrame {


private static final long serialVersionUID = 1L;
private static Random random = new Random();
private static final ArrayList<Double> list = new ArrayList<Double>(100000000);

public MemoryTester(){

init();
}

private void init(){
setTitle("Memory Tester");
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

javax.swing.JButton    memLeakButton = new javax.swing.JButton();
javax.swing.JButton    noMemLeakButton = new javax.swing.JButton();
javax.swing.JLabel   memLeakLabel = new javax.swing.JLabel();
javax.swing.JLabel    noMemLeakLabel = new javax.swing.JLabel();
 
    memLeakLabel.setText("Memory Leak");
    noMemLeakLabel.setText("NO Memory Leak");
    memLeakButton.setText("Test");
    noMemLeakButton.setText("Test");
    
    memLeakButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                System.out.println("Memory leak...");
                try {
testLeak();
} catch (InterruptedException e) {
e.printStackTrace();
}
            }
        });
    
    
    noMemLeakButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                System.out.println("NO Memory leak...");
                addElementsToTheList();
                System.gc();
                Thread.sleep(10000);
            }
        });
        
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(memLeakButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(memLeakLabel))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(noMemLeakButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(noMemLeakLabel)))
                .addContainerGap(27, Short.MAX_VALUE))
        );

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {noMemLeakButton, memLeakButton});

        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(memLeakButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(memLeakLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(noMemLeakButton)
                    .addComponent(noMemLeakLabel))
                .addContainerGap(21, Short.MAX_VALUE))
        );
        pack();
}



private void testLeak() throws InterruptedException{
for (int i = 0; i < 100000000; i++) {
        list.add(random.nextDouble());
    }
    
    System.gc();
    Thread.sleep(10000); // to allow GC do its j
}


private void addElementsToTheList(){
    ArrayList<Double> list = new ArrayList<Double>(100000000);
    Random randomx = new Random();
    for (int i = 0; i < 100000000; i++) {
        list.add(randomx.nextDouble());
    }
}

/**

 * @param args
 */
public static void main(String[] args) {
 java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MemoryTester().setVisible(true);
            }
        });

}


}




Running the code will open this Swing application.




Running 'memory leak' code will display this heap graph, there is no drop in heap memory.






Running 'no memory leak' code will display the graph below. Notice the drop in heap memory which means object was garbage collected.





Tuesday, October 23, 2018

[Java] Lightweight Directory Access Protocol (LDAP) Authentication


Securing an application require some form of user authentication. Most of the time users are contain in database or LDAP to manage logon credentials, i.e. username and password. 

The diagram below shows an application deployed in an application server, e.g. Websphere, JBoss call LDAP to authenticate logon user.



Below is a sample code to authenticate user against LDAP user repository.



import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class LdapAuthenticationAdapter{

  public boolean authenticate(
    String username, 
    String password){

DirContext context = null;
SearchResult result = null;
String usrNamespace = null;
NamingEnumeration<javax.naming.directory.SearchResult> answers = null;

SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[] { "givenName", "sn","memberOf" });
        
    ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
       
    try{

answers = getDirContext().search("ou=bankfusionusers", "(uid="+username+")", ctrls); // Get directory context
result = answers.nextElement();
usrNamespace = result.getNameInNamespace();
       
     Properties props = new Properties();
     props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
     props.put(Context.PROVIDER_URL, "ldap://manvsweqdv0011:10389/dc=misys,dc=com");
     props.put(Context.SECURITY_PRINCIPAL, usrNamespace);
     props.put(Context.SECURITY_CREDENTIALS, password);
       
     context = new InitialDirContext(props);

  }catch(NamingException e){
      return false;
}catch(NullPointerException e){
return false;
}
       
  return true;

}


public DirContext getDirContext()throws NamingException{
// Get admin user, password(encrypted), host, port and other LDAP parameters
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://{hostname}:{ldap_port}/dc={xxxxx},dc=com");
env.put("java.naming.ldap.attributes.binary", "objectSID"); //      validate this line if applicable

return new InitialDirContext(env);

}//end method

}

[Java] Central Authentication Service (CAS) Authentication

To secure the application, only authenticated user should be able to access it. Authorize user can be located in database or LDAP repository. Most of the time the users already have user repository like Active Directory. Providing a solution that can be configured to use different repository would be a good idea. It will decouple the authentication provider with the user repository. Below diagram shows an option for CAS to connect to database.

The diagram below shows an application deployed in application server, e.g. Websphere or JBoss authenticate logon user against LDAP or database.







Below is a sample code to call CAS server to authenticate user.


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.security.sasl.AuthenticationException;



public class CasAuthenticationAdapter{

  private static final String CAS_URL = "http://{hostname}:{port}/cas-server-webapp-3.5.2/v1/tickets";

public boolean authenticate(
  String username, 
  String password){

  String tgt = null;

try{
tgt = getTicketGrantingTicket(username, password);
}catch (IOException e){
e.printStackTrace();
}

if (tgt == null){
return false;
}else{
return true;
}
}


private  String getTicketGrantingTicket(
  String username, 
  String password)throws IOException{

Map<String,Object> params = new LinkedHashMap<>();
params.put("username", username);
params.put("password", password);
HttpURLConnection conn = post(CAS_URL, params);

  if(conn.getResponseCode() == 400){
    throw new AuthenticationException("bad username or password");
  }
        
  String location = conn.getHeaderField("Location");
  System.out.println("TGT LOCATION -> " + location);
  return location;
}


private HttpURLConnection post(
  String url, 
  Map<String, Object> params)throws IOException{
System.out.println("Posting to url '" + url +"' w/ params '" +   params.toString() + "'");

URL connectionUrl = createUrl(url);
byte[] postDataBytes = convertParamMapToBytes(params);
HttpURLConnection conn = (HttpURLConnection)connectionUrl.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);
        conn.getOutputStream().write(postDataBytes);
        return conn;
}


private URL createUrl(String url) throws MalformedURLException{
return new URL(url);
}


private byte[] convertParamMapToBytes(
  Map<String, 
  Object> params)throws UnsupportedEncodingException{
StringBuilder postData = new StringBuilder();
    for (Map.Entry<String,Object> param : params.entrySet()){
      if (postData.length() != 0) postData.append('&');
      postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
      postData.append('=');         postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
      return postData.toString().getBytes("UTF-8");
}

}

Wednesday, October 17, 2018

Logstash read from database table

Sometimes logs are save to database during runtime; and most of the time there are data that can be used to get status of the transaction saved in the table. Below is the sample Logtash database connection configuration that connects to IBMi DB2 for i.


input
{

jdbc{
jdbc_connection_string => "jdbc:as400://{HOSTNAME}"
jdbc_user => "{DB_USERNAME}"
jdbc_password => "{DB_PASSWORD}"
jdbc_driver_library => "/JT400DIR/jt400-6.7.jar"
jdbc_driver_class => "com.ibm.as400.access.AS400JDBCDriver"
schedule => "1 * * * *"
statement => "SELECT * FROM {DB_TABLE_NAME}"
}
}

Friday, October 12, 2018

[Java] Date formatter

Reusable utility for formatting date.


import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;


public static String formatDate(Date date, String format) {

     
   if(date == null || format == null) {
      throw new NullPointerException("Date or Format is null.");
   }

   return new SimpleDateFormat(format).format(date);


}



Sample call to the method:

Date date = Calendar.getInstance().getTime();
String format = "YYYY-MM-dd";
String formattedDate = formatDate(date,format);