Sunday, October 6, 2013

One way to handle all the information of the programmer

Checklist

To check if you need to read this post you should have several of the following characteristics:
  • You are nearly all day at a computer
  • You manage several projects simultaneously
  • You record some pieces of code or data
  • You collect and read several documents in different formats: pdfs, docs, xlsx, etc and take notes of the main parts
  • You are subscribed to several RSS
  • You collect url links to pages that could possibly be useful in the future.

Problem

Day by day we get too much information. this is the reason why we need to arrange it to be able to handle and process it in a better way.
Taking into account that our finite resource is time; and therefore will generate many bottlenecks in the way of our professional development; we need to take control of the time that we dedicate to each of our tasks to align its use with our objectives to medium and long term.
To solve or at least alleviate this problem I developed ATaskBucket which is a desktop program that helps us to organize and handle all the information that we have.

Steps to keep organized all our information.

At the beginning we must do the following:

  1. Identify/Create the main repositories Buckets in which we can place all our tasks. These repositories must be hierarchical
  2. Identify/Create the major tasks of each bucket. Time should be set for these tasks to be executed.
  3. Each bucket/task can have associated one or more resources (files)
  4. For each task at least create the following files:
    • Notes.txt : It will contain any note related to the task.
    • Tasks.task : It will contain the small tasks that come out in the process of developing the main task.

In the day to day

  1. Use the dashboard to see the tasks assigned to be made that day. This dashboard will display the tasks that were created as:
    • asap
    • daily
    • weekly (if the day matches with the current one)
    • monthtly (if the date matches with the current one)
    • at (If it was created to be executed that current date)
  2. Before you start to perform some task click Start. This way we mark the start of the task and we can initialize the timer and keep track of the time taken to execute a task. When you need to perform another task you can click on:
    • stop (If you wish to stop the execution of the task),
    • finish (If you already finished executing the task),
    • pospone (If we want to postpone the task for another day)

Weekend review.

Check the time spent on tasks and buckets, so that we can:
  1. Know:
    • How much time we spent on each bucket
    • How much time we spent on each task
    • In which tasks we spent our time in this week
    • Our pattern of execution of tasks
  2. Set goals such as:
    • The next week I will devote more time to this bucket
    • I will avoid wasting time on this another bucket
  3. Modify the periodicity of the tasks:
    • This task should have a periodicity of daily (so that it appears in our daily dashboard)
    • This task should have a "anytime" periodicity (so that it does not appear in our dashboard, unless we add explicitly)

Tools

  1. GoTo: It allows us to show another task at any time.
  2. Full Text Search: It allows us to search in the data of the buckets, the tasks and all the resources associated with them using full text search
  3. Save information from pdfs that we are reading. For instance, we can save the page where we stayed, or the zoom with which normally we read.
  4. Feeds Reader. It allows us to subscribe to RSS and see the titles of the entries.

Cloud Friendly

The application saves all of the information in a directory; in this way if we make this directory a directory managed by DropBox, Google Drive or other similar; all of our information will be in the cloud and you can have access to it from any computer.

Example of structure

We can use the following structure :

For general tasks (B: Bucket, T:Task):

(B) General
    (T) Meals
    (T) Breaks

For reading assignments (B: Bucket, T:Task, R:Resource):

(B) Reading
    (B) General
        (T) News
        (T) Rss
    (B) Programming
        (T) Read about JQuery
            (R) Notes.txt (Here we can put some excerpts that are interesting for us)
            (R) Novice to Ninja.pdf
        (T) Read about Solr
            (R) Notes.txt

For writing assignments (B: Bucket, T:Task, R:Resource):

(B) Writing
    (B) Programming
        (B) Aplication Design
            (T) Write about DDD applied
    (B) Managment
        (T) Write about time managment
            (R) Blog Entry.md

To handle the tasks of a project (B: Bucket, T:Task, R:Resource):

(B) Project Name 
    (B) Phase I
        (T) Development
            (R) Notes.txt  (Here we can put some things that we want to remember)
            (R) Tasks.task (Here we can put the specific tasks that we are doing each day.)
        (T) Review
            (R) Notes.txt (Here we can put the observations that we found at the time of reviewing the progress of the project)
        (T) Quality Assurance
            (R) QA Report

Thursday, March 14, 2013

