File: MappingLdifReader.java

package info (click to toggle)
libspring-ldap-java 1.3.1.RELEASE-4
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 2,876 kB
  • sloc: java: 12,509; xml: 4,104; jsp: 36; makefile: 31; sh: 13
file content (162 lines) | stat: -rw-r--r-- 5,887 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package org.springframework.ldap.ldif.batch;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.ldap.core.LdapAttributes;
import org.springframework.ldap.ldif.parser.LdifParser;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
 * The {@link MappingLdifReader MappingLdifReader} is an adaptation of the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader} 
 * built around an {@link LdifParser LdifParser}.  It differs from the standard {@link LdifReader LdifReader} in its ability to map
 * {@link LdapAttributes LdapAttributes} objects to POJOs.
 * <p>
 * The {@link MappingLdifReader MappingLdifReader} <i>requires</i> an {@link RecordMapper RecordMapper} implementation. If mapping 
 * is not required, the {@link LdifReader LdifReader} should be used instead. It simply returns an {@link LdapAttributes LdapAttributes} 
 * object which can be consumed and manipulated as necessary by {@link org.springframework.batch.item.ItemProcessor ItemProcessor} or any 
 * output service. 
 * <p>
 * {@link LdifReader LdifReader} usage is mimics that of the FlatFileItemReader for all intensive purposes. Adjustments have been made to 
 * process records instead of lines, however.  As such, the {@link #recordsToSkip recordsToSkip} attribute indicates the number of records 
 * from the top of the file that should not be processed.  Implementations of the {@link RecordCallbackHandler RecordCallbackHandler} 
 * interface can be used to execute operations on those skipped records.
 * <p>
 * As with the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}, the {@link #strict strict} option 
 * differentiates between whether or not to require the resource to exist before processing.  In the case of a value set to false, a warning 
 * is logged instead of an exception being thrown.
 * 
 * @author Keith Barlow
 *
 */
public class MappingLdifReader<T> extends AbstractItemCountingItemStreamItemReader<T> 
		implements ResourceAwareItemReaderItemStream<T>, InitializingBean {

	private static final Log log = LogFactory.getLog(MappingLdifReader.class);

	private Resource resource;
	
	private LdifParser ldifParser;
	
	private int recordCount = 0;

	private int recordsToSkip = 0;

	private boolean strict = true;
	
	private RecordCallbackHandler skippedRecordsCallback;
	
	private RecordMapper<T> recordMapper;
	
	public MappingLdifReader() {
		setName(ClassUtils.getShortName(MappingLdifReader.class));
	}

	/**
	 * In strict mode the reader will throw an exception on
	 * {@link #open(org.springframework.batch.item.ExecutionContext)} if the
	 * input resource does not exist.
	 * @param strict false by default
	 */
	public void setStrict(boolean strict) {
		this.strict = strict;
	}
	
	/**
	 * {@link RecordCallbackHandler RecordCallbackHandler} implementations can be used to take action on skipped records.
	 * 
	 * @param skippedRecordsCallback will be called for each one of the initial
	 * skipped lines before any items are read.
	 */
	public void setSkippedRecordsCallback(RecordCallbackHandler skippedRecordsCallback) {
		this.skippedRecordsCallback = skippedRecordsCallback;
	}

	/**
	 * Public setter for the number of lines to skip at the start of a file. Can
	 * be used if the file contains a header without useful (column name)
	 * information, and without a comment delimiter at the beginning of the
	 * lines.
	 * 
	 * @param recordsToSkip the number of lines to skip
	 */
	public void setRecordsToSkip(int recordsToSkip) {
		this.recordsToSkip = recordsToSkip;
	}

	/**
	 * Setter for object mapper. This property is required to be set.
	 * @param recordMapper maps record to an object
	 */
	public void setRecordMapper(RecordMapper<T> recordMapper) {
		this.recordMapper = recordMapper;
	}
	
	@Override
	protected void doClose() throws Exception {
		if (ldifParser != null) {
			ldifParser.close();
		}
		this.recordCount = 0;
	}

	@Override
	protected void doOpen() throws Exception {
		if (resource == null) 
			throw new IllegalStateException("A resource has not been set.");
		
		if (!resource.exists()) {
			if (strict) {
				throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode): "+resource);
			} else {
				log.warn("Input resource does not exist " + resource.getDescription());
				return;
			}
		}
		
		ldifParser.open();
		
		for (int i = 0; i < recordsToSkip; i++) {
			LdapAttributes record = ldifParser.getRecord();
			if (skippedRecordsCallback != null) {
				skippedRecordsCallback.handleRecord(record);
			}
		}		
	}

	@Override
	protected T doRead() throws Exception {
		LdapAttributes attributes = null;
		
		try {			
			if (ldifParser != null) {
				while (attributes == null && ldifParser.hasMoreRecords()) {
					attributes = ldifParser.getRecord();
				}
				recordCount++;
				return recordMapper.mapRecord(attributes);
			}
			
			return null;
		} catch(Exception ex){
			log.error("Parsing error at record " + recordCount + " in resource=" + 
					resource.getDescription() + ", input=[" + attributes + "]", ex);
			throw ex;
		}
	}

	public void setResource(Resource resource) {
		this.resource = resource;
		this.ldifParser = new LdifParser(resource);		
	}

	public void afterPropertiesSet() throws Exception {
		Assert.notNull(resource, "A resource is required to parse.");
		Assert.notNull(ldifParser);		
	}

}