View Javadoc
1   /*
2    * Copyright 2007 Kasper B. Graversen
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.supercsv.cellprocessor.constraint;
17  
18  import java.util.HashSet;
19  import java.util.Set;
20  
21  import org.supercsv.cellprocessor.CellProcessorAdaptor;
22  import org.supercsv.cellprocessor.ift.BoolCellProcessor;
23  import org.supercsv.cellprocessor.ift.CellProcessor;
24  import org.supercsv.cellprocessor.ift.DateCellProcessor;
25  import org.supercsv.cellprocessor.ift.DoubleCellProcessor;
26  import org.supercsv.cellprocessor.ift.LongCellProcessor;
27  import org.supercsv.cellprocessor.ift.StringCellProcessor;
28  import org.supercsv.exception.SuperCsvCellProcessorException;
29  import org.supercsv.exception.SuperCsvConstraintViolationException;
30  import org.supercsv.util.CsvContext;
31  
32  /**
33   * This processor converts the input to a String, and ensures that the input's hash function matches any of a given set
34   * of hashcodes. Lookup time is O(1).
35   * <p>
36   * This constraint is a very efficient way of ensuring constant expressions are present in certain columns of the CSV
37   * file, such as "BOSS", "EMPLOYEE", or when a column denotes an action to be taken for the input line such as "D"
38   * (delete), "I" (insert), ...
39   * <p>
40   * 
41   * @since 1.50
42   * @author Kasper B. Graversen
43   * @author James Bassett
44   */
45  public class RequireHashCode extends CellProcessorAdaptor implements BoolCellProcessor, DateCellProcessor,
46  	DoubleCellProcessor, LongCellProcessor, StringCellProcessor {
47  	
48  	private final Set<Integer> requiredHashCodes = new HashSet<Integer>();
49  	
50  	/**
51  	 * Constructs a new <tt>RequireHashCode</tt> processor, which converts the input to a String, and ensures that the
52  	 * input's hash function matches any of a given set of hashcodes.
53  	 * 
54  	 * @param requiredHashcodes
55  	 *            one or more hashcodes
56  	 * @throws NullPointerException
57  	 *             if requiredHashcodes is null
58  	 * @throws IllegalArgumentException
59  	 *             if requiredHashcodes is empty
60  	 */
61  	public RequireHashCode(final int... requiredHashcodes) {
62  		super();
63  		checkPreconditions(requiredHashcodes);
64  		for( final int hash : requiredHashcodes ) {
65  			this.requiredHashCodes.add(hash);
66  		}
67  	}
68  	
69  	/**
70  	 * Constructs a new <tt>RequireHashCode</tt> processor, which converts the input to a String, ensures that the
71  	 * input's hash function matches the supplied hashcode, then calls the next processor in the chain.
72  	 * 
73  	 * @param requiredHashcode
74  	 *            the required hashcode
75  	 * @param next
76  	 *            the next processor in the chain
77  	 * @throws NullPointerException
78  	 *             if next is null
79  	 */
80  	public RequireHashCode(final int requiredHashcode, final CellProcessor next) {
81  		this(new int[] { requiredHashcode }, next);
82  	}
83  	
84  	/**
85  	 * Constructs a new <tt>RequireHashCode</tt> processor, which converts the input to a String, ensures that the
86  	 * input's hash function matches any of a given set of hashcodes, then calls the next processor in the chain.
87  	 * 
88  	 * @param requiredHashcodes
89  	 *            one or more hashcodes
90  	 * @param next
91  	 *            the next processor in the chain
92  	 * @throws NullPointerException
93  	 *             if requiredHashcodes or next is null
94  	 * @throws IllegalArgumentException
95  	 *             if requiredHashcodes is empty
96  	 */
97  	public RequireHashCode(final int[] requiredHashcodes, final CellProcessor next) {
98  		super(next);
99  		checkPreconditions(requiredHashcodes);
100 		for( final int hash : requiredHashcodes ) {
101 			this.requiredHashCodes.add(hash);
102 		}
103 	}
104 	
105 	/**
106 	 * Checks the preconditions for creating a new RequireHashCode processor.
107 	 * 
108 	 * @param requiredHashcodes
109 	 *            the supplied hashcodes
110 	 * @throws NullPointerException
111 	 *             if requiredHashcodes is null
112 	 * @throws IllegalArgumentException
113 	 *             if requiredHashcodes is empty
114 	 */
115 	private static void checkPreconditions(final int... requiredHashcodes) {
116 		if( requiredHashcodes == null ) {
117 			throw new NullPointerException("requiredHashcodes should not be null");
118 		} else if( requiredHashcodes.length == 0 ) {
119 			throw new IllegalArgumentException("requiredHashcodes should not be empty");
120 		}
121 	}
122 	
123 	/**
124 	 * {@inheritDoc}
125 	 * 
126 	 * @throws SuperCsvCellProcessorException
127 	 *             if value is null
128 	 * @throws SuperCsvConstraintViolationException
129 	 *             if value isn't one of the required hash codes
130 	 */
131 	public Object execute(final Object value, final CsvContext context) {
132 		validateInputNotNull(value, context);
133 		
134 		int hash = value.hashCode();
135 		if( !requiredHashCodes.contains(hash) ) {
136 			throw new SuperCsvConstraintViolationException(String.format(
137 				"the hashcode of %d for value '%s' does not match any of the required hashcodes", hash, value),
138 				context, this);
139 		}
140 		
141 		return next.execute(value, context);
142 	}
143 	
144 }