View Javadoc

1   /* MapType
2    *
3    * $Id: MapType.java 4661 2006-09-25 23:11:16Z paul_jack $
4    *
5    * Created on Jan 8, 2004
6    *
7    * Copyright (C) 2004 Internet Archive.
8    *
9    * This file is part of the Heritrix web crawler (crawler.archive.org).
10   *
11   * Heritrix is free software; you can redistribute it and/or modify
12   * it under the terms of the GNU Lesser Public License as published by
13   * the Free Software Foundation; either version 2.1 of the License, or
14   * any later version.
15   *
16   * Heritrix is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU Lesser Public License for more details.
20   *
21   * You should have received a copy of the GNU Lesser Public License
22   * along with Heritrix; if not, write to the Free Software
23   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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                  // Element exist, throw an exception
98                  throw new IllegalArgumentException(
99                      "Duplicate element: " + element.getName());
100 
101             } catch (AttributeNotFoundException e) {
102                 // Element doesn't exist, ok to add
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         // Check if value fulfills any constraints
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     /* (non-Javadoc)
244      * @see org.archive.crawler.settings.Type#addConstraint(org.archive.crawler.settings.Constraint)
245      */
246     public void addConstraint(Constraint constraint) {
247         definition.addConstraint(constraint);
248     }
249 
250     /* (non-Javadoc)
251      * @see org.archive.crawler.settings.Type#getConstraints()
252      */
253     public List getConstraints() {
254         return definition.getConstraints();
255     }
256 }