Springframework - Using annotations to register Custom Converters

Source Code: Example. Springframework 3.2.1.RELEASE

Problem

In order to register custom converters we have to do the following:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
     <property name="converters">
         <list>
             <!-- list of converters-->
             <bean class="org.anotes.springexample.converter.PersonToClient" />
             <bean class="org.anotes.springexample.converter.ClientToPerson" />
             ...
         </list>
     </property>
 </bean>

We want to register the converters using only some custom annotation.

Solution

We have to follow the next steps:

Create the annotation

This annotation will be used to mark the classes that are converters

package org.anotes.spring.stereotype;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface TypeConverter {

}

Create the custom BeanDefinitionRegistryPostProcessor

We need to do the following tasks: 1. Add programmatically the bean "conversionService" to the applicationContext 2. Add all the custom converters (identified by the annotation TypeConverter) to the bean "conversionService" define in the previous step.

To complete these tasks we need to create a custom BeanDefinitionRegistryPostProcessor

public class ConverterRegistryPostProcessor implements  BeanDefinitionRegistryPostProcessor, BeanPostProcessor, ApplicationContextAware {

private final String CONVERSION_SERVICE_NAME = "conversionService";

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry                    registry) throws BeansException {
    registry.registerBeanDefinition(CONVERSION_SERVICE_NAME, BeanDefinitionBuilder.rootBeanDefinition(ConversionServiceFactoryBean.class).getBeanDefinition());
}

public void postProcessBeanFactory(ConfigurableListableBeanFactory          beanFactory) throws BeansException {    
}

public Object postProcessBeforeInitialization(Object bean, String           beanName) throws BeansException {
    if (CONVERSION_SERVICE_NAME.equals(beanName)) {
        Map<String, Converter> beansOfType = appCtx.getBeansOfType(Converter.class);
        ConversionServiceFactoryBean conversionfactoryBean = (ConversionServiceFactoryBean) bean;
        Set converters = new HashSet(beansOfType.values());
        conversionfactoryBean.setConverters(converters);
    }
    return bean;
}

public Object postProcessAfterInitialization(Object bean, String            beanName) throws BeansException {
    return bean;
}

ApplicationContext appCtx;

public void setApplicationContext(ApplicationContext                        applicationContext) throws BeansException {
    appCtx = applicationContext;
}

}

In the method: "postProcessBeanDefinitionRegistry" the "conversionService" is added to the context.

In the method: "postProcessBeanFactory" we collect all the beans that have the annotation "TypeConverter" and then add all of these to the conversion service.

Take into account that as the converters are beans you can autowired other beans in these converters.

Register the PostProcessor

We have to include in the application context the post processor as bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <context:component-scan base-package="org.anotes.springexample"/>

    <bean class="org.anotes.spring.postprocessor.ConverterRegistryPostProcessor"/>

</beans>

Test

We have the following converter:

@TypeConverter
public class ClientToPerson implements Converter<Client,Person> {
    @Override
    public Person convert(Client source) {
        Person person = new Person();
        BeanUtils.copyProperties(source,person);
        return person;
    }
}

We test that the converter function properly with :

public static void main(String[] args) {
    String configFiles = "classpath*:/app-context.xml";
    ApplicationContext context = new ClassPathXmlApplicationContext(configFiles);
    Client client = createClient();
    ConversionService conversionService = (ConversionService) context.getBean("conversionService");
    Person person = conversionService.convert(client, Person.class);
    logger.info("Client:{}", client );
    logger.info("Person:{}", person );
}

And we get the following:

springexample.Main Client:Client{name='Joseph', gender='M', address='St Main Square', subscriptionDate=Thu Mar 14 20:37:29 COT 2013} [INFO ]
springexample.Main Person:Person{name='Joseph', gender='M', address='St Main Square'} [INFO ]

With the above we see that all function correctly.

Sunday, January 13, 2013

Generating Java Web Start files using Gradle

Source Code: Example.

Problem

We have a Java Swing program and we need to create the files needed to use webstart in order to execute our program.

Solution

We have to follow the next steps:

Generate the key file

Using the keytool.exe program that is in "\bin" we will generate the key using:

keytool -genkey -alias http://www.anotes.org -keystore D:/temp/anotes.keys

Next to this we have to answer all the questions; at the end the file "anotes.keys" will have been generated

