Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Thursday, November 12, 2020

Java: Solving Anagrams with streams

I have been playing with code problems. Since I'm studying for Java 11 certification, I decided to resolve the Anagrams problem using streams. Here what I do is sort the two strings characters and then making a comparison.


public class Anagrams {
    static boolean isAnagram(String a, String b) {
        return sortStringChars(a).equals(sortStringChars(b));
    }

    static String sortStringChars(String str) {
        return str.toLowerCase().chars()
            .mapToObj(c -> (char) c)
            .sorted()
            .reduce("", (s,c) -> s.concat(String.valueOf(c)), String::concat);
    }

    public static void main(String[] args) {
        String a = "anagram";
        String b = "margana";

        boolean ret = isAnagram(a, b);
        System.out.println( (ret) ? "Yes, Anagrams!" : "Not Anagrams" );
    }
}

Friday, June 14, 2019

Save binary files in MongoDB with Spring-Boot

Saving binary files in MongoDB is pretty simple with Spring-Boot. You simply need to put byte[] type in the CrudRepository entity:



public interface BinayFilesRepository extends MongoRepository<BinaryEntity, String> {

}

@Document(BinaryEntity = "binaries")
public class BinaryEntity {

    private String id;
    private byte[] data;

}

Tuesday, August 1, 2017

Java Lambdas Tips

Creating a lookup method for an Enum



Without lambdas:

public enum Type {
     
     INFO,
     WARNING,
     ERROR;

     final static Map<String, Type> lookup = new HashMap<String, Type>();
     
     static {
      for(Type type : Type.values()) {
       lookup.put(type.name().toLowerCase(), type);
      }
     }

       
     public static Type of(String value){
         Type val = lookup.get(value == null ? null : value.toLowerCase());
         if(val == null){
             val = ERROR;
         }
         return val;
     }
}

With lambda:


public enum Type {
     INFO,
     WARNING,
     ERROR;

     final static Map<String, Type> lookup = Arrays.stream(Type.values())
          .collect(Collectors.toMap(t -> t.name().toLowerCase(), Function.identity()));

     public static Type of(String value){
         Type val = lookup.get(value == null ? null : value.toLowerCase());
         if(val == null){
            val = ERROR;
         }
         return val;
     }
}

Monday, May 25, 2015

JSON Jackson custom deserializer to return empty String instead of null

Needed a way to deserialize null values in a JSON as emptry strings (""). This is the shortest I could come with.
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class NullHandlerDeserializer extends UntypedObjectDeserializer {

  private static final long serialVersionUID = 1L;

  @Override
  public Object deserialize(JsonParser jp, DeserializationContext ctxt)
    throws IOException {
    switch (jp.getCurrentToken()) {
     case VALUE_NULL:      
      return "";
     default: 
      return super.deserialize(jp, ctxt);
    }   
  }
 }

The class extends from an existing deserializer implementation to avoid having to code the handling of all JSON tokens. I needed to worry only about VALUE_NULL token.

And to configure the custom deserializer in the ObjectMapper:

ObjectMapper om = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Object.class, new NullHandlerDeserializer());
om.registerModule(module);

Monday, June 2, 2014

HalBuilder: First steps

My team and I are working on trying to find best Java client to consume Hal REST services. I was trying HalBuilder and took me a time to figure a few tweaks to make the simple example describe in the website to work. Perhaps, I was doing something wrong, but just in case someone is also stuck on that, here's the code:

Maven Dependencies:

<dependency>
 <groupId>com.theoryinpractise</groupId>
 <artifactId>halbuilder-api</artifactId>
 <version>2.2.1</version>
</dependency>
<dependency>
 <groupId>com.theoryinpractise</groupId>
 <artifactId>halbuilder-core</artifactId>
 <version>3.1.3</version>
</dependency>
<dependency>
 <groupId>com.theoryinpractise</groupId>
 <artifactId>halbuilder-json</artifactId>
 <version>3.1.3</version>
</dependency>
<dependency>
 <groupId>com.theoryinpractise</groupId>
 <artifactId>halbuilder-standard</artifactId>
 <version>3.0.1</version>
</dependency>

<dependency>
  <groupId>com.ning</groupId>
  <artifactId>async-http-client</artifactId>
  <version>1.8.9</version>
</dependency>

Java code:

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutionException;

import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Response;
import com.theoryinpractise.halbuilder.api.ReadableRepresentation;
import com.theoryinpractise.halbuilder.api.RepresentationFactory;
import com.theoryinpractise.halbuilder.json.JsonRepresentationFactory;

//http://gotohal.net/
public class TestHalBuilderAPI {
 
 public static void main(String[] args) throws InterruptedException, ExecutionException, IOException {
  RepresentationFactory representationFactory = new JsonRepresentationFactory();
  representationFactory.withFlag(RepresentationFactory.PRETTY_PRINT);  
  
  AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
  Response response = asyncHttpClient.prepareGet("http://gotohal.net/restbucks/api").execute().get();
  
  InputStreamReader inputStreamReader = new InputStreamReader(response.getResponseBodyAsStream());
 
  ReadableRepresentation representation = representationFactory.readRepresentation(inputStreamReader);
  String ordersLinkUrl = representation.getLinkByRel("orders").getHref();  
  System.out.println(ordersLinkUrl);  
  asyncHttpClient.close();
 }
}

Thursday, February 13, 2014

Eclipse: JVM terminated. Exit code=13

I downloaded Eclipse for Scala and tried to open it when I got this error window message:

JVM terminated. Exit code=13



A few forums suggested a possible error in the eclipse.ini Java path but that wasn't my case. It was more related to the incompatibility of my downloaded 64-bit version of Eclipse with my default configured 32-bit Java. I have my 32-bit Java as it's the version that works for my VPN connection. I simply switched to a 64-bit Java using:

>:$ sudo update-alternatives --config java
There are 3 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1071      auto mode
  1            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      manual mode
  2            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1071      manual mode
* 3            /usr/lib/jvm/jre1.7.0_45/bin/java                1         manual mode

Tuesday, February 11, 2014

Java Core: ArrayList vs LinkedList

Performance oriented development is one key aspect of any serious developer. Sometimes we are very accustomed to some practice, or use of a specific programming language feature, that we might forget there are other options that can work better on different scenarios. This could be the case of the different collections provided by Java. In the past I used to create all my list collections using ArrayList and never wondered about the pros/cons of using alternatives like LinkedList until I read some literature explaining the best scenarios for each one.

Pros of ArrayList

