org.apache.geode.internal.cache.xmlcache.CacheXmlParser.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.geode.internal.cache.xmlcache.CacheXmlParser.java

Source

/*
 * 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.geode.internal.cache.xmlcache;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.Stack;
import java.util.StringTokenizer;

import javax.xml.XMLConstants;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.geode.cache.util.GatewayConflictResolver;
import org.apache.logging.log4j.Logger;
import org.apache.commons.lang.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.DefaultHandler2;

import org.apache.geode.DataSerializable;
import org.apache.geode.DataSerializer;
import org.apache.geode.InternalGemFireException;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.CacheLoader;
import org.apache.geode.cache.CacheWriter;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.CacheXmlException;
import org.apache.geode.cache.CustomExpiry;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Declarable;
import org.apache.geode.cache.DiskStoreFactory;
import org.apache.geode.cache.DiskWriteAttributes;
import org.apache.geode.cache.DynamicRegionFactory;
import org.apache.geode.cache.EvictionAction;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.ExpirationAttributes;
import org.apache.geode.cache.GatewayException;
import org.apache.geode.cache.InterestPolicy;
import org.apache.geode.cache.LossAction;
import org.apache.geode.cache.MembershipAttributes;
import org.apache.geode.cache.MirrorType;
import org.apache.geode.cache.PartitionAttributes;
import org.apache.geode.cache.PartitionResolver;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionExistsException;
import org.apache.geode.cache.ResumptionAction;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.SubscriptionAttributes;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.TransactionListener;
import org.apache.geode.cache.TransactionWriter;
import org.apache.geode.cache.asyncqueue.AsyncEventListener;
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
import org.apache.geode.cache.asyncqueue.AsyncEventQueueFactory;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.PoolFactory;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.partition.PartitionListener;
import org.apache.geode.cache.query.IndexType;
import org.apache.geode.cache.query.internal.index.IndexCreationData;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.cache.server.ClientSubscriptionConfig;
import org.apache.geode.cache.server.ServerLoadProbe;
import org.apache.geode.cache.util.ObjectSizer;
import org.apache.geode.cache.wan.GatewayEventFilter;
import org.apache.geode.cache.wan.GatewayEventSubstitutionFilter;
import org.apache.geode.cache.wan.GatewayReceiver;
import org.apache.geode.cache.wan.GatewayReceiverFactory;
import org.apache.geode.cache.wan.GatewaySender;
import org.apache.geode.cache.wan.GatewaySenderFactory;
import org.apache.geode.cache.wan.GatewayTransportFilter;
import org.apache.geode.compression.Compressor;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.InternalDataSerializer;
import org.apache.geode.internal.cache.DiskStoreAttributes;
import org.apache.geode.internal.cache.DiskWriteAttributesImpl;
import org.apache.geode.internal.cache.EvictionAttributesImpl;
import org.apache.geode.internal.cache.FixedPartitionAttributesImpl;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.PartitionAttributesImpl;
import org.apache.geode.internal.cache.PartitionedRegionHelper;
import org.apache.geode.internal.cache.lru.LRUCapacityController;
import org.apache.geode.internal.cache.lru.MemLRUCapacityController;
import org.apache.geode.internal.datasource.ConfigProperty;
import org.apache.geode.internal.i18n.LocalizedStrings;
import org.apache.geode.internal.jndi.JNDIInvoker;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.logging.log4j.LocalizedMessage;
import org.apache.geode.internal.logging.log4j.LogMarker;
import org.apache.geode.pdx.PdxSerializer;

/**
 * Parses an XML file and creates a {@link Cache}/{@link ClientCache} and {@link Region}s from it.
 * It works in two phases. The first phase parses the XML and instantiates {@link Declarable}s. If
 * any problems occur, a {@link CacheXmlException} is thrown. The second phase actually
 * {@linkplain CacheCreation#create creates} the {@link Cache}/{@link ClientCache},{@link Region}s,
 * etc.
 *
 *
 * @since GemFire 3.0
 */
@SuppressWarnings("deprecation")
public class CacheXmlParser extends CacheXml implements ContentHandler {

    private static final Logger logger = LogService.getLogger();

    /**
     * @since GemFire 8.1
     */
    private static final String BUFFER_SIZE = "http://apache.org/xml/properties/input-buffer-size";

    /**
     * @since GemFire 8.1
     */
    private static final String DISALLOW_DOCTYPE_DECL_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";

    /**
     * @since GemFire 8.1
     */
    private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";

    /** The cache to be created */
    private CacheCreation cache;
    /** The stack of intermediate values used while parsing */
    protected Stack<Object> stack = new Stack<>();

    /**
     * Delegate {@link XmlParser}s mapped by namespace URI.
     * 
     * @since GemFire 8.1
     */
    private HashMap<String, XmlParser> delegates = new HashMap<>();

    /**
     * Document {@link Locator} used for {@link SAXParseException}.
     * 
     * @since GemFire 8.2
     */
    protected Locator documentLocator;

