001: /* MapType
002: *
003: * $Id: MapType.java 4661 2006-09-25 23:11:16Z paul_jack $
004: *
005: * Created on Jan 8, 2004
006: *
007: * Copyright (C) 2004 Internet Archive.
008: *
009: * This file is part of the Heritrix web crawler (crawler.archive.org).
010: *
011: * Heritrix is free software; you can redistribute it and/or modify
012: * it under the terms of the GNU Lesser Public License as published by
013: * the Free Software Foundation; either version 2.1 of the License, or
014: * any later version.
015: *
016: * Heritrix is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
019: * GNU Lesser Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser Public License
022: * along with Heritrix; if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: */
025: package org.archive.crawler.settings;
026:
027: import java.util.Iterator;
028: import java.util.List;
029:
030: import javax.management.AttributeNotFoundException;
031: import javax.management.InvalidAttributeValueException;
032:
033: import org.archive.crawler.settings.Constraint.FailedCheck;
034:
035: /** This class represents a container of settings.
036: *
037: * This class is usually used to make it possible to have a dynamic number
038: * of ModuleTypes like for instance a list of filters of different type.
039: *
040: * When this type is overridden on a per domain basis, the following
041: * restrictions apply:
042: * <ul>
043: * <li>Added elements is placed after the elements in the map it overrides.
044: * <li>You can not remove elements from the map it overrides. If it is
045: * necessary to be able to remove an element, this has to be done by
046: * adding some disable feature to the modules referenced by the map. An
047: * example of this is the enabled attribute on the
048: * {@link org.archive.crawler.framework.Filter} class.
049: * <li>All elements defined in maps that this map overrides might have their
050: * settings changed, but the order can not be changed.
051: * </ul>
052: *
053: * @author John Erik Halse
054: */
055: public class MapType extends ComplexType {
056:
057: private static final long serialVersionUID = -3694800285930202700L;
058:
059: /** The content type allowed for this map. */
060: private final Type definition;
061:
062: /** Construct a new MapType object.
063: *
064: * @param name the name of this element.
065: * @param description the description of the attribute.
066: */
067: public MapType(String name, String description) {
068: this (name, description, Object.class);
069: }
070:
071: /** Construct a new MapType object.
072: *
073: * @param name the name of this element.
074: * @param description the description of the attribute.
075: * @param type the type allowed for this map
076: */
077: public MapType(String name, String description, Class type) {
078: super (name, description);
079: this .definition = new SimpleType("dummy", "dummy", null);
080: this .definition.setLegalValueType(type);
081: }
082:
083: /** Add a new element to this map.
084: *
085: * @param settings the settings object for this method to have effect.
086: * @param element the element to be added.
087: * @return Element added.
088: * @throws InvalidAttributeValueException
089: */
090: public Type addElement(CrawlerSettings settings, Type element)
091: throws InvalidAttributeValueException {
092: settings = settings == null ? globalSettings() : settings;
093:
094: if (settings != globalSettings()) {
095: try {
096: getAttribute(settings, element.getName());
097: // Element exist, throw an exception
098: throw new IllegalArgumentException(
099: "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(
110: "Nested maps are not allowed.");
111: }
112: }
113:
114: /** Remove an attribute from the map.
115: *
116: * @param settings the settings object for which this method has effect.
117: * @param name name of the attribute to remove.
118: * @return the element that was removed.
119: * @throws AttributeNotFoundException is thrown if there is no attribute
120: * with the submitted name.
121: */
122: public Object removeElement(CrawlerSettings settings, String name)
123: throws AttributeNotFoundException {
124: settings = settings == null ? globalSettings() : settings;
125: return settings.getData(this ).removeElement(name);
126: }
127:
128: /** Move an attribute up one place in the list.
129: *
130: * @param settings the settings object for which this method has effect.
131: * @param name name of attribute to move.
132: * @return true if attribute was moved, false if attribute was already
133: * at the top.
134: * @throws AttributeNotFoundException is thrown if there is no attribute
135: * with the submitted name.
136: */
137: public boolean moveElementUp(CrawlerSettings settings, String name)
138: throws AttributeNotFoundException {
139: settings = settings == null ? globalSettings() : settings;
140: return settings.getData(this ).moveElementUp(name);
141: }
142:
143: /** Move an attribute down one place in the list.
144: *
145: * @param settings the settings object for which this method has effect.
146: * @param name name of attribute to move.
147: * @return true if attribute was moved, false if attribute was already
148: * at bottom.
149: * @throws AttributeNotFoundException is thrown if there is no attribute
150: * with the submitted name.
151: */
152: public boolean moveElementDown(CrawlerSettings settings, String name)
153: throws AttributeNotFoundException {
154: settings = settings == null ? globalSettings() : settings;
155: return settings.getData(this ).moveElementDown(name);
156: }
157:
158: /** Returns true if this map is empty.
159: *
160: * @param context the settings object for which this set of elements
161: * are valid.
162: * @return true if this map is empty.
163: */
164: public boolean isEmpty(Object context) {
165: Context ctxt = getSettingsFromObject(context);
166:
167: DataContainer data = getDataContainerRecursive(ctxt);
168: while (data != null) {
169: if (data.hasAttributes()) {
170: return false;
171: }
172: ctxt.settings = data.getSettings().getParent();
173: data = getDataContainerRecursive(ctxt);
174: }
175: return true;
176: }
177:
178: /** Get the number of elements in this map.
179: *
180: * @param context the settings object for which this set of elements
181: * are valid.
182: * @return the number of elements in this map.
183: */
184: public int size(Object context) {
185: Context ctxt = getSettingsFromObject(context);
186:
187: int size = 0;
188: DataContainer data = getDataContainerRecursive(ctxt);
189: while (data != null) {
190: size += data.size();
191: ctxt.settings = data.getSettings().getParent();
192: data = getDataContainerRecursive(ctxt);
193: }
194: return size;
195: }
196:
197: /**
198: * Get the content type definition for attributes of this map.
199: *
200: * @param attributeName since all attributes of a map are of the same type,
201: * this value is not used.
202: * @return the content type definition for attributes of this map.
203: */
204: Type getDefinition(String attributeName) {
205: return definition;
206: }
207:
208: /**
209: * Get the content type allowed for this map.
210: *
211: * @return the content type allowed for this map.
212: */
213: public Class getContentType() {
214: return this .definition.getLegalValueType();
215: }
216:
217: FailedCheck checkValue(CrawlerSettings settings,
218: String attributeName, Type definition, Object value) {
219: FailedCheck res = super .checkValue(settings, attributeName,
220: definition, value);
221:
222: definition = super .getDefinition(attributeName);
223:
224: // Check if value fulfills any constraints
225: List constraints = definition != null ? definition
226: .getConstraints() : null;
227: if (constraints != null) {
228: FailedCheck ac = null;
229: for (Iterator it = constraints.iterator(); it.hasNext()
230: && ac == null;) {
231: ac = ((Constraint) it.next()).check(settings, this ,
232: definition, value);
233: if (res == null
234: || ac.getLevel().intValue() >= res.getLevel()
235: .intValue()) {
236: res = ac;
237: }
238: }
239: }
240:
241: return res;
242: }
243:
244: /* (non-Javadoc)
245: * @see org.archive.crawler.settings.Type#addConstraint(org.archive.crawler.settings.Constraint)
246: */
247: public void addConstraint(Constraint constraint) {
248: definition.addConstraint(constraint);
249: }
250:
251: /* (non-Javadoc)
252: * @see org.archive.crawler.settings.Type#getConstraints()
253: */
254: public List getConstraints() {
255: return definition.getConstraints();
256: }
257: }
|