1. ArrayList uses internally an array for internal storage. That makes it particularly fast for random access - get(#n). 

Cons of ArrayList

1. ArrayList is slower for modification operations like add or delete elements in the beginning or middle of the collection. This is due to the need of relocate all subsequent elements one position to the right (or left in case of deletion) in order to make space to the new element.

Let's show this graphically. Let's suppose we have a list of six elements.


And we want to insert an element before the second one.

To be able to add this element, internally, the list needs to copy all elements from index 1 to 5 one position to the right.


2. Similar to before described process. ArrayList has some performance downside when the internal array is completely full, and therefore has to create a bigger array and relocate all elements to new array.

Pros of LinkedList

1. LinkedList follows a different approach. It's more efficient in adding or deleting elements in the beggining or middle of the collection. If you ever programmed from scratch a list data structure, you will remember you have nodes with pointers/references to the next element.



In this case what is done to insert a new node in the middle of the list is to create a new node pointing to the next element (->c), and the before element is updated to point to the new created node (->b).






2. Given the nature of the internal structure which is not restricted to an initial size, LinkedList has no growing problems as ArrayList.

Cons of LinkedList

1. Random access to LinkedList elements are expensive, because in worst case scenarios the entire list has to be traversed to retrieve the desired element (O(n)).

We could say that we should use ArrayList if we have many random accesses. If we think our lists are going to grow unexpectedly, we should favor LinkedList. This is just one scenario. We could have both needs in which case a combination of both approaches could be use. Like using LinkedList to create the list, and then use ArrayList for read access.

Thursday, August 29, 2013

JSP: Get Current Date

Short snippet showing how to get current date in a JSP using scriplet code. In occasions it's needed to have the date served by the server instead of using JavaScript code, which depends of right configuration in user's machine, or differences may arise due to distinct time zones.

<%@ page import="java.util.*" %>
<%@ page import="java.text.SimpleDateFormat"%>
 
<%
   Date dNow = new Date();
   SimpleDateFormat ft = 
   new SimpleDateFormat ("MM/dd/yyyy");
   String currentDate = ft.format(dNow);
%>

<p>The current date is: <%=currentDate%></p>

Wednesday, August 14, 2013

Java: Converting String to Enum


Sometimes is necessary to convert a String value to an Enum, perhaps because we have the value as a String in the database, but we want to manipulate it as an Enumerator in the Java code.

The follow code shows hot to obtain the Enum value from a String. Basically, a static method is added to the Enum to return the specif Enum value. This is accomplished by iterating all the Enum values and making a comparison with the String value passed as a parameter. If the String does not match with any of the values, then an illegal argument exception is thrown.


public enum Volcano {

 IRAZU("Irazu"), POAS("Poas"), ARENAL("Arenal"), RINCON_DE_LA_VIEJA("Rincon de la vieja");

 private String name;

 private Volcano(String name) {
  this.name = name;
 }

 public static Volcano fromString(String name) {
  if (name == null) {
   throw new IllegalArgumentException();
  }
  for (Volcano volcano : values()) {
   if (name.equalsIgnoreCase(volcano.getName())) {
    return volcano;
   }
  }
  // Passed string value does not correspond to a valid enum value.
  throw new IllegalArgumentException();
 }

 public String getName() {
  return this.name;
 }

 public static void main(String[] args) {
  Volcano volcano1 = Volcano.fromString("Poas");
  System.out.println(volcano1);

  Volcano volcano2 = Volcano.fromString("rincon de la vieja");
  System.out.println(volcano2);

  Volcano volcano3 = Volcano.fromString("Fuji");
 }
}

Output:


POAS
RINCON_DE_LA_VIEJA
java.lang.IllegalArgumentException
 at com.bodybuilding.common.enums.Volcano.fromString(Volcano.java:22)
 at com.bodybuilding.common.enums.Volcano.main(Volcano.java:36)

Friday, August 9, 2013

Calculate days lived since birth date

Just a small piece of code showing how to calculate total days lived since birth date (to current date):
import java.util.Calendar;
import java.util.GregorianCalendar;
 
public class TotalLifeTimeDays {
  
 public int getLifeTimeDays(int birthYear, int birthMonth, int birthDay) {
   
  Calendar birthDayCal = new GregorianCalendar();
     Calendar currentDayCal = Calendar.getInstance();
 
  birthDayCal.set(birthYear, birthMonth, birthDay);    
  return (int)((currentDayCal.getTime().getTime() - birthDayCal.getTime().getTime())
     / (1000 * 60 * 60 * 24));  
 }
  
 public static void main(String[] args) {
  TotalLifeTimeDays totalLifeTimeDays = new TotalLifeTimeDays();
  int totalDays = totalLifeTimeDays.getLifeTimeDays(1982, 11, 20);
  System.out.println("Total days lived: " + totalDays);
 }
}

Monday, July 22, 2013

Flyway Validate: Cannot determine latest applied migration. Was the metadata table manually modified?

In our project we use Flyway to control modifications to the database. Recently I started seeing this error on my local environment, which doesn't give too many clues on why it could be failing:


Flyway Validate: Cannot determine latest applied migration. Was the metadata table manually modified?

Given that Flyway is an Open Source project, it wasn't very hard to find the code and search for the error string. We can see what the code does is to look for the column "CURRENT_VERSION":
   /**
     * @return The latest migration applied on the schema. {@code null} if no migration has been applied so far.
     */
    public MetaDataTableRow latestAppliedMigration() {
        if (!hasRows()) {
            return null;
        }

        String query = getSelectStatement() + " where current_version=" + dbSupport.getBooleanTrue();
        @SuppressWarnings({"unchecked"})
        final List metaDataTableRows = jdbcTemplate.query(query, new MetaDataTableRowMapper());

        if (metaDataTableRows.isEmpty()) {
            if (hasRows()) {
                throw new FlywayException("Cannot determine latest applied migration. Was the metadata table manually modified?");
            }
            return null;
        }

        return metaDataTableRows.get(0);
    }

    ...

    /**
     * @return The select statement for reading the metadata table.
     */
    private String getSelectStatement() {
        return "select VERSION, DESCRIPTION, TYPE, SCRIPT, CHECKSUM, INSTALLED_ON, EXECUTION_TIME, STATE from " + schema + "." + table;
    }

So I just identified the last applied migration and manually set the column "CURRENT_VERSION" in 1. Problem solved!

Thursday, June 27, 2013

Java version of a .class


Sometime ago I had an issue with a code that was sent to us already compiled (no sources attached). During deployment we were facing an exception like this one: javax.servlet.ServletException: Bad version number in .class file

What I found reading on the web about this problem is that the problem was probably caused by compiling the Java project in a Java version higher than the one running in the JVM on the server. In my particular case I found that the code was compiled in Java 6, while the JVM was running Java 5.

To confirm this I learned a trick on how to find the Java version of a .class. For this there is a command: javap -verbose ClassName
(The .exe can be found in the JDK bin directory)

It is recommended to save the result of the command on a file since it throws a lot of information. What you need to look for is the combination of minor and major version that is found in the beginning. These two values are the key to determine the Java version used to compile the class.

major  minor Java platform version 
45       3           1.0
45       3           1.1
46       0           1.2
47       0           1.3
48       0           1.4
49       0           1.5
50       0           1.6

Wednesday, May 1, 2013

Spring Jackson library example to consume JSON returned by REST service


A brief example of how to use the Spring Jackson library to consume a JSON returned by a REST service. The class below is a Singleton that initializes the RestTemple one time only.

import java.util.ArrayList;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.http.client.CommonsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

public class RestJsonTest {
 
 private static RestJsonTest instance;
 private RestTemplate restTemplate;
 private String url ="http://rest.service.url";
 
 public static RestJsonTest getInstance() {
  if (instance == null) {
   instance = new RestJsonTest();
  }
  return instance;
 }
 
 private RestJsonTest() {
  // Setup the RestTemplate configuration.
  restTemplate = new RestTemplate();
  restTemplate.setRequestFactory(new CommonsClientHttpRequestFactory());
  List<HttpMessageConverter<?>> messageConverterList = restTemplate.getMessageConverters();
  
  // Set HTTP Message converter using a JSON implementation.
  MappingJacksonHttpMessageConverter jsonMessageConverter = new MappingJacksonHttpMessageConverter();
  
  // Add supported media type returned by BI API.
  List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
  supportedMediaTypes.add(new MediaType("text", "plain"));
  supportedMediaTypes.add(new MediaType("application", "json"));
  jsonMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
  messageConverterList.add(jsonMessageConverter);
  restTemplate.setMessageConverters(messageConverterList);
 }
 
 public SearchResults searchResults() {
  return restTemplate.getForObject(url, SearchResults.class);  
 }
 
 public static void main(String[] args) {
  RestJsonTest jsonTest = RestJsonTest.getInstance();
  SearchResults results = jsonTest.searchResults();
 }
}

The mapping of the JSON to Java classes can be done via annotations like it's shown here:
package com.bodybuilding.api.commerce.clientservice;

import java.util.List;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;


/**
 *{
 * "search_keywords":"Social Networks",
 *  "total_time":200,
 *  "results":{
 *   "result_01":{
 *    "url":"http://www.facebook.com",
 *    "rank": "1"
 *   },
 *   "result_02":{
 *   "url":"http://www.twitter.com",
 *    "rank": "2"
 *   }
 *  }
 * }
 */
@JsonIgnoreProperties(ignoreUnknown=true)
public class SearchResults {
 
 @JsonProperty("search_keywords")
 private String keywords;
 
 @JsonProperty("total_time")
 private long totalTime;
 
 @JsonProperty("results")
 private List<SearchResult> results;
 
 public String getKeywords() {
  return keywords;
 }
 public void setKeywords(String keywords) {
  this.keywords = keywords;
 }
 public long getTotalTime() {
  return totalTime;
 }
 public void setTotalTime(long totalTime) {
  this.totalTime = totalTime;
 }
 public List<SearchResult> getResults() {
  return results;
 }
 public void setResults(List<SearchResult> results) {
  this.results = results;
 } 
}

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown=true)
public class SearchResult {
 