    ////////////////////// Static Methods //////////////////////
    /**
     * Parses XML data and from it creates an instance of <code>CacheXmlParser</code> that can be used
     * to {@link #create}the {@link Cache}, etc.
     *
     * @param is the <code>InputStream</code> of XML to be parsed
     *
     * @return a <code>CacheXmlParser</code>, typically used to create a cache from the parsed XML
     *
     * @throws CacheXmlException Something went wrong while parsing the XML
     *
     * @since GemFire 4.0
     *
     */
    public static CacheXmlParser parse(InputStream is) {

        /**
         * The API doc http://java.sun.com/javase/6/docs/api/org/xml/sax/InputSource.html for the SAX
         * InputSource says: "... standard processing of both byte and character streams is to close
         * them on as part of end-of-parse cleanup, so applications should not attempt to re-use such
         * streams after they have been handed to a parser."
         *
         * In order to block the parser from closing the stream, we wrap the InputStream in a filter,
         * i.e., UnclosableInputStream, whose close() function does nothing.
         * 
         */
        class UnclosableInputStream extends BufferedInputStream {
            public UnclosableInputStream(InputStream stream) {
                super(stream);
            }

            @Override
            public void close() {
            }
        }

        CacheXmlParser handler = new CacheXmlParser();
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setFeature(DISALLOW_DOCTYPE_DECL_FEATURE, true);
            factory.setValidating(true);
            factory.setNamespaceAware(true);
            UnclosableInputStream bis = new UnclosableInputStream(is);
            try {
                SAXParser parser = factory.newSAXParser();
                // Parser always reads one buffer plus a little extra worth before
                // determining that the DTD is there. Setting mark twice the parser
                // buffer size.
                bis.mark((Integer) parser.getProperty(BUFFER_SIZE) * 2);
                parser.setProperty(JAXP_SCHEMA_LANGUAGE, XMLConstants.W3C_XML_SCHEMA_NS_URI);
                parser.parse(bis, new DefaultHandlerDelegate(handler));
            } catch (CacheXmlException e) {
                if (null != e.getCause() && e.getCause().getMessage().contains(DISALLOW_DOCTYPE_DECL_FEATURE)) {
                    // Not schema based document, try dtd.
                    bis.reset();
                    factory.setFeature(DISALLOW_DOCTYPE_DECL_FEATURE, false);
                    SAXParser parser = factory.newSAXParser();
                    parser.parse(bis, new DefaultHandlerDelegate(handler));
                } else {
                    throw e;
                }
            }
            return handler;
        } catch (Exception ex) {
            if (ex instanceof CacheXmlException) {
                while (true /* ex instanceof CacheXmlException */) {
                    Throwable cause = ex.getCause();
                    if (!(cause instanceof CacheXmlException)) {
                        break;
                    } else {
                        ex = (CacheXmlException) cause;
                    }
                }
                throw (CacheXmlException) ex;
            } else if (ex instanceof SAXException) {
                // Silly JDK 1.4.2 XML parser wraps RunTime exceptions in a
                // SAXException. Pshaw!
                SAXException sax = (SAXException) ex;
                Exception cause = sax.getException();
                if (cause instanceof CacheXmlException) {
                    while (true /* cause instanceof CacheXmlException */) {
                        Throwable cause2 = cause.getCause();
                        if (!(cause2 instanceof CacheXmlException)) {
                            break;
                        } else {
                            cause = (CacheXmlException) cause2;
                        }
                    }
                    throw (CacheXmlException) cause;
                }
            }
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_WHILE_PARSING_XML.toLocalizedString(), ex);
        }
    }

    /**
     * Helper method for parsing an integer
     *
     * @throws CacheXmlException If <code>s</code> is a malformed integer
     */
    private static int parseInt(String s) {
        try {
            return Integer.parseInt(s);
        } catch (NumberFormatException ex) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_MALFORMED_INTEGER_0.toLocalizedString(s),
                    ex);
        }
    }

    /**
     * Helper method for parsing a long
     *
     * @throws CacheXmlException If <code>s</code> is a malformed long
     */
    private static long parseLong(String s) {
        try {
            return Long.parseLong(s);
        } catch (NumberFormatException ex) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_MALFORMED_INTEGER_0.toLocalizedString(s),
                    ex);
        }
    }

    /**
     * Helper method for parsing a boolean
     *
     */
    private static boolean parseBoolean(String s) {
        return Boolean.valueOf(s).booleanValue();
    }

    /**
     * Helper method for parsing an float
     *
     * @throws CacheXmlException If <code>s</code> is a malformed float
     */
    private static float parseFloat(String s) {
        try {
            return Float.parseFloat(s);
        } catch (NumberFormatException ex) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_MALFORMED_FLOAT_0.toLocalizedString(s), ex);
        }
    }

    /**
     * Returns the {@link CacheCreation} generated by this parser.
     */
    public CacheCreation getCacheCreation() {
        return this.cache;
    }

    /**
     * Creates cache artifacts ({@link Cache}s, etc.) based upon the XML parsed by this parser.
     */
    public void create(InternalCache cache)
            throws TimeoutException, GatewayException, CacheWriterException, RegionExistsException {
        if (this.cache == null) {
            String s = "A cache or client-cache element is required";
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_NO_CACHE_ELEMENT_SPECIFIED.toLocalizedString());
        }
        this.cache.create(cache);
    }

    /**
     * When a <code>cache</code> element is first encountered, we create a {@link CacheCreation}and
     * fill it in appropriately
     */
    private void startCache(Attributes atts) {
        if (this.cache != null) {
            throw new CacheXmlException("Only a single cache or client-cache element is allowed");
        }
        this.cache = new CacheCreation(true);
        String lockLease = atts.getValue(LOCK_LEASE);
        if (lockLease != null) {
            this.cache.setLockLease(parseInt(lockLease));
        }
        String lockTimeout = atts.getValue(LOCK_TIMEOUT);
        if (lockTimeout != null) {
            this.cache.setLockTimeout(parseInt(lockTimeout));
        }
        String searchTimeout = atts.getValue(SEARCH_TIMEOUT);
        if (searchTimeout != null) {
            this.cache.setSearchTimeout(parseInt(searchTimeout));
        }
        String messageSyncInterval = atts.getValue(MESSAGE_SYNC_INTERVAL);
        if (messageSyncInterval != null) {
            this.cache.setMessageSyncInterval(parseInt(messageSyncInterval));
        }
        String isServer = atts.getValue(IS_SERVER);
        if (isServer != null) {
            boolean b = Boolean.valueOf(isServer).booleanValue();
            this.cache.setIsServer(b);
        }
        String copyOnRead = atts.getValue(COPY_ON_READ);
        if (copyOnRead != null) {
            this.cache.setCopyOnRead(Boolean.valueOf(copyOnRead).booleanValue());
        }
        stack.push(this.cache);
    }

    /**
     * When a <code>client-cache</code> element is first encountered, we create a
     * {@link ClientCacheCreation}and fill it in appropriately
     */
    private void startClientCache(Attributes atts) {
        if (this.cache != null) {
            throw new CacheXmlException("Only a single cache or client-cache element is allowed");
        }
        this.cache = new ClientCacheCreation(true);
        String copyOnRead = atts.getValue(COPY_ON_READ);
        if (copyOnRead != null) {
            this.cache.setCopyOnRead(Boolean.valueOf(copyOnRead).booleanValue());
        }
        stack.push(this.cache);
    }

    /**
     * @since GemFire 5.7
     */
    private void startPool(Attributes atts) {
        PoolFactory f = this.cache.createPoolFactory();
        String name = atts.getValue(NAME).trim();
        stack.push(name);
        stack.push(f);
        String v;
        v = atts.getValue(SOCKET_CONNECT_TIMEOUT);
        if (v != null) {
            f.setSocketConnectTimeout(parseInt(v));
        }
        v = atts.getValue(FREE_CONNECTION_TIMEOUT);
        if (v != null) {
            f.setFreeConnectionTimeout(parseInt(v));
        }
        v = atts.getValue(LOAD_CONDITIONING_INTERVAL);
        if (v != null) {
            f.setLoadConditioningInterval(parseInt(v));
        }
        v = atts.getValue(MIN_CONNECTIONS);
        if (v != null) {
            f.setMinConnections(parseInt(v));
        }
        v = atts.getValue(MAX_CONNECTIONS);
        if (v != null) {
            f.setMaxConnections(parseInt(v));
        }
        v = atts.getValue(RETRY_ATTEMPTS);
        if (v != null) {
            f.setRetryAttempts(parseInt(v));
        }
        v = atts.getValue(IDLE_TIMEOUT);
        if (v != null) {
            f.setIdleTimeout(parseLong(v));
        }
        v = atts.getValue(PING_INTERVAL);
        if (v != null) {
            f.setPingInterval(parseLong(v));
        }
        v = atts.getValue(SUBSCRIPTION_ENABLED);
        if (v != null) {
            f.setSubscriptionEnabled(parseBoolean(v));
        }
        v = atts.getValue(PR_SINGLE_HOP_ENABLED);
        if (v != null) {
            f.setPRSingleHopEnabled(parseBoolean(v));
        }
        v = atts.getValue(SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT);
        if (v != null) {
            f.setSubscriptionMessageTrackingTimeout(parseInt(v));
        }
        v = atts.getValue(SUBSCRIPTION_ACK_INTERVAL);
        if (v != null) {
            f.setSubscriptionAckInterval(parseInt(v));
        }
        v = atts.getValue(SUBSCRIPTION_REDUNDANCY);
        if (v != null) {
            f.setSubscriptionRedundancy(parseInt(v));
        }
        v = atts.getValue(READ_TIMEOUT);
        if (v != null) {
            f.setReadTimeout(parseInt(v));
        }
        v = atts.getValue(SERVER_GROUP);
        if (v != null) {
            f.setServerGroup(v.trim());
        }
        v = atts.getValue(SOCKET_BUFFER_SIZE);
        if (v != null) {
            f.setSocketBufferSize(parseInt(v));
        }
        v = atts.getValue(STATISTIC_INTERVAL);
        if (v != null) {
            f.setStatisticInterval(parseInt(v));
        }
        v = atts.getValue(THREAD_LOCAL_CONNECTIONS);
        if (v != null) {
            f.setThreadLocalConnections(parseBoolean(v));
        }
        v = atts.getValue(MULTIUSER_SECURE_MODE_ENABLED);
        if (v != null) {
            f.setMultiuserAuthentication(parseBoolean(v));
        }
    }

    /**
     * @since GemFire 5.7
     */
    private void endPool() {
        PoolFactory f = (PoolFactory) stack.pop();
        String name = (String) stack.pop();
        f.create(name);
    }

    /**
     * @since GemFire 5.7
     */
    private void doLocator(Attributes atts) {
        PoolFactory f = (PoolFactory) stack.peek();
        String host = atts.getValue(HOST).trim();
        int port = parseInt(atts.getValue(PORT));
        f.addLocator(host, port);
    }

    /**
     * @since GemFire 5.7
     */
    private void doServer(Attributes atts) {
        PoolFactory f = (PoolFactory) stack.peek();
        String host = atts.getValue(HOST).trim();
        int port = parseInt(atts.getValue(PORT));
        f.addServer(host, port);
    }

    /**
     * When a <code>cache-server</code> element is first encountered, we create a new
     * {@link CacheCreation#addCacheServer() CacheServer} in the cache.
     *
     * @since GemFire 4.0
     */
    private void startCacheServer(Attributes atts) {
        CacheServer bridge = this.cache.addCacheServer();
        String port = atts.getValue(PORT);
        if (port != null) {
            bridge.setPort(parseInt(port));
        }
        String bindAddress = atts.getValue(BIND_ADDRESS);
        if (bindAddress != null) {
            bridge.setBindAddress(bindAddress.trim());
        }
        String hostnameForClients = atts.getValue(HOSTNAME_FOR_CLIENTS);
        if (hostnameForClients != null) {
            bridge.setHostnameForClients(hostnameForClients.trim());
        }
        String maxConnections = atts.getValue(MAX_CONNECTIONS);
        if (maxConnections != null) {
            bridge.setMaxConnections(parseInt(maxConnections));
        }
        String maxThreads = atts.getValue(MAX_THREADS);
        if (maxThreads != null) {
            bridge.setMaxThreads(parseInt(maxThreads));
        }
        String notifyBySubscription = atts.getValue(NOTIFY_BY_SUBSCRIPTION);
        if (notifyBySubscription != null) {
            boolean b = Boolean.valueOf(notifyBySubscription).booleanValue();
            bridge.setNotifyBySubscription(b);
        }
        String socketBufferSize = atts.getValue(SOCKET_BUFFER_SIZE);
        if (socketBufferSize != null) {
            bridge.setSocketBufferSize(Integer.parseInt(socketBufferSize));
        }
        String tcpDelay = atts.getValue(TCP_NO_DELAY);
        if (tcpDelay != null) {
            bridge.setTcpNoDelay(Boolean.valueOf(tcpDelay).booleanValue());
        }
        String maximumTimeBetweenPings = atts.getValue(MAXIMUM_TIME_BETWEEN_PINGS);
        if (maximumTimeBetweenPings != null) {
            bridge.setMaximumTimeBetweenPings(Integer.parseInt(maximumTimeBetweenPings));
        }
        String maximumMessageCount = atts.getValue(MAXIMUM_MESSAGE_COUNT);
        if (maximumMessageCount != null) {
            bridge.setMaximumMessageCount(Integer.parseInt(maximumMessageCount));
        }
        String messageTimeToLive = atts.getValue(MESSAGE_TIME_TO_LIVE);
        if (messageTimeToLive != null) {
            bridge.setMessageTimeToLive(Integer.parseInt(messageTimeToLive));
        }
        String loadPollInterval = atts.getValue(LOAD_POLL_INTERVAL);
        if (loadPollInterval != null) {
            bridge.setLoadPollInterval(Long.parseLong(loadPollInterval));
        }
        this.stack.push(bridge);
    }

    private void startGatewaySender(Attributes atts) {
        GatewaySenderFactory gatewaySenderFactory = this.cache.createGatewaySenderFactory();

        String parallel = atts.getValue(PARALLEL);
        if (parallel == null) {
            gatewaySenderFactory.setParallel(GatewaySender.DEFAULT_IS_PARALLEL);
        } else {
            gatewaySenderFactory.setParallel(Boolean.parseBoolean(parallel));
        }

        // manual-start
        String manualStart = atts.getValue(MANUAL_START);
        if (manualStart == null) {
            gatewaySenderFactory.setManualStart(GatewaySender.DEFAULT_MANUAL_START);
        } else {
            gatewaySenderFactory.setManualStart(Boolean.parseBoolean(manualStart));
        }

        // socket-buffer-size
        String socketBufferSize = atts.getValue(SOCKET_BUFFER_SIZE);
        if (socketBufferSize == null) {
            gatewaySenderFactory.setSocketBufferSize(GatewaySender.DEFAULT_SOCKET_BUFFER_SIZE);
        } else {
            gatewaySenderFactory.setSocketBufferSize(Integer.parseInt(socketBufferSize));
        }

        // socket-read-timeout
        String socketReadTimeout = atts.getValue(SOCKET_READ_TIMEOUT);
        if (socketReadTimeout == null) {
            gatewaySenderFactory.setSocketReadTimeout(GatewaySender.DEFAULT_SOCKET_READ_TIMEOUT);
        } else {
            gatewaySenderFactory.setSocketReadTimeout(Integer.parseInt(socketReadTimeout));
        }

        // batch-conflation
        String batchConflation = atts.getValue(ENABLE_BATCH_CONFLATION);
        if (batchConflation == null) {
            gatewaySenderFactory.setBatchConflationEnabled(GatewaySender.DEFAULT_BATCH_CONFLATION);
        } else {
            gatewaySenderFactory.setBatchConflationEnabled(Boolean.parseBoolean(batchConflation));
        }

        // batch-size
        String batchSize = atts.getValue(BATCH_SIZE);
        if (batchSize == null) {
            gatewaySenderFactory.setBatchSize(GatewaySender.DEFAULT_BATCH_SIZE);
        } else {
            gatewaySenderFactory.setBatchSize(Integer.parseInt(batchSize));
        }

        // batch-time-interval
        String batchTimeInterval = atts.getValue(BATCH_TIME_INTERVAL);
        if (batchTimeInterval == null) {
            gatewaySenderFactory.setBatchTimeInterval(GatewaySender.DEFAULT_BATCH_TIME_INTERVAL);
        } else {
            gatewaySenderFactory.setBatchTimeInterval(Integer.parseInt(batchTimeInterval));
        }

        // enable-persistence
        String enablePersistence = atts.getValue(ENABLE_PERSISTENCE);
        if (enablePersistence == null) {
            gatewaySenderFactory.setPersistenceEnabled(GatewaySender.DEFAULT_PERSISTENCE_ENABLED);
        } else {
            gatewaySenderFactory.setPersistenceEnabled(Boolean.parseBoolean(enablePersistence));
        }

        String diskStoreName = atts.getValue(DISK_STORE_NAME);
        if (diskStoreName == null) {
            gatewaySenderFactory.setDiskStoreName(null);
        } else {
            gatewaySenderFactory.setDiskStoreName(diskStoreName);
        }

        String diskSynchronous = atts.getValue(DISK_SYNCHRONOUS);
        if (diskSynchronous == null) {
            gatewaySenderFactory.setDiskSynchronous(GatewaySender.DEFAULT_DISK_SYNCHRONOUS);
        } else {
            gatewaySenderFactory.setDiskSynchronous(Boolean.parseBoolean(diskSynchronous));
        }

        // maximum-queue-memory
        String maxQueueMemory = atts.getValue(MAXIMUM_QUEUE_MEMORY);
        if (maxQueueMemory == null) {
            gatewaySenderFactory.setMaximumQueueMemory(GatewaySender.DEFAULT_MAXIMUM_QUEUE_MEMORY);
        } else {
            gatewaySenderFactory.setMaximumQueueMemory(Integer.parseInt(maxQueueMemory));
        }

        String alertThreshold = atts.getValue(ALERT_THRESHOLD);
        if (alertThreshold == null) {
            gatewaySenderFactory.setAlertThreshold(GatewaySender.DEFAULT_ALERT_THRESHOLD);
        } else {
            gatewaySenderFactory.setAlertThreshold(Integer.parseInt(alertThreshold));
        }

        String dispatcherThreads = atts.getValue(DISPATCHER_THREADS);
        if (dispatcherThreads == null) {
            gatewaySenderFactory.setDispatcherThreads(GatewaySender.DEFAULT_DISPATCHER_THREADS);
        } else {
            gatewaySenderFactory.setDispatcherThreads(Integer.parseInt(dispatcherThreads));
        }

        String id = atts.getValue(ID);
        String orderPolicy = atts.getValue(ORDER_POLICY);
        if (orderPolicy != null) {
            try {
                gatewaySenderFactory.setOrderPolicy(GatewaySender.OrderPolicy.valueOf(orderPolicy.toUpperCase()));
            } catch (IllegalArgumentException e) {
                throw new InternalGemFireException(
                        LocalizedStrings.SerialGatewaySender_UNKNOWN_GATEWAY_ORDER_POLICY_0_1
                                .toLocalizedString(new Object[] { id, orderPolicy }));
            }
        }

        String remoteDS = atts.getValue(REMOTE_DISTRIBUTED_SYSTEM_ID);
        stack.push(id);
        stack.push(remoteDS);
        stack.push(gatewaySenderFactory);
        // GatewaySender sender = gatewaySenderFactory.create(id, Integer.parseInt(remoteDS));
        // stack.push(sender);
    }

    private void startGatewayReceiver(Attributes atts) {
        GatewayReceiverFactory receiverFactory = this.cache.createGatewayReceiverFactory();

        // port
        String startPort = atts.getValue(START_PORT);
        if (startPort == null) {
            receiverFactory.setStartPort(GatewayReceiver.DEFAULT_START_PORT);
        } else {
            receiverFactory.setStartPort(Integer.parseInt(startPort));
        }

        String endPort = atts.getValue(END_PORT);
        if (endPort == null) {
            receiverFactory.setEndPort(GatewayReceiver.DEFAULT_END_PORT);
        } else {
            receiverFactory.setEndPort(Integer.parseInt(endPort));
        }

        String bindAddress = atts.getValue(BIND_ADDRESS);
        if (bindAddress == null) {
            receiverFactory.setBindAddress(GatewayReceiver.DEFAULT_BIND_ADDRESS);
        } else {
            receiverFactory.setBindAddress(bindAddress);
        }

        // maximum-time-between-pings
        String maxTimeBetweenPings = atts.getValue(MAXIMUM_TIME_BETWEEN_PINGS);
        if (maxTimeBetweenPings == null) {
            receiverFactory.setMaximumTimeBetweenPings(GatewayReceiver.DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS);
        } else {
            receiverFactory.setMaximumTimeBetweenPings(Integer.parseInt(maxTimeBetweenPings));
        }

        // socket-buffer-size
        String socketBufferSize = atts.getValue(SOCKET_BUFFER_SIZE);
        if (socketBufferSize == null) {
            receiverFactory.setSocketBufferSize(GatewayReceiver.DEFAULT_SOCKET_BUFFER_SIZE);
        } else {
            receiverFactory.setSocketBufferSize(Integer.parseInt(socketBufferSize));
        }

        // manual-start
        String manualStart = atts.getValue(MANUAL_START);
        if (manualStart == null) {
            receiverFactory.setManualStart(GatewayReceiver.DEFAULT_MANUAL_START);
        } else {
            receiverFactory.setManualStart(Boolean.parseBoolean(manualStart));
        }

        // hostname-for-senders
        String hostnameForSenders = atts.getValue(HOSTNAME_FOR_SENDERS);
        if (hostnameForSenders == null) {
            receiverFactory.setHostnameForSenders(GatewayReceiver.DEFAULT_HOSTNAME_FOR_SENDERS);
        } else {
            receiverFactory.setHostnameForSenders(hostnameForSenders);
        }

        stack.push(receiverFactory);
    }

    /**
     * set attributes from clientHaQueue when we finish a cache server
     */
    private void endCacheServer() {
        List groups = new ArrayList();
        ServerLoadProbe probe = null;
        ClientHaQueueCreation haCreation = null;

        if (stack.peek() instanceof ServerLoadProbe) {
            probe = (ServerLoadProbe) stack.pop();
        }

        if (stack.peek() instanceof ClientHaQueueCreation) {
            haCreation = (ClientHaQueueCreation) stack.pop();
        }

        while (stack.peek() instanceof String) {
            groups.add(stack.pop());
        }
        CacheServer bs = (CacheServer) stack.pop();
        if (groups.size() > 0) {
            Collections.reverse(groups);
            String[] groupArray = new String[groups.size()];
            groups.toArray(groupArray);
            bs.setGroups(groupArray);
        }
        if (probe != null) {
            bs.setLoadProbe(probe);
        }
        if (haCreation != null) {
            ClientSubscriptionConfig csc = bs.getClientSubscriptionConfig();
            String diskStoreName = haCreation.getDiskStoreName();
            if (diskStoreName != null) {
                csc.setDiskStoreName(diskStoreName);
            } else {
                csc.setOverflowDirectory(haCreation.getOverflowDirectory() == null
                        ? ClientSubscriptionConfig.DEFAULT_OVERFLOW_DIRECTORY
                        : haCreation.getOverflowDirectory());
            }
            csc.setCapacity(haCreation.getCapacity());
            csc.setEvictionPolicy(haCreation.getEvictionPolicy());
        }
    }

    /**
     * When a <code>load-probe</code> element is encountered, create a new probe for the current
     * <code>CacheServer</code>.
     *
     * @since GemFire 5.7
     */
    private void endLoadProbe() {
        Declarable d = createDeclarable();
        if (!(d instanceof ServerLoadProbe)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_1
                    .toLocalizedString(new Object[] { d.getClass().getName(), "BridgeLoadProbe" }));
        }
        stack.push(d);
    }

    private void endSerialGatewaySender() {
        GatewaySenderFactory senderFactory = (GatewaySenderFactory) stack.pop();
        String remoteDSString = (String) stack.pop();
        String id = (String) stack.pop();
        senderFactory.create(id, Integer.parseInt(remoteDSString));
    }

    private void endGatewayReceiver() {
        GatewayReceiverFactory receiverFactory = (GatewayReceiverFactory) stack.pop();
        receiverFactory.create();
    }

    private void startDynamicRegionFactory(Attributes atts) {
        // push attributes onto the stack for processing in endDynamicRegionFactory
        String disablePersist = atts.getValue(DISABLE_PERSIST_BACKUP);
        if (disablePersist == null) {
            stack.push("false");
        } else {
            stack.push(disablePersist);
        }
        String disableRegisterInterest = atts.getValue(DISABLE_REGISTER_INTEREST);
        if (disableRegisterInterest == null) {
            stack.push("false");
        } else {
            stack.push(disableRegisterInterest);
        }
        String poolName = atts.getValue(POOL_NAME);
        if (poolName == null) {
            stack.push(null);
        } else {
            stack.push(poolName);
        }

        // hi-jack RegionAttributesCreation for the disk-dirs, loader, writer and compressor
        RegionAttributesCreation attrs = new RegionAttributesCreation(this.cache);
        stack.push(attrs);
    }

    private void endDynamicRegionFactory() {
        File dir = null;
        RegionAttributesCreation attrs;
        {
            Object o = stack.pop();
            if (o instanceof File) {
                dir = (File) o;
                stack.pop(); // dir size to be popped out. being used by persistent directories
                attrs = (RegionAttributesCreation) stack.pop();
            } else {
                attrs = (RegionAttributesCreation) o;
            }
        }
        String poolName = (String) stack.pop();
        String disableRegisterInterest = (String) stack.pop();
        String disablePersistBackup = (String) stack.pop();
        DynamicRegionFactory.Config cfg;
        cfg = new DynamicRegionFactory.Config(dir, poolName, !Boolean.valueOf(disablePersistBackup).booleanValue(),
                !Boolean.valueOf(disableRegisterInterest).booleanValue());
        CacheCreation cache = (CacheCreation) stack.peek();
        cache.setDynamicRegionFactoryConfig(cfg);
    }

    /**
     * When a <code>gateway-conflict-resolver</code> element is encountered, create a new listener for
     * the <code>Cache</code>.
     */
    private void endGatewayConflictResolver() {
        Declarable d = createDeclarable();
        if (!(d instanceof GatewayConflictResolver)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_GATEWAYCONFLICTRESOLVER
                            .toLocalizedString(d.getClass().getName()));
        }
        CacheCreation c = (CacheCreation) stack.peek();
        c.setGatewayConflictResolver((GatewayConflictResolver) d);
    }

    /**
     * When a <code>region</code> element is first encountered, we create a {@link RegionCreation}and
     * push it on the stack.
     */
    private void startRegion(Attributes atts) {
        String name = atts.getValue(NAME);
        String refid = atts.getValue(REFID);
        Assert.assertTrue(name != null);
        RegionCreation region = new RegionCreation(this.cache, name, refid);
        stack.push(region);
    }

    /**
     * When a <code>cache-transaction-manager</code> element is found, create a container for the
     * potential <code>transaction-listener</code> and push it on the stack
     */
    private void startCacheTransactionManager() {
        stack.push(new CacheTransactionManagerCreation());
    }

    /**
     * After popping the current <code>RegionCreation</code> off the stack, if the element on top of
     * the stack is a <code>RegionCreation</code>, then it is the parent region.
     */
    private void endRegion() throws RegionExistsException {
        RegionCreation region = (RegionCreation) stack.pop();
        boolean isRoot = false;
        if (stack.isEmpty()) {
            isRoot = true;
        } else if (!(stack.peek() instanceof RegionCreation)) {
            isRoot = true;
        }
        if (isRoot) {
            this.cache.addRootRegion(region);
        } else {
            RegionCreation parent = (RegionCreation) stack.peek();
            parent.addSubregion(region.getName(), region);
        }
    }

    /**
     * Add the <code>transaction-manager</code> creation code to the cache creation code
     */
    private void endCacheTransactionManager() {
        CacheTransactionManagerCreation txMgrCreation = (CacheTransactionManagerCreation) stack.pop();
        this.cache.addCacheTransactionManagerCreation(txMgrCreation);
    }

    /**
     * Create a <code>transaction-listener</code> using the declarable interface and set the
     * transaction manager with the newly instantiated listener.
     */
    private void endTransactionListener() {
        Declarable d = createDeclarable();
        if (!(d instanceof TransactionListener)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_CACHELISTENER
                    .toLocalizedString(d.getClass().getName()));
        }
        CacheTransactionManagerCreation txMgrCreation = (CacheTransactionManagerCreation) stack.peek();
        txMgrCreation.addListener((TransactionListener) d);
    }

    /**
     * When a <code>disk-store</code> element is first encountered, we create a
     * {@link DiskStoreAttributes}, populate it accordingly, and push it on the stack.
     */
    private void startDiskStore(Attributes atts) {
        // this is the only place to create DSAC objects
        DiskStoreAttributesCreation attrs = new DiskStoreAttributesCreation();
        String name = atts.getValue(NAME);
        if (name == null) {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_NULL_DiskStoreName.toLocalizedString());
        } else {
            attrs.setName(name);
        }

        String autoCompact = atts.getValue(AUTO_COMPACT);
        if (autoCompact != null) {
            attrs.setAutoCompact(Boolean.valueOf(autoCompact).booleanValue());
        }

        String compactionThreshold = atts.getValue(COMPACTION_THRESHOLD);
        if (compactionThreshold != null) {
            attrs.setCompactionThreshold(parseInt(compactionThreshold));
        }

        String allowForceCompaction = atts.getValue(ALLOW_FORCE_COMPACTION);
        if (allowForceCompaction != null) {
            attrs.setAllowForceCompaction(Boolean.valueOf(allowForceCompaction).booleanValue());
        }

        String maxOplogSize = atts.getValue(MAX_OPLOG_SIZE);
        if (maxOplogSize != null) {
            attrs.setMaxOplogSize(parseInt(maxOplogSize));
        }

        String timeInterval = atts.getValue(TIME_INTERVAL);
        if (timeInterval != null) {
            attrs.setTimeInterval(parseInt(timeInterval));
        }

        String writeBufferSize = atts.getValue(WRITE_BUFFER_SIZE);
        if (writeBufferSize != null) {
            attrs.setWriteBufferSize(parseInt(writeBufferSize));
        }

        String queueSize = atts.getValue(QUEUE_SIZE);
        if (queueSize != null) {
            attrs.setQueueSize(parseInt(queueSize));
        }

        String warnPct = atts.getValue(DISK_USAGE_WARNING_PERCENTAGE);
        if (warnPct != null) {
            attrs.setDiskUsageWarningPercentage(parseFloat(warnPct));
        }

        String criticalPct = atts.getValue(DISK_USAGE_CRITICAL_PERCENTAGE);
        if (warnPct != null) {
            attrs.setDiskUsageCriticalPercentage(parseFloat(criticalPct));
        }

        stack.push(attrs);
    }

    private Integer getIntValue(Attributes atts, String param) {
        String maxInputFileSizeMB = atts.getValue(param);
        if (maxInputFileSizeMB != null) {
            try {
                return Integer.valueOf(maxInputFileSizeMB);
            } catch (NumberFormatException e) {
                throw new CacheXmlException(LocalizedStrings.DistributedSystemConfigImpl_0_IS_NOT_A_VALID_INTEGER_1
                        .toLocalizedString(new Object[] { maxInputFileSizeMB, param }), e);
            }
        }
        return null;
    }

    /**
     * Create a <code>transaction-writer</code> using the declarable interface and set the transaction
     * manager with the newly instantiated writer.
     */
    private void endTransactionWriter() {
        Declarable d = createDeclarable();
        if (!(d instanceof TransactionWriter)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_TRANSACTION_WRITER
                            .toLocalizedString(d.getClass().getName()));
        }
        CacheTransactionManagerCreation txMgrCreation = (CacheTransactionManagerCreation) stack.peek();
        txMgrCreation.setWriter((TransactionWriter) d);
    }

    /**
     * When a <code>region-attributes</code> element is first encountered, we create a
     * {@link RegionAttributesCreation}, populate it accordingly, and push it on the stack.
     */
    private void startRegionAttributes(Attributes atts) {
        RegionAttributesCreation attrs = new RegionAttributesCreation(this.cache);
        String scope = atts.getValue(SCOPE);
        if (scope == null) {
        } else if (scope.equals(LOCAL)) {
            attrs.setScope(Scope.LOCAL);
        } else if (scope.equals(DISTRIBUTED_NO_ACK)) {
            attrs.setScope(Scope.DISTRIBUTED_NO_ACK);
        } else if (scope.equals(DISTRIBUTED_ACK)) {
            attrs.setScope(Scope.DISTRIBUTED_ACK);
        } else if (scope.equals(GLOBAL)) {
            attrs.setScope(Scope.GLOBAL);
        } else {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_UNKNOWN_SCOPE_0.toLocalizedString(scope));
        }
        String mirror = atts.getValue(MIRROR_TYPE);
        if (mirror == null) {
        } else if (mirror.equals(NONE)) {
            attrs.setMirrorType(MirrorType.NONE);
        } else if (mirror.equals(KEYS)) {
            attrs.setMirrorType(MirrorType.KEYS);
        } else if (mirror.equals(KEYS_VALUES)) {
            attrs.setMirrorType(MirrorType.KEYS_VALUES);
        } else {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_UNKNOWN_MIRROR_TYPE_0.toLocalizedString(mirror));
        }
        {
            String dp = atts.getValue(DATA_POLICY);
            if (dp == null) {
            } else if (dp.equals(NORMAL_DP)) {
                attrs.setDataPolicy(DataPolicy.NORMAL);
            } else if (dp.equals(PRELOADED_DP)) {
                attrs.setDataPolicy(DataPolicy.PRELOADED);
            } else if (dp.equals(EMPTY_DP)) {
                attrs.setDataPolicy(DataPolicy.EMPTY);
            } else if (dp.equals(REPLICATE_DP)) {
                attrs.setDataPolicy(DataPolicy.REPLICATE);
            } else if (dp.equals(PERSISTENT_REPLICATE_DP)) {
                attrs.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
            } else if (dp.equals(PARTITION_DP)) {
                attrs.setDataPolicy(DataPolicy.PARTITION);
            } else if (dp.equals(PERSISTENT_PARTITION_DP)) {
                attrs.setDataPolicy(DataPolicy.PERSISTENT_PARTITION);
            } else {
                throw new InternalGemFireException(
                        LocalizedStrings.CacheXmlParser_UNKNOWN_DATA_POLICY_0.toLocalizedString(dp));
            }
        }

        String initialCapacity = atts.getValue(INITIAL_CAPACITY);
        if (initialCapacity != null) {
            attrs.setInitialCapacity(parseInt(initialCapacity));
        }
        String concurrencyLevel = atts.getValue(CONCURRENCY_LEVEL);
        if (concurrencyLevel != null) {
            attrs.setConcurrencyLevel(parseInt(concurrencyLevel));
        }
        String concurrencyChecksEnabled = atts.getValue(CONCURRENCY_CHECKS_ENABLED);
        if (concurrencyChecksEnabled != null) {
            attrs.setConcurrencyChecksEnabled(Boolean.valueOf(concurrencyChecksEnabled).booleanValue());
        }
        String loadFactor = atts.getValue(LOAD_FACTOR);
        if (loadFactor != null) {
            attrs.setLoadFactor(parseFloat(loadFactor));
        }
        String statisticsEnabled = atts.getValue(STATISTICS_ENABLED);
        if (statisticsEnabled != null) {
            attrs.setStatisticsEnabled(Boolean.valueOf(statisticsEnabled).booleanValue());
        }
        String ignoreJTA = atts.getValue(IGNORE_JTA);
        if (ignoreJTA != null) {
            attrs.setIgnoreJTA(Boolean.valueOf(ignoreJTA).booleanValue());
        }
        String isLockGrantor = atts.getValue(IS_LOCK_GRANTOR);
        if (isLockGrantor != null) {
            attrs.setLockGrantor(Boolean.valueOf(isLockGrantor).booleanValue());
        }
        String persistBackup = atts.getValue(PERSIST_BACKUP);
        if (persistBackup != null) {
            attrs.setPersistBackup(Boolean.valueOf(persistBackup).booleanValue());
        }
        String earlyAck = atts.getValue(EARLY_ACK);
        if (earlyAck != null) {
            attrs.setEarlyAck(Boolean.valueOf(earlyAck).booleanValue());
        }
        String mcastEnabled = atts.getValue(MULTICAST_ENABLED);
        if (mcastEnabled != null) {
            attrs.setMulticastEnabled(Boolean.valueOf(mcastEnabled).booleanValue());
        }
        String indexUpdateType = atts.getValue(INDEX_UPDATE_TYPE);
        attrs.setIndexMaintenanceSynchronous(
                indexUpdateType == null || indexUpdateType.equals(INDEX_UPDATE_TYPE_SYNCH));

        String poolName = atts.getValue(POOL_NAME);
        if (poolName != null) {
            attrs.setPoolName(poolName);
        }
        String diskStoreName = atts.getValue(DISK_STORE_NAME);
        if (diskStoreName != null) {
            attrs.setDiskStoreName(diskStoreName);
        }
        String isDiskSynchronous = atts.getValue(DISK_SYNCHRONOUS);
        if (isDiskSynchronous != null) {
            attrs.setDiskSynchronous(Boolean.valueOf(isDiskSynchronous).booleanValue());
        }

        String id = atts.getValue(ID);
        if (id != null) {
            attrs.setId(id);
        }
        String refid = atts.getValue(REFID);
        if (refid != null) {
            attrs.setRefid(refid);
        }
        String enableSubscriptionConflation = atts.getValue(ENABLE_SUBSCRIPTION_CONFLATION);
        if (enableSubscriptionConflation != null) {
            attrs.setEnableSubscriptionConflation(Boolean.valueOf(enableSubscriptionConflation).booleanValue());
        }
        String enableBridgeConflation = atts.getValue(ENABLE_BRIDGE_CONFLATION);
        // as of 5.7 enable-bridge-conflation is deprecated.
        // so ignore it if enable-subscription-conflation is set
        if (enableBridgeConflation != null && enableSubscriptionConflation == null) {
            attrs.setEnableSubscriptionConflation(Boolean.valueOf(enableBridgeConflation).booleanValue());
        }
        if (enableBridgeConflation == null && enableSubscriptionConflation == null) {
            // 4.1 compatibility
            enableBridgeConflation = atts.getValue("enable-conflation");
            if (enableBridgeConflation != null) {
                attrs.setEnableSubscriptionConflation(Boolean.valueOf(enableBridgeConflation).booleanValue());
            }
        }
        /*
         * deprecated in prPersistSprint1 String publisherStr = atts.getValue(PUBLISHER); if
         * (publisherStr != null) { attrs.setPublisher(Boolean.valueOf(publisherStr).booleanValue()); }
         */
        String enableAsyncConflation = atts.getValue(ENABLE_ASYNC_CONFLATION);
        if (enableAsyncConflation != null) {
            attrs.setEnableAsyncConflation(Boolean.valueOf(enableAsyncConflation).booleanValue());
        }
        String cloningEnabledStr = atts.getValue(CLONING_ENABLED);
        if (cloningEnabledStr != null) {
            attrs.setCloningEnable(Boolean.valueOf(cloningEnabledStr).booleanValue());
        }
        String gatewaySenderIds = atts.getValue(GATEWAY_SENDER_IDS);
        if (gatewaySenderIds != null && (gatewaySenderIds.length() != 0)) {
            StringTokenizer st = new StringTokenizer(gatewaySenderIds, ",");
            while (st.hasMoreElements()) {
                attrs.addGatewaySenderId(st.nextToken());
            }
        }
        String asyncEventQueueIds = atts.getValue(ASYNC_EVENT_QUEUE_IDS);
        if (asyncEventQueueIds != null && (asyncEventQueueIds.length() != 0)) {
            StringTokenizer st = new StringTokenizer(asyncEventQueueIds, ",");
            while (st.hasMoreElements()) {
                attrs.addAsyncEventQueueId(st.nextToken());
            }
        }
        String offHeapStr = atts.getValue(OFF_HEAP);
        if (offHeapStr != null) {
            attrs.setOffHeap(Boolean.valueOf(offHeapStr).booleanValue());
        }

        stack.push(attrs);
    }

    /**
     * After popping the current <code>DiskStoreAttributesCreation</code> off the stack, we add it to
     * the <code>DiskStoreAttionCreation</code> that should be on the top of the stack.
     */
    private void endDiskStore() {
        DiskStoreAttributesCreation dsac = (DiskStoreAttributesCreation) stack.pop();
        CacheCreation cache;
        Object top = stack.peek();
        if (top instanceof CacheCreation) {
            cache = (CacheCreation) top;
        } else {
            String s = "Did not expected a " + top.getClass().getName() + " on top of the stack.";
            Assert.assertTrue(false, s);
            cache = null; // Dead code
        }
        String name = dsac.getName();
        if (name != null) {
            cache.setDiskStore(name, dsac);
        }
    }

    /**
     * After popping the current <code>RegionAttributesCreation</code> off the stack, we add it to the
     * <code>RegionCreation</code> that should be on the top of the stack.
     */
    private void endRegionAttributes() {
        RegionAttributesCreation attrs = (RegionAttributesCreation) stack.pop();
        CacheCreation cache;
        Object top = stack.peek();
        if (top instanceof RegionCreation) {
            RegionCreation region = (RegionCreation) top;
            region.setAttributes(attrs);
            cache = (CacheCreation) region.getCache();
        } else if (top instanceof CacheCreation) {
            cache = (CacheCreation) top;
        } else {
            String s = "Did not expected a " + top.getClass().getName() + " on top of the stack.";
            Assert.assertTrue(false, s);
            cache = null; // Dead code
        }
        String id = attrs.getId();
        if (id != null) {
            cache.setRegionAttributes(id, attrs);
        }
    }

    /**
     * When a <code>cache</code> element is finished
     */
    private void endCache() {
    }

    /**
     * When a <code>client-cache</code> element is finished
     */
    private void endClientCache() {
    }

    /**
     * <p>
     * When the end of a <code>string</code> element is encountered, convert the data to a
     * <code>String</code>
     */
    // This converts the <code>StringBuffer</code> to a
    // <code>String</code> because a </code>StringBuffer</code> is
    // solely used (as a marker) by the <code>characters</code> method
    // and by doing this conversion we allow for multiple consecutive string
    // elements, otherwise <code>characters</code> would continue to
    // append and our stack order would be out of whack. See bug 32122.
    private void endString() {
        StringBuffer str = (StringBuffer) stack.pop();
        stack.push(str.toString()/* .trim() */);
    }

    /**
     * finish parsing a "group" element which is just a string
     * 
     * @since GemFire 5.7
     */
    private void endGroup() {
        StringBuffer str = (StringBuffer) stack.pop();
        stack.push(str.toString().trim());
    }

    private void endClassName() {
        StringBuffer str = (StringBuffer) stack.pop();
        stack.push(str.toString().trim()); // trim fixes bug 32928
    }

    /**
     * When an <code>entry</code> element is finished, the <code>value</code> should be on the stop of
     * the stack followed by the <code>key</code>. The <code>RegionCreation</code> for the region
     * being created should be below that.
     */
    private void endEntry() {
        Object value = stack.pop();
        Object key = stack.pop();
        RegionCreation region = (RegionCreation) stack.peek();
        // changed by mitul after modifying code for Region implements Map
        region.put(key, value);
    }

    /**
     * When a <code>key-constraint</code> element is finished, the name of the class should be on top
     * of the stack.
     *
     * @throws CacheXmlException If the key constraint class cannot be loaded
     */
    private void endKeyConstraint() {
        String className = ((StringBuffer) stack.pop()).toString().trim();
        Class c;
        try {
            c = InternalDataSerializer.getCachedClass(className);
        } catch (Exception ex) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_COULD_NOT_LOAD_KEYCONSTRAINT_CLASS_0
                    .toLocalizedString(className), ex);
        }
        // The region attributes should be on top of the stack
        RegionAttributesCreation attrs = peekRegionAttributesContext("key-constraint");
        attrs.setKeyConstraint(c);
    }

    /**
     * When a <code>value-constraint</code> element is finished, the name of the class should be on
     * top of the stack.
     *
     * @throws CacheXmlException If the value constraint class cannot be loaded
     */
    private void endValueConstraint() {
        String className = ((StringBuffer) stack.pop()).toString().trim();
        Class c;
        try {
            c = InternalDataSerializer.getCachedClass(className);
        } catch (Exception ex) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_COULD_NOT_LOAD_VALUECONSTRAINT_CLASS_0
                    .toLocalizedString(className), ex);
        }
        // The region attributes should be on top of the stack
        RegionAttributesCreation attrs = peekRegionAttributesContext("value-constraint");
        attrs.setValueConstraint(c);
    }

    /**
     * When a <code>region-time-to-live</code> element is finished, the {@link ExpirationAttributes}
     * are on top of the stack followed by the {@link RegionAttributesCreation} to which the
     * expiration attributes are assigned.
     */
    private void endRegionTimeToLive() {
        ExpirationAttributes expire = (ExpirationAttributes) stack.pop();
        RegionAttributesCreation attrs = peekRegionAttributesContext("region-time-to-live");
        attrs.setRegionTimeToLive(expire);
    }

    /**
     * When a <code>region-idle-time</code> element is finished, the {@link ExpirationAttributes} are
     * on top of the stack followed by the {@link RegionAttributesCreation} to which the expiration
     * attributes are assigned.
     */
    private void endRegionIdleTime() {
        ExpirationAttributes expire = (ExpirationAttributes) stack.pop();
        RegionAttributesCreation attrs = peekRegionAttributesContext("region-idle-time");
        attrs.setRegionIdleTimeout(expire);
    }

    private RegionAttributesCreation peekRegionAttributesContext(String dependentElement) {
        Object a = stack.peek();
        if (!(a instanceof RegionAttributesCreation)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES
                            .toLocalizedString(dependentElement));
        }
        return (RegionAttributesCreation) a;
    }

    private PartitionAttributesImpl peekPartitionAttributesImpl(String dependentElement) {
        Object a = stack.peek();
        if (!(a instanceof PartitionAttributesImpl)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_PARTITIONATTRIBUTES
                            .toLocalizedString(dependentElement));
        }
        return (PartitionAttributesImpl) a;
    }

    /**
     * When a <code>entry-time-to-live</code> element is finished, an optional Declarable (the
     * custom-expiry) is followed by the {@link ExpirationAttributes} are on top of the stack followed
     * by either the {@link RegionAttributesCreation} to which the expiration attributes are assigned,
     * or the attributes for a {@link PartitionAttributes} to which the attributes are assigned.
     */
    private void endEntryTimeToLive() {
        Declarable custom = null;
        if (stack.peek() instanceof Declarable) {
            custom = (Declarable) stack.pop();
        }
        ExpirationAttributes expire = (ExpirationAttributes) stack.pop();
        Object a = stack.peek();
        // if (a instanceof PartitionAttributesFactory) {
        // ((PartitionAttributesFactory) a).setEntryTimeToLive(expire);
        // } else
        if (a instanceof RegionAttributesCreation) {
            ((RegionAttributesCreation) a).setEntryTimeToLive(expire);
            if (custom != null) {
                ((RegionAttributesCreation) a).setCustomEntryTimeToLive((CustomExpiry) custom);
            }
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES_OR_PARTITIONATTRIBUTES
                            .toLocalizedString(ENTRY_TIME_TO_LIVE));
        }
    }

    /**
     * When a <code>entry-idle-time</code> element is finished, an optional Declarable (the
     * custom-expiry) is followed by the {@link ExpirationAttributes} are on top of the stack followed
     * by the {@link RegionAttributesCreation} to which the expiration attributes are assigned.
     */
    private void endEntryIdleTime() {
        Declarable custom = null;
        if (stack.peek() instanceof Declarable) {
            custom = (Declarable) stack.pop();
        }
        ExpirationAttributes expire = (ExpirationAttributes) stack.pop();
        Object a = stack.peek();
        // if (a instanceof PartitionAttributesFactory) {
        // ((PartitionAttributesFactory) a).setEntryIdleTimeout(expire);
        // } else
        if (a instanceof RegionAttributesCreation) {
            ((RegionAttributesCreation) a).setEntryIdleTimeout(expire);
            if (custom != null) {
                ((RegionAttributesCreation) a).setCustomEntryIdleTimeout((CustomExpiry) custom);
            }
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES_OR_PARTITIONATTRIBUTES
                            .toLocalizedString(ENTRY_IDLE_TIME));
        }
    }

    /**
     * When a <code>partition-attributes</code> element is finished, the {@link PartitionAttributes}
     * are on top of the stack followed by the {@link RegionAttributesCreation} to which the partition
     * attributes are assigned.
     */
    private void endPartitionAttributes() {
        PartitionAttributesImpl paf = (PartitionAttributesImpl) stack.pop();
        paf.validateAttributes();

        RegionAttributesCreation rattrs = peekRegionAttributesContext(PARTITION_ATTRIBUTES);
        // change the 5.0 default data policy (EMPTY) to the current default
        if (rattrs.hasDataPolicy() && rattrs.getDataPolicy().isEmpty()
                && (this.version.compareTo(CacheXmlVersion.GEMFIRE_5_0) == 0)) {
            rattrs.setDataPolicy(PartitionedRegionHelper.DEFAULT_DATA_POLICY);
        }
        rattrs.setPartitionAttributes(paf);
    }

    /**
     * When a <code>fixed-partition-attributes</code> element is finished
     */
    private void endFixedPartitionAttributes() {
    }

    /**
     * When a <code>membership-attributes</code> element is finished, the arguments for constructing
     * the MembershipAttributes are on the stack.
     */
    private void endMembershipAttributes() {
        Set roles = new HashSet();
        Object obj = null;
        while (!(obj instanceof Object[])) {
            obj = stack.pop();
            if (obj instanceof String) {
                // found a required-role name
                roles.add(obj);
            }
        }

        Object[] attrs = (Object[]) obj;
        String laName = ((String) attrs[0]).toUpperCase().replace('-', '_');
        String raName = ((String) attrs[1]).toUpperCase().replace('-', '_');

        LossAction laction = LossAction.fromName(laName);
        ResumptionAction raction = ResumptionAction.fromName(raName);

        MembershipAttributes ra = new MembershipAttributes((String[]) roles.toArray(new String[roles.size()]),
                laction, raction);
        RegionAttributesCreation rattrs = (RegionAttributesCreation) stack.peek();
        rattrs.setMembershipAttributes(ra);
    }

    /**
     * When a <code>required-role</code> element is finished,
     */
    private void endRequiredRole() {
        // do nothing... wait for endMembershipAttributes()
    }

    /**
     * When a <code>disk-write-attributes</code> element is finished, the {@link DiskWriteAttributes}
     * is on top of the stack followed by the {@link RegionAttributesCreation} to which the expiration
     * attributes are assigned.
     */
    private void endDiskWriteAttributes() {
        DiskWriteAttributes dwa = (DiskWriteAttributes) stack.pop();
        RegionAttributesCreation attrs = peekRegionAttributesContext(DISK_WRITE_ATTRIBUTES);
        attrs.setDiskWriteAttributes(dwa);
    }

    /**
     * When a <code>disk-dir</code> element is finished, the name of the directory is on top of the
     * stack. Create a new {@link File}and push it on the stack.
     */
    private void endDiskDir() {
        StringBuffer dirName = (StringBuffer) stack.pop();
        File dir = new File(dirName.toString().trim());
        if (!dir.exists()) {

        }
        stack.push(dir);
    }

    /**
     * When a <code>disk-dirs</code> element is finished, the directory {@link File}s are on the stack
     * followed by the {@link RegionAttributesCreation} to which the expiration attributes are
     * assigned.
     */
    private void endDiskDirs() {
        List dirs = new ArrayList();
        List sizes = new ArrayList();
        while (stack.peek() instanceof File) {
            dirs.add(stack.pop());
            sizes.add(stack.pop());
        }
        Assert.assertTrue(!dirs.isEmpty());
        Assert.assertTrue(!sizes.isEmpty());

        // should set the disk-dirs and sizes in reverse order since parsers would have reversed
        // the order because of pushing into stack
        File[] disks = new File[dirs.size()];
        int dirsLength = dirs.size();
        for (int i = 0; i < dirsLength; i++) {
            disks[i] = (File) dirs.get((dirsLength - 1) - i);
        }

        int[] diskSizes = new int[sizes.size()];
        for (int i = 0; i < dirsLength; i++) {
            diskSizes[i] = ((Integer) sizes.get((dirsLength - 1) - i)).intValue();
        }

        Object a = stack.peek();
        if (a instanceof RegionAttributesCreation) {
            RegionAttributesCreation attrs = (RegionAttributesCreation) a;
            attrs.setDiskDirsAndSize(disks, diskSizes);
        } else if (a instanceof DiskStoreAttributesCreation) {
            DiskStoreAttributesCreation attrs = (DiskStoreAttributesCreation) a;
            attrs.setDiskDirsAndSize(disks, diskSizes);
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES
                            .toLocalizedString(DISK_DIRS));
        }
    }

    /**
     * When a <code>synchronous-writes</code> element is encounter, we push a
     * {@link DiskWriteAttributes} for doing synchronous writes on the stack.
     */
    private void startSynchronousWrites() {
        int maxOplogSize = ((Integer) stack.pop()).intValue();
        String rollOplog = (String) stack.pop();
        // convery megabytes to bytes for DiskWriteAttributes creation
        long maxOplogSizeInBytes = maxOplogSize;
        maxOplogSizeInBytes = maxOplogSizeInBytes * 1024 * 1024;
        Properties props = new Properties();
        props.setProperty(MAX_OPLOG_SIZE, String.valueOf(maxOplogSizeInBytes));
        props.setProperty(ROLL_OPLOG, rollOplog);
        props.setProperty(DiskWriteAttributesImpl.SYNCHRONOUS_PROPERTY, "true");
        stack.push(new DiskWriteAttributesImpl(props));
    }

    /**
     * When a <code>asynchronous-writes</code> element is encounter, we push a
     * {@link DiskWriteAttributes} for doing asynchronous writes on the stack.
     */
    private void startAsynchronousWrites(Attributes atts) {
        int maxOplogSize = ((Integer) stack.pop()).intValue();
        String rollOplog = (String) stack.pop();
        // convery megabytes to bytes for DiskWriteAttributes creation
        long maxOplogSizeInBytes = maxOplogSize;
        maxOplogSizeInBytes = maxOplogSizeInBytes * 1024 * 1024;
        long timeInterval = parseLong(atts.getValue(TIME_INTERVAL));
        long bytesThreshold = parseLong(atts.getValue(BYTES_THRESHOLD));
        Properties props = new Properties();
        props.setProperty(MAX_OPLOG_SIZE, String.valueOf(maxOplogSizeInBytes));
        props.setProperty(ROLL_OPLOG, rollOplog);
        props.setProperty(TIME_INTERVAL, String.valueOf(timeInterval));
        props.setProperty(DiskWriteAttributesImpl.SYNCHRONOUS_PROPERTY, "false");
        props.setProperty(BYTES_THRESHOLD, String.valueOf(bytesThreshold));
        stack.push(new DiskWriteAttributesImpl(props));
    }

    /**
     * When a <code>parition-attributes</code> element is encountered, we push a ParitionAttributes??
     * for configuring paritioned storage on the stack.
     */
    private void startPartitionAttributes(Attributes atts) {
        PartitionAttributesImpl paf = new PartitionAttributesImpl();
        String redundancy = atts.getValue(PARTITION_REDUNDANT_COPIES);
        if (redundancy != null) {
            paf.setRedundantCopies(parseInt(redundancy));
        }
        String localMaxMem = atts.getValue(LOCAL_MAX_MEMORY);
        if (localMaxMem != null) {
            paf.setLocalMaxMemory(parseInt(localMaxMem));
        }
        String totalMaxMem = atts.getValue(TOTAL_MAX_MEMORY);
        if (totalMaxMem != null) {
            paf.setTotalMaxMemory(parseLong(totalMaxMem));
        }
        String totalNumBuckets = atts.getValue(TOTAL_NUM_BUCKETS);
        if (totalNumBuckets != null) {
            paf.setTotalNumBuckets(parseInt(totalNumBuckets));
        }
        String colocatedWith = atts.getValue(PARTITION_COLOCATED_WITH);
        if (colocatedWith != null) {
            paf.setColocatedWith(colocatedWith);
        }
        String recoveryDelay = atts.getValue(RECOVERY_DELAY);
        if (recoveryDelay != null) {
            paf.setRecoveryDelay(parseInt(recoveryDelay));
        }
        String startupRecoveryDelay = atts.getValue(STARTUP_RECOVERY_DELAY);
        if (startupRecoveryDelay != null) {
            paf.setStartupRecoveryDelay(parseInt(startupRecoveryDelay));
        }
        stack.push(paf);
    }

    /**
     * When a <code>fixed-partition-attributes</code> element is encountered, we create an instance of
     * FixedPartitionAttributesImpl and add it to the PartitionAttributesImpl stack.
     */
    private void startFixedPartitionAttributes(Attributes atts) {
        FixedPartitionAttributesImpl fpai = new FixedPartitionAttributesImpl();
        String partitionName = atts.getValue(PARTITION_NAME);
        if (partitionName != null) {
            fpai.setPartitionName(partitionName);
        }
        String isPrimary = atts.getValue(IS_PRIMARY);
        if (isPrimary != null) {
            fpai.isPrimary(parseBoolean(isPrimary));
        }
        String numBuckets = atts.getValue(NUM_BUCKETS);
        if (numBuckets != null) {
            fpai.setNumBuckets(parseInt(numBuckets));
        }
        Object a = stack.peek();
        if (a instanceof PartitionAttributesImpl) {
            ((PartitionAttributesImpl) a).addFixedPartitionAttributes(fpai);
        }
    }

    /**
     * When a <code>membership-attributes</code> element is encountered, we push an array of
     * attributes for creation of a MembershipAttributes.
     */
    private void startMembershipAttributes(Attributes atts) {
        Object[] attrs = new Object[2]; // loss-action, resumption-action
        attrs[0] = atts.getValue(LOSS_ACTION) == null ? LossAction.NO_ACCESS.toString()
                : atts.getValue(LOSS_ACTION);
        attrs[1] = atts.getValue(RESUMPTION_ACTION) == null ? ResumptionAction.REINITIALIZE.toString()
                : atts.getValue(RESUMPTION_ACTION);

        stack.push(attrs);
    }

    /**
     * When a <code>subscription-attributes</code> element is first encountered, we create an
     * SubscriptionAttibutes?? object from the element's attributes and stick it in the current region
     * attributes.
     */
    private void startSubscriptionAttributes(Attributes atts) {
        String ip = atts.getValue(INTEREST_POLICY);
        SubscriptionAttributes sa;
        if (ip == null) {
            sa = new SubscriptionAttributes();
        } else if (ip.equals(ALL)) {
            sa = new SubscriptionAttributes(InterestPolicy.ALL);
        } else if (ip.equals(CACHE_CONTENT)) {
            sa = new SubscriptionAttributes(InterestPolicy.CACHE_CONTENT);
        } else {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_UNKNOWN_INTERESTPOLICY_0.toLocalizedString(ip));
        }
        RegionAttributesCreation rattrs = (RegionAttributesCreation) stack.peek();
        rattrs.setSubscriptionAttributes(sa);
    }

    /**
     * When a <code>required-role</code> element is encountered, we push a string for creation of
     * MembershipAttributes.
     */
    private void startRequiredRole(Attributes atts) {
        stack.push(atts.getValue(NAME));
    }

    /**
     * When a <code>index</code> element is encounter, we create the IndexCreationData object from the
     * Stack. Set the required parameters in the IndexCreationData object & push it on stack.
     *
     */
    private void startIndex(Attributes atts) {
        boolean isPrimary = false;
        String type = "";
        IndexCreationData icd = new IndexCreationData(atts.getValue(NAME));

        int len = atts.getLength();
        if (len > 1) {
            if (Boolean.valueOf(atts.getValue(KEY_INDEX))) {
                icd.setIndexType(IndexType.PRIMARY_KEY);
                isPrimary = true;
            }
            type = atts.getValue(INDEX_TYPE);
        }

        if (len > 2) {
            String fromClause = atts.getValue(FROM_CLAUSE);
            String expression = atts.getValue(EXPRESSION);
            String importStr = atts.getValue(IMPORTS);
            if (isPrimary) {
                icd.setIndexData(IndexType.PRIMARY_KEY, null, expression, null);
            } else {
                if (type == null) {
                    type = RANGE_INDEX_TYPE;
                }
                if (type.equals(HASH_INDEX_TYPE)) {
                    icd.setIndexData(IndexType.HASH, fromClause, expression, importStr);
                } else if (type.equals(RANGE_INDEX_TYPE)) {
                    icd.setIndexData(IndexType.FUNCTIONAL, fromClause, expression, importStr);
                } else {
                    logger.trace(LogMarker.CACHE_XML_PARSER,
                            LocalizedMessage.create(LocalizedStrings.CacheXmlParser_UNKNOWN_INDEX_TYPE, type));
                    icd.setIndexData(IndexType.FUNCTIONAL, fromClause, expression, importStr);
                }
            }
        }
        this.stack.push(icd);
    }

    /**
     * When index element is ending we need to verify all attributes because of new index tag
     * definition since 6.6.1 and support previous definition also.
     * 
     * if <code>functional</code> element was not there then we need to validate expression and
     * fromClause as not null.
     */
    private void endIndex() {
        boolean throwExcep = false;
        IndexCreationData icd = (IndexCreationData) this.stack.pop();

        if (icd.getIndexType() == null) {
            throwExcep = true;
        } else {
            if (icd.getIndexType().equals(IndexType.PRIMARY_KEY)) {
                if (icd.getIndexExpression() == null) {
                    throwExcep = true;
                }
            } else {
                if (icd.getIndexExpression() == null && icd.getIndexFromClause() == null) {
                    throwExcep = true;
                }
            }
        }

        if (!throwExcep) {
            RegionCreation rc = (RegionCreation) this.stack.peek();
            rc.addIndexData(icd);
        } else {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_CACHEXMLPARSERENDINDEXINDEX_CREATION_ATTRIBUTE_NOT_CORRECTLY_SPECIFIED
                            .toLocalizedString());
        }
    }

    /**
     * When a <code>functional</code> element is encounter, we pop the IndexCreationData object from
     * the Stack. Set the required parameters in the IndexCreationData object & set it in
     * RegionCreation object.
     *
     */
    private void startFunctionalIndex(Attributes atts) {
        boolean throwExcep = false;
        IndexCreationData icd = (IndexCreationData) this.stack.peek();
        // icd.setIndexType(FUNCTIONAL);
        int len = -1;
        if ((len = atts.getLength()) > 1) {
            String fromClause = atts.getValue(FROM_CLAUSE);
            String expression = atts.getValue(EXPRESSION);
            String importStr = null;
            if (len == 3)
                importStr = atts.getValue(IMPORTS);
            if (fromClause == null || expression == null) {
                throwExcep = true;
            } else {
                icd.setIndexData(IndexType.FUNCTIONAL, fromClause, expression, importStr);
            }
        } else {
            throwExcep = true;
        }
        if (throwExcep) {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_CACHEXMLPARSERSTARTFUNCTIONALINDEXINDEX_CREATION_ATTRIBUTE_NOT_CORRECTLY_SPECIFIED
                            .toLocalizedString());
        }
    }

    /**
     * When a <code>primary-key</code> element is encounter, we pop the IndexCreationData object from
     * the Stack. Set the required parameters in the IndexCreationData object & set it in
     * RegionCreation object.
     *
     */
    private void startPrimaryKeyIndex(Attributes atts) {
        IndexCreationData icd = (IndexCreationData) this.stack.peek();
        // icd.setIndexType(PRIMARY_KEY);
        boolean throwExcep = false;
        if (atts.getLength() == 1) {
            String field = atts.getValue(FIELD);
            if (field == null) {
                throwExcep = true;
            } else {
                icd.setIndexData(IndexType.PRIMARY_KEY, null, field, null);
            }
        } else {
            throwExcep = true;
        }
        if (throwExcep) {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_CACHEXMLPARSERSTARTPRIMARYKEYINDEXPRIMARYKEY_INDEX_CREATION_FIELD_IS_NULL
                            .toLocalizedString());
        }
    }

    /**
     * When a <code>expiration-attributes</code> element is first encountered, we create an
     * ExpirationAttibutes?? object from the element's attributes and push it on the stack.
     */
    private void startExpirationAttributes(Attributes atts) {
        int timeout = parseInt(atts.getValue(TIMEOUT));
        String action = atts.getValue(ACTION);
        ExpirationAttributes expire;
        if (action == null) {
            expire = new ExpirationAttributes(timeout);
        } else if (action.equals(INVALIDATE)) {
            expire = new ExpirationAttributes(timeout, ExpirationAction.INVALIDATE);
        } else if (action.equals(DESTROY)) {
            expire = new ExpirationAttributes(timeout, ExpirationAction.DESTROY);
        } else if (action.equals(LOCAL_INVALIDATE)) {
            expire = new ExpirationAttributes(timeout, ExpirationAction.LOCAL_INVALIDATE);
        } else if (action.equals(LOCAL_DESTROY)) {
            expire = new ExpirationAttributes(timeout, ExpirationAction.LOCAL_DESTROY);
        } else {
            throw new InternalGemFireException(
                    LocalizedStrings.CacheXmlParser_UNKNOWN_EXPIRATION_ACTION_0.toLocalizedString(action));
        }
        stack.push(expire);
    }

    /**
     * When a <code>serializer-registration element is first encountered, we need to create the
     * wrapper object to hold the data, and put it on the stack.
     */
    private void startSerializerRegistration() {
        SerializerCreation sc = new SerializerCreation();
        this.stack.push(sc);
    }

    /**
     * When an <code>instantiator</code> element is first encountered, we need to hang on to the id
     * attribute for use in registration in the end tag function.
     */
    private void startInstantiator(Attributes atts) {
        int id = parseInt(atts.getValue(ID));
        this.stack.push(id);
    }

    /**
     * Creates and initializes an instance of {@link Declarable} from the contents of the stack.
     *
     * @throws CacheXmlException Something goes wrong while instantiating or initializing the
     *         declarable
     */
    private Declarable createDeclarable() {
        Properties props = new Properties();
        Object top = stack.pop();
        while (top instanceof Parameter) {
            Parameter param = (Parameter) top;
            props.put(param.getName(), param.getValue());
            top = stack.pop();
        }
        logger.trace(LogMarker.CACHE_XML_PARSER, LocalizedMessage
                .create(LocalizedStrings.CacheXmlParser_XML_PARSER_CREATEDECLARABLE_PROPERTIES__0, props));
        Assert.assertTrue(top instanceof String);
        String className = (String) top;
        logger.trace(LogMarker.CACHE_XML_PARSER, LocalizedMessage
                .create(LocalizedStrings.CacheXmlParser_XML_PARSER_CREATEDECLARABLE_CLASS_NAME_0, className));
        Object o;
        try {
            Class c = InternalDataSerializer.getCachedClass(className);
            o = c.newInstance();
        } catch (Exception ex) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_WHILE_INSTANTIATING_A_0.toLocalizedString(className), ex);
        }
        if (!(o instanceof Declarable)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_CLASS_0_IS_NOT_AN_INSTANCE_OF_DECLARABLE
                    .toLocalizedString(className));
        }
        Declarable d = (Declarable) o;
        d.init(props);

        this.cache.addDeclarableProperties(d, props);

        return d;
    }

    /**
     * Ending the <code>compressor</code> registration should leave us with a class name on the stack.
     * Pull it off and setup the {@link Compressor} on the region attributes.
     */
    private void endCompressor() {
        Class<?> klass = getClassFromStack();
        if (!Compressor.class.isAssignableFrom(klass)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_COMPRESSOR
                    .toLocalizedString(klass.getName()));
        }

        Compressor compressor;
        try {
            compressor = (Compressor) klass.newInstance();
        } catch (Exception ex) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_WHILE_INSTANTIATING_A_0.toLocalizedString(klass.getName()), ex);
        }

        Object a = stack.peek();

        if (a instanceof RegionAttributesCreation) {
            RegionAttributesCreation attrs = (RegionAttributesCreation) a;
            attrs.setCompressor(compressor);
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES_OR_1
                            .toLocalizedString(new Object[] { COMPRESSOR, DYNAMIC_REGION_FACTORY }));
        }
    }

    /**
     * When a <code>cache-loader</code> element is finished, the {@link Parameter}s and class names
     * are popped off the stack. The cache loader is instantiated and initialized with the parameters,
     * if appropriate. When the loader is being created in a dynamic-region-factory, there may be a
     * disk-dir element on the stack, represented by a File object. Otherwise, dynamic-region-factory
     * uses a RegionAttributesCreation, just like a region, and is treated the same.<p) The loader may
     * also be created in the context of partition-attributes.
     */
    private void endCacheLoader() {
        Declarable d = createDeclarable();
        if (!(d instanceof CacheLoader)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_CACHELOADER
                    .toLocalizedString(d.getClass().getName()));
        }
        // Two peeks required to handle dynamic region context
        Object a = stack.peek();
        // check for disk-dir
        if ((a instanceof File)) {
            Object sav = stack.pop();
            a = stack.peek();
            if (!(a instanceof RegionAttributesCreation)) {
                throw new CacheXmlException(
                        LocalizedStrings.CacheXmlParser_A_CACHELOADER_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES
                                .toLocalizedString());
            }
            stack.push(sav);
            RegionAttributesCreation attrs = (RegionAttributesCreation) a;
            attrs.setCacheLoader((CacheLoader) d);
        }
        // check for normal region-attributes
        else if (a instanceof RegionAttributesCreation) {
            RegionAttributesCreation attrs = (RegionAttributesCreation) a;
            attrs.setCacheLoader((CacheLoader) d);
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES_OR_1
                            .toLocalizedString(new Object[] { CACHE_LOADER, DYNAMIC_REGION_FACTORY }));
        }
    }

    /**
     * When a <code>cache-writer</code> element is finished, the {@link Parameter}s and class names
     * are popped off the stack. The cache writer is instantiated and initialized with the parameters,
     * if appropriate.
     * <p>
     * A cache-writer may be created in the context of region-attributes or dynamic-region-factory. In
     * the latter case, there may be a disk-dir on top of the stack, represented by a File object.
     */
    private void endCacheWriter() {
        Declarable d = createDeclarable();
        if (!(d instanceof CacheWriter)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_CACHEWRITER
                    .toLocalizedString(d.getClass().getName()));
        }

        Object a = stack.peek();
        // check for partition-attributes
        // if (a instanceof PartitionAttributesFactory) {
        // PartitionAttributesFactory fac = (PartitionAttributesFactory) a;
        // fac.setCacheWriter((CacheWriter) d);
        // }
        // else
        // check for disk-dir
        if ((a instanceof File)) {
            Object sav = stack.pop();
            Object size = stack.pop(); // pop out disk size
            a = stack.peek();
            //
            if (!(a instanceof RegionAttributesCreation)) {
                throw new CacheXmlException(LocalizedStrings.CacheXmlParser_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_1
                        .toLocalizedString(new Object[] { CACHE_WRITER, DYNAMIC_REGION_FACTORY }));
            }
            stack.push(size);
            stack.push(sav);
        }
        // check for normal region-attributes
        else if (!(a instanceof RegionAttributesCreation)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_REGIONATTRIBUTES
                            .toLocalizedString(CACHE_WRITER));
        }

        RegionAttributesCreation attrs = (RegionAttributesCreation) a;
        attrs.setCacheWriter((CacheWriter) d);
    }

    private void endCustomExpiry() {

        Declarable d = createDeclarable();
        if (!(d instanceof CustomExpiry)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_CUSTOMEXPIRY
                    .toLocalizedString(d.getClass().getName()));
        }
        stack.push(d);
    }

    /**
     * Create an <code>lru-entry-count</code> eviction controller, assigning it to the enclosed
     * <code>region-attributes</code>. Allow any combination of attributes to be provided. Use the
     * default values for any attribute that is not provided.
     * 
     * @param atts
     */
    /**
     * @param atts
     */
    private void startLRUEntryCount(Attributes atts) {
        final String maximum = atts.getValue(MAXIMUM);
        int max = LRUCapacityController.DEFAULT_MAXIMUM_ENTRIES;
        if (maximum != null) {
            max = parseInt(maximum);
        }
        final String lruAction = atts.getValue(ACTION);
        EvictionAction action = EvictionAction.DEFAULT_EVICTION_ACTION;
        if (lruAction != null) {
            action = EvictionAction.parseAction(lruAction);
        }
        RegionAttributesCreation regAttrs = peekRegionAttributesContext(LRU_ENTRY_COUNT);
        regAttrs.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(max, action));
    }

    /**
     * Start the configuration of a <code>lru-memory-size</code> eviction controller. Allow for any of
     * the attributes to be missing. Store the attributes on the stack anticipating the declaration of
     * an {@link ObjectSizer}.
     * 
     * @param atts
     */
    private void startLRUMemorySize(Attributes atts) {
        String lruAction = atts.getValue(ACTION);
        EvictionAction action = EvictionAction.DEFAULT_EVICTION_ACTION;
        if (lruAction != null) {
            action = EvictionAction.parseAction(lruAction);
        }
        String maximum = atts.getValue(MAXIMUM);
        int max = MemLRUCapacityController.DEFAULT_MAXIMUM_MEGABYTES;
        if (maximum != null) {
            max = parseInt(maximum);
        }
        // Store for later addition of ObjectSizer, if any (the cast is for clarity sake)
        stack.push(EvictionAttributes.createLRUMemoryAttributes(max, null, action));
    }

    /**
     * Complete the configuration of a <code>lru-memory-size</code> eviction controller. Check for the
     * declaration of an {@link ObjectSizer}. Assign the attributes to the enclose
     * <code>region-attributes</code>
     */
    private void endLRUMemorySize() {
        Object declCheck = stack.peek();
        Declarable d = null;
        if (declCheck instanceof String || declCheck instanceof Parameter) {
            d = createDeclarable();
            if (!(d instanceof ObjectSizer)) {
                throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_OBJECTSIZER
                        .toLocalizedString(d.getClass().getName()));
            }
        }
        EvictionAttributesImpl eai = (EvictionAttributesImpl) stack.pop();
        if (d != null) {
            eai.setObjectSizer((ObjectSizer) d);
        }
        RegionAttributesCreation regAttrs = peekRegionAttributesContext(LRU_MEMORY_SIZE);
        regAttrs.setEvictionAttributes(eai);
    }

    /**
     * Create an <code>lru-heap-percentage</code> eviction controller, assigning it to the enclosed
     * <code>region-attributes</code>
     * 
     * @param atts
     */
    private void startLRUHeapPercentage(Attributes atts) {
        final String lruAction = atts.getValue(ACTION);
        EvictionAction action = EvictionAction.DEFAULT_EVICTION_ACTION;
        if (lruAction != null) {
            action = EvictionAction.parseAction(lruAction);
        }
        // Store for later addition of ObjectSizer, if any
        stack.push(EvictionAttributes.createLRUHeapAttributes(null, action));
    }

    /**
     * Complete the configuration of a <code>lru-heap-percentage</code> eviction controller. Check for
     * the declaration of an {@link ObjectSizer}. Assign the attributes to the enclosed
     * <code>region-attributes</code>
     */
    private void endLRUHeapPercentage() {
        Object declCheck = stack.peek();
        Declarable d = null;
        if (declCheck instanceof String || declCheck instanceof Parameter) {
            d = createDeclarable();
            if (!(d instanceof ObjectSizer)) {
                String s = "A " + d.getClass().getName() + " is not an instance of a ObjectSizer";
                throw new CacheXmlException(s);
            }
        }
        EvictionAttributesImpl eai = (EvictionAttributesImpl) stack.pop();
        if (d != null) {
            eai.setObjectSizer((ObjectSizer) d);
        }
        RegionAttributesCreation regAttrs = peekRegionAttributesContext(LRU_HEAP_PERCENTAGE);
        regAttrs.setEvictionAttributes(eai);
    }

    /**
     * When a <code>cache-listener</code> element is finished, the {@link Parameter}s and class names
     * are popped off the stack. The cache listener is instantiated and initialized with the
     * parameters, if appropriate.
     */
    private void endCacheListener() {
        Declarable d = createDeclarable();
        if (!(d instanceof CacheListener)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_CACHELISTENER
                    .toLocalizedString(d.getClass().getName()));
        }
        RegionAttributesCreation attrs = peekRegionAttributesContext(CACHE_LISTENER);
        attrs.addCacheListener((CacheListener) d);
    }

    private void startAsyncEventQueue(Attributes atts) {
        AsyncEventQueueCreation asyncEventQueueCreation = new AsyncEventQueueCreation();

        // id
        String id = atts.getValue(ID);
        asyncEventQueueCreation.setId(id);

        String parallel = atts.getValue(PARALLEL);
        if (parallel == null) {
            asyncEventQueueCreation.setParallel(GatewaySender.DEFAULT_IS_PARALLEL);
        } else {
            asyncEventQueueCreation.setParallel(Boolean.parseBoolean(parallel));
        }
        // batch-size
        String batchSize = atts.getValue(BATCH_SIZE);
        if (batchSize == null) {
            asyncEventQueueCreation.setBatchSize(GatewaySender.DEFAULT_BATCH_SIZE);
        } else {
            asyncEventQueueCreation.setBatchSize(Integer.parseInt(batchSize));
        }

        // batch-time-interval
        String batchTimeInterval = atts.getValue(BATCH_TIME_INTERVAL);
        if (batchTimeInterval == null) {
            asyncEventQueueCreation.setBatchTimeInterval(GatewaySender.DEFAULT_BATCH_TIME_INTERVAL);
        } else {
            asyncEventQueueCreation.setBatchTimeInterval(Integer.parseInt(batchTimeInterval));
        }

        // batch-conflation
        String batchConflation = atts.getValue(ENABLE_BATCH_CONFLATION);
        if (batchConflation == null) {
            asyncEventQueueCreation.setBatchConflationEnabled(GatewaySender.DEFAULT_BATCH_CONFLATION);
        } else {
            asyncEventQueueCreation.setBatchConflationEnabled(Boolean.parseBoolean(batchConflation));
        }

        // maximum-queue-memory
        String maxQueueMemory = atts.getValue(MAXIMUM_QUEUE_MEMORY);
        if (maxQueueMemory == null) {
            asyncEventQueueCreation.setMaximumQueueMemory(GatewaySender.DEFAULT_MAXIMUM_QUEUE_MEMORY);
        } else {
            asyncEventQueueCreation.setMaximumQueueMemory(Integer.parseInt(maxQueueMemory));
        }

        // persistent
        String persistent = atts.getValue(PERSISTENT);
        if (persistent == null) {
            asyncEventQueueCreation.setPersistent(GatewaySender.DEFAULT_PERSISTENCE_ENABLED);
        } else {
            asyncEventQueueCreation.setPersistent(Boolean.parseBoolean(persistent));
        }

        // diskStoreName
        String diskStoreName = atts.getValue(DISK_STORE_NAME);
        if (diskStoreName == null) {
            asyncEventQueueCreation.setDiskStoreName(null);
        } else {
            asyncEventQueueCreation.setDiskStoreName(diskStoreName);
        }

        // diskSynchronous
        String diskSynchronous = atts.getValue(DISK_SYNCHRONOUS);
        if (diskSynchronous == null) {
            asyncEventQueueCreation.setDiskSynchronous(GatewaySender.DEFAULT_DISK_SYNCHRONOUS);
        } else {
            asyncEventQueueCreation.setDiskSynchronous(Boolean.parseBoolean(diskSynchronous));
        }

        String dispatcherThreads = atts.getValue(DISPATCHER_THREADS);
        if (dispatcherThreads == null) {
            asyncEventQueueCreation.setDispatcherThreads(GatewaySender.DEFAULT_DISPATCHER_THREADS);
        } else {
            asyncEventQueueCreation.setDispatcherThreads(Integer.parseInt(dispatcherThreads));
        }

        String orderPolicy = atts.getValue(ORDER_POLICY);
        if (orderPolicy != null) {
            try {
                asyncEventQueueCreation
                        .setOrderPolicy(GatewaySender.OrderPolicy.valueOf(orderPolicy.toUpperCase()));
            } catch (IllegalArgumentException e) {
                throw new InternalGemFireException(LocalizedStrings.AsyncEventQueue_UNKNOWN_ORDER_POLICY_0_1
                        .toLocalizedString(new Object[] { id, orderPolicy }));
            }
        }

        // forward expiration destroy events.
        String forward = atts.getValue(FORWARD_EXPIRATION_DESTROY);
        if (forward != null) {
            asyncEventQueueCreation.setForwardExpirationDestroy(Boolean.parseBoolean(forward));
        }

        stack.push(asyncEventQueueCreation);
    }

    private void endAsyncEventListener() {
        Declarable d = createDeclarable();
        if (!(d instanceof AsyncEventListener)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_ASYNCEVENTLISTENER
                            .toLocalizedString(d.getClass().getName()));
        }
        AsyncEventQueueCreation eventChannel = peekAsyncEventQueueContext(ASYNC_EVENT_LISTENER);
        eventChannel.setAsyncEventListener((AsyncEventListener) d);
    }

    private AsyncEventQueueCreation peekAsyncEventQueueContext(String dependentElement) {
        Object a = stack.peek();
        if (!(a instanceof AsyncEventQueueCreation)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_ASYNCEVENTQUEUE
                            .toLocalizedString(dependentElement));
        }
        return (AsyncEventQueueCreation) a;
    }

    private void endAsyncEventQueue() {
        AsyncEventQueueCreation asyncEventChannelCreation = (AsyncEventQueueCreation) stack.peek();
        AsyncEventQueueFactory factory = cache.createAsyncEventQueueFactory();
        factory.setParallel(asyncEventChannelCreation.isParallel());
        factory.setBatchSize(asyncEventChannelCreation.getBatchSize());
        factory.setBatchTimeInterval(asyncEventChannelCreation.getBatchTimeInterval());
        factory.setBatchConflationEnabled(asyncEventChannelCreation.isBatchConflationEnabled());
        factory.setPersistent(asyncEventChannelCreation.isPersistent());
        factory.setDiskStoreName(asyncEventChannelCreation.getDiskStoreName());
        factory.setDiskSynchronous(asyncEventChannelCreation.isDiskSynchronous());
        factory.setMaximumQueueMemory(asyncEventChannelCreation.getMaximumQueueMemory());
        factory.setDispatcherThreads(asyncEventChannelCreation.getDispatcherThreads());
        factory.setOrderPolicy(asyncEventChannelCreation.getOrderPolicy());
        factory.setForwardExpirationDestroy(asyncEventChannelCreation.isForwardExpirationDestroy());
        List<GatewayEventFilter> gatewayEventFilters = asyncEventChannelCreation.getGatewayEventFilters();
        for (GatewayEventFilter gatewayEventFilter : gatewayEventFilters) {
            factory.addGatewayEventFilter(gatewayEventFilter);
        }
        factory.setGatewayEventSubstitutionListener(asyncEventChannelCreation.getGatewayEventSubstitutionFilter());
        AsyncEventQueue asyncEventChannel = factory.create(asyncEventChannelCreation.getId(),
                asyncEventChannelCreation.getAsyncEventListener());

        stack.pop();
    }

    /**
     * When a <code>partition-resolver</code> element is finished, the {@link Parameter}s and class
     * names are popped off the stack. The <code>PartitionResolver</code> is instantiated and
     * initialized with the parameters, if appropriate.
     */
    private void endPartitionResolver() {
        Declarable d = createDeclarable();
        if (!(d instanceof PartitionResolver)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_1
                    .toLocalizedString(new Object[] { d.getClass().getName(), "PartitionResolver" }));

        }

        PartitionAttributesImpl pai = peekPartitionAttributesImpl(PARTITION_ATTRIBUTES);
        pai.setPartitionResolver((PartitionResolver) d);
    }

    /**
     * When a <code>partition-listener</code> element is finished, the {@link Parameter}s and class
     * names are popped off the stack. The <code>PartitionListener</code> is instantiated and
     * initialized with the parameters, if appropriate.
     */
    private void endPartitionListener() {
        Declarable d = createDeclarable();
        if (!(d instanceof PartitionListener)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_1
                    .toLocalizedString(new Object[] { d.getClass().getName(), "PartitionListener" }));

        }
        PartitionAttributesImpl pai = peekPartitionAttributesImpl(PARTITION_ATTRIBUTES);
        pai.addPartitionListener((PartitionListener) d);
    }

    /**
     * When we have encountered a FunctionService element, we create the object and push it onto stack
     */
    private void startFunctionService() {
        this.stack.push(new FunctionServiceCreation());
    }

    /**
     * When we have finished a FunctionService element, we create the object and push it onto stack
     */
    private void endFunctionService() {
        Object top = stack.pop();
        if (!(top instanceof FunctionServiceCreation)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_EXPECTED_A_FUNCTIONSERVICECREATION_INSTANCE
                    .toLocalizedString());
        }
        FunctionServiceCreation fsc = (FunctionServiceCreation) top;
        fsc.create();
    }

    /**
     * Start the Resource Manager element configuration
     * 
     * @param atts XML attributes for the resource-manager
     */
    private void startResourceManager(final Attributes atts) {
        ResourceManagerCreation rmc = new ResourceManagerCreation();
        {
            String chp = atts.getValue(CRITICAL_HEAP_PERCENTAGE);
            if (chp != null) {
                rmc.setCriticalHeapPercentage(parseFloat(chp));
            } else {
                rmc.setCriticalHeapPercentageToDefault();
            }
        }

        {
            String ehp = atts.getValue(EVICTION_HEAP_PERCENTAGE);
            if (ehp != null) {
                rmc.setEvictionHeapPercentage(parseFloat(ehp));
            } else {
                rmc.setEvictionHeapPercentageToDefault();
            }
        }

        {
            String chp = atts.getValue(CRITICAL_OFF_HEAP_PERCENTAGE);
            if (chp != null) {
                rmc.setCriticalOffHeapPercentage(parseFloat(chp));
            } else {
                rmc.setCriticalOffHeapPercentageToDefault();
            }
        }

        {
            String ehp = atts.getValue(EVICTION_OFF_HEAP_PERCENTAGE);
            if (ehp != null) {
                rmc.setEvictionOffHeapPercentage(parseFloat(ehp));
            } else {
                rmc.setEvictionOffHeapPercentageToDefault();
            }
        }
        this.stack.push(rmc);
    }

    private void endResourceManager() {
        Object top = stack.pop();
        if (!(top instanceof ResourceManagerCreation)) {
            throw new CacheXmlException("Expected a ResourceManagerCreation instance");
        }
        ResourceManagerCreation rmc = (ResourceManagerCreation) top;
        // TODO set any listeners here
        // rmc.addResourceListener(null);
        this.cache.setResourceManagerCreation(rmc);
    }

    private void endBackup() {
        StringBuffer str = (StringBuffer) stack.pop();
        File backup = new File(str.toString().trim());
        this.cache.addBackup(backup);
    }

    /**
     * When we have finished a function element, we create the Declarable and push it onto stack
     */
    private void endFunctionName() {
        Declarable d = createDeclarable();
        if (!(d instanceof Function)) {
            String s = LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_FUNCTION
                    .toLocalizedString(d.getClass().getName());
            throw new CacheXmlException(s);
        }

        Object fs = stack.peek();
        if (!(fs instanceof FunctionServiceCreation)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_IS_ONLY_ALLOWED_IN_THE_CONTEXT_OF_1_MJTDEBUG_E_2
                            .toLocalizedString(new Object[] { FUNCTION, FUNCTION_SERVICE, fs }));
        }
        FunctionServiceCreation funcService = (FunctionServiceCreation) fs;
        funcService.registerFunction((Function) d);
    }

    private Class getClassFromStack() {
        Object o = this.stack.peek();
        if (!(o instanceof String)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_NO_CLASSNAME_FOUND.toLocalizedString());
        }
        String className = (String) this.stack.pop();

        try {
            Class c = InternalDataSerializer.getCachedClass(className);
            return c;
        } catch (Exception e) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_CLASS_NOT_FOUND.toLocalizedString(className), e);
        }
    }

    /**
     * Ending the top level <code>serialization-registration</code> element and actually doing the
     * work of registering all the components.
     */
    private void endSerializerRegistration() {
        SerializerCreation sc = (SerializerCreation) this.stack.pop();
        sc.create();
        this.cache.setSerializerCreation(sc);
    }

    /**
     * Ending the serialization registration should leave us with a class name on the stack. We will
     * call the DataSerializer.register() with the class once we find it.
     */
    private void endSerializer() {
        Class c = getClassFromStack();
        if (!(DataSerializer.class.isAssignableFrom(c))) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_NOT_A_SERIALIZER.toLocalizedString(c.getName()));
        }

        SerializerCreation sr = (SerializerCreation) this.stack.peek();
        sr.registerSerializer(c);
    }

    /**
     * Ending the instantiator registration should leave us with a class name and an Integer ID on the
     * stack. Pull them off, and setup the instantiator with an anonymous inner class to do the work.
     */
    private void endInstantiator() {
        final Class c = getClassFromStack();
        Class[] ifaces = c.getInterfaces();
        boolean found = false;
        for (Class clazz : ifaces) {
            if (clazz == DataSerializable.class) {
                found = true;
                break;
            }
        }
        if (!found) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_IS_NOT_DATA_SERIALIZABLE.toLocalizedString(c.getName()));
        }

        // the next thing on the stack should be the Integer registration ID
        Object o = this.stack.peek();
        if (!(o instanceof Integer)) {
            String s = LocalizedStrings.CacheXmlParser_NO_SERIALIZATION_ID.toLocalizedString();
            throw new CacheXmlException(s);
        }

        Integer id = (Integer) this.stack.pop();
        SerializerCreation sc = (SerializerCreation) this.stack.peek();
        sc.registerInstantiator(c, id);
    }

    /**
     * When we first encounter a <code>parameter</code> element, we push its name element on to the
     * stack.
     */
    private void startParameter(Attributes atts) {
        String name = atts.getValue(NAME);
        Assert.assertTrue(name != null);
        stack.push(name);
    }

    /**
     * When we have finished a <code>parameter</code> element, create a {@link Parameter}from the top
     * two elements of the stack.
     */
    private void endParameter() {
        Object value = stack.pop();
        String name = (String) stack.pop();
        stack.push(new Parameter(name, value));
    }

    /**
     * When we have finished a <code>declarable</code>, instantiate an instance of the
     * {@link Declarable}and push it on the stack.
     */
    private void endDeclarable() {
        Declarable d = createDeclarable();
        stack.push(d);
    }

    public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
            throws SAXException {
        // This while loop pops all StringBuffers at the top of the stack
        // that contain only whitespace; see GEODE-3306
        while (!stack.empty()) {
            Object o = stack.peek();
            if (o instanceof StringBuffer && StringUtils.isBlank(((StringBuffer) o).toString())) {
                stack.pop();
            } else {
                break;
            }
        }

        if (qName.equals(CACHE)) {
            startCache(atts);
        } else if (qName.equals(CLIENT_CACHE)) {
            startClientCache(atts);
        } else if (qName.equals(BRIDGE_SERVER)) {
            startCacheServer(atts);
        } else if (qName.equals(CACHE_SERVER)) {
            startCacheServer(atts);
        } else if (qName.equals(LOAD_PROBE)) {
        } else if (qName.equals(CONNECTION_POOL)) {
            startPool(atts);
        } else if (qName.equals(CLIENT_SUBSCRIPTION)) {
            startClientHaQueue(atts);
        } else if (qName.equals(DYNAMIC_REGION_FACTORY)) {
            startDynamicRegionFactory(atts);
        } else if (qName.equals(GATEWAY_SENDER)) {
            startGatewaySender(atts);
        } else if (qName.equals(GATEWAY_RECEIVER)) {
            startGatewayReceiver(atts);
        } else if (qName.equals(GATEWAY_EVENT_FILTER)) {
        } else if (qName.equals(GATEWAY_TRANSPORT_FILTER)) {
        } else if (qName.equals(GATEWAY_EVENT_LISTENER)) {
        } else if (qName.equals(GATEWAY_EVENT_SUBSTITUTION_FILTER)) {
        } else if (qName.equals(ASYNC_EVENT_QUEUE)) {
            startAsyncEventQueue(atts);
        } else if (qName.equals(GATEWAY_CONFLICT_RESOLVER)) {
        } else if (qName.equals(LOCATOR)) {
            doLocator(atts);
        } else if (qName.equals(REGION)) {
            startRegion(atts);
        } else if (qName.equals(VM_ROOT_REGION)) {
            startRegion(atts);
        } else if (qName.equals(REGION_ATTRIBUTES)) {
            startRegionAttributes(atts);
        } else if (qName.equals(DISK_STORE)) {
            startDiskStore(atts);
        } else if (qName.equals(KEY_CONSTRAINT)) {
        } else if (qName.equals(VALUE_CONSTRAINT)) {
        } else if (qName.equals(INDEX_UPDATE_TYPE)) {
        } else if (qName.equals(REGION_TIME_TO_LIVE)) {
        } else if (qName.equals(REGION_IDLE_TIME)) {
        } else if (qName.equals(ENTRY_TIME_TO_LIVE)) {
        } else if (qName.equals(ENTRY_IDLE_TIME)) {
        } else if (qName.equals(EXPIRATION_ATTRIBUTES)) {
            startExpirationAttributes(atts);
        } else if (qName.equals(SERVER)) {
            doServer(atts);
        } else if (qName.equals(CUSTOM_EXPIRY)) {
        } else if (qName.equals(SUBSCRIPTION_ATTRIBUTES)) {
            startSubscriptionAttributes(atts);
        } else if (qName.equals(ENTRY)) {
        } else if (qName.equals(CLASS_NAME)) {
        } else if (qName.equals(PARAMETER)) {
            startParameter(atts);
        } else if (qName.equals(DISK_WRITE_ATTRIBUTES)) {
            startDiskWriteAttributes(atts);
        } else if (qName.equals(SYNCHRONOUS_WRITES)) {
            startSynchronousWrites();
        } else if (qName.equals(ASYNCHRONOUS_WRITES)) {
            startAsynchronousWrites(atts);
        } else if (qName.equals(DISK_DIRS)) {
        } else if (qName.equals(DISK_DIR)) {
            startDiskDir(atts);
        } else if (qName.equals(GROUP)) {
        } else if (qName.equals(PARTITION_ATTRIBUTES)) {
            startPartitionAttributes(atts);
        } else if (qName.equals(FIXED_PARTITION_ATTRIBUTES)) {
            startFixedPartitionAttributes(atts);
        } else if (qName.equals(REQUIRED_ROLE)) {
            startRequiredRole(atts);
        } else if (qName.equals(MEMBERSHIP_ATTRIBUTES)) {
            startMembershipAttributes(atts);
        } else if (qName.equals(LOCAL_PROPERTIES)) {
            startPartitionProperties(atts, LOCAL_PROPERTIES);
        } else if (qName.equals(GLOBAL_PROPERTIES)) {
            startPartitionProperties(atts, GLOBAL_PROPERTIES);
        } else if (qName.equals(CACHE_LOADER)) {
        } else if (qName.equals(CACHE_WRITER)) {
        } else if (qName.equals(EVICTION_ATTRIBUTES)) {
        } else if (qName.equals(LRU_ENTRY_COUNT)) {
            startLRUEntryCount(atts); // internal to eviction-attributes
        } else if (qName.equals(LRU_MEMORY_SIZE)) {
            // internal to eviction-attributes
            // Visit endLRUMemorySize() to know the completion
            // of lru-memory-size eviction configuration
            startLRUMemorySize(atts);
        } else if (qName.equals(LRU_HEAP_PERCENTAGE)) {
            startLRUHeapPercentage(atts); // internal to eviction-attributes
        } else if (qName.equals(CACHE_LISTENER)) {
        } else if (qName.equals(ASYNC_EVENT_LISTENER)) {
        } else if (qName.equals(KEY)) {
        } else if (qName.equals(VALUE)) {
        } else if (qName.equals(STRING)) {
        } else if (qName.equals(DECLARABLE)) {
        } else if (qName.equals(INDEX)) {
            // Asif: Create an object of type IndexCreationData &
            // push it in stack
            startIndex(atts);
            // this.stack.push(new IndexCreationData(atts.getValue(NAME)));
        } else if (qName.equals(FUNCTIONAL)) {
            startFunctionalIndex(atts);
        } else if (qName.equals(PRIMARY_KEY)) {
            startPrimaryKeyIndex(atts);
        } else if (qName.equals(TRANSACTION_MANAGER)) {
            startCacheTransactionManager();
        } else if (qName.equals(TRANSACTION_LISTENER)) {
        } else if (qName.equals(TRANSACTION_WRITER)) {
        } else if (qName.equals(JNDI_BINDINGS)) { // added by Nand Kishor
        } else if (qName.equals(JNDI_BINDING)) { // added by Nand Kishor
            // Asif: Push the BindingCreation object in the stack
            Map gfSpecific = new HashMap();
            mapJNDI(atts, gfSpecific);
            List vendorSpecific = new ArrayList();
            this.stack.push(new BindingCreation(gfSpecific, vendorSpecific));
        } else if (qName.equals(CONFIG_PROPERTY_BINDING)) {
            // Asif : Peek at the BindingCreation object from stack
            // & get the vendor specific data map
            BindingCreation bc = (BindingCreation) this.stack.peek();
            List vendorSpecific = bc.getVendorSpecificList();
            // Rohit: Add a ConfigProperty Data Object to the list.
            vendorSpecific.add(new ConfigProperty());
        } else if (qName.equals(CONFIG_PROPERTY_NAME)) {
        } else if (qName.equals(CONFIG_PROPERTY_VALUE)) {
        } else if (qName.equals(CONFIG_PROPERTY_TYPE)) {
        } else if (qName.equals(PARTITION_RESOLVER)) {
        } else if (qName.equals(PARTITION_LISTENER)) {
        } else if (qName.equals(FUNCTION_SERVICE)) {
            startFunctionService();
        } else if (qName.equals(FUNCTION)) {
        } else if (qName.equals(TOP_SERIALIZER_REGISTRATION)) {
            startSerializerRegistration();
        } else if (qName.equals(INITIALIZER)) {
            startInitializer();
        } else if (qName.equals(INSTANTIATOR_REGISTRATION)) {
            startInstantiator(atts);
        } else if (qName.equals(SERIALIZER_REGISTRATION)) {
            // do nothing
        } else if (qName.equals(RESOURCE_MANAGER)) {
            startResourceManager(atts);
        } else if (qName.equals(BACKUP)) {
            // do nothing
        } else if (qName.equals(PDX)) {
            startPdx(atts);
        } else if (qName.equals(PDX_SERIALIZER)) {
            // do nothing
        } else if (qName.equals(COMPRESSOR)) {
        } else {
            final XmlParser delegate = getDelegate(namespaceURI);
            if (null == delegate) {
                throw new CacheXmlException(
                        LocalizedStrings.CacheXmlParser_UNKNOWN_XML_ELEMENT_0.toLocalizedString(qName));
            }

            delegate.startElement(namespaceURI, localName, qName, atts);
        }
    }

    /**
     * Get delegate {@link XmlParser} for the given <code>namespaceUri</code>
     * 
     * @param namespaceUri to find {@link XmlParser} for.
     * @return {@link XmlParser} if found, otherwise null.
     * @since GemFire 8.1
     */
    // UnitTest CacheXmlParser.testGetDelegate()
    private XmlParser getDelegate(final String namespaceUri) {
        XmlParser delegate = delegates.get(namespaceUri);
        if (null == delegate) {
            try {
                final ServiceLoader<XmlParser> serviceLoader = ServiceLoader.load(XmlParser.class,
                        ClassPathLoader.getLatestAsClassLoader());
                for (final XmlParser xmlParser : serviceLoader) {
                    if (xmlParser.getNamespaceUri().equals(namespaceUri)) {
                        delegate = xmlParser;
                        delegate.setStack(stack);
                        delegate.setDocumentLocator(documentLocator);
                        delegates.put(xmlParser.getNamespaceUri(), xmlParser);
                        break;
                    }
                }
            } catch (final Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        return delegate;
    }

    private void startPdx(Attributes atts) {
        String readSerialized = atts.getValue(READ_SERIALIZED);
        if (readSerialized != null) {
            cache.setPdxReadSerialized(Boolean.parseBoolean(readSerialized));
        }
        String ignoreUnreadFields = atts.getValue(IGNORE_UNREAD_FIELDS);
        if (ignoreUnreadFields != null) {
            cache.setPdxIgnoreUnreadFields(Boolean.parseBoolean(ignoreUnreadFields));
        }
        String persistent = atts.getValue(PERSISTENT);
        if (persistent != null) {
            cache.setPdxPersistent(Boolean.parseBoolean(persistent));
        }
        String diskStoreName = atts.getValue(DISK_STORE_NAME);
        if (diskStoreName != null) {
            cache.setPdxDiskStore(diskStoreName);
        }
    }

    /**
     * When a <code>client-subscription</code> element is first encountered, create a new
     * {@link ClientSubscriptionConfig } to store the <code>eviction-policy</code>,
     * <p>
     * <code>capacity</code> and <code>overflow-directory</code>, then pass these values to Bridge
     * Server
     * 
     * @since GemFire 5.7
     */
    private void startClientHaQueue(Attributes atts) {
        ClientHaQueueCreation clientHaQueue = new ClientHaQueueCreation();
        String haEvictionPolicy = atts.getValue(CLIENT_SUBSCRIPTION_EVICTION_POLICY);
        if (haEvictionPolicy != null) {
            clientHaQueue.setEvictionPolicy(haEvictionPolicy);
        }
        String haCapacity = atts.getValue(CLIENT_SUBSCRIPTION_CAPACITY);
        if (haCapacity != null) {
            clientHaQueue.setCapacity(Integer.parseInt(haCapacity));
        }
        String diskStoreName = atts.getValue(DISK_STORE_NAME);
        if (diskStoreName != null) {
            clientHaQueue.setDiskStoreName(diskStoreName);
        } else {
            String haOverflowDirectory = atts.getValue(OVERFLOW_DIRECTORY);
            if (haOverflowDirectory != null) {
                clientHaQueue.setOverflowDirectory(haOverflowDirectory);
            }
        }
        this.stack.push(clientHaQueue);
    }

    /**
     * Add a marker string to look for when in endPartitionProperties
     * 
     * @param atts
     * @param localOrGlobal either the string LOCAL_PROPERTIES or GLOBAL_PROPERTIES
     */
    private void startPartitionProperties(Attributes atts, String localOrGlobal) {
        stack.push(localOrGlobal);
    }

    private void startDiskDir(Attributes atts) {
        String size = atts.getValue(DIR_SIZE);
        Integer diskSize = null;
        if (size == null) {
            diskSize = Integer.valueOf(DiskStoreFactory.DEFAULT_DISK_DIR_SIZE);
        } else {
            diskSize = Integer.valueOf(size);
        }
        stack.push(diskSize);
    }

    private void startDiskWriteAttributes(Attributes atts) {
        String roll = atts.getValue(ROLL_OPLOG);
        if (roll == null) {
            roll = "true"; // because it defaults to true
        }

        String maxOp = atts.getValue(MAX_OPLOG_SIZE);
        int maxOplogSize = 0;
        if (maxOp != null) {
            maxOplogSize = parseInt(maxOp);
        } else {
            maxOplogSize = DiskWriteAttributesImpl.getDefaultMaxOplogSize();
        }
        stack.push(roll);
        stack.push(Integer.valueOf(maxOplogSize));
    }

    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
        // This while loop pops all StringBuffers at the top of the stack
        // that contain only whitespace; see GEODE-3306
        while (!stack.empty()) {
            Object o = stack.peek();
            if (o instanceof StringBuffer && StringUtils.isBlank(((StringBuffer) o).toString())) {
                stack.pop();
            } else {
                break;
            }
        }

        try {
            // logger.debug("endElement namespaceURI=" + namespaceURI
            // + "; localName = " + localName + "; qName = " + qName);
            if (qName.equals(CACHE)) {
                endCache();
            } else if (qName.equals(CLIENT_CACHE)) {
                endClientCache();
            } else if (qName.equals(BRIDGE_SERVER)) {
                endCacheServer();
            } else if (qName.equals(CACHE_SERVER)) {
                endCacheServer();
            } else if (qName.equals(LOAD_PROBE)) {
                endLoadProbe();
            } else if (qName.equals(CLIENT_SUBSCRIPTION)) {
                endClientHaQueue();
            } else if (qName.equals(CONNECTION_POOL)) {
                endPool();
            } else if (qName.equals(DYNAMIC_REGION_FACTORY)) {
                endDynamicRegionFactory();
            } else if (qName.equals(GATEWAY_SENDER)) {
                endSerialGatewaySender();
            } else if (qName.equals(GATEWAY_RECEIVER)) {
                endGatewayReceiver();
            } else if (qName.equals(GATEWAY_EVENT_FILTER)) {
                endGatewayEventFilter();
            } else if (qName.equals(GATEWAY_EVENT_SUBSTITUTION_FILTER)) {
                endGatewayEventSubstitutionFilter();
            } else if (qName.equals(GATEWAY_TRANSPORT_FILTER)) {
                endGatewayTransportFilter();
            } else if (qName.equals(ASYNC_EVENT_QUEUE)) {
                endAsyncEventQueue();
            } else if (qName.equals(REGION)) {
                endRegion();
            } else if (qName.equals(GATEWAY_CONFLICT_RESOLVER)) {
                endGatewayConflictResolver();
            } else if (qName.equals(VM_ROOT_REGION)) {
                endRegion();
            } else if (qName.equals(REGION_ATTRIBUTES)) {
                endRegionAttributes();
            } else if (qName.equals(DISK_STORE)) {
                endDiskStore();
            } else if (qName.equals(KEY_CONSTRAINT)) {
                endKeyConstraint();
            } else if (qName.equals(VALUE_CONSTRAINT)) {
                endValueConstraint();
            } else if (qName.equals(REGION_TIME_TO_LIVE)) {
                endRegionTimeToLive();
            } else if (qName.equals(REGION_IDLE_TIME)) {
                endRegionIdleTime();
            } else if (qName.equals(ENTRY_TIME_TO_LIVE)) {
                endEntryTimeToLive();
            } else if (qName.equals(ENTRY_IDLE_TIME)) {
                endEntryIdleTime();
            } else if (qName.equals(CUSTOM_EXPIRY)) {
                endCustomExpiry();
            } else if (qName.equals(DISK_WRITE_ATTRIBUTES)) {
                endDiskWriteAttributes();
            } else if (qName.equals(SYNCHRONOUS_WRITES)) {
            } else if (qName.equals(ASYNCHRONOUS_WRITES)) {
            } else if (qName.equals(DISK_DIRS)) {
                endDiskDirs();
            } else if (qName.equals(DISK_DIR)) {
                endDiskDir();
            } else if (qName.equals(GROUP)) {
                endGroup();
            } else if (qName.equals(PARTITION_ATTRIBUTES)) {
                endPartitionAttributes();
            } else if (qName.equals(FIXED_PARTITION_ATTRIBUTES)) {
                endFixedPartitionAttributes();
            } else if (qName.equals(LOCAL_PROPERTIES)) {
                endPartitionProperites(LOCAL_PROPERTIES);
            } else if (qName.equals(GLOBAL_PROPERTIES)) {
                endPartitionProperites(GLOBAL_PROPERTIES);
            } else if (qName.equals(MEMBERSHIP_ATTRIBUTES)) {
                endMembershipAttributes();
            } else if (qName.equals(REQUIRED_ROLE)) {
                endRequiredRole();
            } else if (qName.equals(EXPIRATION_ATTRIBUTES)) {
            } else if (qName.equals(CUSTOM_EXPIRY)) {
                endCustomExpiry();
            } else if (qName.equals(SUBSCRIPTION_ATTRIBUTES)) {
            } else if (qName.equals(ENTRY)) {
                endEntry();
            } else if (qName.equals(CLASS_NAME)) {
                endClassName();
            } else if (qName.equals(PARAMETER)) {
                endParameter();
            } else if (qName.equals(CACHE_LOADER)) {
                endCacheLoader();
            } else if (qName.equals(CACHE_WRITER)) {
                endCacheWriter();
            } else if (qName.equals(EVICTION_ATTRIBUTES)) {
            } else if (qName.equals(LRU_ENTRY_COUNT)) {
                // internal to eviction-attributes
            } else if (qName.equals(LRU_MEMORY_SIZE)) {
                endLRUMemorySize(); // internal to eviction-attributes
            } else if (qName.equals(LRU_HEAP_PERCENTAGE)) {
                endLRUHeapPercentage(); // internal to eviction-attributes
            } else if (qName.equals(CACHE_LISTENER)) {
                endCacheListener();
            } else if (qName.equals(ASYNC_EVENT_LISTENER)) {
                endAsyncEventListener();
            } else if (qName.equals(KEY)) {
            } else if (qName.equals(VALUE)) {
            } else if (qName.equals(STRING)) {
                endString();
            } else if (qName.equals(DECLARABLE)) {
                endDeclarable();
            } else if (qName.equals(FUNCTIONAL)) {
            } else if (qName.equals(INDEX)) {
                endIndex();
            } else if (qName.equals(PRIMARY_KEY)) {
            } else if (qName.equals(TRANSACTION_MANAGER)) {
                endCacheTransactionManager();
            } else if (qName.equals(TRANSACTION_LISTENER)) {
                endTransactionListener();
            } else if (qName.equals(TRANSACTION_WRITER)) {
                endTransactionWriter();
            } else if (qName.equals(JNDI_BINDINGS)) {
            } else if (qName.equals(JNDI_BINDING)) {
                // Asif Pop the BindingCreation object
                BindingCreation bc = (BindingCreation) this.stack.pop();
                JNDIInvoker.mapDatasource(bc.getGFSpecificMap(), bc.getVendorSpecificList());
            } else if (qName.equals(CONFIG_PROPERTY_BINDING)) {
            } else if (qName.equals(CONFIG_PROPERTY_NAME)) {
                String name = null;
                if (this.stack.peek() instanceof StringBuffer)
                    // Pop the config-property-name element value from the stack.
                    name = ((StringBuffer) this.stack.pop()).toString();
                BindingCreation bc = (BindingCreation) this.stack.peek();
                List vsList = bc.getVendorSpecificList();
                ConfigProperty cp = (ConfigProperty) vsList.get(vsList.size() - 1);
                if (name == null) {
                    String excep = LocalizedStrings.CacheXmlParser_EXCEPTION_IN_PARSING_ELEMENT_0_THIS_IS_A_REQUIRED_FIELD
                            .toLocalizedString(qName);
                    throw new CacheXmlException(excep);
                } else {
                    // set the name.
                    cp.setName(name);
                }
            } else if (qName.equals(CONFIG_PROPERTY_VALUE)) {
                String value = null;
                // Pop the config-property-value element value from the stack.
                if (this.stack.peek() instanceof StringBuffer)
                    value = ((StringBuffer) this.stack.pop()).toString();
                BindingCreation bc = (BindingCreation) this.stack.peek();
                List vsList = bc.getVendorSpecificList();
                ConfigProperty cp = (ConfigProperty) vsList.get(vsList.size() - 1);
                // Set the value to the ConfigProperty Data Object.
                cp.setValue(value);
            } else if (qName.equals(CONFIG_PROPERTY_TYPE)) {
                String type = null;
                if (this.stack.peek() instanceof StringBuffer)
                    type = ((StringBuffer) this.stack.pop()).toString();
                BindingCreation bc = (BindingCreation) this.stack.peek();
                List vsList = bc.getVendorSpecificList();
                ConfigProperty cp = (ConfigProperty) vsList.get(vsList.size() - 1);
                if (type == null) {
                    String excep = LocalizedStrings.CacheXmlParser_EXCEPTION_IN_PARSING_ELEMENT_0_THIS_IS_A_REQUIRED_FIELD
                            .toLocalizedString(qName);
                    throw new CacheXmlException(excep);
                } else {
                    cp.setType(type);
                }
            } else if (qName.equals(LRU_MEMORY_SIZE)) { // internal to eviction-attributes
                // Visit startLRUMemorySize() to know the begining
                // of lru-memory-size eviction configuration
                endLRUMemorySize();
            } else if (qName.equals(LOCATOR)) {
                // nothing needed
            } else if (qName.equals(SERVER)) {
                // nothing needed
            } else if (qName.equals(PARTITION_RESOLVER)) {
                endPartitionResolver();
            } else if (qName.equals(PARTITION_LISTENER)) {
                endPartitionListener();
            } else if (qName.equals(FUNCTION)) {
                endFunctionName();
            } else if (qName.equals(FUNCTION_SERVICE)) {
                endFunctionService();
            } else if (qName.equals(TOP_SERIALIZER_REGISTRATION)) {
                endSerializerRegistration();
            } else if (qName.equals(INITIALIZER)) {
                endInitializer();
            } else if (qName.equals(SERIALIZER_REGISTRATION)) {
                endSerializer();
            } else if (qName.equals(INSTANTIATOR_REGISTRATION)) {
                endInstantiator();
            } else if (qName.equals(RESOURCE_MANAGER)) {
                endResourceManager();
            } else if (qName.equals(BACKUP)) {
                endBackup();
            } else if (qName.equals(PDX)) {
                // nothing needed
            } else if (qName.equals(PDX_SERIALIZER)) {
                endPdxSerializer();
            } else if (qName.equals(COMPRESSOR)) {
                endCompressor();
            } else {
                final XmlParser delegate = getDelegate(namespaceURI);
                if (null == delegate) {
                    throw new CacheXmlException(
                            LocalizedStrings.CacheXmlParser_UNKNOWN_XML_ELEMENT_0.toLocalizedString(qName));
                }

                delegate.endElement(namespaceURI, localName, qName);
            }
        } catch (CacheException ex) {
            throw new SAXException(LocalizedStrings.CacheXmlParser_A_CACHEEXCEPTION_WAS_THROWN_WHILE_PARSING_XML
                    .toLocalizedString(), ex);
        }
    }

    private void endGatewayTransportFilter() {
        Declarable d = createDeclarable();
        if (!(d instanceof GatewayTransportFilter)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_1
                    .toLocalizedString(new Object[] { d.getClass().getName(), "GatewayTransportFilter" }));

        }
        Object a = stack.peek();
        if (a instanceof GatewaySenderFactory) {
            GatewaySenderFactory senderFactory = (GatewaySenderFactory) a;
            senderFactory.addGatewayTransportFilter((GatewayTransportFilter) d);
        } else if (a instanceof GatewayReceiverFactory) {
            GatewayReceiverFactory receiverFactory = (GatewayReceiverFactory) a;
            receiverFactory.addGatewayTransportFilter((GatewayTransportFilter) d);
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_GATEWAYSENDER_OR_GATEWAYRECEIVER
                            .toLocalizedString(GATEWAY_TRANSPORT_FILTER));
        }
    }

    private void endGatewayEventFilter() {
        Declarable d = createDeclarable();
        if (!(d instanceof GatewayEventFilter)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_1
                    .toLocalizedString(new Object[] { d.getClass().getName(), "GatewayEventFilter" }));
        }
        Object obj = stack.peek();
        if (obj instanceof GatewaySenderFactory) {
            GatewaySenderFactory senderFactory = (GatewaySenderFactory) obj;
            senderFactory.addGatewayEventFilter((GatewayEventFilter) d);
        } else if (obj instanceof AsyncEventQueueCreation) {
            AsyncEventQueueCreation asyncEventQueueCreation = (AsyncEventQueueCreation) obj;
            asyncEventQueueCreation.addGatewayEventFilter((GatewayEventFilter) d);
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_GATEWAY_SENDER_OR_ASYNC_EVENT_QUEUE
                            .toLocalizedString("GatewayEventFilter"));
        }
    }

    private void endGatewayEventSubstitutionFilter() {
        Declarable d = createDeclarable();
        if (!(d instanceof GatewayEventSubstitutionFilter)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_1
                    .toLocalizedString(new Object[] { d.getClass().getName(), "GatewayEventSubstitutionFilter" }));
        }
        Object obj = stack.peek();
        if (obj instanceof GatewaySenderFactory) {
            GatewaySenderFactory senderFactory = (GatewaySenderFactory) obj;
            senderFactory.setGatewayEventSubstitutionFilter((GatewayEventSubstitutionFilter) d);
        } else if (obj instanceof AsyncEventQueueCreation) {
            AsyncEventQueueCreation asyncEventQueueCreation = (AsyncEventQueueCreation) obj;
            asyncEventQueueCreation.setGatewayEventSubstitutionFilter((GatewayEventSubstitutionFilter) d);
        } else {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_GATEWAY_SENDER_OR_ASYNC_EVENT_QUEUE
                            .toLocalizedString("GatewayEventSubstitutionFilter"));
        }
    }

    private GatewaySenderFactory peekGatewaySender(String dependentElement) {
        Object a = stack.peek();
        if (!(a instanceof GatewaySenderFactory)) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_A_0_MUST_BE_DEFINED_IN_THE_CONTEXT_OF_GATEWAY_SENDER
                            .toLocalizedString(dependentElement));
        }
        return (GatewaySenderFactory) a;
    }

    /**
     * 
     */
    private void endPdxSerializer() {
        Declarable d = createDeclarable();
        if (!(d instanceof PdxSerializer)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_A_0_IS_NOT_AN_INSTANCE_OF_A_PDX_SERIALIZER
                    .toLocalizedString(d.getClass().getName()));
        }
        PdxSerializer serializer = (PdxSerializer) d;
        this.cache.setPdxSerializer(serializer);
    }

    private void startInitializer() {

    }

    private void endInitializer() {
        Properties props = new Properties();
        Object top = stack.pop();
        while (top instanceof Parameter) {
            Parameter param = (Parameter) top;
            props.put(param.getName(), param.getValue());
            top = stack.pop();
        }
        Assert.assertTrue(top instanceof String);
        String className = (String) top;
        Object o;
        try {
            Class c = InternalDataSerializer.getCachedClass(className);
            o = c.newInstance();
        } catch (Exception ex) {
            throw new CacheXmlException(
                    LocalizedStrings.CacheXmlParser_WHILE_INSTANTIATING_A_0.toLocalizedString(className), ex);
        }
        if (!(o instanceof Declarable)) {
            throw new CacheXmlException(LocalizedStrings.CacheXmlParser_CLASS_0_IS_NOT_AN_INSTANCE_OF_DECLARABLE
                    .toLocalizedString(className));
        }
        Declarable d = (Declarable) o;
        this.cache.setInitializer(d, props);
    }

    /**
     * Do nothing
     * 
     * @since GemFire 5.7
     */
    private void endClientHaQueue() {
    }

    /**
     * Process either the <code>local-properties</code> or <code>global-properties</code> for a
     * {@link org.apache.geode.internal.cache.PartitionedRegion}
     * 
     * @param globalOrLocal either the string {@link CacheXml#LOCAL_PROPERTIES} or
     *        {@link CacheXml#GLOBAL_PROPERTIES}
     */
    private void endPartitionProperites(String globalOrLocal) {
        Properties props = new Properties();
        Object top = stack.pop();
        while (!top.equals(globalOrLocal)) {
            if (!(top instanceof Parameter)) {
                throw new CacheXmlException(
                        LocalizedStrings.CacheXmlParser_ONLY_A_PARAMETER_IS_ALLOWED_IN_THE_CONTEXT_OF_0
                                .toLocalizedString(globalOrLocal));
            }
            Parameter param = (Parameter) top;
            props.put(param.getName(), param.getValue());
            top = stack.pop();
        }
        if (globalOrLocal.equals(GLOBAL_PROPERTIES)) {
            PartitionAttributesImpl pai = peekPartitionAttributesImpl(GLOBAL_PROPERTIES);
            pai.setGlobalProperties(props);
        } else if (globalOrLocal.equals(LOCAL_PROPERTIES)) {
            PartitionAttributesImpl pai = peekPartitionAttributesImpl(LOCAL_PROPERTIES);
            pai.setLocalProperties(props);
        } else {
            Assert.assertTrue(false, "Argument globalOrLocal has unexpected value " + globalOrLocal);
        }
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        // This method needs to handle XML chunking, so its uses a
        // StringBuffer to uniquely identify previous calls and will
        // append to the existing StringBuffer for each subsequent call
        Object o = null;
        try {
            o = stack.peek();
        } catch (EmptyStackException firstTime) {
            // No entries on the stack, this is the first element that
            // performs any stack operations, initialize a StringBuffer (see
            // finally block)
        } finally {
            StringBuffer chars = null;
            if (o instanceof StringBuffer) {
                chars = (StringBuffer) o;
                chars.append(ch, start, length);
                logger.trace(LogMarker.CACHE_XML_PARSER, LocalizedMessage.create(
                        LocalizedStrings.CacheXmlParser_XML_PARSER_CHARACTERS_APPENDED_CHARACTER_DATA_0, chars));
            } else {
                chars = new StringBuffer(length);
                chars.append(ch, start, length);
                stack.push(chars);
                logger.trace(LogMarker.CACHE_XML_PARSER, LocalizedMessage
                        .create(LocalizedStrings.CacheXmlParser_XML_PARSER_CHARACTERS_NEW_CHARACTER_DATA_0, chars));
            }
        }
    }

    ////////// Inherited methods that don't do anything //////////
    @Override
    public void setDocumentLocator(Locator locator) {
        this.documentLocator = locator;
    }

    public void startDocument() throws SAXException {
    }

    public void endDocument() throws SAXException {
    }

    public void startPrefixMapping(String prefix, String uri) throws SAXException {
    }

    public void endPrefixMapping(String prefix) throws SAXException {
    }

    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
    }

    public void processingInstruction(String target, String data) throws SAXException {
    }

    public void skippedEntity(String name) throws SAXException {
    }

    /*
     * Binds a jndi name of datasource to a context. @param atts Attributes of <jndi-name> jndi name
     * and Datasource related information.
     *
     */
    private void mapJNDI(Attributes atts, Map gfSpecific) {
        int attsLen = atts.getLength();
        String key = "";
        String value = "";
        // put attributes into a Map
        for (int i = 0; i < attsLen; i++) {
            key = atts.getQName(i);
            value = atts.getValue(key);
            gfSpecific.put(key, value);
        }
    }

    /////////////////////// Inner Classes ///////////////////////
    /**
     * Class that delegates all of the methods of a {@link org.xml.sax.helpers.DefaultHandler} to a
     * {@link CacheXmlParser} that implements all of the methods of <code>DefaultHandler</code>, but
     * <B>is not </B> a <code>DefaultHandler</code>.
     */
    static class DefaultHandlerDelegate extends DefaultHandler2 {

        /** The <code>CacheXmlParser</code> that does the real work */
        private CacheXmlParser handler;

        /**
         * Creates a new <code>DefaultHandlerDelegate</code> that delegates to the given
         * <code>CacheXmlParser</code>.
         */
        public DefaultHandlerDelegate(CacheXmlParser handler) {
            this.handler = handler;
        }

        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            return handler.resolveEntity(publicId, systemId);
        }

        @Override
        public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId)
                throws SAXException, IOException {
            return handler.resolveEntity(name, publicId, baseURI, systemId);
        }

        @Override
        public void setDocumentLocator(Locator locator) {
            handler.setDocumentLocator(locator);
        }

        @Override
        public void startDocument() throws SAXException {
            handler.startDocument();
        }

        @Override
        public void endDocument() throws SAXException {
            handler.endDocument();
        }

        @Override
        public void startPrefixMapping(String prefix, String uri) throws SAXException {
            handler.startPrefixMapping(prefix, uri);
        }

        @Override
        public void endPrefixMapping(String prefix) throws SAXException {
            handler.endPrefixMapping(prefix);
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            handler.startElement(uri, localName, qName, attributes);
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            handler.endElement(uri, localName, qName);
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            handler.characters(ch, start, length);
        }

        @Override
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
            handler.ignorableWhitespace(ch, start, length);
        }

        @Override
        public void processingInstruction(String target, String data) throws SAXException {
            handler.processingInstruction(target, data);
        }

        @Override
        public void skippedEntity(String name) throws SAXException {
            handler.skippedEntity(name);
        }

        @Override
        public void warning(SAXParseException e) throws SAXException {
            handler.warning(e);
        }

        @Override
        public void error(SAXParseException e) throws SAXException {
            handler.error(e);
        }

        @Override
        public void fatalError(SAXParseException e) throws SAXException {
            handler.fatalError(e);
        }
    }

    /**
     * Represents a parameter used to initialize a {@link Declarable}
     */
    static class Parameter {

        /** The name of the parameter */
        private String name;
        /** The value of the parameter */
        private Object value;

        /**
         * Creates a new <code>Parameter</code> with the given name and value.
         */
        public Parameter(String name, Object value) {
            this.name = name;
            this.value = value;
        }

        public String getName() {
            return this.name;
        }

        public Object getValue() {
            return this.value;
        }
    }
}