1 25 package org.archive.crawler.settings; 26 27 import java.util.ArrayList ; 28 import java.util.HashMap ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.Stack ; 33 import java.util.logging.Level ; 34 import java.util.logging.Logger ; 35 36 import javax.management.Attribute ; 37 import javax.management.AttributeList ; 38 import javax.management.AttributeNotFoundException ; 39 import javax.management.DynamicMBean ; 40 import javax.management.InvalidAttributeValueException ; 41 import javax.management.MBeanAttributeInfo ; 42 import javax.management.MBeanException ; 43 import javax.management.MBeanInfo ; 44 import javax.management.ReflectionException ; 45 46 import org.apache.commons.httpclient.URIException; 47 import org.archive.crawler.datamodel.CandidateURI; 48 import org.archive.crawler.datamodel.CrawlOrder; 49 import org.archive.crawler.datamodel.CrawlURI; 50 import org.archive.crawler.settings.Constraint.FailedCheck; 51 import org.archive.net.UURI; 52 53 71 public abstract class ComplexType extends Type implements DynamicMBean { 72 private static Logger logger = 73 Logger.getLogger("org.archive.crawler.settings.ComplexType"); 74 75 private transient SettingsHandler settingsHandler; 76 private transient ComplexType parent; 77 private String description; 78 private String absoluteName; 79 private final List <Type> definition = new ArrayList <Type>(); 80 protected final Map <String ,Type> definitionMap = new HashMap <String ,Type>(); 81 private boolean initialized = false; 82 private String [] preservedFields = new String [0]; 83 84 88 private ComplexType() { 89 super(null, null); 90 } 91 92 97 public ComplexType(String name, String description) { 98 super(name, null); 99 this.description = description.intern(); 100 } 101 102 protected void setAsOrder(SettingsHandler settingsHandler) 103 throws InvalidAttributeValueException { 104 this.settingsHandler = settingsHandler; 105 this.absoluteName = ""; 106 globalSettings().addTopLevelModule((CrawlOrder) this); 107 addComplexType(settingsHandler.getSettingsObject(null), this); 108 this.parent = null; 109 } 110 111 115 public CrawlerSettings globalSettings() { 116 if (settingsHandler == null) { 117 return null; 118 } 119 return settingsHandler.getSettingsObject(null); 120 } 121 122 public Type addElement(CrawlerSettings settings, Type type) 123 throws InvalidAttributeValueException { 124 getOrCreateDataContainer(settings).addElementType(type); 125 if (type instanceof ComplexType) { 126 addComplexType(settings, (ComplexType) type); 127 } 128 return type; 129 } 130 131 private ComplexType addComplexType(CrawlerSettings settings, 132 ComplexType object) throws InvalidAttributeValueException { 133 134 if (this.settingsHandler == null) { 135 throw new IllegalStateException ("Can't add ComplexType to 'free' ComplexType"); 136 } 137 setupVariables(object); 138 settings.addComplexType(object); 139 if (!object.initialized) { 140 Iterator it = object.definition.iterator(); 141 while (it.hasNext()) { 142 Type t = (Type) it.next(); 143 object.addElement(settings, t); 144 } 145 object.earlyInitialize(settings); 146 } 147 object.initialized = true; 148 149 return object; 150 } 151 152 private ComplexType replaceComplexType(CrawlerSettings settings, 153 ComplexType object) throws InvalidAttributeValueException , 154 AttributeNotFoundException { 155 if (this.settingsHandler == null) { 156 throw new IllegalStateException ( 157 "Can't add ComplexType to 'free' ComplexType"); 158 } 159 String [] preservedFields = object.getPreservedFields(); 160 161 setupVariables(object); 162 163 DataContainer oldData = settings.getData(object); 164 settings.addComplexType(object); 165 DataContainer newData = settings.getData(object); 166 167 if (!object.initialized) { 168 Iterator it = object.definition.iterator(); 169 while (it.hasNext()) { 170 Type t = (Type) it.next(); 171 172 boolean found = false; 174 if (preservedFields.length > 0) { 175 for (int i = 0; i < preservedFields.length; i++) { 176 if (preservedFields[i].equals(t.getName())) { 177 found = true; 178 break; 179 } 180 } 181 } 182 if (found && oldData.copyAttribute(t.getName(), newData)) { 183 if (t instanceof ComplexType) { 184 object.setupVariables((ComplexType) t); 185 } 186 } else { 187 object.addElement(settings, t); 188 } 189 } 190 object.earlyInitialize(settings); 191 } 192 object.initialized = true; 193 194 return object; 195 } 196 197 202 protected void setPreservedFields(String [] preservedFields) { 203 this.preservedFields = preservedFields; 204 } 205 206 211 protected String [] getPreservedFields() { 212 return this.preservedFields; 213 } 214 215 228 protected DataContainer getDataContainerRecursive(Context context) { 229 if (context.settings == null) { 230 return null; 231 } 232 DataContainer data = context.settings.getData(this); 233 if (data == null && context.settings.getParent(context.uri) != null) { 234 context.settings = context.settings.getParent(context.uri); 235 data = getDataContainerRecursive(context); 236 } 237 return data; 238 } 239 240 256 protected DataContainer getDataContainerRecursive(Context context, 257 String key) throws AttributeNotFoundException { 258 Context c = new Context(context.settings, context.uri); 259 DataContainer data = getDataContainerRecursive(c); 260 while (data != null) { 261 if (data.containsKey(key)) { 262 return data; 263 } 264 c.settings = data.getSettings().getParent(c.uri); 265 data = getDataContainerRecursive(c); 266 } 267 throw new AttributeNotFoundException (key); 268 } 269 270 277 private void setupVariables(ComplexType object) { 278 object.parent = this; 279 object.settingsHandler = getSettingsHandler(); 280 object.absoluteName = 281 (getAbsoluteName() + '/' + object.getName()).intern(); 282 } 283 284 public SettingsHandler getSettingsHandler() { 285 return settingsHandler; 286 } 287 288 294 public String getAbsoluteName() { 295 return absoluteName; 296 } 297 298 316 Context getSettingsFromObject(Object o, String attributeName) { 317 Context context; 318 if (o == null) { 319 context = null; 320 } else if (o instanceof Context) { 321 context = (Context) o; 322 } else if (o instanceof CrawlerSettings) { 323 context = new Context((CrawlerSettings) o, null); 324 } else if (o instanceof UURI || o instanceof CandidateURI) { 325 context = new Context(); 328 context.uri = (o instanceof CandidateURI)? 329 ((CandidateURI) o).getUURI(): (UURI)o; 330 try { 331 context.settings = getSettingsHandler(). 332 getSettings(context.uri.getReferencedHost(), 333 context.uri); 334 } 335 catch (URIException e1) { 336 logger.severe("Failed to get host"); 337 } 338 339 if (attributeName != null) { 340 try { 341 context.settings = 342 getDataContainerRecursive(context, attributeName). 343 getSettings(); 344 } catch (AttributeNotFoundException e) { 345 } 347 } 348 } else { 349 logger.warning("Unknown object type: " + 350 o.getClass().getName()); 351 context = null; 352 } 353 354 if (context == null) { 356 context = new Context(globalSettings(), null); 357 } 358 return context; 359 } 360 361 370 Context getSettingsFromObject(Object o) { 371 return getSettingsFromObject(o, null); 372 } 373 374 382 public boolean isOverridden(CrawlerSettings settings, String name) 383 throws AttributeNotFoundException { 384 settings = settings == null ? globalSettings() : settings; 385 DataContainer data = settings.getData(this); 386 if (data == null || !data.containsKey(name)) { 387 return false; 388 } 389 390 Context context = new Context(settings.getParent(), null); 392 getDataContainerRecursive(context, name); 393 return true; 394 } 395 396 407 public Object getAttribute(String name) 408 throws AttributeNotFoundException , MBeanException , ReflectionException { 409 return getAttribute(null, name); 410 } 411 412 427 public Object getAttribute(String name, CrawlURI uri) 428 throws AttributeNotFoundException { 429 return getAttribute(uri, name); 430 } 431 432 447 public Object getAttribute(Object context, String name) 448 throws AttributeNotFoundException { 449 Context ctxt = getSettingsFromObject(context); 450 451 if (ctxt.settings == null) { 453 try { 454 return ((Type) definitionMap.get(name)).getDefaultValue(); 455 } catch (NullPointerException e) { 456 throw new AttributeNotFoundException ( 457 "Could not find attribute: " + name); 458 } 459 } 460 461 return getDataContainerRecursive(ctxt, name).get(name); 462 } 463 464 487 public Object getUncheckedAttribute(Object context, String name) { 488 try { 489 return getAttribute(context, name); 490 } catch (AttributeNotFoundException e) { 491 throw new IllegalArgumentException ("Was passed '" + name + 492 "' and got this exception: " + e); 493 } 494 } 495 496 510 public Object getLocalAttribute(CrawlerSettings settings, String name) 511 throws AttributeNotFoundException { 512 513 settings = settings == null ? globalSettings() : settings; 514 515 DataContainer data = settings.getData(this); 516 if (data != null && data.containsKey(name)) { 517 return data.get(name); 519 } 520 Context context = new Context(settings, null); 522 getDataContainerRecursive(context, name); 523 return null; 524 } 525 526 544 public synchronized final void setAttribute(Attribute attribute) 545 throws 546 AttributeNotFoundException , 547 InvalidAttributeValueException , 548 MBeanException , 549 ReflectionException { 550 setAttribute(settingsHandler.getSettingsObject(null), attribute); 551 } 552 553 568 public synchronized final void setAttribute(CrawlerSettings settings, 569 Attribute attribute) throws InvalidAttributeValueException , 570 AttributeNotFoundException { 571 572 if(settings==null){ 573 settings = globalSettings(); 574 } 575 576 DataContainer data = getOrCreateDataContainer(settings); 577 Object value = attribute.getValue(); 578 579 ModuleAttributeInfo attrInfo = (ModuleAttributeInfo) getAttributeInfo( 580 settings.getParent(), attribute.getName()); 581 582 ModuleAttributeInfo localAttrInfo = (ModuleAttributeInfo) data 583 .getAttributeInfo(attribute.getName()); 584 585 if (attrInfo == null && localAttrInfo == null) { 587 throw new AttributeNotFoundException (attribute.getName()); 588 } 589 590 if (localAttrInfo == null) { 592 if (!attrInfo.isOverrideable()) { 593 throw new InvalidAttributeValueException ( 594 "Attribute not overrideable: " + attribute.getName()); 595 } 596 localAttrInfo = new ModuleAttributeInfo(attrInfo); 597 } 598 599 Class typeClass = getDefinition(attribute.getName()).getLegalValueType(); 602 if (!(typeClass.isInstance(value)) && value instanceof String ) { 603 try { 604 value = SettingsHandler.StringToType((String ) value, 605 SettingsHandler.getTypeName(typeClass.getName())); 606 } catch (ClassCastException e) { 607 throw new InvalidAttributeValueException ( 608 "Unable to decode string '" + value + "' into type '" 609 + typeClass.getName() + "'"); 610 } 611 } 612 613 FailedCheck error = checkValue(settings, attribute.getName(), value); 615 if (error != null) { 616 if (error.getLevel() == Level.SEVERE) { 617 throw new InvalidAttributeValueException (error.getMessage()); 618 } else if (error.getLevel() == Level.WARNING) { 619 if (!getSettingsHandler().fireValueErrorHandlers(error)) { 620 throw new InvalidAttributeValueException (error.getMessage()); 621 } 622 } else { 623 getSettingsHandler().fireValueErrorHandlers(error); 624 } 625 } 626 627 localAttrInfo.setType(value); 629 Object oldValue = data.put(attribute.getName(), localAttrInfo, value); 630 631 if (value instanceof ComplexType && value != oldValue) { 634 ComplexType complex = (ComplexType) value; 635 replaceComplexType(settings, complex); 636 } 637 } 638 639 645 Type getDefinition(String attributeName) { 646 return (Type) definitionMap.get(attributeName); 647 } 648 649 660 public FailedCheck checkValue(CrawlerSettings settings, 661 String attributeName, Object value) { 662 return checkValue(settings, attributeName, 663 getDefinition(attributeName), value); 664 } 665 666 FailedCheck checkValue(CrawlerSettings settings, String attributeName, 667 Type definition, Object value) { 668 FailedCheck res = null; 669 670 List constraints = definition.getConstraints(); 672 if (constraints != null) { 673 for (Iterator it = constraints.iterator(); it.hasNext() 674 && res == null;) { 675 res = ((Constraint) it.next()).check(settings, this, 676 definition, value); 677 } 678 } 679 680 return res; 681 } 682 683 694 public Object unsetAttribute(CrawlerSettings settings, String name) 695 throws AttributeNotFoundException { 696 697 if (settings == globalSettings()) { 698 throw new IllegalArgumentException ( 699 "Not allowed to unset attributes in Crawl Order."); 700 } 701 702 DataContainer data = settings.getData(this); 703 if (data != null && data.containsKey(name)) { 704 return data.removeElement(name); 706 } 707 708 Context context = new Context(settings, null); 711 getDataContainerRecursive(context, name); 712 return null; 713 } 714 715 private DataContainer getOrCreateDataContainer(CrawlerSettings settings) 716 throws InvalidAttributeValueException { 717 718 DataContainer data = settings.getData(this); 720 721 if (data == null) { 723 ComplexType parent = getParent(); 724 if (parent == null) { 725 settings.addTopLevelModule((ModuleType) this); 726 } else { 727 DataContainer parentData = 728 settings.getData(parent); 729 if (parentData == null) { 730 if (this instanceof ModuleType) { 731 settings.addTopLevelModule((ModuleType) this); 732 } else { 733 settings.addTopLevelModule((ModuleType) parent); 734 try { 735 parent.setAttribute(settings, this); 736 } catch (AttributeNotFoundException e) { 737 logger.severe(e.getMessage()); 738 } 739 } 740 } else { 741 globalSettings().getData(parent).copyAttributeInfo( 742 getName(), 743 parentData); 744 } 745 } 746 747 data = settings.addComplexType(this); 749 } 750 751 if (data.getComplexType() != this) { 753 if (this instanceof ModuleType) { 754 data = settings.addComplexType(this); 755 } 756 } 757 return data; 758 } 759 760 763 public AttributeList getAttributes(String [] name) { 764 return null; 765 } 766 767 770 public AttributeList setAttributes(AttributeList attributes) { 771 return null; 772 } 773 774 777 public Object invoke(String arg0, Object [] arg1, String [] arg2) 778 throws MBeanException , ReflectionException { 779 throw new ReflectionException ( 780 new NoSuchMethodException ("No methods to invoke.")); 781 } 782 783 786 public MBeanInfo getMBeanInfo() { 787 return getMBeanInfo(globalSettings()); 788 } 789 790 public MBeanInfo getMBeanInfo(Object context) { 791 MBeanAttributeInfoIterator it = getAttributeInfoIterator(context); 792 MBeanAttributeInfo [] attributes = new MBeanAttributeInfo [it.size()]; 793 int index = 0; 794 while(it.hasNext()) { 795 attributes[index++] = (MBeanAttributeInfo ) it.next(); 796 } 797 798 MBeanInfo info = 799 new MBeanInfo (getClass().getName(), getDescription(), attributes, 800 null, null, null); 801 return info; 802 } 803 804 812 public MBeanAttributeInfo getAttributeInfo(CrawlerSettings settings, 813 String name) { 814 815 MBeanAttributeInfo info = null; 816 817 Context context = new Context(settings, null); 818 DataContainer data = getDataContainerRecursive(context); 819 while (data != null && info == null) { 820 info = data.getAttributeInfo(name); 821 if (info == null) { 822 context.settings = data.getSettings().getParent(); 823 data = getDataContainerRecursive(context); 824 } 825 } 826 827 return info; 828 } 829 830 836 public MBeanAttributeInfo getAttributeInfo(String name) { 837 return getAttributeInfo(globalSettings(), name); 838 } 839 840 846 public String getDescription() { 847 return description; 848 } 849 850 854 public ComplexType getParent() { 855 return parent; 856 } 857 858 864 public void setDescription(String string) { 865 description = string; 866 } 867 868 871 public Object getDefaultValue() { 872 return this; 873 } 874 875 884 public Type addElementToDefinition(Type type) { 885 if (isInitialized()) { 886 throw new IllegalStateException ( 887 "Elements should only be added to definition in the " + 888 "constructor."); 889 } 890 if (definitionMap.containsKey(type.getName())) { 891 definition.remove(definitionMap.remove(type.getName())); 892 } 893 894 definition.add(type); 895 definitionMap.put(type.getName(), type); 896 return type; 897 } 898 899 908 public Type getElementFromDefinition(String name) { 909 if (isInitialized()) { 910 throw new IllegalStateException ( 911 "Elements definition can only be accessed in the " + 912 "constructor."); 913 } 914 return (Type) definitionMap.get(name); 915 } 916 917 928 public void earlyInitialize(CrawlerSettings settings) { 929 } 930 931 935 public boolean isInitialized() { 936 return initialized; 937 } 938 939 public Object [] getLegalValues() { 940 return null; 941 } 942 943 951 public Object getValue() { 952 return this; 953 } 954 955 class Context { 956 CrawlerSettings settings; 957 UURI uri; 958 959 Context() { 960 settings = null; 961 uri = null; 962 } 963 964 Context(CrawlerSettings settings, UURI uri) { 965 this.settings = settings; 966 this.uri = uri; 967 } 968 } 969 970 975 public Iterator iterator(Object context) { 976 return new AttributeIterator(context); 977 } 978 979 984 public MBeanAttributeInfoIterator getAttributeInfoIterator(Object context) { 985 return new MBeanAttributeInfoIterator(context); 986 } 987 988 993 private class AttributeIterator implements Iterator { 994 private Context context; 995 private Stack <Iterator <MBeanAttributeInfo >> attributeStack 996 = new Stack <Iterator <MBeanAttributeInfo >>(); 997 private Iterator currentIterator; 998 999 public AttributeIterator(Object ctxt) { 1000 this.context = getSettingsFromObject(ctxt); 1001 Context c = new Context(context.settings, context.uri); 1002 DataContainer data = getDataContainerRecursive(c); 1003 while (data != null) { 1004 this.attributeStack.push(data.getLocalAttributeInfoList(). 1005 iterator()); 1006 c.settings = data.getSettings().getParent(); 1007 data = getDataContainerRecursive(c); 1008 } 1009 1010 this.currentIterator = (Iterator ) this.attributeStack.pop(); 1011 } 1012 1013 public boolean hasNext() { 1014 if (this.currentIterator.hasNext()) { 1015 return true; 1016 } 1017 if (this.attributeStack.isEmpty()) { 1018 return false; 1019 } 1020 this.currentIterator = (Iterator ) this.attributeStack.pop(); 1021 return this.currentIterator.hasNext(); 1022 } 1023 1024 public Object next() { 1025 hasNext(); 1026 try { 1027 MBeanAttributeInfo attInfo = (MBeanAttributeInfo ) this.currentIterator.next(); 1028 Object attr = getAttribute(this.context, attInfo.getName()); 1029 if (!(attr instanceof Attribute )) { 1030 attr = new Attribute (attInfo.getName(), attr); 1031 } 1032 return attr; 1033 } catch (AttributeNotFoundException e) { 1034 e.printStackTrace(); 1036 return null; 1037 } 1038 } 1039 1040 public void remove() { 1041 throw new UnsupportedOperationException (); 1042 } 1043 } 1044 1045 1050 public class MBeanAttributeInfoIterator implements Iterator { 1051 private Context context; 1052 private Stack <Iterator <MBeanAttributeInfo >> attributeStack 1053 = new Stack <Iterator <MBeanAttributeInfo >>(); 1054 private Iterator currentIterator; 1055 private int attributeCount = 0; 1056 1057 public MBeanAttributeInfoIterator(Object ctxt) { 1058 this.context = getSettingsFromObject(ctxt); 1059 DataContainer data = getDataContainerRecursive(context); 1062 while (data != null) { 1063 attributeStack.push(data.getLocalAttributeInfoList().iterator()); 1064 attributeCount += data.getLocalAttributeInfoList().size(); 1065 context.settings = data.getSettings().getParent(); 1066 data = getDataContainerRecursive(context); 1067 } 1068 1069 this.currentIterator = (Iterator ) this.attributeStack.pop(); 1070 } 1071 1072 public boolean hasNext() { 1073 if (this.currentIterator.hasNext()) { 1074 return true; 1075 } 1076 if (this.attributeStack.isEmpty()) { 1077 return false; 1078 } 1079 this.currentIterator = (Iterator )this.attributeStack.pop(); 1080 return this.currentIterator.hasNext(); 1081 } 1082 1083 public Object next() { 1084 hasNext(); 1085 MBeanAttributeInfo attInfo = (MBeanAttributeInfo ) this.currentIterator.next(); 1086 return attInfo; 1087 } 1088 1089 public void remove() { 1090 throw new UnsupportedOperationException (); 1091 } 1092 1093 public int size() { 1094 return attributeCount; 1095 } 1096 } 1097 1098 @Override 1099 public String toString() { 1100 return getName() + ": " + 1105 getClass().getName() + "@" + Integer.toHexString(hashCode()); 1106 } 1107} | Popular Tags |