 @JsonProperty("url")
 private String url;
 
 @JsonProperty("rank")
 private int rank;
 
 public String getUrl() {
  return url;
 }
 public void setUrl(String url) {
  this.url = url;
 }
 public int getRank() {
  return rank;
 }
 public void setRank(int rank) {
  this.rank = rank;
 }
}

The RestTemplate bean can be also configure with Spring injection:

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
     <property name="requestFactory">
      <bean id="clientHttpRequestFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory" />   
     </property>
     <property name="messageConverters">
      <list>
       <bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
        <property name="supportedMediaTypes">
         <list>
          <bean id="jsonMediaTypeTextPlain" class="org.springframework.http.MediaType">
           <constructor-arg value="text"/>
          <constructor-arg value="plain"/>
          </bean>
          <bean id="jsonMediaTypeApplicationJson" class="org.springframework.http.MediaType">
           <constructor-arg value="application"/>
          <constructor-arg value="json"/>
          </bean>
         </list>
        </property>
       </bean>
      </list>
     </property>  
</bean>

Wednesday, November 7, 2012

Simple code for finding missing alphabet letters in a sentence

I consider no code is trash even if it's too trivial. And I also hate the sensation of knowing I code something similar before, but have to repeat the coding because I didn't save it. Some time ago I had to code a solution for a simple problem as part of the recruiting process in a company. The problem to solve is to find the missing letters of the alphabet in a given sentence.


import java.util.HashSet;
import java.util.Set;
 
/**
* Test code to find missing letters of the alphabet from a String sentence.
* @author gabriel.solano
*
*/
public class MissingLetters {
 
private final int ASCII_CODE_FOR_LETTER_A = 97;
private final int ASCII_CODE_FOR_LETTER_Z = 122;
 
/**
* Gets the missing letters of a sentence in lower case.
* @param sentence
* @return String having all the letters that the sentence is missing from the alphabet.
*/
public String getMissingLetters(String sentence){
/*
 * 1. Let's populate a set with the unique characters of the sentence.
 *    This approach avoids having two nested for's in the code (better performance).
 */
Set<Integer> uniqueASCIICodes = new HashSet<Integer>();
 
for (char character : sentence.toLowerCase().toCharArray() ) {
 if (character >= ASCII_CODE_FOR_LETTER_A
   && character <= ASCII_CODE_FOR_LETTER_Z) { // Range of lower case letters.
  uniqueASCIICodes.add((int)character);
 
  if (uniqueASCIICodes.size() == 26) {
   break; // Sentence already covered all letter from the alphabet.
  }
 }
}
/*
 * 2. Move in the range of ascii codes of lower case alphabet
 * and check if letter was present in sentence.
 */
StringBuilder misingLettersBuilder = new StringBuilder();
 
for (int i=ASCII_CODE_FOR_LETTER_A; i <= ASCII_CODE_FOR_LETTER_Z; i++) {
 if (!uniqueASCIICodes.contains(i)) {
  misingLettersBuilder.append((char)i);
 }
}
   return misingLettersBuilder.toString();
}
 
public static void main(String[] args) {

   String case1 = "A quick brown fox jumps over the lazy dog";
   String case2 = "bjkmqz";
   String case3 = "cfjkpquvwxz";
   String case4 = "";
 
   MissingLetters missingLetters = new MissingLetters();
 
  System.out.println("Missing letters for[" + case1 + "]: " +
  missingLetters.getMissingLetters(case1));
  System.out.println("Missing letters for[" + case2 + "]: " +
  missingLetters.getMissingLetters(case2));
  System.out.println("Missing letters for[" + case3 + "]: " +
  missingLetters.getMissingLetters(case3));
  System.out.println("Missing letters for[" + case4 + "]: " +
  missingLetters.getMissingLetters(case4));
   }
}
This will be the program output:
Missing letters for[A quick brown fox jumps over the lazy dog]: 
Missing letters for[bjkmqz]: acdefghilnoprstuvwxy
Missing letters for[cfjkpquvwxz]: abdeghilmnorsty
Missing letters for[]: abcdefghijklmnopqrstuvwxyz

Tuesday, November 6, 2012

Tres Amigos of Persistance (DAO - DAOFactory - BO)

