gt: 		if (implicitMapping) {
context: /*
   * jETeL/CloverETL - Java based ETL application framework.
   * Copyright (c) Javlin, a.s. (info@cloveretl.com)
   *  
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  package org.jetel.component;
  
  import java.io.Closeable;
  import java.io.File;
  import java.io.IOException;
  import java.io.Reader;
  import java.io.UnsupportedEncodingException;
  import java.io.Writer;
  import java.net.URL;
  import java.nio.channels.Channels;
  import java.nio.channels.Pipe;
  import java.nio.channels.ReadableByteChannel;
  import java.nio.charset.Charset;
  import java.util.Arrays;
  import java.util.Date;
  import java.util.HashSet;
  import java.util.Set;
  
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerConfigurationException;
  import javax.xml.transform.TransformerException;
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.TransformerFactoryConfigurationError;
  import javax.xml.transform.sax.SAXSource;
  import javax.xml.transform.stream.StreamResult;
  
  import org.apache.commons.io.IOUtils;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jetel.component.tree.reader.AbortParsingException;
  import org.jetel.component.tree.reader.DataRecordProvider;
  import org.jetel.component.tree.reader.DataRecordReceiver;
  import org.jetel.component.tree.reader.FieldFillingException;
  import org.jetel.component.tree.reader.InputAdapter;
  import org.jetel.component.tree.reader.TreeReaderParserProvider;
  import org.jetel.component.tree.reader.TreeStreamParser;
  import org.jetel.component.tree.reader.TreeXMLReaderAdaptor;
  import org.jetel.component.tree.reader.TreeXmlContentHandlerAdapter;
  import org.jetel.component.tree.reader.XPathEvaluator;
  import org.jetel.component.tree.reader.XPathPushParser;
  import org.jetel.component.tree.reader.XPathSequenceProvider;
  import org.jetel.component.tree.reader.mappping.FieldMapping;
  import org.jetel.component.tree.reader.mappping.FieldNameEncoder;
  import org.jetel.component.tree.reader.mappping.ImplicitMappingAddingVisitor;
  import org.jetel.component.tree.reader.mappping.MalformedMappingException;
  import org.jetel.component.tree.reader.mappping.MappingContext;
  import org.jetel.component.tree.reader.mappping.MappingElementFactory;
  import org.jetel.component.tree.reader.mappping.MappingVisitor;
  import org.jetel.component.tree.reader.xml.XmlXPathEvaluator;
  import org.jetel.data.DataField;
  import org.jetel.data.DataRecord;
  import org.jetel.data.DataRecordFactory;
  import org.jetel.data.Defaults;
  import org.jetel.data.sequence.Sequence;
  import org.jetel.data.sequence.SequenceFactory;
  import org.jetel.exception.AttributeNotFoundException;
  import org.jetel.exception.BadDataFormatException;
  import org.jetel.exception.ComponentNotReadyException;
  import org.jetel.exception.ConfigurationStatus;
  import org.jetel.exception.JetelException;
  import org.jetel.exception.JetelRuntimeException;
  import org.jetel.exception.PolicyType;
  import org.jetel.exception.XMLConfigurationException;
  import org.jetel.graph.Node;
  import org.jetel.graph.OutputPort;
  import org.jetel.graph.Result;
  import org.jetel.graph.TransformationGraph;
  import org.jetel.graph.runtime.CloverWorker;
  import org.jetel.graph.runtime.FutureOfRunnable;
  import org.jetel.metadata.DataFieldMetadata;
  import org.jetel.metadata.DataFieldType;
  import org.jetel.metadata.DataRecordMetadata;
  import org.jetel.sequence.PrimitiveSequence;
  import org.jetel.util.AutoFilling;
  import org.jetel.util.ExceptionUtils;
  import org.jetel.util.SourceIterator;
  import org.jetel.util.XmlUtils;
  import org.jetel.util.file.FileUtils;
  import org.jetel.util.property.ComponentXMLAttributes;
  import org.jetel.util.property.RefResFlag;
  import org.jetel.util.string.StringUtils;
  import org.w3c.dom.Document;
  import org.xml.sax.InputSource;
  import org.xml.sax.XMLReader;
  
  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  
  /**
   * @author lkrejci (info@cloveretl.com) (c) Javlin, a.s. (www.cloveretl.com)
   * 
   * @created 19 Jan 2012
   */
  public abstract class TreeReader extends Node implements DataRecordProvider, DataRecordReceiver, XPathSequenceProvider {
  
  	/**
  	 * TreeReader works in several processing modes. Chosen processing mode depends on provided
  	 * {@link TreeReaderParserProvider} and mapping complexity. The priority of modes:
  	 * <ol>
  	 * <li>{@link ProcessingMode#STREAM}</li>
  	 * <li>{@link ProcessingMode#XPATH_DIRECT}</li>
  	 * <li>{@link ProcessingMode#XPATH_CONVERT_STREAM}</li>
  	 * </ol>
  	 * 
  	 * @author krejcil (info@cloveretl.com) (c) Javlin, a.s. (www.cloveretl.com)
  	 */
  	private static enum ProcessingMode {
  		/**
  		 * #NOT IMPLEMENTED# {@link TreeReaderParserProvider} provides {@link TreeStreamParser} and mapping is simple
  		 * enough input is processed in SAX-like manner
  		 */
  		STREAM,
  		/**
  		 * {@link TreeReaderParserProvider} provides {@link XPathEvaluator} xpath expressions are evaluated directly on
  		 * input
  		 */
  		XPATH_DIRECT,
  		/**
  		 * {@link TreeReaderParserProvider} provides {@link TreeReaderParserProvider} -- input is converted to xml and
  		 * xml xpath evaluator is used to resolve xpath expressions on converted input
  		 */
  		XPATH_CONVERT_STREAM
  	}
  
  	private static final Log LOG = LogFactory.getLog(TreeReader.class);
  
  	private static final int INPUT_PORT_INDEX = 0;
  
  	// this attribute is not used at runtime right now
  	public static final String XML_SCHEMA_ATTRIBUTE = "schema";
  	protected final static String XML_FILE_URL_ATTRIBUTE = "fileURL";
  	public final static String XML_MAPPING_URL_ATTRIBUTE = "mappingURL";
  	public final static String XML_MAPPING_ATTRIBUTE = "mapping";
  	public final static String XML_DATAPOLICY_ATTRIBUTE = "dataPolicy";
  	public static final String XML_CHARSET_ATTRIBUTE = "charset";
  	public static final String XML_IMPLICIT_MAPPING_ATTRIBUTE = "implicitMapping";
  
  	protected static void readCommonAttributes(TreeReader treeReader, ComponentXMLAttributes xattribs)
  			throws XMLConfigurationException, AttributeNotFoundException {
  		treeReader.setFileURL(xattribs.getStringEx(XML_FILE_URL_ATTRIBUTE, null, RefResFlag.URL));
  		if (xattribs.exists(XML_CHARSET_ATTRIBUTE)) {
  			treeReader.setCharset(xattribs.getString(XML_CHARSET_ATTRIBUTE));
  		}
  		treeReader.setPolicyType(xattribs.getString(XML_DATAPOLICY_ATTRIBUTE, null));
  
  		String mappingURL = xattribs.getStringEx(XML_MAPPING_URL_ATTRIBUTE, null, RefResFlag.URL);
  		String mapping = xattribs.getString(XML_MAPPING_ATTRIBUTE, null);
  		if (mappingURL != null) {
  			treeReader.setMappingURL(mappingURL);
  		} else {
  			treeReader.setMappingString(mapping);
  		}
  
  		treeReader.setImplicitMapping(xattribs.getBoolean(XML_IMPLICIT_MAPPING_ATTRIBUTE, false));
  	}
  
  	// DataRecordProvider, DataRecordReceiver, XPathSequenceProvider properties
  	private DataRecord outputRecords[];
  	private OutputPort outputPorts[];
  	private boolean recordReadWithException[];
  	private String defaultSequenceId;
  	protected String fileURL;
  	protected String charset;
  	private SourceIterator sourceIterator;
  
  	private String policyTypeStr;
  	private PolicyType policyType;
  
  	private String mappingString;
  	private String mappingURL;
  	private boolean implicitMapping;
  
  	private TreeReaderParserProvider parserProvider;
  	private TreeProcessor treeProcessor;
  
  	private AutoFilling autoFilling = new AutoFilling();
  	private int[] sourcePortRecordCounters; // counters of records written to particular ports per source
  
  	private boolean errorPortLogging;
  	private DataRecord errorLogRecord;
  	private int maxErrors = -1;
  	private int errorsCount;
  	
  	public TreeReader(String id) {
  		super(id);
  	}
  
  	protected abstract TreeReaderParserProvider getTreeReaderParserProvider();
  	
  	protected FieldNameEncoder getFieldNameEncoder() {
  		// no encoding by default
  		return null;
  	}
  
  	protected ConfigurationStatus disallowEmptyCharsetOnDictionaryAndPort(ConfigurationStatus status) {
  		ConfigurationStatus configStatus = super.checkConfig(status);
  		
  		for (String fileUrlEntry : this.getFileUrl().split(";")) {
  			if ((fileUrlEntry.startsWith("dict:") || fileUrlEntry.startsWith("port:")) && charset == null) {
  				status.addError(this, null, "Charset cannot be auto-detected for input from a port or dictionary. Define it in the \"Charset\" attribute explicitly.");
  			}
  		}
  		
  		return configStatus;
  	}
  
  	
  	@Override
  	public ConfigurationStatus checkConfig(ConfigurationStatus status) {
  		super.checkConfig(status);
  		if (!checkInputPorts(status, 0, 1) || !checkOutputPorts(status, 1, Integer.MAX_VALUE)) {
  			return status;
  		}
  
  		if (!PolicyType.isPolicyType(policyTypeStr)) {
  			status.addError(this, XML_DATAPOLICY_ATTRIBUTE, "Invalid data policy: " + policyTypeStr);
  		} else {
  			policyType = PolicyType.valueOfIgnoreCase(policyTypeStr);
  		}
  
  		if (StringUtils.isEmpty(this.getFileUrl())) {
  			status.addError(this, XML_FILE_URL_ATTRIBUTE, "Missing required attribute 'File URL'");
  		}
  
  		if (StringUtils.isEmpty(mappingURL) && StringUtils.isEmpty(mappingString)) {
  			status.addError(this, null, "Missing required attribute 'Mapping'");
  		}
  
  		if (charset != null && !Charset.isSupported(charset)) {
  			status.addError(this, XML_CHARSET_ATTRIBUTE, "Charset " + charset + " not supported!");
  		}
  
  		/*
  		 * TODO validate mapping model in checkConfig with respect to port metadata i.e. that there are all fields
  		 * available and all mentioned ports are connected
  		 */
  
  		return status;
  	}
  
  	@Override
  	public void init() throws ComponentNotReadyException {
  		if (isInitialized()) {
  			return;
  		}
  		super.init();
  		
  		policyType = PolicyType.valueOfIgnoreCase(policyTypeStr);
  
  		this.parserProvider = getTreeReaderParserProvider();
  
  		recordProviderReceiverInit();
  		for (OutputPort outPort : outPortsArray) {
  			autoFilling.addAutoFillingFields(outPort.getMetadata());
  		}
  		sourcePortRecordCounters = new int[outPortsSize];
  
  		sourceIterator = createSourceIterator();
  
  		// FIXME: mapping should not be initialized here in init if is passed via external file, since it is possible
  		// that mapping file does not exist at this moment, or its content can change
  		MappingContext rootContext = createMapping();
  		
  