View Javadoc

1   package org.tinyjee.maven.dim.utils;
2   
3   import org.apache.maven.doxia.logging.Log;
4   import org.tinyjee.maven.dim.spi.Globals;
5   
6   import java.util.ArrayList;
7   import java.util.Arrays;
8   import java.util.Collection;
9   import java.util.List;
10  import java.util.regex.Pattern;
11  
12  /**
13   * Implements an array list that allows sub-list selections via regular expressions and / or selectors.
14   *
15   * @author Juergen_Kellerer, 2011-10-09
16   */
17  public class SelectableArrayList<E> extends ArrayList<E> {
18  
19  	private static final long serialVersionUID = 7547555631109691023L;
20  
21  	/**
22  	 * Defines a selector to be used when selecting a sub-list.
23  	 *
24  	 * @param <E> the type of element that the selector operates on.
25  	 */
26  	public interface Selector<E> {
27  		boolean accept(E element);
28  	}
29  
30  	public SelectableArrayList() {
31  	}
32  
33  	public SelectableArrayList(int initialCapacity) {
34  		super(initialCapacity);
35  	}
36  
37  	public SelectableArrayList(Collection<? extends E> collection) {
38  		super(collection);
39  	}
40  
41  	@Override
42  	@SuppressWarnings("unchecked")
43  	public SelectableArrayList<E> clone() {
44  		return (SelectableArrayList) super.clone();
45  	}
46  
47  	/**
48  	 * Selects a sub list of all elements that were matched by the given selector.
49  	 *
50  	 * @param selector the selector to use for matching the elements.
51  	 * @return a sub list of matched elements.
52  	 */
53  	public SelectableArrayList<E> select(Selector<E> selector) {
54  		// Using clone to copy the list to allow extending this class.
55  		SelectableArrayList<E> clone = clone();
56  
57  		// Note: clear + add should be more effective on ArrayList than iterating and removing.
58  		clone.clear();
59  		for (E e : this) {
60  			if (selector.accept(e)) clone.add(e);
61  		}
62  
63  		if (clone.isEmpty() && !isEmpty()) {
64  			Log log = Globals.getLog();
65  			log.debug("No elements were matched when selecting from " + size() + " elements by selector: " + selector);
66  		}
67  
68  		return clone;
69  	}
70  
71  	/**
72  	 * Selects all elements whose string representation matches the given regular expression.
73  	 *
74  	 * @param regularExpression the regular expression to match.
75  	 * @return A sub list of all elements that match the given regular expression.
76  	 */
77  	public SelectableArrayList<E> selectMatching(String regularExpression) {
78  		return select(createRegularExpressionSelector(regularExpression));
79  	}
80  
81  	/**
82  	 * Selects all elements whose string representation matches the one of given regular expressions.
83  	 *
84  	 * @param regularExpressions the regular expressions to match using OR.
85  	 * @return A sub list of all elements that matches one of the given regular expressions.
86  	 */
87  	@SuppressWarnings("unchecked")
88  	public SelectableArrayList<E> selectMatching(String... regularExpressions) {
89  		List<Selector<E>> selectors = new ArrayList<Selector<E>>(regularExpressions.length);
90  		for (String regularExpression : regularExpressions)
91  			selectors.add(createRegularExpressionSelector(regularExpression));
92  		return select(createOrSelector(selectors.toArray(new Selector[selectors.size()])));
93  	}
94  
95  	/**
96  	 * Selects all elements whose string representation does NOT match the given regular expression.
97  	 *
98  	 * @param regularExpression the regular expression to match.
99  	 * @return A sub list of all elements that do NOT match the given regular expression.
100 	 */
101 	public SelectableArrayList<E> selectNonMatching(String regularExpression) {
102 		return select(createInvertSelector(createRegularExpressionSelector(regularExpression)));
103 	}
104 
105 	/**
106 	 * Creates a selector that combines the given selectors with OR (accepts the element if one of the given selectors accepts it).
107 	 *
108 	 * @param selectors the selectors that match the actual content.
109 	 * @return a selector that combines the given selectors with OR.
110 	 */
111 	public Selector<E> createOrSelector(final Selector<E>... selectors) {
112 		return new Selector<E>() {
113 			public boolean accept(E element) {
114 				for (Selector<E> selector : selectors)
115 					if (selector.accept(element)) return true;
116 				return false;
117 			}
118 
119 			@Override
120 			public String toString() {
121 				return "OrSelector{" +
122 						"selectors=" + Arrays.toString(selectors) +
123 						'}';
124 			}
125 		};
126 	}
127 
128 	/**
129 	 * Creates a selector that inverts the given selector.
130 	 *
131 	 * @param other the selector to invert.
132 	 * @return a selector that inverts the given selector.
133 	 */
134 	public Selector<E> createInvertSelector(final Selector<E> other) {
135 		return new Selector<E>() {
136 			public boolean accept(E element) {
137 				return !other.accept(element);
138 			}
139 
140 			@Override
141 			public String toString() {
142 				return "InvertSelector{" +
143 						"selector=" + other +
144 						'}';
145 			}
146 		};
147 	}
148 
149 	/**
150 	 * Creates a selector that matches the given regular expression against the string representation of the element to select.
151 	 *
152 	 * @param regularExpression the regular expression to use for selecting.
153 	 * @return a selector that matches the given regular expression against the string representation of the element to select.
154 	 */
155 	public Selector<E> createRegularExpressionSelector(final String regularExpression) {
156 		return new Selector<E>() {
157 			final Pattern pattern = Pattern.compile(regularExpression);
158 
159 			public boolean accept(E element) {
160 				return pattern.matcher(String.valueOf(element)).matches();
161 			}
162 
163 			@Override
164 			public String toString() {
165 				return "RegularExpressionSelector{" +
166 						"pattern=" + pattern +
167 						'}';
168 			}
169 		};
170 	}
171 }