Nowadays, even with all the good accumulated knowledge we have in design patterns, software engineers still tend to program classes where business logic is mixed with persistence logic. Even some experienced developers omit this important aspect of software architecture maybe for lack of knowledge, or just for the rush to start programming quickly. I consider the last reason is the most common of all. 

Now why should we bother too much about this separation? well, the idea is not to develop a case for what is basic in software architecture: multi-tier(layer) programming, but to help with some useful patterns to accomplish this fundamental aspect of a well design application. I think almost everyone is aware of this principle but I know for experience that for many it is not so obvious how we can meet all the details of persistence logic independence. 

First let's start with the most known pattern: Data Access Object (DAO). Citing from one design patterns book I have [1]:

Problem: You want to encapsulate data access and manipulation in a separate layer
 Forces:

  1. You want to implement data access mechanisms to access and manipulate data in a persistence storage.
  2. You want to decouple the persistent storage implementation from the rest of your application.
  3. You want to provide a uniform data access API for a persistent mechanism to various types of data sources, such as RDBMS, LDAP, OODB, XML repositories, flat files, and so on.
  4. You want to organize data access logic and encapsulate proprietary features to facilitate maintainability and portability. 


 The DAO classes will contain all the logic to connect for example to a database and get the needed data from the corresponding tables. One important aspect of this DAO is that any implementation should always avoid to return any persistence proprietary object. For example if someone codes a DAO where the returned object is a ResultSet, the class wouldn't be meeting the point #4. The application would be coupled to the JDBC implementation. That is why in the next UML diagram the returned object from the DAO is a "TransferObject". 

We don't have to get into much details of TransferObject pattern but I can say with just having domain objects is enough to ensure decoupling with business and persistence layers.

Having implemented the DAO pattern in our app does not decouple in 100% the business layer from the persistence one. Imagine for example you have this DAO class and the client that consumes it:
package com.foo.dao.jdbc;

class FooDAOJDBCImpl {
 public void updateFoo(Foo foo) {  
  ...
 }
}

public class FooClient {
 void updateChangesInFoo(Foo foo) {
  com.foo.dao.jdbc.FooDAOJDBCImpl fooDAOJDBCImpl = new com.foo.dao.jdbc.FooDAOJDBCImpl();
  fooDAOJDBCImpl.update(foo);
 }
}

Notice that the client needs to instantiate directly the JDBC implementation. Even though it is hidden for the client how the DAO class internally updates the data in the data source, the client still knows that the implementation uses JDBC to persist data. If the JDBC implementation has to be replaced by another one, the client code will have to be updated to use the new DAO class. 

To make our design more flexible to such type of possible changes, and also to have our code prepared for unit testing (use of mock DAO classes), we can marry our DAO pattern with the AbstractFactory pattern to have a child named DAOFactory. The DAOFactory class uses reflection (one way to do it) to instantiate the DAO class.


 
public interface DAO {

}

public interface FooDAO extends DAO {
 public void update(Foo foo);
}

package com.foo.dao.jdbc;
public class FooJDBCImpl implements FooDAO {
 public void update(Foo foo) {
  ....
 }
}

public class FooClient {
 void updateChangesInFoo(Foo foo) {
  FooDAO dao = (FooDAO) DAOFactory.getDAO("foo") ;
  dao.update(foo);
 }
}


It is not until execution time that is known what DAO class will be used to execute the persistence method. The name of the classes can be stored in a properties file. If the implementation of the DAO class is changed, it will be totally transparent to the Client class.

/**
Properties in some file:
foo=com.foo.dao.jdbc.FooDAOJDBCImpl
foo2=com.foo.dao.jdbc.Foo2DAOJDBCImpl

**/

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class DAOFactory {
 
 private static Properties props = new Properties();
 private static boolean loadedProperties = false;
 private static String propertiesPath;
 
 public static void init(String propertiesPath) {
  propertiesPath = path;
 }

 public static DAOFactory getDAO(String name) {
  try {
   
   Class daoClass = Class.forName( getClass( name ) ); 
   return (DAO) daoClass.newInstance();   
  }
  catch (ClassNotFoundException e) { 
   e.printStackTrace();
   return null;
  }
  catch (Exception e) {
   e.printStackTrace();
   return null;   
  }

 }
 
 private static String getClass( String propertyName ) {
  String className = null;
  try {
 
   if ( !loadedProperties ) {
    
    FileInputStream file = new FileInputStream( propertiesPath );
    props.load( file );    
    loadedProperties = true;
   }

   className = props.getProperty( propertyName, "");
   if ( className.length() == 0)
    return null;
  }
  catch ( FileNotFoundException e) { 
   e.printStackTrace();
  }
  catch ( IOException e) {   
   e.printStackTrace();
  }
  catch (Exception e) {
   e.printStackTrace();
  }
  return className;
 }

}

The last design pattern to complete our gang is the Business Object (BO). I'm still learning how to use it correctly, I just realized writing this post that I have some fixes to do in a current implementation I have. But anyways, one of the main purposes of this pattern is to separate the persistence logic from the business logic. Normally in our applications we have a complex conceptual model containing structured, interrelated composite objects. Those complex composite relationships between classes require a lot of logic just to persist. So to avoid mixing these two logic's, an intermediate layer between business logic and data access is created; the BO's layer. 

Let's suppose we have a class Foo containing a list of Foo2 objects:

public class Foo {
 private List<oo2> foo2s;
 private String someAttribute; 

}
public class Foo2 {
 private String someAttribute;
} 
If we want to persist our Foo class, we create two BO classes. The FooBO is the main entry point to save all the composite objects contained inside Foo2 domain class.
 public class FooBO {
 
 public void saveFoo(Foo foo) {
  FooDAO fooDAO = (FooDAO) DAOFactory.getDAO("foo") ;
  fooDAO.saveBasicFooInfo(foo);
  Foo2BO foo2Bo = new Foo2BO();
  
  for (Foo2 foo2 : foo.getFoo2s()) {
    foo2Bo.saveFoo2(foo2);
  }  
 }
}

public class Foo2BO {
 public void saveFoo2(Foo foo) {
  FooDAO2 fooDAO2 = (FooDAO2) DAOFactory.getDAO("foo2") ;
  fooDAO2.saveFoo2(foo2);
 }
}
There can be different ways to implement any of the 3 patterns described in this post; nothing is written in stone in the programming field. The idea was to provide a quick look on these three main patterns. If anyone has anything interesting to add, comments are well welcome. [1] Deepak Alur, John Crupi, Dan Malks. "Core J2EE Patterns, Best Practices and Design Strategies", 2003. Pags: 462,463.

Monday, November 5, 2012

A Few File Operations || Building a Synchronizer

