com.microsoft.tfs.core.util.CodePageData.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.core.util.CodePageData.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the repository root.

package com.microsoft.tfs.core.util;

import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.SAXParser;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.microsoft.tfs.core.Messages;
import com.microsoft.tfs.util.xml.SAXUtils;

/**
 * {@link CodePageData} reads the code page mappings that are stored in
 * codepages.xml. This class loads codepages.xml as a resource, parses it, and
 * stores the data. It is intended for use only by the {@link CodePageMapping}
 * class.
 */
class CodePageData {
    private static final Log log = LogFactory.getLog(CodePageData.class);

    private static final Object lock = new Object();
    private static boolean initialized = false;
    private static Map codePageToCharsetNames = new HashMap();
    private static Map charsetNameToCodePage = new HashMap();

    /**
     * Gets the array of charset names that are configured and can be mapped to
     * a code page.
     *
     * @return the charset names that can be resolved to code pages
     */
    static String[] getCharsetNames() {
        synchronized (lock) {
            if (!initialized) {
                initialize();
            }

            final Set charsetNameSet = charsetNameToCodePage.keySet();
            return (String[]) charsetNameSet.toArray(new String[charsetNameSet.size()]);
        }
    }

    /**
     * Gets the array of code pages that are configured and can be mapped to a
     * charset
     *
     * @return the code pages that can be resolved to charsets
     */
    static Integer[] getCodePages() {
        synchronized (lock) {
            if (!initialized) {
                initialize();
            }

            final Set codePageSet = codePageToCharsetNames.keySet();
            return (Integer[]) codePageSet.toArray(new Integer[codePageSet.size()]);
        }
    }

    /**
     * Gets the array of canonical charset names for the specified code page.
     *
     * @param codePage
     *        the code page to look up
     * @return the canonical charset names for the code page, or
     *         <code>null</code> if the code page is unknown
     */
    static String[] getCharsetNames(final int codePage) {
        final Integer key = new Integer(codePage);

        synchronized (lock) {
            if (!initialized) {
                initialize();
            }

            return (String[]) codePageToCharsetNames.get(key);
        }
    }

    /**
     * Gets the code page for the specified canonical charset name.
     *
     * @param charsetName
     *        the charset name to look up (must not be <code>null</code>)
     * @return the code page, <code>null</code> if the charset is unknown
     */
    static Integer getCodePage(final String charsetName) {
        synchronized (lock) {
            if (!initialized) {
                initialize();
            }

            return (Integer) charsetNameToCodePage.get(charsetName.toLowerCase());
        }
    }

    private static void initialize() {
        initialized = true;

        final InputStream inputStream = CodePageData.class.getResourceAsStream("codepages.xml"); //$NON-NLS-1$

        if (inputStream == null) {
            log.error("Unable to load the codepages.xml resource"); //$NON-NLS-1$
            return;
        }

        try {
            final SAXParser parser = SAXUtils.newSAXParser();
            final InputSource inputSource = new InputSource(inputStream);
            parser.parse(inputSource, new CodePagesHandler());
        } catch (final Exception e) {
            log.error(Messages.getString("CodePageData.ErrorDuringParsing"), e); //$NON-NLS-1$
        } finally {
            try {
                inputStream.close();
            } catch (final IOException e) {
            }
        }
    }

    private static class CodePagesHandler extends DefaultHandler {
        private int currentCodePage = -1;
        private final List currentCharsetNames = new ArrayList();

        @Override
        public void startElement(final String uri, final String localName, final String qName,
                final Attributes attributes) throws SAXException {
            if ("codePage".equals(qName)) //$NON-NLS-1$
            {
                try {
                    currentCodePage = Integer.parseInt(attributes.getValue("value")); //$NON-NLS-1$
                    currentCharsetNames.clear();
                } catch (final NumberFormatException ex) {

                }
            } else if ("charset".equals(qName) && currentCodePage != -1) //$NON-NLS-1$
            {
                final String name = attributes.getValue("name"); //$NON-NLS-1$

                if (name != null) {
                    currentCharsetNames.add(name);

                    final String sReverseMapping = attributes.getValue("reverseMapping"); //$NON-NLS-1$
                    final boolean reverseMapping = !"false".equalsIgnoreCase(sReverseMapping); //$NON-NLS-1$

                    if (reverseMapping) {
                        if (charsetNameToCodePage.containsKey(name.toLowerCase())) {
                            log.warn(MessageFormat.format(
                                    "charset name [{0}] is mapped to more than one code page: {1} {2}", //$NON-NLS-1$
                                    name, charsetNameToCodePage.get(name).toString(),
                                    Integer.toString(currentCodePage)));
                        } else {
                            charsetNameToCodePage.put(name.toLowerCase(), new Integer(currentCodePage));
                        }
                    }
                }
            }
        }

        @Override
        public void endElement(final String uri, final String localName, final String qName) throws SAXException {
            if ("codePage".equals(qName) && currentCodePage != -1) //$NON-NLS-1$
            {
                final Integer codePageKey = new Integer(currentCodePage);
                if (codePageToCharsetNames.containsKey(codePageKey)) {
                    log.warn(MessageFormat.format("code page [{0}] is duplicated in the mappings", //$NON-NLS-1$
                            Integer.toString(currentCodePage)));
                } else if (currentCharsetNames.size() == 0) {
                    log.warn(MessageFormat.format("code page [{0}] had no charset mappings", //$NON-NLS-1$
                            Integer.toString(currentCodePage)));
                } else {
                    final String[] charsetNames = (String[]) currentCharsetNames
                            .toArray(new String[currentCharsetNames.size()]);
                    codePageToCharsetNames.put(codePageKey, charsetNames);
                }

                currentCodePage = -1;
            }
        }
    }
}