
org.jberet.support.io.BeanIOItemReaderWriterBase Maven / Gradle / Ivy
/*
* Copyright (c) 2014 Red Hat, Inc. and/or its affiliates.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.jberet.support.io;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.WeakHashMap;
import javax.naming.InitialContext;
import org.beanio.StreamFactory;
import org.jberet.support._private.SupportLogger;
import org.jberet.support._private.SupportMessages;
import jakarta.batch.api.BatchProperty;
import jakarta.batch.runtime.context.JobContext;
import jakarta.inject.Inject;
/**
* The base class of BeanIO-based reader and writer classes: {@link org.jberet.support.io.BeanIOItemReader} and
* {@link org.jberet.support.io.BeanIOItemWriter}.
*
* @see BeanIOItemReader
* @see BeanIOItemWriter
* @since 1.1.0
*/
public abstract class BeanIOItemReaderWriterBase extends ItemReaderWriterBase {
/**
* Name of the BeanIO stream defined in BeanIO mapping file. It corresponds to the batch job property
*/
@Inject
@BatchProperty
protected String streamName;
/**
* Location of the BeanIO mapping file, which can be a file path, a URL, or a resource loadable by the current
* class loader.
*/
@Inject
@BatchProperty
protected String streamMapping;
/**
* JNDI name for looking up {@code org.beanio.StreamFactory} when running in application server. When
* {@code streamFactoryLookup} property is specified in job xml and hence injected here, {@code org.beanio.StreamFactory}
* will be looked up with JNDI, and {@link BeanIOItemReaderWriterBase#streamMapping} and
* {@link org.jberet.support.io.BeanIOItemReaderWriterBase#mappingProperties}will be ignored.
*/
@Inject
@BatchProperty
protected String streamFactoryLookup;
/**
* User properties that can be used for property substitution in BeanIO mapping file. When used with batch job
* JSL properties, they provide dynamic BeanIO mapping attributes. For example,
*
* in batch job client class, set the properties values as comma-separated key-value pairs:
*
* {@code params.setProperty("mappingProperties", "zipCodeFieldName=zipCode, zipCodeFieldType=string");}
*
* in job xml file, make the properties available for {@link org.jberet.support.io.BeanIOItemReader} or
* {@link org.jberet.support.io.BeanIOItemWriter} via {@code @BatchProperty} injection:
*
* {@code }
*
* in BeanIO mapping file, reference the properties defined above:
*
* {@code }
*/
@Inject
@BatchProperty
protected Map mappingProperties;
/**
* The name of the character set to be used for reading and writing data, e.g., UTF-8. This property is optional,
* and if not set, the platform default charset is used.
*/
@Inject
@BatchProperty
protected String charset;
@Inject
protected JobContext jobContext;
StreamFactoryKey mappingFileKey;
private static final WeakHashMap beanIOMappings =
new WeakHashMap();
static StreamFactory getStreamFactory(final String streamFactoryLookup,
final StreamFactoryKey key,
final Map mappingProperties) throws Exception {
if (streamFactoryLookup != null) {
return InitialContext.doLookup(streamFactoryLookup);
}
synchronized (beanIOMappings) {
StreamFactory streamFactory = beanIOMappings.get(key);
if (streamFactory != null) {
return streamFactory;
}
final InputStream mappingInputStream = getInputStream(key.mappingFile, false);
if (mappingInputStream == null) {
throw SupportMessages.MESSAGES.invalidReaderWriterProperty(null, null, "streamMapping");
}
streamFactory = StreamFactory.newInstance();
try {
if (mappingProperties == null) {
streamFactory.load(mappingInputStream);
} else {
final Properties p = new Properties();
p.putAll(mappingProperties);
streamFactory.load(mappingInputStream, p);
}
} finally {
try {
mappingInputStream.close();
} catch (final IOException ioe) {
SupportLogger.LOGGER.tracef(ioe,
"exception while closing BeanIO mapping InputStream, mappingFile: %s", key.mappingFile);
}
}
beanIOMappings.put(key, streamFactory);
return streamFactory;
}
}
static class StreamFactoryKey {
private final JobContext jobContext;
private final String mappingFile;
StreamFactoryKey(final JobContext jobContext, final String mappingFile) {
this.jobContext = jobContext;
this.mappingFile = mappingFile;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("StreamFactoryKey{");
sb.append("jobContext=").append(jobContext);
sb.append(", mappingFile='").append(mappingFile).append('\'');
sb.append('}');
return sb.toString();
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final StreamFactoryKey that = (StreamFactoryKey) o;
if (jobContext != that.jobContext) return false;
if (!mappingFile.equals(that.mappingFile)) return false;
return true;
}
@Override
public int hashCode() {
int result = jobContext.hashCode();
result = 31 * result + mappingFile.hashCode();
return result;
}
}
}