Recently in the project I’ve been working in the last couple of months, we had to think in a way to solve the problem of keep updated some local copies of repositories where the originals are located in remote servers. Due to the kind operations we need to run, we couldn’t afford to do them directly in the remote servers. If you are thinking right now, “well duh! Use SVN you dummy” , well, let’s say that our client does not have it and there is no close possibility he will install it for us. We only had access to the share drives where we could read the file systems. That’s all we had. This kind of operation we required is known (at least that’s how we use it) as directory synchronization. In our case we needed to keep the most updated version as possible of the remote files. The synchronization is very useful when the cost to copy everything is too high. 

For example if you have a remote directory with 200GB, you don’t want to copy everything every time you want to update your local copy. It just takes too much time. I did some research to find a tool that could do what I wanted, and I did find some good ones, but with the only inconvenience that I needed something I could customize to our processes. So I started playing a bit with the java.io.File class and realized that I could program a Synchronizer.

In this post I want to share some useful operations of the File class in light of the problem that my team needed to solve. Let’s put an example of what the Synchronizer needs to do. 

Let’s suppose we have this remote directory:
gsolano_remote
 + 20100514
++ calculations.xls
+ 20100514
++ HelloWorld.java
+ readme.txt

 And we have the local copy that need s to be updated:
 gsolano_local
+ 20100514
++ calculations.xls
++ deletelater
+ bck-ups
+ readme.txt
+ dir.txt

 If we compare the two directories, the local copy would have to execute the next actions (enclosed in parentheses).
 gsolano_local
+ 20100514
++ calculations.xls
++ deletelater (remove)
+ bck-ups (remove)
+ readme.txt (update)
+ dir.txt (remove)
+ 20100514 (add)
++ HelloWorld.java (add)

 The logic that needs to be coded to run those actions is very simple. First we list the files from source (gsolano_remote) and target (gsolano_local), then we compare them to extract: + List of new files to copy from source to target, + List of files that need to be updated because they were modified in the source. + Files and directories that are no longer present in the source and for instance need to be removed from target. Once we get these lists we just have to execute the respective copies and deletions. Let’s examine first how to scan files from a directory.
package gsolano;
import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

public class Dir { 
 
 /**
  * Returns a list of all file paths relative to the provided path.
  * @param path
  * @return list of relative paths.
  */
 public static Map<String, Long> scan(String path) {
  Map<String, Long> fileList = new LinkedHashMap<String, Long>();
  scanFiles(path.toLowerCase(), path, fileList);
  return fileList;
 }
 
 /**
  * Method for recursively scan. 
  * @param rootSource
  * @param path
  * @param fileList
  */
 private static void scanFiles(String rootSource, String path, Map<String, Long> fileList) {
   File folder = new File(path); // This is the root directory.
  // List files from first level of root directory.
   File[] listOfFiles = folder.listFiles(); 
   
   if (listOfFiles.length == 0) {
    // Used to keep record of empty folders.
    fileList.put(path.toLowerCase().replace(rootSource, "") 
        + File.separator + ".", new Long(0));
   }
   else {
    for (int i = 0; i < listOfFiles.length; i++) {
     if (listOfFiles[i].isFile()) { // Is it a file?     
      try {
       // Add it to the file list with the last modified date.
      fileList.put(listOfFiles[i].getAbsolutePath().toLowerCase()
        .replace(rootSource, ""), listOfFiles[i].lastModified());
      
     } catch (Exception e) {  
      e.printStackTrace();
     }
     } else if (listOfFiles[i].isDirectory()) { // Is it a directory?
      try {
       // Recursively call for new found directory.
       scanFiles(rootSource, listOfFiles[i].getCanonicalPath(), fileList);
     } catch (IOException e) {     
      e.printStackTrace();
     }
     }   
    }
   }
  
 }
}

In this code we start exploring some capabilities of the File class. The first one is the ability to list files from a directory. We simply create an instance of a File class with the path of a directory and then we use the function “listFiles()”.

File folder = new File(path); 
File[] listOfFiles = folder.listFiles();
Now, this function only gets the files and directories at the first level, it does not retrieve the files of subsequent directories in the next levels; that’s why in the Dir class the file scanning works with a recursively function. To determine if we need to execute a recursively call, we use the functions “isFile()” and “isDirectory()”. If the file that is read is a directory (sound weird, I agree), then a recursively call is made. If it is a file, then it is added to the list. In this class we are also using the function “lastModified()” to store the last modified of each of the files scanned. This will be used to determine if the file from source changed causing to have to update the file in the target. Before jumping to the main class, let’s take a look of the class used to copy files. I modified a bit a class the I found in the Internet :
package gsolano;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy {

 /**
  * Copies one file from the source to specified target.
  * @param fromFileName
  * @param toFileName
  * @param overrideFiles
  * @throws IOException
  */
 public static void copy(String fromFileName, String toFileName,
   boolean overrideFiles) throws IOException {
  
  File toFile = new File(toFileName);
  if (toFile.exists() && !overrideFiles) {
   return;
  }
  File fromFile = new File(fromFileName);

  if (!fromFile.exists())
   throw new IOException("FileCopy: " + "no such source file: "
     + fromFileName);
  if (!fromFile.isFile())
   throw new IOException("FileCopy: " + "can't copy directory: "
     + fromFileName);
  if (!fromFile.canRead())
   throw new IOException("FileCopy: " + "source file is unreadable: "
     + fromFileName);

  if (toFile.isDirectory()) {
   toFile = new File(toFile, fromFile.getName());
  }
  if (toFile.exists()) {
   if (!toFile.canWrite()) {
    throw new IOException("FileCopy: "
      + "destination file is unwriteable: " + toFileName);
   }
   String parent = toFile.getParent();
   if (parent == null)
    parent = System.getProperty("user.dir");
   File dir = new File(parent);
   if (!dir.exists())
    throw new IOException("FileCopy: "
      + "destination directory doesn't exist: " + parent);
   if (dir.isFile())
    throw new IOException("FileCopy: "
      + "destination is not a directory: " + parent);
   if (!dir.canWrite())
    throw new IOException("FileCopy: "
      + "destination directory is unwriteable: " + parent);
  } else {
   // Create directory structure.
   new File(toFile.getParent()).mkdirs();
  }
  createCopy(toFile, fromFile);
 }

 /**
  * Writes the copy from source to target.
  * @param toFile
  * @param fromFile
  * @throws FileNotFoundException
  * @throws IOException
  */
 private static void createCopy(File toFile, File fromFile)
   throws FileNotFoundException, IOException {
  FileInputStream from = null;
  FileOutputStream to = null;
  try {
   from = new FileInputStream(fromFile);
   to = new FileOutputStream(toFile);
   byte[] buffer = new byte[4096];
   int bytesRead;

   while ((bytesRead = from.read(buffer)) != -1)
    to.write(buffer, 0, bytesRead); // write
  } finally {
   if (from != null)
    try {
     from.close();
    } catch (IOException e) {
     ;
    }
   if (to != null)
    try {
     to.close();
     toFile.setLastModified(fromFile.lastModified());

    } catch (IOException e) {
     ;
    }
  }
 }
}
The FileCopy uses six more functions of the java File class: 
1.“exists()”: used to double-check if the source file really exists. 
2.“canRead()”: used to determine if the source file can be read. 
3.“canWrite():”: used to determine if target file can be overwrite. This is used in the cases where we need to update the file. 
4."getParent()”: to get the parent path of the file.
5.“mkDirs()”: I have to say this is my favorite one; it creates all the directory hierarchy of the file’s path.
6.“setLastModifiedDate()”: when we finish copying the file in the target directory, we wanted to leave the same modified date of the source. 

