Wednesday, July 30, 2014

Log4j: Make a file appender that rolls the log file every time the application runs

When to Use It:

You want your log file that opens as a new file every time the application runs. The previous log file will be saved with a serial number appended to its file name.

For example,

stdout.log
stdout.log.1
stdout.log.2
...

How to Do It:

Let the code explain everything.

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Files;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.ErrorCode;

public class EveryRunRollingFileAppender extends FileAppender {

    public EveryRunRollingFileAppender() {
        super();
    }

    public EveryRunRollingFileAppender(Layout layout, String filename,
            boolean append, boolean bufferedIO, int bufferSize)
            throws IOException {
        super(layout, filename, append, bufferedIO, bufferSize);
    }

    public EveryRunRollingFileAppender(Layout layout, String filename, boolean append)
            throws IOException {
        super(layout, filename, append);
    }

    public EveryRunRollingFileAppender(Layout layout, String filename)
            throws IOException {
        super(layout, filename);
    }

    @Override
    public void activateOptions() {
        if (fileName != null) {
            try {
                rollLogFile();
                setFile(fileName, false, bufferedIO, bufferSize);
            } catch (IOException e) {
                errorHandler.error("setFile(" + fileName + "," + fileAppend
                        + ") call failed.", e, ErrorCode.FILE_OPEN_FAILURE);
            }
        } else {
            LogLog.warn("File option not set for appender [" + name + "].");
            LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
        }
    }

    private void rollLogFile() throws IOException {
        File logFile = new File(fileName);

        if (!logFile.exists()) {
            return;
        }

        String logFilenameSuffix = logFile.getName() + ".";

        File logDir = logFile.getParentFile();
        String[] logFilenames = logDir.list(new RollingFilenameFilter(logFilenameSuffix));

        long lastLogFileSeq = 0;

        for (String logFilename : logFilenames) {
            String logFileSeqName = logFilename.substring(
                    logFilename.lastIndexOf(logFilenameSuffix) + logFilenameSuffix.length());

            try {
                long logFileSeq = Long.valueOf(logFileSeqName);

                if (logFileSeq > lastLogFileSeq) {
                    lastLogFileSeq = logFileSeq;
                }
            } catch (NumberFormatException e) {
            }
        }

        StringBuilder rollingLogFilename = new StringBuilder(fileName);
        rollingLogFilename.append(".");
        rollingLogFilename.append(lastLogFileSeq + 1);

        File rollingLogFile = new File(rollingLogFilename.toString());

        Files.copy(logFile.toPath(), rollingLogFile.toPath());
    }

    private static class RollingFilenameFilter implements FilenameFilter {

        private final String logFilenameSuffix;

        RollingFilenameFilter(String logFilenameSuffix) {
            this.logFilenameSuffix = logFilenameSuffix;
        }

        @Override
        public boolean accept(File dir, String name) {
            return name.lastIndexOf(logFilenameSuffix) != -1;
        }
    }
}

How to Use It:

Set the custom appender in your log4j.properties.

log4j.appender.file=com.foo.logging.EveryRunRollingFileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-5p %d{ISO8601} [%c.%M():%L] - %m%n
log4j.appender.file.file=stdout.log

Thursday, August 09, 2012

Spring: Dynamic Import with Properties-configured Resource Path


     As we know, it's not allowed to pass properties variables in import tag in application context. So here I use a simple solution -- create a sub application context.

First, let's see what the parent application context looks like:

<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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="my.propertyPlaceholderConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:/foo/my.properties</value>
            </list>
        </property>
    </bean>

    <import resource="classpath:META-INF/foo/bundle-service.xml"/>
    
    <bean id="my.applicationContextLoader"
          class="foo.config.ApplicationContextLoader"
          init-method="initialize"
          destroy-method="close">
        <property name="propertyPlaceholder" ref="my.propertyPlaceholderConfigurer"/>
        <property name="contextLocations">
            <list>
                <value>classpath:META-INF/foo/bundle-jms-${jms.server.type}.xml</value>
                <value>classpath:META-INF/foo/bundle-jms-service.xml</value>
            </list>
        </property>
    </bean>

</beans>

You can see that in my.applicationContextLoader I can use different kinds of JMS application contexts depending on the value of jms.server.type in properties. It could be hornetq or activemq. I guess you already understand how it works now.

So let's briefly see how ApplicationContextLoader implements:

public class ApplicationContextLoader implements ApplicationContextAware {
    ...
    
    public void initialize() throws Exception {
        loadedAppContext = new GenericApplicationContext(applicationContext);

        XmlBeanDefinitionReader beanReader = null;
        beanReader = new XmlBeanDefinitionReader(loadedAppContext);

        /* only needed when those settings in spring jar are invisible, e.g. in OSGi platform 
        beanReader.setNamespaceHandlerResolver(new DefaultNamespaceHandlerResolver(
                applicationContext.getClassLoader(), YOUR_HANDLER_MAPPINGS_LOCATION));
        beanReader.setEntityResolver(new PluggableSchemaResolver(
                applicationContext.getClassLoader(), YOUR_SCHEMA_MAPPINGS_LOCATION));
        */

        for (Resource contextLocation : contextLocations) {
            beanReader.loadBeanDefinitions(contextLocation);
        }

        if (propertyPlaceholder != null) {
            propertyPlaceholder.postProcessBeanFactory(loadedAppContext.getBeanFactory());
        }

        loadedAppContext.refresh();
    }

