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 package org.archive.crawler.settings;
26
27 import java.util.Iterator;
28 import java.util.List;
29
30 import javax.management.AttributeNotFoundException;
31 import javax.management.InvalidAttributeValueException;
32
33 import org.archive.crawler.settings.Constraint.FailedCheck;
34
35 /*** This class represents a container of settings.
36 *
37 * This class is usually used to make it possible to have a dynamic number
38 * of ModuleTypes like for instance a list of filters of different type.
39 *
40 * When this type is overridden on a per domain basis, the following
41 * restrictions apply:
42 * <ul>
43 * <li>Added elements is placed after the elements in the map it overrides.
44 * <li>You can not remove elements from the map it overrides. If it is
45 * necessary to be able to remove an element, this has to be done by
46 * adding some disable feature to the modules referenced by the map. An
47 * example of this is the enabled attribute on the
48 * {@link org.archive.crawler.framework.Filter} class.
49 * <li>All elements defined in maps that this map overrides might have their
50 * settings changed, but the order can not be changed.
51 * </ul>
52 *
53 * @author John Erik Halse
54 */
55 public class MapType extends ComplexType {
56
57 private static final long serialVersionUID = -3694800285930202700L;
58
59 /*** The content type allowed for this map. */
60 private final Type definition;
61
62 /*** Construct a new MapType object.
63 *
64 * @param name the name of this element.
65 * @param description the description of the attribute.
66 */
67 public MapType(String name, String description) {
68 this(name, description, Object.class);
69 }
70
71 /*** Construct a new MapType object.
72 *
73 * @param name the name of this element.
74 * @param description the description of the attribute.
75 * @param type the type allowed for this map
76 */
77 public MapType(String name, String description, Class type) {
78 super(name, description);
79 this.definition = new SimpleType("dummy", "dummy", null);
80 this.definition.setLegalValueType(type);
81 }
82
83 /*** Add a new element to this map.
84 *
85 * @param settings the settings object for this method to have effect.
86 * @param element the element to be added.
87 * @return Element added.
88 * @throws InvalidAttributeValueException
89 */
90 public Type addElement(CrawlerSettings settings, Type element)
91 throws InvalidAttributeValueException {
92 settings = settings == null ? globalSettings() : settings;
93
94 if (settings != globalSettings()) {
95 try {
96 getAttribute(settings, element.getName());
97
98 throw new IllegalArgumentException(
99 "Duplicate element: " + element.getName());
100
101 } catch (AttributeNotFoundException e) {
102
103 }
104 }
105
106 if (!(element instanceof MapType)) {
107 return super.addElement(settings, element);
108 } else {
109 throw new IllegalArgumentException("Nested maps are not allowed.");
110 }
111 }
112
113 /*** Remove an attribute from the map.
114 *
115 * @param settings the settings object for which this method has effect.
116 * @param name name of the attribute to remove.
117 * @return the element that was removed.
118 * @throws AttributeNotFoundException is thrown if there is no attribute
119 * with the submitted name.
120 */
121 public Object removeElement(CrawlerSettings settings, String name)
122 throws AttributeNotFoundException {
123 settings = settings == null ? globalSettings() : settings;
124 return settings.getData(this).removeElement(name);
125 }
126
127 /*** Move an attribute up one place in the list.
128 *
129 * @param settings the settings object for which this method has effect.
130 * @param name name of attribute to move.
131 * @return true if attribute was moved, false if attribute was already
132 * at the top.
133 * @throws AttributeNotFoundException is thrown if there is no attribute
134 * with the submitted name.
135 */
136 public boolean moveElementUp(CrawlerSettings settings, String name)
137 throws AttributeNotFoundException {
138 settings = settings == null ? globalSettings() : settings;
139 return settings.getData(this).moveElementUp(name);
140 }
141
142 /*** Move an attribute down one place in the list.
143 *
144 * @param settings the settings object for which this method has effect.
145 * @param name name of attribute to move.
146 * @return true if attribute was moved, false if attribute was already
147 * at bottom.
148 * @throws AttributeNotFoundException is thrown if there is no attribute
149 * with the submitted name.
150 */
151 public boolean moveElementDown(CrawlerSettings settings, String name)
152 throws AttributeNotFoundException {
153 settings = settings == null ? globalSettings() : settings;
154 return settings.getData(this).moveElementDown(name);
155 }
156
157 /*** Returns true if this map is empty.
158 *
159 * @param context the settings object for which this set of elements
160 * are valid.
161 * @return true if this map is empty.
162 */
163 public boolean isEmpty(Object context) {
164 Context ctxt = getSettingsFromObject(context);
165
166 DataContainer data = getDataContainerRecursive(ctxt);
167 while (data != null) {
168 if (data.hasAttributes()) {
169 return false;
170 }
171 ctxt.settings = data.getSettings().getParent();
172 data = getDataContainerRecursive(ctxt);
173 }
174 return true;
175 }
176
177 /*** Get the number of elements in this map.
178 *
179 * @param context the settings object for which this set of elements
180 * are valid.
181 * @return the number of elements in this map.
182 */
183 public int size(Object context) {
184 Context ctxt = getSettingsFromObject(context);
185
186 int size = 0;
187 DataContainer data = getDataContainerRecursive(ctxt);
188 while (data != null) {
189 size += data.size();
190 ctxt.settings = data.getSettings().getParent();
191 data = getDataContainerRecursive(ctxt);
192 }
193 return size;
194 }
195
196 /***
197 * Get the content type definition for attributes of this map.
198 *
199 * @param attributeName since all attributes of a map are of the same type,
200 * this value is not used.
201 * @return the content type definition for attributes of this map.
202 */
203 Type getDefinition(String attributeName) {
204 return definition;
205 }
206
207 /***
208 * Get the content type allowed for this map.
209 *
210 * @return the content type allowed for this map.
211 */
212 public Class getContentType() {
213 return this.definition.getLegalValueType();
214 }
215
216 FailedCheck checkValue(CrawlerSettings settings, String attributeName,
217 Type definition, Object value) {
218 FailedCheck res = super.checkValue(settings, attributeName, definition,
219 value);
220
221 definition = super.getDefinition(attributeName);
222
223
224 List constraints = definition != null ? definition.getConstraints()
225 : null;
226 if (constraints != null) {
227 FailedCheck ac = null;
228 for (Iterator it = constraints.iterator(); it.hasNext()
229 && ac == null;) {
230 ac = ((Constraint) it.next()).check(settings, this, definition,
231 value);
232 if (res == null
233 || ac.getLevel().intValue() >= res.getLevel()
234 .intValue()) {
235 res = ac;
236 }
237 }
238 }
239
240 return res;
241 }
242
243
244
245
246 public void addConstraint(Constraint constraint) {
247 definition.addConstraint(constraint);
248 }
249
250
251
252
253 public List getConstraints() {
254 return definition.getConstraints();
255 }
256 }