To conclude with the Synchronizer class we just have to see one more function and a constant: 
+ “delete()”: deletes the file or directory. 
+ “File.separator”: system dependant character used to separate directories in a path. In this example the separator is the back-slash (“\”). 

The Synchronizer class do all the basic steps required to synchronize the two directories. The list of copies and deletions are calculated with simple comparisons of collections (sets and maps). I would like to test if this works in other OS but I'm kind of lazy for that. Theoretically it does work ;).

package gsolano;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 
 * Class used to synchronize two directories. One directory (source)
 * is used as base of another directory (target).
 * The class determines the operations required to leave the target
 * with the same structure as the source.
 * 
 * @author gsolano
 *
 */
public class Synchronizer {
 
 public static void main(String[] args) {
  Synchronizer.run("c:\\gsolano_remote\\", "c:\\gsolano_local\\");
 } 
 
 public static void run(String source, String target) {
  System.out.println("Scanning source directory...");
  Map<String, Long> sourceFiles = Dir.scan(source);
  System.out.println("[DONE]");
  
  System.out.println("Scanning target directory...");
  Map<String, Long> targetFiles = Dir.scan(target);
  System.out.println("[DONE]");
  
  List<String> newFilesToCopy = getNewFilesToCopy(sourceFiles.keySet(), targetFiles.keySet());
  System.out.println("Total new files to copy: " + newFilesToCopy.size());
  
  List<String> filesToUpdate = getFilesToUpdate(sourceFiles, targetFiles);
  System.out.println("Total files to update: " + filesToUpdate.size());
  
  List<String> filesToRemove = getFilesToRemove(sourceFiles.keySet(), targetFiles.keySet());
  System.out.println("Total files to remove: " + filesToRemove.size());
  
  List<String> dirsToRemove = getDirectoriesToRemove(sourceFiles.keySet(), targetFiles.keySet());
  System.out.println("Total dirs to remove: " + dirsToRemove.size());
  
  System.out.println("Copying new files...");
  for(String fileToCopy : newFilesToCopy) {
   try {
    FileCopy.copy(source + File.separator + fileToCopy, 
      target + File.separator + fileToCopy, false);
   } catch (IOException e) {
    System.out.println("Couldn't copy file: " + fileToCopy + "(" + e.getMessage() + ")");
   }
  }
  
  System.out.println("Updating files...");
  for(String fileToUpdate : filesToUpdate) {
   try {
    FileCopy.copy(source + File.separator + fileToUpdate, 
      target + File.separator +fileToUpdate, true);
   } catch (IOException e) {
    System.out.println("Couldn't copy file: " + fileToUpdate + "(" + e.getMessage() + ")");
   }
  }
  
  System.out.println("Removing files from target...");
  for(String fileToRemove : filesToRemove) {   
   new File(target + fileToRemove).delete();   
  }
  
  System.out.println("Removing directories from target...");
  for(String dirToRemove : dirsToRemove) {
   new File(target  + dirToRemove).delete();   
  }  
 }
 
 /**
  * Return the list of directories to be removed. A directory is removed
  * if it is present in the target but not in the source.
  * @param sourceFiles
  * @param targetFiles
  * @return
  */
 private static List<String> getDirectoriesToRemove(Set<String> sourceFiles, 
    Set<String> targetFiles) {
  List<String> directoriesToRemove = new ArrayList<String>();
  
  Set<String> sourceDirs = buildDirectorySet(sourceFiles);
  Set<String> targetDirs = buildDirectorySet(targetFiles);
  
  for(String dir : targetDirs) {
   if (!sourceDirs.contains(dir)) {
    directoriesToRemove.add(dir);
   }
  }  
  return directoriesToRemove;  
 }
 
 /**
  * Return the list of files to be removed.
  * A file is removed if it is present in the target
  * but not in the source.
  * @param sourceFiles
  * @param targetFiles
  * @return
  */
 private static List<String> getFilesToRemove(Set<String> sourceFiles, 
   Set<String> targetFiles) {
   List<String> filesToRemove = new ArrayList<String>();   
      
   for (String filePath : targetFiles) {       
         if (!sourceFiles.contains(filePath) && 
           !filePath.endsWith(File.separator + ".")) {
          filesToRemove.add(filePath);          
         }
      }
  return filesToRemove;
 }
 
 /**
  * Gets the the list of files missing in the target directory.
  * @param sourceFiles
  * @param targetFiles
  * @return
  */
 private static List<String> getNewFilesToCopy(Set<String> sourceFiles, 
   Set<String> targetFiles) {
   List<String> filesToCopy = new ArrayList<String>();  
        
   for (String filePath : sourceFiles) {
          if (!targetFiles.contains(filePath)) {
           if(!filePath.endsWith(File.separator + ".")) {
           filesToCopy.add(filePath);
           }
         }
      }  
  return filesToCopy;
 }
 
 /**
  * Gets the list of files to be updated according to the last
  * modified date.
  * @param sourceFiles
  * @param targetFiles
  * @return
  */
 private static List<String> getFilesToUpdate(Map<String, Long> sourceFiles, 
   Map<String, Long> targetFiles) {
   List<String> filesToUpdate = new ArrayList<String>();  
   Iterator<Map.Entry<String, Long>> it = sourceFiles.entrySet().iterator();
      
   while (it.hasNext()) {
         Map.Entry<String, Long> pairs = it.next();
         String filePath = pairs.getKey();
         if (targetFiles.containsKey(filePath) &&
           !filePath.endsWith(File.separator + ".")) {
          long sourceModifiedDate = sourceFiles.get(filePath);
          long targetModifiedDate = targetFiles.get(filePath);
          
          if(sourceModifiedDate != targetModifiedDate) {
           filesToUpdate.add(filePath);
          }                    
         }
      } 
  return filesToUpdate;
 }

 /**
  * Returns the set of directories contained in the set of file paths.
  * @param files
  * @return Set of directories representing the directory structure.
  */
 private static Set<String> buildDirectorySet(Set<String> files) {
  Set<String> directories = new HashSet<String>();  
  for(String filePath : files) { 
   if (filePath.contains(File.separator)) {
    directories.add(filePath.substring(0, 
      filePath.lastIndexOf(File.separator)));
   } 
  }  
  return directories;
 }
}

Output: ;

Friday, November 2, 2012

Using Observer Pattern to track progress while loading a page

