biz.c24.io.spring.batch.writer.C24ItemWriter.java Source code

Java tutorial

Introduction

Here is the source code for biz.c24.io.spring.batch.writer.C24ItemWriter.java

Source

/*
 * Copyright 2012 C24 Technologies.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package biz.c24.io.spring.batch.writer;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.AfterStep;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.util.Assert;

import biz.c24.io.api.data.ComplexDataObject;
import biz.c24.io.api.presentation.Sink;
import biz.c24.io.spring.batch.writer.source.WriterSource;

/**
 * ItemWriter that sinks and writes ComplexDataObjects to a Writer.
 * 
 * Allows concurrent calls to write but synchronises on individual CDO write to the writer.
 * 
 * @author Andrew Elmore
 */
public class C24ItemWriter implements ItemWriter<ComplexDataObject> {

    private Sink templateSink = null;
    private ThreadLocal<Sink> sink = new ThreadLocal<Sink>();
    private WriterSource writerSource = null;

    /**
     * Asserts that the object has been properly configured
     */
    @PostConstruct
    public void validateConfiguration() {
        Assert.notNull(templateSink, "Sink must be set");
        Assert.notNull(writerSource, "WriterSource must be set");
    }

    /**
     * Initialise our context
     * 
     * @param stepExecution The step execution context
     */
    @BeforeStep
    public void setup(StepExecution stepExecution) {
        writerSource.initialise(stepExecution);
    }

    /**
     * Clean up any resources we're consuming
     */
    @AfterStep
    public void cleanup() {
        writerSource.close();
    }

    /**
     * Writes the contents of the StringWriter to our output file
     * 
     * @param writer The StringWriter to read the data from
     */
    private void write(Sink sink) throws IOException {

        StringWriter writer = (StringWriter) sink.getWriter();

        writer.flush();

        StringBuffer buffer = writer.getBuffer();

        // Sadly StringBuffer doesn't allow us read-only access to its internal array, so we have to copy
        String element = buffer.toString();

        Writer outputWriter = writerSource.getWriter();
        synchronized (outputWriter) {
            outputWriter.write(element);
        }

        // Reset the buffer for next time
        buffer.setLength(0);

    }

    /**
     * Get a thread-safe Sink
     */
    private Sink getThreadsafeSink() {

        Sink sink = this.sink.get();

        if (sink == null) {
            // First time this thread has used a sink; create one
            sink = (Sink) templateSink.clone();
            sink.setWriter(new StringWriter());
            this.sink.set(sink);
        }

        return sink;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.batch.item.ItemWriter#write(java.util.List)
     */
    @Override
    public void write(List<? extends ComplexDataObject> items) throws Exception {

        // Get a sink to use
        Sink sink = getThreadsafeSink();

        for (ComplexDataObject cdo : items) {
            // Sink the CDO
            sink.writeObject(cdo);
        }

        // Now write the whole lot out
        write(sink);

    }

    /**
     * The prototype sink used by this C24ItemWriter
     * 
     * @return The prototype sink
     */
    public Sink getSink() {
        return templateSink;
    }

    /**
     * Provides a prototype sink for this C24ItemWriter to use when sinking ComplexDataObjects
     * 
     * @param sink The prototype sink
     */
    @Required
    public void setSink(Sink sink) {
        templateSink = sink;
    }

    /**
     * Gets the WriterSource used by this C24ItemWriter to get a Writer to persist sunk ComplexDataObjects to
     * 
     * @return The WriterSource used by this C24ItemWriter
     */
    public WriterSource getWriterSource() {
        return writerSource;
    }

    /**
     * Sets the WriterSource that this C24ItemWriter will use to get a Writer to write sunk ComplexDataObjects to
     * 
     * @param writerSource The WriterSource to use
     */
    @Required
    public void setWriterSource(WriterSource writerSource) {
        this.writerSource = writerSource;
    }

}