![JAR search and dependency download from the Maven repository](/logo.png)
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider Maven / Gradle / Ivy
Show all versions of json-provider Show documentation
/*
* Copyright (c) 2014, Francis Galiegue ([email protected])
*
* This software is dual-licensed under:
*
* - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
* later version;
* - the Apache Software License (ASL) version 2.0.
*
* The text of this file and of both licenses is available at the root of this
* project or, if you have the jar distribution, in directory META-INF/, under
* the names LGPL-3.0.txt and ASL-2.0.txt respectively.
*
* Direct link to the sources:
*
* - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
* - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
*/
package com.github.fge.msgsimple.provider;
import com.github.fge.msgsimple.InternalBundle;
import com.github.fge.msgsimple.source.MessageSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.management.RuntimeErrorException;
/**
* A caching, on-demand loading message source provider with configurable expiry
*
*
* This class uses a {@link MessageSourceLoader} internally to look up message
* sources. As is the case for {@link StaticMessageSourceProvider}, you can also
* set a default source if the loader fails to grab a source.
*
*
* Apart from the loader, you can customize two aspects of the provider:
*
*
* - its load timeout (1 second by default);
* - its expiry time (10 minutes by default).
*
*
*
* Note that the expiry time is periodic only, and not per source. The loading
* result (success or failure) is recorded permanently until the expiry time
* kicks in.
*
*
* In the event of a timeout, the task remains active until it gets a result;
* this means, for instance, that if you set up a timeout of 500 milliseconds,
* but the task takes 2 seconds to complete, during these two seconds, the
* default source will be returned instead.
*
*
* You can also configure a loader so that it never expires.
*
*
* You cannot instantiate that class directly; use {@link #newBuilder()} to
* obtain a builder class and set up your provider.
*
* @see Builder
*/
public final class LoadingMessageSourceProvider
implements MessageSourceProvider {
private static final InternalBundle BUNDLE = InternalBundle.getInstance();
/*
* Loader and default source
*/
private final MessageSourceLoader loader;
private final MessageSource defaultSource;
/*
* List of sources
*/
private final Map> sources
= new HashMap>();
private LoadingMessageSourceProvider(final Builder builder) {
loader = builder.loader;
defaultSource = builder.defaultSource;
}
/**
* Create a new builder
*
* @return an empty builder
*/
public static Builder newBuilder() {
return new Builder();
}
@Override
public MessageSource getMessageSource(final Locale locale) {
try {
return loader.load(locale);
} catch (Exception ex) {
return defaultSource;
}
}
/**
* Builder class for a {@link LoadingMessageSourceProvider}
*/
public static final class Builder {
/*
* NOTE: apart from requiring them to be positive, we do no checks at
* all on what the user submits as timeout/expiry values; it could
* want a 1 ns expiry that we woudln't prevent it.
*/
private MessageSourceLoader loader;
private MessageSource defaultSource;
private long timeoutDuration = 1L;
private TimeUnit timeoutUnit = TimeUnit.SECONDS;
private long expiryDuration = 10L;
private TimeUnit expiryUnit = TimeUnit.MINUTES;
private Builder() {
}
/**
* Set the message source loader
*
* @param loader the loader
* @throws NullPointerException loader is null
* @return this
*/
public Builder setLoader(final MessageSourceLoader loader) {
BUNDLE.checkNotNull(loader, "cfg.nullLoader");
this.loader = loader;
return this;
}
/**
* Set the default message source if the loader fails to load
*
* @param defaultSource the default source
* @throws NullPointerException source is null
* @return this
*/
public Builder setDefaultSource(final MessageSource defaultSource) {
BUNDLE.checkNotNull(defaultSource, "cfg.nullDefaultSource");
this.defaultSource = defaultSource;
return this;
}
/**
* Set the load timeout (1 second by default)
*
*
* If the loader passed as an argument fails to load a message source
* after the specified timeout is elapsed, then the default
* messagesource will be returned (if any).
*
* @param duration number of units
* @param unit the time unit
* @throws IllegalArgumentException {@code duration} is negative or zero
* @throws NullPointerException {@code unit} is null
* @return this
*
* @see #setLoader(MessageSourceLoader)
* @see #setDefaultSource(MessageSource)
*/
public Builder setLoadTimeout(final long duration, final TimeUnit unit) {
BUNDLE.checkArgument(duration > 0L, "cfg.nonPositiveDuration");
BUNDLE.checkNotNull(unit, "cfg.nullTimeUnit");
timeoutDuration = duration;
timeoutUnit = unit;
return this;
}
/**
* Set the source expiry time (10 minutes by default)
*
*
* Do not use this method if you want no expiry at all; use
* {@link #neverExpires()} instead.
*
* @since 0.5
*
* @param duration number of units
* @param unit the time unit
* @throws IllegalArgumentException {@code duration} is negative or zero
* @throws NullPointerException {@code unit} is null
* @return this
*/
public Builder setExpiryTime(final long duration, final TimeUnit unit) {
BUNDLE.checkArgument(duration > 0L, "cfg.nonPositiveDuration");
BUNDLE.checkNotNull(unit, "cfg.nullTimeUnit");
expiryDuration = duration;
expiryUnit = unit;
return this;
}
/**
* Set this loading provider so that entries never expire
*
* @since 0.5
*
* @return this
*/
public Builder neverExpires() {
expiryDuration = 0L;
return this;
}
/**
* Build the provider
*
* @return a {@link LoadingMessageSourceProvider}
* @throws IllegalArgumentException no loader has been provided
*/
public MessageSourceProvider build() {
BUNDLE.checkArgument(loader != null, "cfg.noLoader");
return new LoadingMessageSourceProvider(this);
}
}
}