Have you ever been in a site where there is a heavy process that takes a long time in finishing? If the web page is not user friendly designed, you may end it up with an annoying forever loading page. If we want to avoid this feeling of slowness in our pages, we should consider adding a progress indicator in the page to show how much is left until process is finished. To accomplish this we can take advantage of the Observer pattern. To do this we need to run the process asynchronously, or in other words, running it as a different thread. The next diagram shows how the long process is contained in Thread class.

 

The following class is going to emulate a long process by taking various naps.

package com.gsolano.longprocess

import java.util.Observable;

/**
 * Class with an observable mock long progress.
 * @author gsolano
 *
 */
public class LongProcess extends Observable {
 
 /**
  * Keeps the progress of the process.
  */
 protected Float progress;
 
 /**
  * Simulates a long process.
  */
 public void start() {
  int n =10;
  for (int i=0;i <= n; i++) {
   progress = (float)i/(float)n * 100; // Calculates progress.
   try {
    Thread.currentThread();
    Thread.sleep(2000);  
    this.setChanged();
    this.notifyObservers(progress);
   } catch (InterruptedException e) {   
    e.printStackTrace();
   }
  }  
 }
}


The progress of this class is calculated in every iteration, notifying also the observers with the change in the progress. The next class will observe the LongProcess class.

package com.gsolano.longprocess;

import java.util.Observable;
import java.util.Observer;

/**
 * Observer class
 * 
 * @author gsolano
 */
public class LongProcessObserver implements Observer{

 protected Float progress;
 /**
  * Tracks the progress of the long process.
  * @return
  */
 public Float getProgress() {
  return progress;
 }

 public void update(Observable o, Object arg) {  
  progress = (Float) arg;  
 }
}


To complete the diagram shown before, we need to create a class extending from Thread to wrap the LongProcess and be able to launch in a separate thread.

/**
 * 
 * Class to run a LongProcess in a separate thread.
 * 
 * @author gsolano
 *
 */
public class LongProcessThread extends Thread {
 
 private LongProcess longProcess;
 
 public LongProcess getLongProcess() {
  return longProcess;
 }

 public void setLongProcess(LongProcess longProcess) {
  this.longProcess = longProcess;
 }

 @Override
 public void run() {
  if(longProcess != null) {
   longProcess.start();
  }
 }
}


Now, let’s jump to the web application side. In the next struts action class we handle two events:

1.Start the long process:
  a .Long process is created.
  b. Observer is added to the long process.
  c. Long process is run in a separate thread.
  d. Observer is saved in session variable.

2.Send an update on the progress of the long process
  a. Observer is retrieved from session.
  b. Progress value is taken from observer and written to response.

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class FooProgressAction extends Action{
 
 @Override
 public ActionForward execute(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response)
   throws Exception {
  
  String action = request.getParameter("action");
  
  if(action != null) {
   if(action.equalsIgnoreCase("progress")) { // If action is ajax request to get progress.
    // Get the observer.
    LongProcessObserver longProcessObserver = (LongProcessObserver)
      request.getSession().getAttribute("observer");
    if(longProcessObserver != null) {
     // Get the progress from the observer.
     Float progress = longProcessObserver.getProgress();
     if(progress != null) {
      // Send the progress to the page.
      response.getWriter().write(progress.toString());
     }
     return null;
    }
   } else if(action.equalsIgnoreCase("start")) { // Did someone click the start button?
    launchLongProcess(request); 
   }   
  }
  return mapping.findForward("success"); 
 }

 private void launchLongProcess(HttpServletRequest request) {
  LongProcess longProcess = new LongProcess();
  LongProcessObserver observer = new LongProcessObserver();
  // Add the observer to the long process.
  longProcess.addObserver(observer);
  // Launch long process in a thread.
  LongProcessThread longProcessThread = new LongProcessThread();
  longProcessThread.setLongProcess(longProcess);
  longProcessThread.start();  
  // Keep the observer in session.
  request.getSession().setAttribute("observer", observer);
  // Send a flag indicating that party just started!
  request.setAttribute("processStarted", true);
 }
}

In the client side we just need some logic to start the Ajax cycle to ask for progress update until it reaches the 100%.

<%@ taglib uri="/WEB-INF/tld/c.tld" prefix="c" %>

<html>
<head>
 <script language="Javascript">
 var seconds = 1;  
 var run = false;
 var ajaxURL;
 
 function checkProgress(url) {
  if(typeof url != 'undefined') {
   ajaxURL = url;
  } 
    
  var xmlHttp;
  try {
   xmlHttp = new XMLHttpRequest(); // Firefox, Opera 8.0+, Safari
  } catch (e) {
   try {
    xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); // Internet Explorer
   } catch (e) {
    try {
     xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
     alert("Ajax not supported");
     return false;
    }
   }
  } 
  xmlHttp.onreadystatechange = function() {
   if (xmlHttp.readyState == 4 ) {
    var progress = xmlHttp.responseText;
    if(progress == 100.0) {
     document.getElementById('progress').innerHTML = "Finished!!"; 
     return;
    }else {
     if(progress) {
      document.getElementById('progress').innerHTML = progress + "%";
     }    
     setTimeout('checkProgress()', seconds * 1000);
    }
   }
  };
  xmlHttp.open("GET", ajaxURL, true);
  xmlHttp.send(null);
 }
 </script>
</head>
 <body>
 <div style="position: absolute; left:40%; text-align:center; border: 1px solid; margin: 20px; padding:20px; width: 150px;">
  <form action="${pageContext.request.contextPath}/longProcess.do">
   <input type="hidden" name="action" value="start" />
   <input type="submit" value="Start!" />
  </form>
  
  <div id="progress"></div>
  
  <c:if test="${not empty processStarted}">
   <script language="Javascript">
    setTimeout('checkProgress(\'${pageContext.request.contextPath}/longProcess.do?action=progress\')', 1000);
   </script>
  </c:if>
 </div>
 </body>
</html>

Result:

 

Thursday, November 1, 2012

Determining redirects when accessing an URL

Here’s a basic example on how to determine when opening a HTTP request, if the URL redirects to another one. The function of this class gets the HTTP response code from the HTTP connection, and if the code is any of the ones associated with redirection: 301/302/303, it obtains the final destination from the "Location" header.

import java.net.HttpURLConnection;
import java.net.URL;

