public void readFunction(Element function) throws MaltChainedException {
		boolean hasSubFunctions = function.getAttribute("hasSubFunctions").equalsIgnoreCase("true");
		
		boolean hasFactory = false;
		if (function.getAttribute("hasFactory").length() > 0) {
			hasFactory = function.getAttribute("hasFactory").equalsIgnoreCase("true");
		}
		Class<?> clazz = null;
		try {
			if (PluginLoader.instance() != null) {
				clazz = PluginLoader.instance().getClass(function.getAttribute("class"));
			}
			if (clazz == null) {
				clazz = Class.forName(function.getAttribute("class"));
			}
		} catch (ClassNotFoundException e) { 
			throw new FeatureException("The feature system could not find the function class"+function.getAttribute("class")+".", e);
		}
		if (hasSubFunctions) {
			NodeList subfunctions = function.getElementsByTagName("subfunction");
			for (int i = 0; i < subfunctions.getLength(); i++) {
				readSubFunction((Element)subfunctions.item(i), clazz, hasFactory);
			}
		} else {
			int i = 0;
			String n = null;
			while (true) {
				n = function.getAttribute("name") + "~~" + i;
				if (!containsKey(n)) {
					break;
				}
				i++;
			}
			put(n, new FunctionDescription(function.getAttribute("name"), clazz, false, hasFactory));
		}
	}