    1   /* DataContainer
    2    *
    3    * $Id: DataContainer.java 4661 2006-09-25 23:11:16Z paul_jack $
    4    *
    5    * Created on Dec 17, 2003
    6    *
    7    * Copyright (C) 2003 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   */
    26  package org.archive.crawler.settings;
    27
    28  import java.lang.ref.Reference;
    29  import java.lang.ref.WeakReference;
    30  import java.util.HashMap;
    31  import java.util.List;
    32  import java.util.Map;
    33
    34  import javax.management.AttributeNotFoundException;
    35  import javax.management.InvalidAttributeValueException;
    36  import javax.management.MBeanAttributeInfo;
    37  import javax.management.MBeanInfo;
    38
    39  import java.util.concurrent.CopyOnWriteArrayList;
    40
    41  /*** This class holds the data for a ComplexType for a settings object.
    42   *
    43   * @author John Erik Halse
    44   */
    45  public class DataContainer extends HashMap<String,Object> {
    46
    47      private static final long serialVersionUID = 2089160108643429282L;
    48
    49      /*** The ComplexType for which this DataContainer keeps data */
    50      private ComplexType complexType;
    51
    52      /*** The Settings object for which this data is valid */
    53      private Reference<CrawlerSettings> settings;
    54
    55      /*** The attributes defined for this DataContainers combination of
    56       * ComplexType and CrawlerSettings.
    57       */
    58      private List<MBeanAttributeInfo> attributes;
    59
    60      /*** All attributes that have their value set for this DataContainers
    61       * combination of ComplexType and CrawlerSettings. This includes overrides.
    62       */
    63      private Map<String,MBeanAttributeInfo> attributeNames;
    64
    65      /*** Create a data container for a module.
    66       *
    67       * @param settings Settings to use.
    68       * @param module the module to create the data container for.
    69       */
    70      public DataContainer(CrawlerSettings settings, ComplexType module) {
    71          super();
    72          this.settings = new WeakReference<CrawlerSettings>(settings);
    73          this.complexType = module;
    74          attributes =
    75              new CopyOnWriteArrayList<MBeanAttributeInfo>();
    76          attributeNames = new HashMap<String,MBeanAttributeInfo>();
    77      }
    78
    79      /*** Add a new element to the data container.
    80       *
    81       * @param type the element to add.
    82       * @param index index at which the specified element is to be inserted.
    83       * @throws InvalidAttributeValueException
    84       */
    85      public void addElementType(Type type, int index)
    86              throws InvalidAttributeValueException {
    87
    88          if (attributeNames.containsKey(type.getName())) {
    89              throw new IllegalArgumentException(
    90                      "Duplicate field: " + type.getName());
    91          }
    92          if (type.getDefaultValue() == null) {
    93              throw new InvalidAttributeValueException(
    94                      "null is not allowed as default value for attribute '"
    95                              + type.getName() + "' in class '"
    96                              + complexType.getClass().getName() + "'");
    97          }
    98          MBeanAttributeInfo attribute = new ModuleAttributeInfo(type);
    99          attributes.add(index, attribute);
    100         //attributeNames.put(type.getName(), attribute);
    101         try {
    102             put(type.getName(), attribute, type.getDefaultValue());
    103         } catch (InvalidAttributeValueException e) {
    104             e.printStackTrace();
    105         } catch (AttributeNotFoundException e) {
    106             e.printStackTrace();
    107         }
    108     }
    109
    110     /*** Appends the specified element to the end of this data container.
    111      *
    112      * @param type the element to add.
    113      * @throws InvalidAttributeValueException
    114      */
    115     public void addElementType(Type type) 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(complexType.getClass().getName(),
    124                 complexType.getDescription(), attrs, null, null, null);
    125         return info;
    126     }
    127
    128     protected List<MBeanAttributeInfo> getLocalAttributeInfoList() {
    129         return attributes;
    130     }
    131
    132     protected boolean hasAttributes() {
    133         return !attributes.isEmpty();
    134     }
    135
    136     public int size() {
    137         return attributes.size();
    138     }
    139
    140     protected MBeanAttributeInfo getAttributeInfo(String name) {
    141         return (MBeanAttributeInfo) attributeNames.get(name);
    142     }
    143
    144     protected void copyAttributeInfo(String name, DataContainer destination) {
    145         if (this != destination) {
    146             ModuleAttributeInfo attribute = (ModuleAttributeInfo) attributeNames.get(name);
    147             destination.attributeNames.put(name, new ModuleAttributeInfo(attribute));
    148         }
    149     }
    150
    151     protected boolean copyAttribute(String name, DataContainer destination)
    152             throws InvalidAttributeValueException, AttributeNotFoundException {
    153         if (this != destination) {
    154             ModuleAttributeInfo attribute = (ModuleAttributeInfo) attributeNames
    155                     .get(name);
    156
    157             if (attribute == null) {
    158                 return false;
    159             } else {
    160                 int index = attributes.indexOf(attribute);
    161                 if (index != -1 && !destination.attributes.contains(attribute)) {
    162                     destination.attributes.add(index, attribute);
    163                 }
    164                 destination.put(attribute.getName(), attribute, get(attribute
    165                         .getName()));
    166             }
    167         }
    168         return true;
    169     }
    170
    171     public Object put(String key, Object value) {
    172         throw new UnsupportedOperationException();
    173     }
    174
    175     public Object get(Object key) {
    176         throw new UnsupportedOperationException();
    177     }
    178
    179     /* (non-Javadoc)
    180      * @see java.util.Map#put(java.lang.Object, java.lang.Object)
    181      */
    182     protected Object put(String key, MBeanAttributeInfo info, Object value)
    183         throws InvalidAttributeValueException, AttributeNotFoundException {
    184         attributeNames.put(key, info);
    185         return super.put(key, value);
    186     }
    187
    188     /* (non-Javadoc)
    189      * @see java.util.Map#get(java.lang.Object)
    190      */
    191     public Object get(String key) throws AttributeNotFoundException {
    192         Object res = super.get(key);
    193         if (res == null && complexType.definitionMap.get(key) == null) {
    194             throw new AttributeNotFoundException(key);
    195         }
    196         return res;
    197     }
    198
    199     /*** Move an attribute up one place in the list.
    200      *
    201      * @param key name of attribute to move.
    202      * @return true if attribute was moved, false if attribute was already
    203      *              at the top.
    204      * @throws AttributeNotFoundException is thrown if there is no attribute
    205      *         with the submitted key.
    206      */
    207     protected boolean moveElementUp(String key)
    208             throws AttributeNotFoundException {
    209         MBeanAttributeInfo element = getAttributeInfo(key);
    210         if (element == null) {
    211             throw new AttributeNotFoundException(key);
    212         }
    213
    214         int prevIndex = attributes.indexOf(element);
    215         if (prevIndex == 0) {
    216             return false;
    217         }
    218
    219         attributes.remove(prevIndex);
    220         attributes.add(prevIndex-1, element);
    221
    222         return true;
    223     }
    224
    225     /*** Move an attribute down one place in the list.
    226      *
    227      * @param key name of attribute to move.
    228      * @return true if attribute was moved, false if attribute was already
    229      *              at bottom.
    230      * @throws AttributeNotFoundException is thrown if there is no attribute
    231      *         with the submitted key.
    232      */
    233     protected boolean moveElementDown(String key)
    234             throws AttributeNotFoundException {
    235         MBeanAttributeInfo element = getAttributeInfo(key);
    236         if (element == null) { throw new AttributeNotFoundException(key); }
    237
    238         int prevIndex = attributes.indexOf(element);
    239         if (prevIndex == attributes.size() - 1) { return false; }
    240
    241         attributes.remove(prevIndex);
    242         attributes.add(prevIndex + 1, element);
    243
    244         return true;
    245     }
    246
    247     /***
    248      * Remove an attribute from the DataContainer.
    249      *
    250      * @param key name of the attribute to remove.
    251      * @return the element that was removed.
    252      * @throws AttributeNotFoundException is thrown if there is no attribute
    253      *             with the submitted key.
    254      */
    255     protected Object removeElement(String key) throws AttributeNotFoundException {
    256         MBeanAttributeInfo element = getAttributeInfo(key);
    257         if (element == null) {
    258             throw new AttributeNotFoundException(key);
    259         }
    260
    261         attributes.remove(element);
    262         attributeNames.remove(element.getName());
    263         return super.remove(element.getName());
    264     }
    265
    266     /*** Get the ComplexType for which this DataContainer keeps data.
    267      *
    268      * @return the ComplexType for which this DataContainer keeps data.
    269      */
    270     protected ComplexType getComplexType() {
    271         return complexType;
    272     }
    273
    274     /*** Get the settings object for which this DataContainers data are valid.
    275      *
    276      * @return the settings object for which this DataContainers data are valid.
    277      */
    278     protected CrawlerSettings getSettings() {
    279         return (CrawlerSettings) settings.get();
    280     }
    281
    282 }