public class URLUtils {
    /**
     * Prints the redirect URL for the provided input URL (if it applies). 
     * @param url
     */
    public static void printRedirect(String url) {
        try {
            URL urlToPing = new URL(url);
            HttpURLConnection urlConn = (HttpURLConnection) urlToPing.openConnection();
            // Needed to check if it is a redirect. 
            urlConn.setInstanceFollowRedirects(false);
            // It's any of these response codes: 301/302/303 
            if (urlConn.getResponseCode() == HttpURLConnection.HTTP_MOVED_PERM 
               || urlConn.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP 
               || urlConn.getResponseCode() == HttpURLConnection.HTTP_SEE_OTHER) {
                System.out.println("URL <" + url + "> redirects to: <" + urlConn.getHeaderField("Location") + ">, Response Code: " + +urlConn.getResponseCode());
            } else {
                System.out.println("URL <" + url + "> has no redirect, Response Code: " + urlConn.getResponseCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        URLUtils.printRedirect("http://www.google.com");
        URLUtils.printRedirect("http://www.crjug.org");
    }
} 

Result:
URL <http://www.google.com> redirects to: <http://www.google.co.cr/>, Response Code: 302
URL <http://www.crjug.org> has no redirect, Response Code: 200

Wednesday, October 31, 2012

Java: Parsing an HTML page

I wanted to share an example code showing how to parse an HTML page using the open library HTML Parser. I used this library in the past for a project where we required to extract all links of a site, and now I’m about to use it again for a project where we need to validate certain HTML coding rules. This library is simple and very straightforward to use. So let’s assume we need to find all the absolute URL’s referenced in a page. First, we create our parser class:

import java.io.IOException;
import java.net.URL;
import org.htmlparser.Node;
import org.htmlparser.Tag;
import org.htmlparser.lexer.Lexer;
import org.htmlparser.util.ParserException;

/**
 * Parses the HTML code of the page specified by it's URL.
 * @author gabriel.solano
 *
 */
public class URLHTMLParser {
 
 /*
  * Tag handler that will be used to process the tags.
  * (This could be improved by implementing an observer 
  * pattern to be able to add more than one TagHandler)
  */
 private TagHandler tagHandler;
 
 /**
  * Constructor.
  * @param tagHandler
  */
 public URLHTMLParser(TagHandler tagHandler) {
  this.tagHandler = tagHandler;
 }
 
 /**
  * Scans the specified URL.
  * @param url
  * @throws ParserException
  * @throws IOException
  */
 public void scanURL(URL url) throws ParserException, IOException {
  Lexer lexer = new Lexer(url.openConnection());
  extractHTMLNodes(lexer);
 }
 
 /**
  * Extracts the HTML nodes and lets the TagHandler to do something
  * with the tags.
  * @param lexer
  * @throws ParserException
  */
 private void extractHTMLNodes(Lexer lexer) throws ParserException {
  Node node;

  while (null != (node = lexer.nextNode(false))) {  
   if (node instanceof Tag) {
    Tag tag = (Tag) node;
    tagHandler.handleTag(tag);
   }
  }
 }
}

As you can see, the last function of this class is in charge of moving across the HTML nodes. I just let the TagHandler class to do whatever is required with the tag. This is the interface for the TagHandler:
import org.htmlparser.Tag;

/**
 * Defines the interface for a TagHandler.
 * @author gabriel.solano
 *
 */
public interface TagHandler {
 
 /**
  * Handles the process of an HTML tag.
  * @param tag
  */
 public void handleTag(Tag tag);
 
}

And here’s my implementation to handle anchor tags:

import java.util.HashSet;
import java.util.Set;

import org.htmlparser.Tag;

/**
 * Handles the event when an anchor tag is found while parsing 
 * HTML code of a page.
 * This class has a functionality to count all absolute URLs
 * found in the parsing process.
 * @author gabriel.solano
 *
 */
public class AnchorTagHandler implements TagHandler{

 private Set<String> absoluteURLs; // All URLs found.
 
 /**
  * Constructor.
  */
 public AnchorTagHandler() {
  absoluteURLs = new HashSet<String>();
 }
 
 /**
  * Gets the found absolute URLs. 
  * The collection is filled only during the scanning process
  * of an HTML page.
  * @return
  */
 public Set<String> getAbsoluteURLs() {
  return absoluteURLs;
 }
 
 /**
  * Handles the tag only if it is an anchor tag.
  */
 public void handleTag(Tag tag) {
  if (tag.getTagName().equalsIgnoreCase("a")) { 
   // Process only if it's an anchor tag.
   processTag(tag);
  }
 }

 /**
  * Processes the anchor tag. In this case 
  * adds all absolute URL's found.
  * @param tag
  */
 private void processTag(Tag tag) {
  String href = tag.getAttribute("href");
  
  if (href != null) {
   href = href.toLowerCase();   
   if (href.startsWith("http://") || href.startsWith("https://")) {
    // Add all URLs with HTTP protocol.
    absoluteURLs.add(href);
   }
  }  
 }
}
The “processTag” function simply extracts the “href” attribute and verifies if it is an absolute URL. Finally we just create a main class to run the code:
import java.net.URL;
import java.util.Set;

public class FindAbsoluteURLs {
 
 public static void main(String[] args) {
  
  AnchorTagHandler anchorTagHandler = new AnchorTagHandler();  
  URLHTMLParser htmlParser = new  URLHTMLParser(anchorTagHandler);
  
  try {
   htmlParser.scanURL(new URL("http://www.crjug.org/"));
   Set<String> urls = anchorTagHandler.getAbsoluteURLs();
   
   for(String url : urls) {
    System.out.println(url);
   }
   
  } catch (Exception e) {   
   e.printStackTrace();
  } 
 }
}
Here’s the maven dependency in case you need to use this helpful library:
<java>
<dependency>
   <groupId>org.htmlparser</groupId>
   <artifactId>htmlparser</artifactId>
   <version>1.6</version>
</dependency>
</java>

Monday, October 22, 2012

Not afraid of looking uncool

Sometimes I feel like software development world behave in certain way like fashion mode. I don’t say it because I think it is completely subject of trivial conditions like the influence of a pop star over young teenagers, but in small scale, most popular rock star frameworks tend to monopolize software engineers with recipes, sometimes to the point of thinking that anything distinct from the recipe is out fashion.

Frameworks like Struts, Spring or Hibernate are excellent tools for a lot of development efforts. The problem I think starts when a developer sets his mind to think that all projects should be implemented with the standard “fits all” recipe he uses. If someone else suggests to do something different, or just tells in a friendly conversation that he is using a different approach in an application, the framework recipe guy could look at him as the “uncool” or even mock him as the dinosaur of the team.

I've been watching the lectures from the recent Java Zone 2011 conference, and two short presentations caught my attention for their braveness to questions the “status-quo”. One exposes a different approach for dependency injection:


Dependency injection when you only have one dependency from JavaZone on Vimeo.

And the other one, which is the one that I particularly enjoy the most, is the one from this young lady where she stands firmly, and with good arguments, why she doeen’t like Hibernate.


Hibernate should be to programmers what cake mixes are to bakers: beneath their dignity. from JavaZone on Vimeo.

I’m not taking sides on these two presentations, I must confess that I need more experience to have a more informed position on the specific topics, but I truly admire these two fella for showing their out of the box approach on software development. Innovation comes frequently from setting apart from the rest.

We have a lot to learn as still young developers, and we should always be receptive to new ideas in this always changing business that is the software development world. Some ideas could be crap, but we need to have the humbleness to examine all of them to make a rational judgment on why we discard it. Let’s not be fanatic just because everyone uses a specific tool.