001: /* DataContainer
002: *
003: * $Id: DataContainer.java 4661 2006-09-25 23:11:16Z paul_jack $
004: *
005: * Created on Dec 17, 2003
006: *
007: * Copyright (C) 2003 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: */
026: package org.archive.crawler.settings;
027:
028: import java.lang.ref.Reference;
029: import java.lang.ref.WeakReference;
030: import java.util.HashMap;
031: import java.util.List;
032: import java.util.Map;
033:
034: import javax.management.AttributeNotFoundException;
035: import javax.management.InvalidAttributeValueException;
036: import javax.management.MBeanAttributeInfo;
037: import javax.management.MBeanInfo;
038:
039: import java.util.concurrent.CopyOnWriteArrayList;
040:
041: /** This class holds the data for a ComplexType for a settings object.
042: *
043: * @author John Erik Halse
044: */
045: public class DataContainer extends HashMap<String, Object> {
046:
047: private static final long serialVersionUID = 2089160108643429282L;
048:
049: /** The ComplexType for which this DataContainer keeps data */
050: private ComplexType complexType;
051:
052: /** The Settings object for which this data is valid */
053: private Reference<CrawlerSettings> settings;
054:
055: /** The attributes defined for this DataContainers combination of
056: * ComplexType and CrawlerSettings.
057: */
058: private List<MBeanAttributeInfo> attributes;
059:
060: /** All attributes that have their value set for this DataContainers
061: * combination of ComplexType and CrawlerSettings. This includes overrides.
062: */
063: private Map<String, MBeanAttributeInfo> attributeNames;
064:
065: /** Create a data container for a module.
066: *
067: * @param settings Settings to use.
068: * @param module the module to create the data container for.
069: */
070: public DataContainer(CrawlerSettings settings, ComplexType module) {
071: super ();
072: this .settings = new WeakReference<CrawlerSettings>(settings);
073: this .complexType = module;
074: attributes = new CopyOnWriteArrayList<MBeanAttributeInfo>();
075: attributeNames = new HashMap<String, MBeanAttributeInfo>();
076: }
077:
078: /** Add a new element to the data container.
079: *
080: * @param type the element to add.
081: * @param index index at which the specified element is to be inserted.
082: * @throws InvalidAttributeValueException
083: */
084: public void addElementType(Type type, int index)
085: throws InvalidAttributeValueException {
086:
087: if (attributeNames.containsKey(type.getName())) {
088: throw new IllegalArgumentException("Duplicate field: "
089: + type.getName());
090: }
091: if (type.getDefaultValue() == null) {
092: throw new InvalidAttributeValueException(
093: "null is not allowed as default value for attribute '"
094: + type.getName() + "' in class '"
095: + complexType.getClass().getName() + "'");
096: }
097: MBeanAttributeInfo attribute = new ModuleAttributeInfo(type);
098: attributes.add(index, attribute);
099: //attributeNames.put(type.getName(), attribute);
100: try {
101: put(type.getName(), attribute, type.getDefaultValue());
102: } catch (InvalidAttributeValueException e) {
103: e.printStackTrace();
104: } catch (AttributeNotFoundException e) {
105: e.printStackTrace();
106: }
107: }
108:
109: /** Appends the specified element to the end of this data container.
110: *
111: * @param type the element to add.
112: * @throws InvalidAttributeValueException
113: */
114: public void addElementType(Type type)
115: throws InvalidAttributeValueException {
116:
117: addElementType(type, attributes.size());
118: }
119:
120: public MBeanInfo getMBeanInfo() {
121: MBeanAttributeInfo attrs[] = (MBeanAttributeInfo[]) attributes
122: .toArray(new MBeanAttributeInfo[0]);
123: MBeanInfo info = new MBeanInfo(
124: complexType.getClass().getName(), complexType
125: .getDescription(), attrs, null, null, null);
126: return info;
127: }
128:
129: protected List<MBeanAttributeInfo> getLocalAttributeInfoList() {
130: return attributes;
131: }
132:
133: protected boolean hasAttributes() {
134: return !attributes.isEmpty();
135: }
136:
137: public int size() {
138: return attributes.size();
139: }
140:
141: protected MBeanAttributeInfo getAttributeInfo(String name) {
142: return (MBeanAttributeInfo) attributeNames.get(name);
143: }
144:
145: protected void copyAttributeInfo(String name,
146: DataContainer destination) {
147: if (this != destination) {
148: ModuleAttributeInfo attribute = (ModuleAttributeInfo) attributeNames
149: .get(name);
150: destination.attributeNames.put(name,
151: new ModuleAttributeInfo(attribute));
152: }
153: }
154:
155: protected boolean copyAttribute(String name,
156: DataContainer destination)
157: throws InvalidAttributeValueException,
158: AttributeNotFoundException {
159: if (this != destination) {
160: ModuleAttributeInfo attribute = (ModuleAttributeInfo) attributeNames
161: .get(name);
162:
163: if (attribute == null) {
164: return false;
165: } else {
166: int index = attributes.indexOf(attribute);
167: if (index != -1
168: && !destination.attributes.contains(attribute)) {
169: destination.attributes.add(index, attribute);
170: }
171: destination.put(attribute.getName(), attribute,
172: get(attribute.getName()));
173: }
174: }
175: return true;
176: }
177:
178: public Object put(String key, Object value) {
179: throw new UnsupportedOperationException();
180: }
181:
182: public Object get(Object key) {
183: throw new UnsupportedOperationException();
184: }
185:
186: /* (non-Javadoc)
187: * @see java.util.Map#put(java.lang.Object, java.lang.Object)
188: */
189: protected Object put(String key, MBeanAttributeInfo info,
190: Object value) throws InvalidAttributeValueException,
191: AttributeNotFoundException {
192: attributeNames.put(key, info);
193: return super .put(key, value);
194: }
195:
196: /* (non-Javadoc)
197: * @see java.util.Map#get(java.lang.Object)
198: */
199: public Object get(String key) throws AttributeNotFoundException {
200: Object res = super .get(key);
201: if (res == null && complexType.definitionMap.get(key) == null) {
202: throw new AttributeNotFoundException(key);
203: }
204: return res;
205: }
206:
207: /** Move an attribute up one place in the list.
208: *
209: * @param key name of attribute to move.
210: * @return true if attribute was moved, false if attribute was already
211: * at the top.
212: * @throws AttributeNotFoundException is thrown if there is no attribute
213: * with the submitted key.
214: */
215: protected boolean moveElementUp(String key)
216: throws AttributeNotFoundException {
217: MBeanAttributeInfo element = getAttributeInfo(key);
218: if (element == null) {
219: throw new AttributeNotFoundException(key);
220: }
221:
222: int prevIndex = attributes.indexOf(element);
223: if (prevIndex == 0) {
224: return false;
225: }
226:
227: attributes.remove(prevIndex);
228: attributes.add(prevIndex - 1, element);
229:
230: return true;
231: }
232:
233: /** Move an attribute down one place in the list.
234: *
235: * @param key name of attribute to move.
236: * @return true if attribute was moved, false if attribute was already
237: * at bottom.
238: * @throws AttributeNotFoundException is thrown if there is no attribute
239: * with the submitted key.
240: */
241: protected boolean moveElementDown(String key)
242: throws AttributeNotFoundException {
243: MBeanAttributeInfo element = getAttributeInfo(key);
244: if (element == null) {
245: throw new AttributeNotFoundException(key);
246: }
247:
248: int prevIndex = attributes.indexOf(element);
249: if (prevIndex == attributes.size() - 1) {
250: return false;
251: }
252:
253: attributes.remove(prevIndex);
254: attributes.add(prevIndex + 1, element);
255:
256: return true;
257: }
258:
259: /**
260: * Remove an attribute from the DataContainer.
261: *
262: * @param key name of the attribute to remove.
263: * @return the element that was removed.
264: * @throws AttributeNotFoundException is thrown if there is no attribute
265: * with the submitted key.
266: */
267: protected Object removeElement(String key)
268: throws AttributeNotFoundException {
269: MBeanAttributeInfo element = getAttributeInfo(key);
270: if (element == null) {
271: throw new AttributeNotFoundException(key);
272: }
273:
274: attributes.remove(element);
275: attributeNames.remove(element.getName());
276: return super .remove(element.getName());
277: }
278:
279: /** Get the ComplexType for which this DataContainer keeps data.
280: *
281: * @return the ComplexType for which this DataContainer keeps data.
282: */
283: protected ComplexType getComplexType() {
284: return complexType;
285: }
286:
287: /** Get the settings object for which this DataContainers data are valid.
288: *
289: * @return the settings object for which this DataContainers data are valid.
290: */
291: protected CrawlerSettings getSettings() {
292: return (CrawlerSettings) settings.get();
293: }
294:
295: }
|