    public void close() {
        if (loadedAppContext != null) {
            loadedAppContext.close();
        }
    }
}

That's it.

Note that remember that sub application context should avoid importing contexts in parent application context. This will cause beans being initialized twice even it's singleton.

Saturday, May 19, 2012

Java: Builder Pattern in Inheritance

When to Use:

My use case is to build one or more immutable data models that inherit the same abstract class. The data model usually has too many properties to initialize them in a constructor so it's the excellent time to use a builder pattern.

How to Do It:

You may find a couple of examples to do a builder pattern with subclasses, but here I wanna have a simple and clean implementation that aims at data models.

Let's give it a try...

Parent Class without Builder: PurchaseItem

// Take three properties for example
public abstract class PurchaseItem implements Serializable {

    private final String itemNo;
    private final String itemName;
    private final Date itemCreateDate;

    protected <T extends PurchaseItem> PurchaseItem(Builder<T> builder) {
        this.itemNo = builder.itemNo();
        this.itemName = builder.itemName();
        this.itemCreateDate = builder.itemCreateDate();
    }

    public String getItemNo() {
        return itemNo;
    }

    public String getItemName() {
        return itemName;
    }

    public Date getItemCreateDate() {
        return (itemCreateDate != null) ? new Date(itemCreateDate.getTime()) : null;
    }
    
    // omit hashCode, equals, toString, serialVersionUID...
}

Child Class without Builder: GameSubscription

// An immutable class
public final class GameSubscription extends PurchaseItem {

    private final Long duration;
    private final DurationUnit durationUnit;
    
    public enum DurationUnit {
        MONTH, UNDEFINED
    }

    private GameSubscription(Builder builder) {
        super(builder);

        this.duration = builder.duration();
        this.durationUnit = builder.durationUnit();
    }

    public Long getDuration() {
        return duration;
    }

    public DurationUnit getDurationUnit() {
        return durationUnit;
    }
    
    // omit hashCode, equals, toString, serialVersionUID...
}

I think the code is pretty self-explained. The PurchaseItem class defines a bunch of common properties used by its subclasses. However, there is no setter provided so let's see how a builder involves in...

Parent Class with Builder: PurchaseItem


public abstract class PurchaseItem implements Serializable {
    
    // omit properties, getters
    
    public static class Builder<T extends PurchaseItem> {
        private final Class<T> itemClass;

        // Declare properties to avoid complaining private access in Java 7
        private String itemNo;
        private String itemName;
        private Date itemCreateDate;

        protected Builder(Class<T> itemClass) {
            this.itemClass = itemClass;
        }

        public Builder<T> itemNo(String itemNo) {
            this.itemNo = itemNo;
            return this;
        }

        public Builder<T> itemName(String itemName) {
            this.itemName = itemName;
            return this;
        }

        public Builder<T> itemCreateDate(Date itemCreateDate) {
            if (itemCreateDate != null) {
                this.itemCreateDate = new Date(itemCreateDate.getTime());
            }
            return this;
        }

        public T build() {
            try {
                Constructor<T> constructor = null;
                constructor = itemClass.getDeclaredConstructor(getClass());
                constructor.setAccessible(true);

                return constructor.newInstance(this);

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

The parent builder provides a constructor for a generic subclass so the parent builder can set the properties belong to it. Also, the parent builder provides a build method to get the subclass.

Child Class with Builder: GameSubscription


public final class GameSubscription extends PurchaseItem {

    // omit properties, getters
    
    public static final class Builder extends PurchaseItem.Builder<GameSubscription> {

        private Long duration;
        private DurationUnit durationUnit;

        public Builder() {
            super(GameSubscription.class);
        }

        public Builder duration(Long duration) {
            this.duration = duration;
            return this;
        }

        public Builder durationUnit(DurationUnit durationUnit) {
            this.durationUnit = durationUnit;
            return this;
        }

    }
}

The subclass builder can do set properties easily. It just needs to extend the parent builder and provide a subclass type. Then it's done!

How to Use It:

The example shows how to create an immutable object from a domain object.

class FooUtils {

    public static GameSubscription toGameSubscription(com.foo.domain.GameSubscription domainSub) {
        if (domainSub == null) {
            return null;
        }

        return toPurchaseItem(new GameSubscription.Builder()
                .duration(domainSub.getDuration())
                .durationUnit(toDurationUnit(domainSub.getDurationUnit())), domainSub)
                .build();
    }


    private static <T extends PurchaseItem> PurchaseItem.Builder<T> toPurchaseItem(
            PurchaseItem.Builder<T> builder, com.foo.domain.PurchaseItem domainItem) {
        return builder
                .itemNo(domainItem.getId())
                .itemName(domainItem.getItemName())
                .itemCreateDate(copyDate(domainItem.getItemCreateDate()));
    }
}

Here I made a toPurchaseItem method to make more reusable for different subclasses. The interesting part is that the visibility of a subclass builder is different from a parent builder. So the subclass builder has to be used first; otherwise, once the parent builder is returned, you will not be able to set subclass properties.

That's it. Hope it's simple enough... :D