/* $Id$ */ /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.manifoldcf.crawler.connectors.webcrawler; import org.apache.manifoldcf.core.interfaces.*; import java.util.*; import java.util.regex.*; /** This class accumulates form data and allows overrides */ public class FormDataAccumulator implements FormData { // Note well: We don't handle multipart posts at this time!! // Element categorization protected final static int ELEMENTCATEGORY_FREEFORM = 0; protected final static int ELEMENTCATEGORY_FIXEDEXCLUSIVE = 1; protected final static int ELEMENTCATEGORY_FIXEDINCLUSIVE = 2; /** The form's action URI */ protected String actionURI; /** The form's submit method */ protected int submitMethod; /** The set of elements */ protected ArrayList elementList = new ArrayList(); public FormDataAccumulator(String actionURI, int submitMethod) { this.actionURI = actionURI; this.submitMethod = submitMethod; } public void addElement(Map attributes) { // Interpret the input tag, and make a list of the potential elements we'll want to submit String type = (String)attributes.get("type"); if (type == null) type = "text"; String name = (String)attributes.get("name"); if (name != null) { String lowerType = type.toLowerCase(Locale.ROOT); if (lowerType.equals("submit")) { String value = (String)attributes.get("value"); if (value == null) value = "Submit Form"; elementList.add(new FormItem(name,value,ELEMENTCATEGORY_FREEFORM,true)); } else if (lowerType.equals("hidden") || lowerType.equals("text") || lowerType.equals("password")) { String value = (String)attributes.get("value"); if (value == null) value = ""; elementList.add(new FormItem(name,value,ELEMENTCATEGORY_FREEFORM,true)); } else if (lowerType.equals("select")) { String value = (String)attributes.get("value"); if (value == null) value = ""; String selected = (String)attributes.get("selected"); boolean isSelected = false; if (selected != null) isSelected = true; String multiple = (String)attributes.get("multiple"); boolean isMultiple = false; if (multiple != null) isMultiple = true; elementList.add(new FormItem(name,value,isMultiple?ELEMENTCATEGORY_FIXEDINCLUSIVE:ELEMENTCATEGORY_FIXEDEXCLUSIVE,isSelected)); } else if (lowerType.equals("radio")) { String value = (String)attributes.get("value"); if (value == null) value = ""; String selected = (String)attributes.get("checked"); boolean isSelected = false; if (selected != null) isSelected = true; elementList.add(new FormItem(name,value,ELEMENTCATEGORY_FIXEDEXCLUSIVE,isSelected)); } else if (lowerType.equals("checkbox")) { String value = (String)attributes.get("value"); if (value == null) value = ""; String selected = (String)attributes.get("checked"); boolean isSelected = false; if (selected != null) isSelected = true; elementList.add(new FormItem(name,value,ELEMENTCATEGORY_FIXEDINCLUSIVE,isSelected)); } else if (lowerType.equals("textarea")) { elementList.add(new FormItem(name,"",ELEMENTCATEGORY_FREEFORM,true)); } } } public void overrideActionURI(String overrideURI) { this.actionURI = overrideURI; } public void applyOverrides(LoginParameters lp) { // This map contains the control names we have ALREADY wiped clean. Map overrideMap = new HashMap(); // Override the specified elements with the specified values int i = 0; while (i < lp.getParameterCount()) { Pattern namePattern = lp.getParameterNamePattern(i); String value = lp.getParameterValue(i); i++; // For each parameter specified, go through the element list and do the right thing. This will require us to keep some state around about // what exactly we've done to the element list so far, so that each parameter rule in turn applies properly. // // Each rule regular expression will be deemed to apply to all matching controls. If the rule matches the control name, then the precise behavior // will depend on the type of the control. // // Controls can be categorized in the following way: // - free-form value // - specified exclusive value (e.g. radio button) // - specified inclusive value (e.g. checkbox) // // For free-form values, the value given will simply override the value of the element. // For exclusive controls, all values in the family will be disabled, and the value matching the one specified will be enabled. // For inclusive controls, all values in the family will be cleared ONCE, and then subsequently the value matching the one specified will be enabled. // int j = 0; while (j < elementList.size()) { FormItem fi = (FormItem)elementList.get(j++); Matcher m = namePattern.matcher(fi.getElementName()); if (m.find()) { // Hey, it seems to apply! switch (fi.getType()) { case ELEMENTCATEGORY_FREEFORM: // Override immediately fi.setValue(value); break; case ELEMENTCATEGORY_FIXEDEXCLUSIVE: // If it doesn't match the value, disable. fi.setEnabled(fi.getElementValue().equals(value)); break; case ELEMENTCATEGORY_FIXEDINCLUSIVE: // Make sure we clear the entire control ONCE (and only once). if (overrideMap.get(fi.getElementName()) == null) { // Zip through the entire list int k = 0; while (k < elementList.size()) { FormItem fi2 = (FormItem)elementList.get(k++); if (fi2.getElementName().equals(fi.getElementName())) fi.setEnabled(false); } overrideMap.put(fi.getElementName(),fi.getElementName()); } if (fi.getElementValue().equals(value)) fi.setEnabled(true); default: break; } } } } } /** Get the full action URI for this form. */ public String getActionURI() { return actionURI; } /** Get the submit method for this form. */ public int getSubmitMethod() { return submitMethod; } /** Iterate over the active form data elements. The returned iterator returns FormDataElement objects. */ public Iterator getElementIterator() { return new FormItemIterator(elementList); } /** Iterator over FormItems */ protected static class FormItemIterator implements Iterator { protected ArrayList elementList; protected int currentIndex = 0; public FormItemIterator(ArrayList elementList) { this.elementList = elementList; } public boolean hasNext() { while (true) { if (currentIndex == elementList.size()) return false; if (((FormItem)elementList.get(currentIndex)).getEnabled() == false) currentIndex++; else break; } return true; } public Object next() { while (true) { if (currentIndex == elementList.size()) throw new NoSuchElementException("No such element"); if (((FormItem)elementList.get(currentIndex)).getEnabled() == false) currentIndex++; else break; } return elementList.get(currentIndex++); } public void remove() { throw new UnsupportedOperationException("Unsupported operation"); } } }