We have to copy this file to: "\src\jnlp\keys"

Create the graddle tasks

We need to do the following tasks:

  • Generate the jar of the project
  • Collect all jars and copy to specific directory
  • Sign all jars
  • Generate the jnlp files
  • Create the public task that will do all the process

Generate the jar of the project

Gradle has the "jar" task to do this.

Collect all jars and copy to specific directory

We have to create the following gradle task:

task copyFiles(type: Copy, dependsOn: [jar]) {
    from configurations.runtime
    from("build/libs")
    into("webstart/lib")
    include('*.jar')
}

In essence we are copying all jars ('*.jar') from both "configurations.runtime" (all dependent jars) and "build/libs" (all project jars) to "webstart/lib"

Sign all jars

We have to create the following gradle task:

task signAll(dependsOn: [copyFiles]) << {
    new File('webstart/signed').mkdirs()
    def libFiles = files { file('webstart/lib').listFiles() }
    libFiles.each {
        ant.signjar(
                destDir: 'webstart/signed',
                alias: 'http://www.anotes.org',
                jar: it,
                keystore: 'src/jnlp/keys/anotes.keys',
                storepass: 'anotes123',
                preservelastmodified: 'true')
    }
}

This task make the following:

  • Create directory "webstart/signed"
  • Sign all files that are in "webstart/lib" and put these ones in "webstart/signed". To do the signing the file "anotes.keys" is used.

Generate the jnlp files

We have to create the following task:

task generateJnlp(dependsOn: [signAll]) << {
    File jnlpTemplateFile = new File('src/jnlp/template/template.vm')
    def root = new XmlParser().parse(jnlpTemplateFile)
    def jnlpFileName = "gradle-webstart-example-${version}.jnlp"
    // Setting values in the jnlp template
    // Setting root values
    // File CodeBase
    // root.@codebase = 'file:/'+new File('webstart/signed').absolutePath
    // Http CodeBase
    root.@codebase = 'https://dl.dropbox.com/u/24028482/jnlp/gradle-webstart-example'
    root.@href = jnlpFileName
    // Setting information values
    def information = root.information[0]
    def title = information.title[0]
    def vendor = information.vendor[0]
    title.setValue("Gradle Webstart example")
    vendor.setValue("ANotes")
    def descriptionList = information.description
    descriptionList.each {
        it.setValue("Simple example of generating webstart files using gradle")
    }
    // Setting resources
    def resource = root.resources[0]
    def j2se = resource.j2se[0]
    j2se.@version = "1.6+"
    def collection = files { file('webstart/lib').listFiles() }
    def mainJar = "gradle-webstart-example-${version}.jar"
    collection.each {
        def resourceValues = [href: it.name]
        if (mainJar == it.name) {
            resourceValues = [href: it.name, main: 'true']
        }
        resource.appendNode('jar', resourceValues)
    }
    // Setting the main class
    def applicationDesc = root.'application-desc'[0]
    applicationDesc.'@main-class' = "org.anotes.example.gradlewebstart.MainApp"
    // Writing the jnlp file filled
    File jnlpFile = new File('webstart/signed/' + jnlpFileName)
    new XmlNodePrinter(new PrintWriter(jnlpFile)).print(root)
}

This task make the following:

  • Load the jnlp template from "src/jnlp/template/template.vm" using the XmlParser; that will facilitate the operations of reading and writing of the xml.
  • Setting values in the jnlp template

    • Setting codebase. If you want to use local file system uncomment the following:

      // File CodeBase    
      //root.@codebase = 'file:/'+new File('webstart/signed').absolutePath
      

      If you want to use url reference mantain the following (change the url for your specific path):

      // Http CodeBase
      root.@codebase = 'https://dl.dropbox.com/u/24028482/jnlp/gradle-webstart-example'
      
    • Setting information values

    • Setting resources - Write all the jar names, put "main=true" to the project jar
    • Setting the main Class
  • Save the new xml to:webstart/signed/gradle-webstart-example-1.jnlp"

Create the public task that will do all the process

task generateWebStartFiles (dependsOn: [generateJnlp])<< {
    println("Generating all webstart files in:webstart/signed")
}

From the command line you have to execute the following:

gradle generateWebStartFiles

and all the webstart files will be in: "webstart/signed/"