com.tinspx.util.io.charset.AbstractCharDet.java Source code

Java tutorial

Introduction

Here is the source code for com.tinspx.util.io.charset.AbstractCharDet.java

Source

/* Copyright (C) 2013-2014 Ian Teune <ian.teune@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.tinspx.util.io.charset;

import static com.google.common.base.Preconditions.*;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.tinspx.util.base.BasicError;
import com.tinspx.util.base.Errors;
import com.tinspx.util.collect.Predicated;
import com.tinspx.util.io.ErrorIOException;
import java.io.IOException;
import java.util.List;
import javax.annotation.Nullable;
import lombok.ToString;

/**
 * Set the detected {@code Charset} through {@link #onCharset(String)}. Report
 * any errors through {@link #onError(BasicError)}. {@link #failIfNotDetected()}
 * will cause the future to fail if no {@code Charset} has been detected.
 *
 * @see AbstractContentCharDet
 * @see AbstractHeaderCharDet
 * @author Ian
 */
@ToString(callSuper = true, of = { "detected", "complete" })
public abstract class AbstractCharDet implements CharsetDetector, BasicError.Listener {

    protected final SettableFuture<String> future = SettableFuture.create();
    /**
     * true when a {@code Charset} has been detected
     */
    protected boolean detected;
    /**
     * true when a {@code Charset} has been detected or detection has failed
     */
    protected boolean complete;

    private final List<BasicError> errors = Lists.newCopyOnWriteArrayList();

    @Override
    public ListenableFuture<String> charsetFuture() {
        return future;
    }

    /**
     * if no {@code Charset} has been detected, sets an {@code IOException} on
     * {@link #future} with all errors reported through
     * {@link #onError(com.tinspx.util.base.BasicError)}.
     */
    protected void failIfNotDetected() {
        if (!complete) {
            final String msg = "charset detection failed";
            if (errors != null) {
                future.setException(new ErrorIOException(msg, errors));
            } else {
                future.setException(new IOException(msg));
            }
            complete = true;
        }
    }

    /**
     * subclasses should call this method once a {@code Charset} has been
     * successfully detected
     *
     * @param charset non-null detected {@code Charset}
     */
    protected void onCharset(String charset) {
        if (future.set(checkNotNull(charset))) {
            detected = true;
        }
        complete = true;
    }

    /**
     * Determines is {@code name} is a valid {@code Charset} name. A valid name
     * is neither null nor empty.
     */
    @SuppressWarnings("null")
    protected boolean isValidName(@Nullable String name) {
        return !Strings.isNullOrEmpty(name) && !name.trim().isEmpty();
    }

    /**
     * Sets the {@code Charset} to {@code name} if it is a valid {@code Charset}
     * same. Returns {@code true} if {@code name} was valid and the
     * {@code Charset} was set.
     */
    @SuppressWarnings("null")
    protected boolean setIfValid(@Nullable String name) {
        if (!Strings.isNullOrEmpty(name) && !(name = name.trim()).isEmpty()) {
            onCharset(name);
            return true;
        }
        return false;
    }

    /**
     * Sets the {@code Charset} from the first valid name in
     * {@code charsetNames}. A valid name is not null and not empty. Returns
     * {@code true} if the {@code Charset} was found and set.
     */
    protected boolean setFirstValid(@Nullable Iterable<String> charsetNames) {
        if (charsetNames != null) {
            String name = null;
            for (String n : charsetNames) {
                if (!Strings.isNullOrEmpty(n) && !(n = n.trim()).isEmpty()) {
                    name = n;
                    break;
                }
            }
            if (name != null) {
                onCharset(name);
                return true;
            }
        }
        return false;
    }

    @Override
    public void onError(BasicError error) {
        if (error == null) {
            error = Errors.message("null error");
        }
        errors.add(error);
    }

    public List<BasicError> errors() {
        return Predicated.list(errors, Predicates.notNull());
    }
}