All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.nomou.spreadsheet.Spreadsheet Maven / Gradle / Ivy

The newest version!
package com.github.nomou.spreadsheet;

import com.github.nomou.spreadsheet.spi.SpreadsheetParserFactory;
import com.github.nomou.spreadsheet.spi.SpreadsheetWriterFactory;
import com.github.nomou.spreadsheet.util.SpreadsheetUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

/**
 * Spreadsheet parser/writer locator.
 *
 * @author changhe.yang
 * @since 20190807
 */
public final class Spreadsheet {
    private static final List ALL_FORMATS = new LinkedList<>();
    private static final Map> PARSER_FACTORIES_MAP;
    private static final Map> WRITER_FACTORIES_MAP;


    static {
        PARSER_FACTORIES_MAP = loadSpreadsheetParserFactories();
        WRITER_FACTORIES_MAP = loadSpreadsheetWriterFactories();
    }

    /**
     * Spreadsheet format.
     */
    public static class Format {
        private final String name;
        private final byte[] header;
        private final String[] extensions;

        public Format(final String name, final byte[] header, final String... extensions) {
            this.name = name;
            this.header = header;
            this.extensions = extensions;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            final Format format = (Format) o;

            if (!Arrays.equals(header, format.header)) {
                return false;
            }
            // Probably incorrect - comparing Object[] arrays with Arrays.equals
            return Arrays.equals(extensions, format.extensions);
        }

        @Override
        public int hashCode() {
            int result = Arrays.hashCode(header);
            result = 31 * result + Arrays.hashCode(extensions);
            return result;
        }

        @Override
        public String toString() {
            return "Format {" + name + "(" + Arrays.toString(extensions) + ") }";
        }
    }

    /**
     * Get a spreadsheet writer factory that supports a given extension.
     *
     * @param extension the extension
     * @return the spreadsheet writer factory
     */
    public static SpreadsheetWriterFactory getWriterFactory(final String extension) {
        final List factories = WRITER_FACTORIES_MAP.get(extension.toLowerCase());
        if (null == factories || factories.isEmpty()) {
            throw new IllegalStateException("No suite SpreadsheetWriterFactory found for " + extension);
        }
        return factories.iterator().next();
    }

    /**
     * Get a spreadsheet parser factory that supports a given extensions.
     *
     * 

if 'extensions' is not specified, the returned factory will support all supported formats.

* * @param extensions the extensions * @return the spreadsheet parser factory */ public static SpreadsheetParserFactory getParserFactory(final String... extensions) { List formats; Map> factoryMap; if (0 == extensions.length) { // using all formats = getFormatsByHeaders(PARSER_FACTORIES_MAP.keySet()); factoryMap = PARSER_FACTORIES_MAP; } else { final Map> filtered = new HashMap<>(); formats = getFormatsByExtensions(extensions); for (final Format format : formats) { filtered.put(format.header, PARSER_FACTORIES_MAP.get(format.header)); } factoryMap = filtered; } if (factoryMap.isEmpty()) { throw new IllegalStateException("No suite SpreadsheetParserFactory found for " + Arrays.toString(extensions)); } final Format[] formatArray = new Format[formats.size()]; return new MixedSpreadsheetParserFactory(formats.toArray(formatArray), factoryMap); } /* ************************************ * * ********************************** */ private static List getFormatsByExtensions(final String... extensions) { final List formats = new ArrayList<>(extensions.length); for (final Format format : ALL_FORMATS) { for (final String ext : extensions) { if (Arrays.asList(format.extensions).contains(ext)) { formats.add(format); } } } return formats; } private static List getFormatsByHeaders(final Collection headers) { final List formats = new ArrayList<>(headers.size()); for (final byte[] header : headers) { final Format format = getFormatByHeader(header); if (null != format) { formats.add(format); } } return formats; } private static Format getFormatByHeader(final byte[] header) { for (final Format format : ALL_FORMATS) { if (Arrays.equals(format.header, header)) { return format; } } return null; } /* ************************************ * * ********************************** */ /** * Loads all spreadsheet parser factories. * * @return the spreadsheet parser factories, map.key: file header bytes, map.value: file-header-bytes-factories */ private static Map> loadSpreadsheetParserFactories() { final Map> factoriesMap = new HashMap<>(); final ServiceLoader loader = ServiceLoader.load(SpreadsheetParserFactory.class); for (final SpreadsheetParserFactory factory : loader) { final Format[] formats = factory.getSupportedFormats(); for (final Format format : formats) { if (!ALL_FORMATS.contains(format)) { ALL_FORMATS.add(format); } final byte[] header = format.header; List factories = factoriesMap.get(header); if (null == factories) { factories = new ArrayList<>(); factoriesMap.put(header, factories); } factories.add(factory); } } return factoriesMap; } /** * Loads all spreadsheet writer factories. * * @return the spreadsheet writer factories, map.key: extensions, map.value: extension-factories */ private static Map> loadSpreadsheetWriterFactories() { final Map> factoriesMap = new HashMap<>(10); final ServiceLoader loader = ServiceLoader.load(SpreadsheetWriterFactory.class); for (final SpreadsheetWriterFactory factory : loader) { final Format[] formats = factory.getSupportedFormats(); for (final Format format : formats) { if (!ALL_FORMATS.contains(format)) { ALL_FORMATS.add(format); } for (final String extension : format.extensions) { List factories = factoriesMap.get(extension.toLowerCase()); if (null == factories) { factories = new ArrayList<>(); factoriesMap.put(extension.toLowerCase(), factories); } factories.add(factory); } } } return factoriesMap; } /* ***************************************** * * *************************************** */ /** * Mixed spreadsheet parser factory. */ private static class MixedSpreadsheetParserFactory implements SpreadsheetParserFactory { private final Format[] formats; private final Map> factoriesMap; private MixedSpreadsheetParserFactory(final Format[] formats, final Map> factories) { this.formats = formats; this.factoriesMap = factories; } /** * {@inheritDoc} */ @Override public Format[] getSupportedFormats() { return formats; } /** * {@inheritDoc} */ @Override public SpreadsheetParser create(final InputStream in) throws SpreadsheetException { try { List factories = SpreadsheetUtils.matches(in, factoriesMap); if (null != factories) { if (factories.isEmpty()) { throw new SpreadsheetException("file type error"); } SpreadsheetException lastError = null; for (final SpreadsheetParserFactory factory : factories) { try { return factory.create(in); } catch (final SpreadsheetException ex) { lastError = ex; } } throw lastError; } else { // unsupported 'mark' method, try first factory. for (final List tryFactories : factoriesMap.values()) { for (final SpreadsheetParserFactory tryFactory : tryFactories) { try { return tryFactory.create(in); } catch (final SpreadsheetException ex) { // 'in.markSupported()' always 'false' if (!in.markSupported()) { throw new SpreadsheetException("input must be available markSupported,you can do like this 'new BufferedInputStream(new FileInputStream(\"/xxxx\"))'"); } } } } throw new SpreadsheetException("not supported"); } } catch (IOException e) { throw new SpreadsheetException(e); } } } /** * Private constructor. */ private Spreadsheet() { } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy