Package javax.time.calendar.format

Source Code of javax.time.calendar.format.ZonePrinterParser

/*
* Copyright (c) 2008-2009, Stephen Colebourne & Michael Nascimento Santos
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  * Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  * Neither the name of JSR-310 nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package javax.time.calendar.format;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.time.calendar.Calendrical;
import javax.time.calendar.TimeZone;
import javax.time.calendar.format.DateTimeFormatterBuilder.TextStyle;
import javax.time.calendar.zone.ZoneRulesGroup;

/**
* Prints or parses a zone offset.
* <p>
* ZonePrinterParser is immutable and thread-safe.
*
* @author Stephen Colebourne
*/
class ZonePrinterParser implements DateTimePrinter, DateTimeParser {

    /**
     * The text style to output, null means the id.
     */
    private final TextStyle textStyle;

    /**
     * Constructor.
     */
    ZonePrinterParser() {
        this.textStyle = null;
    }

    /**
     * Constructor.
     *
     * @param textStyle  the test style to output, not null
     */
    ZonePrinterParser(TextStyle textStyle) {
        // validated by caller
        this.textStyle = textStyle;
    }

    //-----------------------------------------------------------------------
    /** {@inheritDoc} */
    public void print(Calendrical calendrical, Appendable appendable, DateTimeFormatSymbols symbols) throws IOException {
        TimeZone zone = calendrical.getZone();
        if (zone == null) {
            throw new CalendricalFormatException("Unable to print TimeZone");
        }
        if (textStyle == null) {
            appendable.append(zone.getID());
        } else if (textStyle == TextStyle.FULL) {
            appendable.append(zone.getName())// TODO: Use symbols
        } else {
            appendable.append(zone.getShortName())// TODO: Use symbols
        }
    }

    /** {@inheritDoc} */
    public boolean isPrintDataAvailable(Calendrical calendrical) {
        return (calendrical.getZone() != null);
    }

    //-----------------------------------------------------------------------
    /**
     * The cached tree to speed up parsing.
     */
    private static SubstringTree preparedTree;
    /**
     * The cached IDs.
     */
    private static Set<String> preparedIDs;

    /**
     * {@inheritDoc}
     * <p>
     * This implementation looks for the longest matching string.
     * For example, parsing Etc/GMT-2 will return Etc/GMC-2 rather than just
     * Etc/GMC although both are valid.
     * <p>
     * This implementation uses a tree to search for valid time zone names in
     * the parseText. The top level node of the tree has a length equal to the
     * length of the shortest time zone as well as the beginning characters of
     * all other time zones.
     */
    public int parse(DateTimeParseContext context, String parseText, int position) {
        int length = parseText.length();
        if (position > length) {
            throw new IndexOutOfBoundsException();
        }
       
        // setup parse tree
        Set<String> ids = ZoneRulesGroup.getParsableIDs();
        if (ids.size() == 0) {
            return ~position;
        }
        SubstringTree tree;
        synchronized (ZonePrinterParser.class) {
            if (preparedTree == null || preparedIDs.size() < ids.size()) {
                ids = new HashSet<String>(ids);
                preparedTree = prepareParser(ids);
                preparedIDs = ids;
            }
            tree = preparedTree;
        }
       
        // handle fixed time zone ids
        if (parseText.substring(position).startsWith("UTC")) {
            DateTimeParseContext newContext = new DateTimeParseContext(context.getSymbols());
            int startPos = position + 3;
            int endPos = new ZoneOffsetPrinterParser("", true, true).parse(newContext, parseText, startPos);
            if (endPos < 0) {
                context.setZone(TimeZone.UTC);
                return startPos;
            }
            context.setZone(TimeZone.timeZone(newContext.getOffset()));
            return endPos;
        }
       
        // parse
        String parsedZoneId = null;
        int count = 0;
        while (tree != null) {
            int nodeLength = tree.length;
            if (position + nodeLength > length) {
                break;
            }
            parsedZoneId = parseText.substring(position, position + nodeLength);
            tree = tree.get(parsedZoneId);
            ++count;
        }
       
        if (parsedZoneId != null && preparedIDs.contains(parsedZoneId)) {
            TimeZone zone = TimeZone.timeZone(parsedZoneId);
            context.setZone(zone);
            return position + parsedZoneId.length();
        } else {
            return ~position;
        }
    }

    //-----------------------------------------------------------------------
    /**
     * Model a tree of substrings to make the parsing easier. Due to the nature
     * of time zone names, it can be faster to parse based in unique substrings
     * rather than just a character by character match.
     * <p>
     * For example, to parse America/Denver we can look at the first two
     * character "Am". We then notice that the shortest time zone that starts
     * with Am is America/Nome which is 12 characters long. Checking the first
     * 12 characters of America/Denver giver America/Denv which is a substring
     * of only 1 time zone: America/Denver. Thus, with just 3 comparisons that
     * match can be found.
     * <p>
     * This structure maps substrings to substrings of a longer length. Each
     * node of the tree contains a length and a map of valid substrings to
     * sub-nodes. The parser gets the length from the root node. It then
     * extracts a substring of that length from the parseText. If the map
     * contains the substring, it is set as the possible time zone and the
     * sub-node for that substring is retrieved. The process continues until the
     * substring is no longer found, at which point the matched text is checked
     * against the real time zones.
     */
    private static class SubstringTree {
        /**
         * The length of the substring this node of the tree contains.
         * Subtrees will have a longer length.
         */
        final int length;
        /**
         * Map of a substring to a set of substrings that contain the key.
         */
        private final Map<String, SubstringTree> substringMap = new HashMap<String, SubstringTree>();

        /**
         * Constructor.
         *
         * @param length  the length of this tree
         */
        private SubstringTree(int length) {
            this.length = length;
        }

        private SubstringTree get(String substring2) {
            return substringMap.get(substring2);

        }

        /**
         * Values must be added from shortest to longest.
         *
         * @param newSubstring  the substring to add, not null
         */
        private void add(String newSubstring) {
            int idLen = newSubstring.length();
            if (idLen == length) {
                substringMap.put(newSubstring, null);
            } else if (idLen > length) {
                String substring = newSubstring.substring(0, length);
                SubstringTree parserTree = substringMap.get(substring);
                if (parserTree == null) {
                    parserTree = new SubstringTree(idLen);
                    substringMap.put(substring, parserTree);
                }
                parserTree.add(newSubstring);
            }
        }
    }

    /**
     * Builds an optimized parsing tree.
     *
     * @param availableIDs  the available IDs, not null, not empty
     * @return the tree, never null
     */
    private static SubstringTree prepareParser(Set<String> availableIDs) {
        // sort by length
        List<String> ids = new ArrayList<String>(availableIDs);
        Collections.sort(ids, new Comparator<String>() {
            public int compare(String str1, String str2) {
                return str1.length() == str2.length() ? str1.compareTo(str2) : str1.length() - str2.length();
            }
        });
       
        // build the tree
        SubstringTree tree = new SubstringTree(ids.get(0).length());
        for (String id : ids) {
            tree.add(id);
        }
        return tree;
    }

    //-----------------------------------------------------------------------
    /** {@inheritDoc} */
    @Override
    public String toString() {
        if (textStyle == null) {
            return "ZoneId()";
        }
        return "ZoneText(" + textStyle + ")";
    }

}
TOP

Related Classes of javax.time.calendar.format.ZonePrinterParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
ww.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');