public static int parsePort(final String address) {
        int sp = address.indexOf(":");
        if (sp == -1 && sp + 1 >= address.length()) {
            throw new IllegalArgumentException("not found port '" + address + "'");
        }

        try {
            return Integer.parseInt(address.substring(sp + 1, address.length()).trim());
        } catch (NumberFormatException nfe) {
            throw new IllegalArgumentException("bad port number '" + address + "'");
        }
    }

public
static
int
parsePort
(
final
String
address
)
{
int
sp
=
address
.
indexOf
(
":"
)
;
if
(
sp
==
1
&&
sp
+
1
>=
address
.
length
(
)
)
{
throw
new
IllegalArgumentException
(
"not found port '"
+
address
+
"'"
)
;
}
try
{
return
Integer
.
parseInt
(
address
.
substring
(
sp
+
1
,
address
.
length
(
)
)
.
trim
(
)
)
;
}
catch
(
NumberFormatException
nfe
)
{
throw
new
IllegalArgumentException
(
"bad port number '"
+
address
+
"'"
)
;
}
}

Parses the port.

@param address the address
@return the int


public void set(final String key, final String value) {
        set(SafeEncoder.encode(key), SafeEncoder.encode(value));
    }

public void set ( final String key , final String value ) { set ( SafeEncoder . encode ( key ) , SafeEncoder . encode ( value ) ) ; }

Sets the.

@param key   the key
@param value the value


public void sync() {
        if (this.client == null) {
            return;
        }

        List<Object> unformatted = null;
        try {
            unformatted = this.client.getAll();
        } catch (Exception e) {
            this.brokenResource = true;
            throw new GatewayException("gateway=" + this.server + ", connect=" + this.redis.connectInfo(), e);
        }

        if (unformatted == null) {
            return;
        }

        for (Object o : unformatted) {
            try {
                generateResponse(o);
            } catch (Exception ignored) {
            }
        }
    }

public
void
sync
(
)
{
if
(
this
.
client
==
)
{
return
;
}
List
<
Object
>
unformatted
=
;
try
{
unformatted
=
this
.
client
.
getAll
(
)
;
}
catch
(
Exception
e
)
{
this
.
brokenResource
=
true
;
throw
new
GatewayException
(
"gateway="
+
this
.
server
+
", connect="
+
this
.
redis
.
connectInfo
(
)
,
e
)
;
}
if
(
unformatted
==
)
{
return
;
}
for
(
Object
o
:
unformatted
)
{
try
{
generateResponse
(
o
)
;
}
catch
(
Exception
ignored
)
{
}
}
}

Synchronize pipeline by reading all responses. This operation close the
pipeline. In order to get return values from pipelined commands, capture
the different Response<?> of the commands you execute.

Synchronize pipeline by reading all responses . This operation close the pipeline . In order to get return values from pipelined commands capture the different Response&lt ; ?&gt ; of the commands you execute .


private Set<Tuple> getTupledSet() {
        List<String> membersWithScores = client.getMultiBulkReply();
        Set<Tuple> set = new LinkedHashSet<Tuple>();
        Iterator<String> iterator = membersWithScores.iterator();
        while (iterator.hasNext()) {
            set.add(new Tuple(iterator.next(), Double.valueOf(iterator.next())));
        }
        return set;
    }

private Set < Tuple > getTupledSet ( ) { List < String > membersWithScores = client . getMultiBulkReply ( ) ; Set < Tuple > set = new LinkedHashSet < Tuple > ( ) ; Iterator < String > iterator = membersWithScores . iterator ( ) ; while ( iterator . hasNext ( ) ) { set . add ( new Tuple ( iterator . next ( ) , Double . valueOf ( iterator . next ( ) ) ) ) ; } return set ; }

Gets the tupled set.

@return the tupled set


public synchronized void stop() {
        state = State.STOP;
        dispatchEvent(LeaderElectionEventType.STOP_START);

        logger.info("Stopping leader election support");

        if (leaderOffer != null) {
            try {
                zooKeeper.delete(leaderOffer.getNodePath(), -1);
                logger.info("Removed leader offer {}",
                        leaderOffer.getNodePath());
            } catch (InterruptedException e) {
                becomeFailed(e);
            } catch (KeeperException e) {
                becomeFailed(e);
            }
        }

        dispatchEvent(LeaderElectionEventType.STOP_COMPLETE);
    }

public
synchronized
void
stop
(
)
{
state
=
State
.
STOP
;
dispatchEvent
(
LeaderElectionEventType
.
STOP_START
)
;
logger
.
info
(
"Stopping leader election support"
)
;
if
(
leaderOffer
!=
)
{
try
{
zooKeeper
.
delete
(
leaderOffer
.
getNodePath
(
)
,
1
)
;
logger
.
info
(
"Removed leader offer {}"
,
leaderOffer
.
getNodePath
(
)
)
;
}
catch
(
InterruptedException
e
)
{
becomeFailed
(
e
)
;
}
catch
(
KeeperException
e
)
{
becomeFailed
(
e
)
;
}
}
dispatchEvent
(
LeaderElectionEventType
.
STOP_COMPLETE
)
;
}

Stops all election services, revokes any outstanding leader offers, and
disconnects from ZooKeeper.

Stops all election services revokes any outstanding leader offers and disconnects from ZooKeeper .


String toExecuteInfo(final int tryCount, final long startedTime, final GatewayServer server,
                         final RedisCluster redis) {
        final StringBuilder sb = new StringBuilder();
        final long executedTime = System.currentTimeMillis() - startedTime;
        sb.append("time=").append(executedTime).append(", ");
        sb.append("retry=").append(tryCount).append(", ");
        sb.append("gateway=").append(server);
        if (redis != null) {
            sb.append(", ").append("connect=").append(redis.connectInfo());
        }

        return sb.toString();
    }

String
toExecuteInfo
(
final
int
tryCount
,
final
long
startedTime
,
final
GatewayServer
server
,
final
RedisCluster
redis
)
{
final
StringBuilder
sb
=
new
StringBuilder
(
)
;
final
long
executedTime
=
System
.
currentTimeMillis
(
)
startedTime
;
sb
.
append
(
"time="
)
.
append
(
executedTime
)
.
append
(
", "
)
;
sb
.
append
(
"retry="
)
.
append
(
tryCount
)
.
append
(
", "
)
;
sb
.
append
(
"gateway="
)
.
append
(
server
)
;
if
(
redis
!=
)
{
sb
.
append
(
", "
)
.
append
(
"connect="
)
.
append
(
redis
.
connectInfo
(
)
)
;
}
return
sb
.
toString
(
)
;
}

time, retry, gateway server information.


public void setquorum(PartitionGroupServer master, int q,
            String quorumMembers) throws MgmtSetquorumException,
            MgmtSmrCommandException {
        master.setQuorum(q, quorumMembers);
    }

public void setquorum ( PartitionGroupServer master , int q , String quorumMembers ) throws MgmtSetquorumException , MgmtSmrCommandException { master . setQuorum ( q , quorumMembers ) ; }

Since it is a singleton instance and represents a part of workflow logic running in multiple threads.

Since it is a singleton instance and represents a part of workflow logic running in multiple threads .


public static void checkPermission(String path, LockType type) throws MgmtZooKeeperException {
        if (znodePermission.get() != null) {
            znodePermission.get().checkPermission(path, type);
        }
    }

public static void checkPermission ( String path , LockType type ) throws MgmtZooKeeperException { if ( znodePermission . get ( ) != null ) { znodePermission . get ( ) . checkPermission ( path , type ) ; } }

Clear ZNodePermission of current-thread to null.

If znodePermission.get() returns null, this method skip permission-check. Otherwise, do permission-check.

There are two different scenarios.
1. workflows, commands, watch-event for clusters do permission-check.
2. leader-election, confmaster-init/release skip permission-check.

It is not deterministic that what thread will allocated to the scenarios.
Call this method not to affect a next thread, after calling addPermission() method.

Clear ZNodePermission of current - thread to null .


private byte[][] joinParameters(byte[] first, byte[][] rest) {
        byte[][] result = new byte[rest.length + 1][];
        result[0] = first;
        for (int i = 0; i < rest.length; i++) {
            result[i + 1] = rest[i];
        }
        return result;
    }

private byte [ ] [ ] joinParameters ( byte [ ] first , byte [ ] [ ] rest ) { byte [ ] [ ] result = new byte [ rest . length + 1 ] [ ] ; result [ 0 ] = first ; for ( int i = 0 ; i < rest . length ; i ++ ) { result [ i + 1 ] = rest [ i ] ; } return result ; }

Join parameters.

@param first the first
@param rest  the rest
@return the byte[][]


public void expireAt(final byte[] key, final long millisecondsTimestamp) {
        sendCommand(Command.EXPIREAT, key, RedisProtocol.toByteArray(millisecondsTimestamp));
    }

public void expireAt ( final byte [ ] key , final long millisecondsTimestamp ) { sendCommand ( Command . EXPIREAT , key , RedisProtocol . toByteArray ( millisecondsTimestamp ) ) ; }

Expire at.

@param key                   the key
@param millisecondsTimestamp the unix time


public void decrBy(final byte[] key, final long integer) {
        sendCommand(Command.DECRBY, key, RedisProtocol.toByteArray(integer));
    }

public void decrBy ( final byte [ ] key , final long integer ) { sendCommand ( Command . DECRBY , key , RedisProtocol . toByteArray ( integer ) ) ; }

Decr by.

@param key     the key
@param integer the integer


public void incrBy(final byte[] key, final long integer) {
        sendCommand(Command.INCRBY, key, RedisProtocol.toByteArray(integer));
    }

public void incrBy ( final byte [ ] key , final long integer ) { sendCommand ( Command . INCRBY , key , RedisProtocol . toByteArray ( integer ) ) ; }

Incr by.

@param key     the key
@param integer the integer


public void zaddBinary(final byte[] key, Map<Double, byte[]> scoreMembers) {
        ArrayList<byte[]> args = new ArrayList<byte[]>(scoreMembers.size() * 2 + 1);

        args.add(key);

        for (Map.Entry<Double, byte[]> entry : scoreMembers.entrySet()) {
            args.add(RedisProtocol.toByteArray(entry.getKey()));
            args.add(entry.getValue());
        }

        byte[][] argsArray = new byte[args.size()][];
        args.toArray(argsArray);

        sendCommand(Command.ZADD, argsArray);
    }

public void zaddBinary ( final byte [ ] key , Map < Double , byte [ ] > scoreMembers ) { ArrayList < byte [ ] > args = new ArrayList < byte [ ] > ( scoreMembers . size ( ) * 2 + 1 ) ; args . add ( key ) ; for ( Map . Entry < Double , byte [ ] > entry : scoreMembers . entrySet ( ) ) { args . add ( RedisProtocol . toByteArray ( entry . getKey ( ) ) ) ; args . add ( entry . getValue ( ) ) ; } byte [ ] [ ] argsArray = new byte [ args . size ( ) ] [ ] ; args . toArray ( argsArray ) ; sendCommand ( Command . ZADD , argsArray ) ; }

Zadd binary.

@param key          the key
@param scoreMembers the score members


public void zrangeByScore(final byte[] key, final byte[] min, final byte[] max) {
        sendCommand(Command.ZRANGEBYSCORE, key, min, max);
    }

public void zrangeByScore ( final byte [ ] key , final byte [ ] min , final byte [ ] max ) { sendCommand ( Command . ZRANGEBYSCORE , key , min , max ) ; }

Zrange by score.

@param key the key
@param min the min
@param max the max


public void zrangeByScoreWithScores(final byte[] key, final byte[] min, final byte[] max, final int offset,
                                        final int count) {
        sendCommand(Command.ZRANGEBYSCORE, key, min, max, Keyword.LIMIT.raw, RedisProtocol.toByteArray(offset), RedisProtocol.toByteArray(count), Keyword.WITHSCORES.raw);
    }

public void zrangeByScoreWithScores ( final byte [ ] key , final byte [ ] min , final byte [ ] max , final int offset , final int count ) { sendCommand ( Command . ZRANGEBYSCORE , key , min , max , Keyword . LIMIT . raw , RedisProtocol . toByteArray ( offset ) , RedisProtocol . toByteArray ( count ) , Keyword . WITHSCORES . raw ) ; }

Zrange by score with scores.

@param key    the key
@param min    the min
@param max    the max
@param offset the offset
@param count  the count


public void slaveofNoOne() {
        sendCommand(Command.SLAVEOF, Keyword.NO.raw, Keyword.ONE.raw);
    }

public void slaveofNoOne ( ) { sendCommand ( Command . SLAVEOF , Keyword . NO . raw , Keyword . ONE . raw ) ; }


public void configSet(final byte[] parameter, final byte[] value) {
        sendCommand(Command.CONFIG, Keyword.SET.raw, parameter, value);
    }

public void configSet ( final byte [ ] parameter , final byte [ ] value ) { sendCommand ( Command . CONFIG , Keyword . SET . raw , parameter , value ) ; }

Config set.

@param parameter the parameter
@param value     the value


public void getbit(byte[] key, long offset) {
        sendCommand(Command.GETBIT, key, RedisProtocol.toByteArray(offset));
    }

public void getbit ( byte [ ] key , long offset ) { sendCommand ( Command . GETBIT , key , RedisProtocol . toByteArray ( offset ) ) ; }

Gets the bit.

@param key    the key
@param offset the offset


public void getrange(byte[] key, long startOffset, long endOffset) {
        sendCommand(Command.GETRANGE, key, RedisProtocol.toByteArray(startOffset), RedisProtocol.toByteArray(endOffset));
    }

public void getrange ( byte [ ] key , long startOffset , long endOffset ) { sendCommand ( Command . GETRANGE , key , RedisProtocol . toByteArray ( startOffset ) , RedisProtocol . toByteArray ( endOffset ) ) ; }

Gets the range.

@param key         the key
@param startOffset the start offset
@param endOffset   the end offset


public void shutdown() throws IOException {
        try {
            selector.close();
        } catch (IOException e) {
            Logger.error("Close nio event selector fail.", e);
            throw e;
        }
    }

public
void
shutdown
(
)
throws
IOException
{
try
{
selector
.
close
(
)
;
}
catch
(
IOException
e
)
{
Logger
.
error
(
"Close nio event selector fail."
,
e
)
;
throw
e
;
}
}


public ElapsedTime process() {
        try {
            long start = System.currentTimeMillis();
            ioProcess();
            long ioDone = System.currentTimeMillis();
            loopProcess();
            long end = System.currentTimeMillis();

            return new ElapsedTime(start, ioDone, end);
        } catch (Exception e) {
            Logger.error("-ERR error occurs in hbMain", e);
        }

        return null;
    }

public
ElapsedTime
process
(
)
{
try
{
long
start
=
System
.
currentTimeMillis
(
)
;
ioProcess
(
)
;
long
ioDone
=
System
.
currentTimeMillis
(
)
;
loopProcess
(
)
;
long
end
=
System
.
currentTimeMillis
(
)
;
return
new
ElapsedTime
(
start
,
ioDone
,
end
)
;
}
catch
(
Exception
e
)
{
Logger
.
error
(
"-ERR error occurs in hbMain"
,
e
)
;
}
return
;
}


public void ioProcess()
    {
        int numberOfKeys;
        try {
            numberOfKeys = selector.select(selectTimeout);
        } catch (IOException e) {
            Logger.error("Selector.select error.", e);
            return;
        }
        if (0 == numberOfKeys) {
            return;
        }

        Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
        while (keyIter.hasNext())
        {
            SelectionKey key = keyIter.next();
            Session session = (Session) key.attachment();

            long timeMillis = System.currentTimeMillis();

            try {
                if (key.isValid() && key.isReadable()) {
                    long start = System.currentTimeMillis();
                    session.callbackRead(key, timeMillis);
                    long end = System.currentTimeMillis();
                    Statistics.updateNioRead(end - start);
                }

                if (key.isValid() && key.isWritable()) {
                    long start = System.currentTimeMillis();
                    session.callbackWrite(key, timeMillis);
                    long end = System.currentTimeMillis();
                    Statistics.updateNioWrite(end - start);
                }

                if (key.isValid() && key.isAcceptable()) {
                    session.callbackAccept(key, timeMillis);
                }

                if (key.isValid() && key.isConnectable()) {
                    session.callbackConnect(key, timeMillis);
                }
            } catch (CancelledKeyException e) {
                Logger.warn("Closed connection {}", session, e);
            } catch (ClosedChannelException e) {
                Logger.warn("Closed connection {}", session, e);
            } catch (IOException e) {
                Logger.warn("Closed connection {}", session, e);
            } catch (Exception e) {
                Logger.error("Exception occurs on {}", session, e);
            }

            keyIter.remove();
        }
    }

public
void
ioProcess
(
)
{
int
numberOfKeys
;
try
{
numberOfKeys
=
selector
.
select
(
selectTimeout
)
;
}
catch
(
IOException
e
)
{
Logger
.
error
(
"Selector.select error."
,
e
)
;
return
;
}
if
(
0
==
numberOfKeys
)
{
return
;
}
Iterator
<
SelectionKey
>
keyIter
=
selector
.
selectedKeys
(
)
.
iterator
(
)
;
while
(
keyIter
.
hasNext
(
)
)
{
SelectionKey
key
=
keyIter
.
next
(
)
;
Session
session
=
(
Session
)
key
.
attachment
(
)
;
long
timeMillis
=
System
.
currentTimeMillis
(
)
;
try
{
if
(
key
.
isValid
(
)
&&
key
.
isReadable
(
)
)
{
long
start
=
System
.
currentTimeMillis
(
)
;
session
.
callbackRead
(
key
,
timeMillis
)
;
long
end
=
System
.
currentTimeMillis
(
)
;
Statistics
.
updateNioRead
(
end
start
)
;
}
if
(
key
.
isValid
(
)
&&
key
.
isWritable
(
)
)
{
long
start
=
System
.
currentTimeMillis
(
)
;
session
.
callbackWrite
(
key
,
timeMillis
)
;
long
end
=
System
.
currentTimeMillis
(
)
;
Statistics
.
updateNioWrite
(
end
start
)
;
}
if
(
key
.
isValid
(
)
&&
key
.
isAcceptable
(
)
)
{
session
.
callbackAccept
(
key
,
timeMillis
)
;
}
if
(
key
.
isValid
(
)
&&
key
.
isConnectable
(
)
)
{
session
.
callbackConnect
(
key
,
timeMillis
)
;
}
}
catch
(
CancelledKeyException
e
)
{
Logger
.
warn
(
"Closed connection {}"
,
session
,
e
)
;
}
catch
(
ClosedChannelException
e
)
{
Logger
.
warn
(
"Closed connection {}"
,
session
,
e
)
;
}
catch
(
IOException
e
)
{
Logger
.
warn
(
"Closed connection {}"
,
session
,
e
)
;
}
catch
(
Exception
e
)
{
Logger
.
error
(
"Exception occurs on {}"
,
session
,
e
)
;
}
keyIter
.
remove
(
)
;
}
}


public void loopProcess()
    {
        for (Session session : sessions.values())
        {
            long timeMillis = System.currentTimeMillis();
            try {
                session.callbackOnLoop(timeMillis);
            } catch (Exception e) {
                Logger.error("Exception occurs while callbackOnLoop on {}", session, e);
            }
        }
    }

to be called on each loop to process idle routines.

to be called on each loop to process idle routines .


public void register(Session session, int ops) throws ClosedChannelException {
        if (sessions.containsKey(session.getID())) {
            throw new IllegalStateException("Altready registered session");
        }

        SelectionKey selKey;
        try {
            selKey = session.getChannel().register(selector, ops, session);
        } catch (ClosedChannelException e) {
            Logger.error("Error while register channel to selector. {}", session, e);
            throw e;
        }
        session.setSelectionKey(selKey);
    }

register session to Selector in order to detect IO events.
@param session
@param ops interest IO operations, such as SelectionKey.OP_ACCEPT, SelectionKey.OP_CONNECT, SelectionKey.OP_READ, SelectionKey.OP_WRITE
@throws ClosedChannelException

register session to Selector in order to detect IO events .


public void addDefaultHeader(final String name, final String value) {
        Validate.notEmpty(name, "header name cannot be empty");
        Validate.notNull(value, "header value cannot be null, use an empty string instead");
        this.checkConfigurable();
        this.defaultHeaders.put(name, value);
    }

Adds a default header to be added to every stub http response.
@param name header name (cannot be empty)
@param value header value (cannot be <tt>null</tt>)

Adds a default header to be added to every stub http response .


public void receivedTimes(final Matcher<Integer> nrRequestsPredicate) {
        Validate.notNull(nrRequestsPredicate, "predicate cannot be null");

        this.requestManager.evaluateVerification(predicates, nrRequestsPredicate);
    }

public
void
receivedTimes
(
final
Matcher
<
Integer
>
nrRequestsPredicate
)
{
Validate
.
notNull
(
nrRequestsPredicate
,
"predicate cannot be null"
)
;
this
.
requestManager
.
evaluateVerification
(
predicates
,
nrRequestsPredicate
)
;
}

Checks whether the number of requests described in this verifying object received so far matches the given predicate.
@param nrRequestsPredicate to be applied on the number of requests
@throws VerificationException if the number of requests described by this verifying is not matched by the given
predicate

Checks whether the number of requests described in this verifying object received so far matches the given predicate .


public String getValue(final String key) {
        Validate.notEmpty(key, "key cannot be empty");

        final List<String> allValues = this.getValues(key);
        return allValues != null ? allValues.get(0) : null;
    }

public
String
getValue
(
final
String
key
)
{
Validate
.
notEmpty
(
key
,
"key cannot be empty"
)
;
final
List
<
String
>
allValues
=
this
.
getValues
(
key
)
;
return
allValues
!=
allValues
.
get
(
0
)
:
;
}

Returns the first value for the given key
@param key key (case insensitive)
@return single (first) value for the given key or {@code null}, if there is no such a key in this instance


public List<String> getValues(final String key) {
        Validate.notEmpty(key, "name cannot be empty");

        @SuppressWarnings("unchecked")
        final List<String> result = (List<String>) values.get(key.toLowerCase());
        return result == null || result.isEmpty() ? null : new ArrayList<String>(result);
    }

public
List
<
String
>
getValues
(
final
String
key
)
{
Validate
.
notEmpty
(
key
,
"name cannot be empty"
)
;
@
SuppressWarnings
(
"unchecked"
)
final
List
<
String
>
result
=
(
List
<
String
>
)
values
.
get
(
key
.
toLowerCase
(
)
)
;
return
result
==
||
result
.
isEmpty
(
)
:
new
ArrayList
<
String
>
(
result
)
;
}

Returns all values for the given key
@param key key (case insensitive)
@return all values of the given header or {@code null}, if there is no such a key in this instance


static void addEncoding(final Request.Builder builder, final HttpExchange httpExchange) {
        final String contentType = httpExchange.getRequestHeaders().getFirst("Content-Type");
        if (contentType != null) {
            final Matcher matcher = CHARSET_PATTERN.matcher(contentType);
            if (matcher.matches()) {
                try {
                    builder.encoding(Charset.forName(matcher.group(1)));
                }
                catch (UnsupportedCharsetException e) {
                    //just ignore, fallback encoding will be used instead
                }
            }
        }
    }


public Stubbing createStubbing(final Charset defaultEncoding, final int defaultStatus,
            final MultiMap defaultHeaders) {

        return new Stubbing(defaultEncoding, defaultStatus, defaultHeaders);
    }

public Stubbing createStubbing ( final Charset defaultEncoding , final int defaultStatus , final MultiMap defaultHeaders ) { return new Stubbing ( defaultEncoding , defaultStatus , defaultHeaders ) ; }

Creates new stubbing instance.
@param defaultEncoding default encoding of every stub response body
@param defaultStatus default http status of every stub response
@param defaultHeaders default response headers of every stub response
@return new {@link Stubbing} instance


public static String encode(JSONObject claims, String secret) {
        String encodedHeader = getCommonHeader();
        String encodedClaims = encodeJson(claims);

        String secureBits = new StringBuilder(encodedHeader).append(TOKEN_SEP).append(encodedClaims).toString();

        String sig = sign(secret, secureBits);

        return new StringBuilder(secureBits).append(TOKEN_SEP).append(sig).toString();
    }

public static String encode ( JSONObject claims , String secret ) { String encodedHeader = getCommonHeader ( ) ; String encodedClaims = encodeJson ( claims ) ; String secureBits = new StringBuilder ( encodedHeader ) . append ( TOKEN_SEP ) . append ( encodedClaims ) . toString ( ) ; String sig = sign ( secret , secureBits ) ; return new StringBuilder ( secureBits ) . append ( TOKEN_SEP ) . append ( sig ) . toString ( ) ; }

Encode and sign a set of claims.

@param claims
@param secret
@return


private Date copyDate(Date date) {
        return (date != null) ? new Date(date.getTime()) : null;
    }

private Date copyDate ( Date date ) { return ( date != null ) ? new Date ( date . getTime ( ) ) : null ; }

Copies the date, since Date objects are mutable.

Copies the date since Date objects are mutable .


public String createToken(Map<String, Object> data, TokenOptions options) {
        if ((data == null || data.size() == 0) && (options == null || (!options.isAdmin() && !options.isDebug()))) {
            throw new IllegalArgumentException("TokenGenerator.createToken: data is empty and no options are set.  This token will have no effect on Firebase.");
        }

        JSONObject claims = new JSONObject();

        try {
            claims.put("v", TOKEN_VERSION);
            claims.put("iat", new Date().getTime() / 1000);

            boolean isAdminToken = (options != null && options.isAdmin());
            validateToken("TokenGenerator.createToken", data, isAdminToken);

            if (data != null && data.size() > 0) {
                claims.put("d", new JSONObject(data));
            }

            // Handle options
            if (options != null) {
                if (options.getExpires() != null) {
                    claims.put("exp", options.getExpires().getTime() / 1000);
                }

                if (options.getNotBefore() != null) {
                    claims.put("nbf", options.getNotBefore().getTime() / 1000);
                }

                // Only add these claims if they're true to avoid sending them over the wire when false.
                if (options.isAdmin()) {
                    claims.put("admin", options.isAdmin());
                }

                if (options.isDebug()) {
                    claims.put("debug", options.isDebug());
                }
            }
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }

        String token = computeToken(claims);
        if (token.length() > 1024) {
            throw new IllegalArgumentException("TokenGenerator.createToken: Generated token is too long. The token cannot be longer than 1024 bytes.");
        }
        return token;
    }

Create a token for the given object and options.

@param data
@param options
@return

Create a token for the given object and options .


Dialog getErrorDialog(int errorCode, int requestCode) {
        final Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(activity, errorCode, requestCode);
        dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialogInterface) {
                resolvingError = false;
            }
        });
        return dialog;
    }

Dialog getErrorDialog ( int errorCode , int requestCode ) { final Dialog dialog = GoogleApiAvailability . getInstance ( ) . getErrorDialog ( activity , errorCode , requestCode ) ; dialog . setOnDismissListener ( new DialogInterface . OnDismissListener ( ) { @ Override public void onDismiss ( DialogInterface dialogInterface ) { resolvingError = false ; } } ) ; return dialog ; }

Helper to create a new dialog from an error code.

@param errorCode   the code int to explain
@param requestCode the request code to use when you expect the result.
@return a new dialog instance ready to show

Helper to create a new dialog from an error code .


void connectAndRequestGoogleAccount(int signInRequestCode, int errorResolutionRequestCode) {
        if (client.isConnected()) {
            requestGoogleAccount(signInRequestCode);
        } else if (!client.isConnecting()) {
            this.signInRequestCode = signInRequestCode;
            this.errorResolutionRequestCode = errorResolutionRequestCode;
            client.connect();
        }
    }

void connectAndRequestGoogleAccount ( int signInRequestCode , int errorResolutionRequestCode ) { if ( client . isConnected ( ) ) { requestGoogleAccount ( signInRequestCode ) ; } else if ( ! client . isConnecting ( ) ) { this . signInRequestCode = signInRequestCode ; this . errorResolutionRequestCode = errorResolutionRequestCode ; client . connect ( ) ; } }

Checks if the Google API Client is connected and tries to request the user Account.

@param signInRequestCode          the request code to use when you expect the sign in result.
@param errorResolutionRequestCode the request code to use when you expect the erorr resolution result.

Checks if the Google API Client is connected and tries to request the user Account .


public void logoutAndClearState() {
        if (client != null && client.isConnected()) {
            logout();
            client.disconnect();
        }
        activity = null;
        client = null;
    }

public void logoutAndClearState ( ) { if ( client != null && client . isConnected ( ) ) { logout ( ) ; client . disconnect ( ) ; } activity = null ; client = null ; }

Clears this helper state. After this method is called the provider should not be used.

Clears this helper state . After this method is called the provider should not be used .


@Override
  public boolean invalidateIfNecessary(BaragonRequest request) {
    if (request.getLoadBalancerService().getEdgeCacheDomains().isEmpty()) {
      return false;
    }

    try {
      boolean allSucceeded = true;
      for (String edgeCacheDNS : request.getLoadBalancerService().getEdgeCacheDomains()) {
        List<CloudflareZone> matchingZones = getCloudflareZone(edgeCacheDNS);

        if (matchingZones.isEmpty()) {
          LOG.warn("`edgeCacheDNS` was defined on the request, but no matching Cloudflare Zone was found!");
          return false;
        }

        for (CloudflareZone matchingZone : matchingZones) {
          String zoneId = matchingZone.getId();
          Optional<CloudflareDnsRecord> matchingDnsRecord = getCloudflareDnsRecord(edgeCacheDNS, zoneId);

          if (!matchingDnsRecord.isPresent()) {
            LOG.warn("`edgeCacheDNS` was defined on the request, but no matching Cloudflare DNS Record was found!");
            return false;
          }

          if (!matchingDnsRecord.get().isProxied()) {
            LOG.warn("`edgeCacheDNS` was defined on the request, but {} is not a proxied DNS record!", edgeCacheDNS);
            return false;
          }

          String cacheTag = String.format(
              edgeCacheConfiguration.getIntegrationSettings().get("cacheTagFormat"),
              request.getLoadBalancerService().getServiceId()
          );

          LOG.debug("Sending cache purge request against {} for {} to Cloudflare...", matchingDnsRecord.get().getName(), cacheTag);

          allSucceeded = cf.purgeEdgeCache(zoneId, Collections.singletonList(cacheTag)) && allSucceeded;
        }
      }
      return allSucceeded;

    } catch (CloudflareClientException e) {
      LOG.error("Unable to invalidate Cloudflare cache for request {}", request, e);
      return false;
    }
  }

Invalidation will eventually occur when the TTL expires, so it's not a showstopper if this fails.

Invalidation will eventually occur when the TTL expires so it s not a showstopper if this fails .


public Optional<BaragonServiceStatus> getBaragonServiceStatus(String baseUrl) {
    final String uri = String.format(STATUS_FORMAT, baseUrl);
    return getSingle(uri, "status", "", BaragonServiceStatus.class);
  }

public Optional < BaragonServiceStatus > getBaragonServiceStatus ( String baseUrl ) { final String uri = String . format ( STATUS_FORMAT , baseUrl ) ; return getSingle ( uri , "status" , "" , BaragonServiceStatus . class ) ; }


public Collection<BaragonServiceState> getGlobalState() {
    final String uri = String.format(STATE_FORMAT, getBaseUrl());
    return getCollection(uri, "global state", BARAGON_SERVICE_STATE_COLLECTION);
  }

public
Collection
<
BaragonServiceState
>
getGlobalState
(
)
{
final
String
uri
=
String
.
format
(
STATE_FORMAT
,
getBaseUrl
(
)
)
;
return
getCollection
(
uri
,
"global state"
,
BARAGON_SERVICE_STATE_COLLECTION
)
;
}


public Collection<String> getLoadBalancerGroups() {
    final String requestUri = String.format(LOAD_BALANCER_FORMAT, getBaseUrl());
    return getCollection(requestUri, "load balancer groups", STRING_COLLECTION);
  }

public
Collection
<
String
>
getLoadBalancerGroups
(
)
{
final
String
requestUri
=
String
.
format
(
LOAD_BALANCER_FORMAT
,
getBaseUrl
(
)
)
;
return
getCollection
(
requestUri
,
"load balancer groups"
,
STRING_COLLECTION
)
;
}

BaragonService load balancer group actions


public Collection<String> getOccupiedBasePaths(String loadBalancerGroupName) {
    final String requestUri = String.format(LOAD_BALANCER_ALL_BASE_PATHS_FORMAT, getBaseUrl(), loadBalancerGroupName);
    return getCollection(requestUri, "occupied base paths", STRING_COLLECTION);
  }

public
Collection
<
String
>
getOccupiedBasePaths
(
String
loadBalancerGroupName
)
{
final
String
requestUri
=
String
.
format
(
LOAD_BALANCER_ALL_BASE_PATHS_FORMAT
,
getBaseUrl
(
)
,
loadBalancerGroupName
)
;
return
getCollection
(
requestUri
,
"occupied base paths"
,
STRING_COLLECTION
)
;
}


public Optional<BaragonResponse> getRequest(String requestId) {
    final String uri = String.format(REQUEST_ID_FORMAT, getBaseUrl(), requestId);
    return getSingle(uri, "request", requestId, BaragonResponse.class);
  }

public Optional < BaragonResponse > getRequest ( String requestId ) { final String uri = String . format ( REQUEST_ID_FORMAT , getBaseUrl ( ) , requestId ) ; return getSingle ( uri , "request" , requestId , BaragonResponse . class ) ; }


public Collection<QueuedRequestId> getQueuedRequests() {
    final String uri = String.format(REQUEST_FORMAT, getBaseUrl());
    return getCollection(uri, "queued requests", QUEUED_REQUEST_COLLECTION);
  }

public
Collection
<
QueuedRequestId
>
getQueuedRequests
(
)
{
final
String
uri
=
String
.
format
(
REQUEST_FORMAT
,
getBaseUrl
(
)
)
;
return
getCollection
(
uri
,
"queued requests"
,
QUEUED_REQUEST_COLLECTION
)
;
}


private void guaranteeRegistered(TrafficSource trafficSource,
                                   TargetGroup targetGroup,
                                   Collection<TargetDescription> targets,
                                   Collection<BaragonAgentMetadata> baragonAgents,
                                   Collection<LoadBalancer> loadBalancers) {
    /*
    - Check that load balancers, baragon agents, target groups are on same VPC
    - Check that load balancers, targets are on same subnet (== AZ)
    - Check that all baragon agents are associated with a target on target group
    - Check that load balancers has listeners, rules to make talk to target group
     */

    if (configuration.isPresent() && configuration.get().isCheckForCorrectVpc()) {
      guaranteeSameVPC(targetGroup, baragonAgents, loadBalancers);
    }

    guaranteeAzEnabled(baragonAgents, loadBalancers);
    guaranteeHasAllTargets(trafficSource, targetGroup, targets, baragonAgents);
    //guaranteeListenersPresent(targetGroup, loadBalancers);
  }

Ensure that the given baragon agent is attached to the given target group. When this function
completes, the baragon agent will be attached to the load balancer, whether or not it originally
was.

@param baragonAgents BaragonAgent to register with given load balancer
@param loadBalancers Load balancer to register with

Ensure that the given baragon agent is attached to the given target group . When this function completes the baragon agent will be attached to the load balancer whether or not it originally was .


private void deregisterRemovableTargets(TrafficSource trafficSource,
                                          BaragonGroup baragonGroup,
                                          TargetGroup targetGroup,
                                          Collection<BaragonAgentMetadata> agents,
                                          Collection<TargetDescription> targets) {
    Collection<TargetDescription> removableTargets = listRemovableTargets(trafficSource, baragonGroup, targets, agents);

    for (TargetDescription removableTarget : removableTargets) {
      try {
        if (configuration.isPresent()
            && !configuration.get().isRemoveLastHealthyEnabled()
            && isLastHealthyInstance(removableTarget, targetGroup)) {
          LOG.info("Will not de-register target {} because it is last healthy instance in {}", removableTarget, targetGroup);
        } else {
          elbClient.deregisterTargets(new DeregisterTargetsRequest()
              .withTargetGroupArn(targetGroup.getTargetGroupArn())
              .withTargets(removableTarget));
          LOG.info("De-registered target {} from target group {}", removableTarget, targetGroup);
        }
      } catch (AmazonClientException acexn) {
        LOG.error("Could not de-register target {} from target group {} due to error",
            removableTarget, targetGroup, acexn);
        exceptionNotifier.notify(acexn, ImmutableMap
            .of("targetGroup", targetGroup.getTargetGroupName()));
      }
    }
  }

De-register any targets representing agents that are not known to the BaragonService,
or which otherwise need to be removed.

@param targetGroup TargetGroup to check for old agents
@param agents Known agents, to be used as a reference sheet

De - register any targets representing agents that are not known to the BaragonService or which otherwise need to be removed .


private void guaranteeSameVPC(TargetGroup targetGroup,
                                Collection<BaragonAgentMetadata> agents,
                                Collection<LoadBalancer> loadBalancers) {
    String vpcId = targetGroup.getVpcId();

    for (BaragonAgentMetadata agent : agents) {
      if (agent.getEc2().getVpcId().isPresent()) {
        if (! agent.getEc2().getVpcId().get().equals(vpcId)) {
          LOG.error("Agent {} not on same VPC as its target group {}", agent, targetGroup);
          throw new IllegalStateException(String.format("Agent %s not on same VPC as its target group %s", agent, targetGroup));
        }
      } else {
        LOG.error("Agent {} not assigned to a VPC", agent);
        throw new IllegalStateException(String.format("Agent %s not assigned to a VPC", agent));
      }
    }

    for (LoadBalancer loadBalancer : loadBalancers) {
      if (!vpcId.equals(loadBalancer.getVpcId())) {
        LOG.error("Load balancer {} on different VPC from target group {}", loadBalancer, targetGroup);
        throw new IllegalStateException(String.format("Load balancer %s on different VPC from target group %s", loadBalancer, targetGroup));
      }
    }
  }

When this method completes, the target group, the agents, and the loadBalancers are
all on the same VPC.
The target group, each of the agents, and each of the load balancers should think
that they are on the same VPC, otherwise they won't be able to talk to each other.

@param targetGroup Group - and consequently all targets - to check
@param agents Agents to check
@param loadBalancers Load balances to check

When this method completes the target group the agents and the loadBalancers are all on the same VPC . The target group each of the agents and each of the load balancers should think that they are on the same VPC otherwise they won t be able to talk to each other .


private void guaranteeHasAllTargets(TrafficSource trafficSource,
                                      TargetGroup targetGroup,
                                      Collection<TargetDescription> targets,
                                      Collection<BaragonAgentMetadata> baragonAgents) {
    Collection<TargetDescription> targetDescriptions = new HashSet<>();
    for (BaragonAgentMetadata agent : baragonAgents) {
      try {
        if ((trafficSource.getRegisterBy() == RegisterBy.INSTANCE_ID && agent.getEc2().getInstanceId().isPresent())
            || (trafficSource.getRegisterBy() == RegisterBy.PRIVATE_IP && agent.getEc2().getPrivateIp().isPresent())) {
          String id = trafficSource.getRegisterBy() == RegisterBy.INSTANCE_ID ? agent.getEc2().getInstanceId().get() : agent.getEc2().getPrivateIp().get();
          if (agentShouldRegisterInTargetGroup(id, targets)) {
            targetDescriptions.add(new TargetDescription()
                .withId(id));
            LOG.info("Will register agent {} to target in group {}", agent, targetGroup);
          } else {
            LOG.debug("Agent {} is already registered", agent);
          }
        }
      } catch (Exception exn) {
        LOG.error("Could not create request to register agent {} due to error", agent, exn);
        exceptionNotifier.notify(exn, ImmutableMap.of("agent", agent.toString()));
      }
    }

    if (targetDescriptions.isEmpty()) {
      LOG.debug("No new instances to register with target group");
    } else {
      try {
        RegisterTargetsRequest registerTargetsRequest = new RegisterTargetsRequest()
            .withTargetGroupArn(targetGroup.getTargetGroupArn())
            .withTargets(targetDescriptions);
        elbClient.registerTargets(registerTargetsRequest);
        LOG.info("Registered targets {} onto target group {}", targetDescriptions, targetGroup);
      } catch (AmazonClientException acexn) {
        LOG.error("Failed to register targets {} onto target group {}", targetDescriptions, targetGroup);
        exceptionNotifier.notify(acexn, ImmutableMap.of(
            "targets", targetDescriptions.toString(),
            "targetGroup", targetGroup.toString()));
      }
    }
  }

After this method completes, every agent in baragonAgents should be associated with
a target in the given target group.

@param targetGroup group to register in
@param baragonAgents agents to be registered

After this method completes every agent in baragonAgents should be associated with a target in the given target group .


public void setHref(String href) {
		if (href.contains("%7B")) {
			try {
				href = URLDecoder.decode(href, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				throw new RuntimeException(e);
			}
		}
		this.href = new UriTemplate(href);
	}

public void setHref ( String href ) { if ( href . contains ( "%7B" ) ) { try { href = URLDecoder . decode ( href , "UTF-8" ) ; } catch ( UnsupportedEncodingException e ) { throw new RuntimeException ( e ) ; } } this . href = new UriTemplate ( href ) ; }

backwards compatibility, would be canged in next version

backwards compatibility would be canged in next version


static MemberKey newInstance(Object contextObject, String name) {
        if (contextObject instanceof Class<?>) {
            Class<?> clazz = (Class<?>) contextObject;
            if (clazz.isEnum() && ("values".equals(name) || Reflections.isConstantName(clazz, name))) {
                // Special handling for enums - allows to access values() and constants
                return new MemberKey(clazz, name);
            }
        }
        return new MemberKey(contextObject.getClass(), name);
    }

Simple factory method to obtain a new instance for the given context
object and name.

@param contextObject
@param name
@return a new instance

Simple factory method to obtain a new instance for the given context object and name .


private void lineSeparatorFound(String lineSeparator) {
        flushText();
        flushLineSeparator(lineSeparator);
        line++;
        state = State.TEXT;
        separatorIdx = 0;
    }

private void lineSeparatorFound ( String lineSeparator ) { flushText ( ) ; flushLineSeparator ( lineSeparator ) ; line ++ ; state = State . TEXT ; separatorIdx = 0 ; }

Line separator end - flush.

@param lineSeparator


private void flushTag() {
        state = State.TEXT;
        handler.tag(deriveTag(buffer.toString()));
        delimiterIdx = 0;
        clearBuffer();
    }

private void flushTag ( ) { state = State . TEXT ; handler . tag ( deriveTag ( buffer . toString ( ) ) ) ; delimiterIdx = 0 ; clearBuffer ( ) ; }


private String extractContent(MustacheTagType tagType, String buffer) {

        switch (tagType) {
        case VARIABLE:
            return buffer.trim();
        case UNESCAPE_VARIABLE:
            return (buffer.charAt(0) == ((String) EngineConfigurationKey.START_DELIMITER
                    .getDefaultValue()).charAt(0) ? buffer.substring(1,
                    buffer.length() - 1).trim() : buffer.substring(1).trim());
        case SECTION:
        case INVERTED_SECTION:
        case PARTIAL:
        case EXTEND:
        case EXTEND_SECTION:
        case SECTION_END:
        case NESTED_TEMPLATE:
        case COMMENT:
            return buffer.substring(1).trim();
        case DELIMITER:
            return buffer.trim();
        default:
            return null;
        }
    }

private String extractContent ( MustacheTagType tagType , String buffer ) { switch ( tagType ) { case VARIABLE : return buffer . trim ( ) ; case UNESCAPE_VARIABLE : return ( buffer . charAt ( 0 ) == ( ( String ) EngineConfigurationKey . START_DELIMITER . getDefaultValue ( ) ) . charAt ( 0 ) ? buffer . substring ( 1 , buffer . length ( ) - 1 ) . trim ( ) : buffer . substring ( 1 ) . trim ( ) ) ; case SECTION : case INVERTED_SECTION : case PARTIAL : case EXTEND : case EXTEND_SECTION : case SECTION_END : case NESTED_TEMPLATE : case COMMENT : return buffer . substring ( 1 ) . trim ( ) ; case DELIMITER : return buffer . trim ( ) ; default : return null ; } }

Extract the tag content.

@param buffer
@return


private static List<List<SegmentBase>> readSegmentLines(
            ContainerSegmentBase container) {
        List<List<SegmentBase>> lines = new ArrayList<>();
        // Add the last line manually - there is no line separator to trigger
        // flush
        lines.add(readSegmentLines(lines, null, container));
        return lines;
    }

Read segment lines recursively.

@param container
@return


public static Pattern newMustacheTagPattern(Configuration configuration) {
        StringBuilder regex = new StringBuilder();
        regex.append(Pattern.quote(configuration
                .getStringPropertyValue(EngineConfigurationKey.START_DELIMITER)));
        regex.append(".*?");
        regex.append(Pattern.quote(configuration
                .getStringPropertyValue(EngineConfigurationKey.END_DELIMITER)));
        return Pattern.compile(regex.toString());
    }

public static Pattern newMustacheTagPattern ( Configuration configuration ) { StringBuilder regex = new StringBuilder ( ) ; regex . append ( Pattern . quote ( configuration . getStringPropertyValue ( EngineConfigurationKey . START_DELIMITER ) ) ) ; regex . append ( ".*?" ) ; regex . append ( Pattern . quote ( configuration . getStringPropertyValue ( EngineConfigurationKey . END_DELIMITER ) ) ) ; return Pattern . compile ( regex . toString ( ) ) ; }

Delimiters are quoted to avoid regexp reserved characters conflict.

@param configuration
@return the new delimiters pattern

Delimiters are quoted to avoid regexp reserved characters conflict .


public static <T> Decorator<T> decorate(T delegate, Map<String, Function<T, Object>> mappings, String delegateKey,
            Configuration configuration) {
        return IterableDecorator.isIterable(delegate)
                ? new IterableDecorator<>(delegate, ImmutableMap.copyOf(mappings), delegateKey, configuration)
                : new Decorator<>(delegate, ImmutableMap.copyOf(mappings), delegateKey, configuration);
    }

public static < T > Decorator < T > decorate ( T delegate , Map < String , Function < T , Object > > mappings , String delegateKey , Configuration configuration ) { return IterableDecorator . isIterable ( delegate ) ? new IterableDecorator <> ( delegate , ImmutableMap . copyOf ( mappings ) , delegateKey , configuration ) : new Decorator <> ( delegate , ImmutableMap . copyOf ( mappings ) , delegateKey , configuration ) ; }

Returns a decorator instance for the specified delegate and mappings.

@param delegate
@param mappings
@param delegateKey
May be null
@param configuration
@return a new decorator instance

Returns a decorator instance for the specified delegate and mappings .


@SuppressWarnings("unchecked")
    public static <T> T unwrap(T instance) {
        return instance instanceof Decorator ? unwrap(((Decorator<T>) instance).delegate) : instance;
    }

@ SuppressWarnings ( "unchecked" ) public static < T > T unwrap ( T instance ) { return instance instanceof Decorator ? unwrap ( ( ( Decorator < T > ) instance ) . delegate ) : instance ; }

This method is recursive.

@return the underlying delegate instance


public synchronized MustacheEngine build() {
        MustacheEngine engine = new DefaultMustacheEngine(this);
        for (EngineBuiltCallback callback : engineReadyCallbacks) {
            callback.engineBuilt(engine);
        }
        BuildInfo buildInfo = BuildInfo.load();
        LOGGER.info("Engine built {} ({})", buildInfo.getVersion(), buildInfo.getTimestampDate());
        LOGGER.debug("Engine configuration: {}",
                engine.getConfiguration().getInfo());
        isBuilt = true;
        return engine;
    }

public
synchronized
MustacheEngine
build
(
)
{
MustacheEngine
engine
=
new
DefaultMustacheEngine
(
this
)
;
for
(
EngineBuiltCallback
callback
:
engineReadyCallbacks
)
{
callback
.
engineBuilt
(
engine
)
;
}
BuildInfo
buildInfo
=
BuildInfo
.
load
(
)
;
LOGGER
.
info
(
"Engine built {} ({})"
,
buildInfo
.
getVersion
(
)
,
buildInfo
.
getTimestampDate
(
)
)
;
LOGGER
.
debug
(
"Engine configuration: {}"
,
engine
.
getConfiguration
(
)
.
getInfo
(
)
)
;
isBuilt
=
true
;
return
engine
;
}

Builds the engine instance.

@return the built engine


public MustacheEngineBuilder addTemplateLocator(TemplateLocator locator) {
        checkArgumentNotNull(locator);
        checkNotBuilt();
        this.templateLocators.add(locator);
        return this;
    }

public MustacheEngineBuilder addTemplateLocator ( TemplateLocator locator ) { checkArgumentNotNull ( locator ) ; checkNotBuilt ( ) ; this . templateLocators . add ( locator ) ; return this ; }

Adds a template locator.

@param locator
@return self


public MustacheEngineBuilder addResolver(Resolver resolver) {
        checkArgumentNotNull(resolver);
        checkNotBuilt();
        this.resolvers.add(resolver);
        return this;
    }

public MustacheEngineBuilder addResolver ( Resolver resolver ) { checkArgumentNotNull ( resolver ) ; checkNotBuilt ( ) ; this . resolvers . add ( resolver ) ; return this ; }

Adds a value resolver.

@param resolver
@return self


public MustacheEngineBuilder registerCallback(
            EngineBuiltCallback callback) {
        checkArgumentNotNull(callback);
        checkNotBuilt();
        this.engineReadyCallbacks.add(callback);
        return this;
    }

public MustacheEngineBuilder registerCallback ( EngineBuiltCallback callback ) { checkArgumentNotNull ( callback ) ; checkNotBuilt ( ) ; this . engineReadyCallbacks . add ( callback ) ; return this ; }

Callback is useful to configure a component instantiated before the
engine is built.

@param callback
@return self

Callback is useful to configure a component instantiated before the engine is built .


public MustacheEngineBuilder addValueConverter(ValueConverter converter) {
        checkArgumentNotNull(converter);
        checkNotBuilt();
        this.valueConverters.add(converter);
        return this;
    }

public MustacheEngineBuilder addValueConverter ( ValueConverter converter ) { checkArgumentNotNull ( converter ) ; checkNotBuilt ( ) ; this . valueConverters . add ( converter ) ; return this ; }

Add a value converter.

@param converter
@return self


public MustacheEngineBuilder addContextConverter(ContextConverter converter) {
        checkArgumentNotNull(converter);
        checkNotBuilt();
        this.contextConverters.add(converter);
        return this;
    }

public MustacheEngineBuilder addContextConverter ( ContextConverter converter ) { checkArgumentNotNull ( converter ) ; checkNotBuilt ( ) ; this . contextConverters . add ( converter ) ; return this ; }

Add a context converter.

@param converter
@return self


public static String capitalizeFully(String text, Character delimiter) {
        if (isEmpty(text)) {
            return text;
        }
        text = text.toLowerCase();
        boolean capitalizeNext = true;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {
            final char ch = text.charAt(i);
            if (delimiter.equals(ch)) {
                capitalizeNext = true;
                builder.append(ch);
            } else if (capitalizeNext) {
                builder.append(Character.toTitleCase(ch));
                capitalizeNext = false;
            } else {
                builder.append(ch);
            }
        }
        return builder.toString();
    }

public static String capitalizeFully ( String text , Character delimiter ) { if ( isEmpty ( text ) ) { return text ; } text = text . toLowerCase ( ) ; boolean capitalizeNext = true ; StringBuilder builder = new StringBuilder ( ) ; for ( int i = 0 ; i < text . length ( ) ; i ++ ) { final char ch = text . charAt ( i ) ; if ( delimiter . equals ( ch ) ) { capitalizeNext = true ; builder . append ( ch ) ; } else if ( capitalizeNext ) { builder . append ( Character . toTitleCase ( ch ) ) ; capitalizeNext = false ; } else { builder . append ( ch ) ; } } return builder . toString ( ) ; }

Capitalizes all the delimiter separated words.

@param text
@param delimiter
@return the capitalized input

Capitalizes all the delimiter separated words .


protected void append(Options options, CharSequence sequence) {
        TextSupport textSupport = this.textSupport;
        if (textSupport == null || isUnescapeVariable(options)) {
            options.append(sequence);
        } else {
            try {
                textSupport.appendEscapedHtml(sequence.toString(),
                        options.getAppendable());
            } catch (IOException e) {
                throw new MustacheException(MustacheProblem.RENDER_IO_ERROR, e);
            }
        }
    }

protected void append ( Options options , CharSequence sequence ) { TextSupport textSupport = this . textSupport ; if ( textSupport == null || isUnescapeVariable ( options ) ) { options . append ( sequence ) ; } else { try { textSupport . appendEscapedHtml ( sequence . toString ( ) , options . getAppendable ( ) ) ; } catch ( IOException e ) { throw new MustacheException ( MustacheProblem . RENDER_IO_ERROR , e ) ; } } }

Escape appended sequence if needed.

@param options
@param sequence
@see TextSupport


private ComputingCache<String, Optional<String>> buildSourceCache() {
        return buildCache("Source",
                key ->
                        Optional.ofNullable(locateAndRead(key)),
                (key, cause) ->
                        LOGGER.debug("Removed template source from cache [templateId: {}, cause: {}]", key, cause));
    }

Properties of the source cache are dependent on that of the template
cache.

Properties of the source cache are dependent on that of the template cache .


private void push(ContainerSegmentBase container) {
        containerStack.addFirst(container);
        LOGGER.trace("Push {} [name: {}]", container.getType(),
                container.getContent());
    }

private
void
push
(
ContainerSegmentBase
container
)
{
containerStack
.
addFirst
(
container
)
;
LOGGER
.
trace
(
"Push {} [name: {}]"
,
container
.
getType
(
)
,
container
.
getContent
(
)
)
;
}

Push the container wrapper on the stack.

@param container

Push the container wrapper on the stack .


private void addSegment(SegmentBase segment) {
        containerStack.peekFirst().addSegment(segment);
        LOGGER.trace("Add {}", segment);
    }

private
void
addSegment
(
SegmentBase
segment
)
{
containerStack
.
peekFirst
(
)
.
addSegment
(
segment
)
;
LOGGER
.
trace
(
"Add {}"
,
segment
)
;
}

Add the segment to the container on the stack.

@param segment

Add the segment to the container on the stack .


private RootSegmentBase validate() {

        ContainerSegmentBase root = containerStack.peekFirst();

        if (!(root instanceof RootSegmentBase)) {
            throw new MustacheException(
                    MustacheProblem.COMPILE_INVALID_TEMPLATE,
                    "Incorrect last container segment on the stack: %s",
                    containerStack.peekFirst().toString(), line);
        }
        return (RootSegmentBase) root;
    }


static Iterator<String> splitHelperName(String name, Segment segment) {

        boolean stringLiteral = false;
        boolean arrayLiteral = false;
        boolean space = false;
        List<String> parts = new ArrayList<>();
        StringBuilder buffer = new StringBuilder();

        for (int i = 0; i < name.length(); i++) {
            if (name.charAt(i) == ' ') {
                if (!space) {
                    if (!stringLiteral && !arrayLiteral) {
                        if (buffer.length() > 0) {
                            parts.add(buffer.toString());
                            buffer = new StringBuilder();
                        }
                        space = true;
                    } else {
                        buffer.append(name.charAt(i));
                    }
                }
            } else {
                if (!arrayLiteral
                        && Strings.isStringLiteralSeparator(name.charAt(i))) {
                    stringLiteral = !stringLiteral;
                } else if (!stringLiteral
                        && Strings.isListLiteralStart(name.charAt(i))) {
                    arrayLiteral = true;
                } else if (!stringLiteral
                        && Strings.isListLiteralEnd(name.charAt(i))) {
                    arrayLiteral = false;
                }
                space = false;
                buffer.append(name.charAt(i));
            }
        }

        if (buffer.length() > 0) {
            if (stringLiteral || arrayLiteral) {
                throw new MustacheException(
                        MustacheProblem.COMPILE_HELPER_VALIDATION_FAILURE,
                        "Unterminated string or array literal detected: %s",
                        segment);
            }
            parts.add(buffer.toString());
        }
        return parts.iterator();
    }

Extracts parts from an input string. This implementation is quite naive
and should be possibly rewritten. Note that we can't use a simple
splitter because of string literals may contain whitespace chars.

@param name
@param segment
@return the parts of the helper name
@throws MustacheException
If a compilation problem occurs

Extracts parts from an input string . This implementation is quite naive and should be possibly rewritten . Note that we can t use a simple splitter because of string literals may contain whitespace chars .


public static <T> Builder<T> decorate(Class<T> delegateType) {
        return decorate(o -> (delegateType.isAssignableFrom(Decorator.unwrap(o).getClass())));
    }

public static < T > Builder < T > decorate ( Class < T > delegateType ) { return decorate ( o -> ( delegateType . isAssignableFrom ( Decorator . unwrap ( o ) . getClass ( ) ) ) ) ; }

Returns a decorator converter builder for the specified delegate type.

@param delegateType
@return a new builder instance

Returns a decorator converter builder for the specified delegate type .


private void flush() {
        try {
            parent.append(future.get(60, TimeUnit.SECONDS).collect(this));
            parent.append(buffer);
            if (parent instanceof AsyncAppendable) {
                ((AsyncAppendable) parent).flush();
            }
        } catch (Exception e) {
            throw new MustacheException(
                    MustacheProblem.RENDER_ASYNC_PROCESSING_ERROR, e);
        }
    }

private void flush ( ) { try { parent . append ( future . get ( 60 , TimeUnit . SECONDS ) . collect ( this ) ) ; parent . append ( buffer ) ; if ( parent instanceof AsyncAppendable ) { ( ( AsyncAppendable ) parent ) . flush ( ) ; } } catch ( Exception e ) { throw new MustacheException ( MustacheProblem . RENDER_ASYNC_PROCESSING_ERROR , e ) ; } }


static Field findField(Class<?> clazz, String name) {

        checkArgumentNotNull(clazz);
        checkArgumentNotNull(name);

        Field found = null;

        for (Field field : SecurityActions.getFields(clazz)) {
            if (field.getName().equals(name)) {
                found = field;
            }
        }
        LOGGER.debug("Field {} {}found on type: {}", name, found != null ? "" : "not ", clazz.getName());
        return found;
    }

static
Field
findField
(
Class
<
>
clazz
,
String
name
)
{
checkArgumentNotNull
(
clazz
)
;
checkArgumentNotNull
(
name
)
;
Field
found
=
;
for
(
Field
field
:
SecurityActions
.
getFields
(
clazz
)
)
{
if
(
field
.
getName
(
)
.
equals
(
name
)
)
{
found
=
field
;
}
}
LOGGER
.
debug
(
"Field {} {}found on type: {}"
,
name
,
found
!=
""
:
"not "
,
clazz
.
getName
(
)
)
;
return
found
;
}

Tries to find a public field with the given name on the given class.

@param clazz
@param name
@return the found field or null

Tries to find a public field with the given name on the given class .


public static void registerHelpers(ConfigurationExtensionBuilder builder, Map<String, Helper> helpers) {
        Checker.checkArgumentsNotNull(builder, helpers);
        for (Entry<String, Helper> entry : helpers.entrySet()) {
            registerHelper(builder, entry.getKey(), entry.getValue());
        }
    }

public static void registerHelpers ( ConfigurationExtensionBuilder builder , Map < String , Helper > helpers ) { Checker . checkArgumentsNotNull ( builder , helpers ) ; for ( Entry < String , Helper > entry : helpers . entrySet ( ) ) { registerHelper ( builder , entry . getKey ( ) , entry . getValue ( ) ) ; } }

Register helper and do nothing if a helper with the same name is already registered.

@param builder
@param helpers

Register helper and do nothing if a helper with the same name is already registered .


public static void registerHelper(ConfigurationExtensionBuilder builder, String name, Helper helper) {
        Checker.checkArgumentsNotNull(builder, name, helper);
        try {
            builder.registerHelper(name, helper);
        } catch (IllegalArgumentException ignored) {
        }
    }

public static void registerHelper ( ConfigurationExtensionBuilder builder , String name , Helper helper ) { Checker . checkArgumentsNotNull ( builder , name , helper ) ; try { builder . registerHelper ( name , helper ) ; } catch ( IllegalArgumentException ignored ) { } }

Register helpers and do nothing if a helper with the same name is already registered.

@param builder
@param name
@param helper

Register helpers and do nothing if a helper with the same name is already registered .


static List<List<Segment>> readSegmentLinesBeforeRendering(
            AbstractContainerSegment container) {
        List<List<Segment>> lines = new ArrayList<>();
        List<Segment> currentLine = new ArrayList<>();

        for (Segment segment : container) {
            if (!SegmentType.LINE_SEPARATOR.equals(segment.getType())) {
                currentLine.add(segment);
            } else {
                // New line separator - flush the line
                currentLine.add(segment);
                lines.add(currentLine);
                currentLine = new ArrayList<>();
            }
        }
        // Add the last line manually - there is no line separator to trigger
        // flush
        if (!currentLine.isEmpty()) {
            lines.add(currentLine);
        }
        return lines;
    }

Read segment lines before rendering.

@param container
@return


public void invalidateFragments(final String keyPart) {
        if (fragments == null || keyPart == null) {
            return;
        }
        fragments.invalidate(fragmentKey -> fragmentKey.getKey().contains(keyPart));
    }

public void invalidateFragments ( final String keyPart ) { if ( fragments == null || keyPart == null ) { return ; } fragments . invalidate ( fragmentKey -> fragmentKey . getKey ( ) . contains ( keyPart ) ) ; }

Invalidate the cache fragments whose key contains the given part of the
key.

@param keyPart

Invalidate the cache fragments whose key contains the given part of the key .


protected TemporalAccessor getFormattableObject(Object value,
            Locale locale, TimeZone timeZone, MustacheTagInfo tagInfo) {

        if (value instanceof TemporalAccessor) {
            return (TemporalAccessor) value;
        } else if (value instanceof Date) {
            return LocalDateTime.ofInstant(((Date) value).toInstant(),
                    timeZone.toZoneId());
        } else if (value instanceof Calendar) {
            return LocalDateTime.ofInstant(((Calendar) value).toInstant(),
                    timeZone.toZoneId());
        } else if (value instanceof Number) {
            return LocalDateTime.ofInstant(
                    Instant.ofEpochMilli(((Number) value).longValue()),
                    timeZone.toZoneId());
        } else {
            throw valueNotAFormattableObject(value, tagInfo);
        }
    }

protected TemporalAccessor getFormattableObject ( Object value , Locale locale , TimeZone timeZone , MustacheTagInfo tagInfo ) { if ( value instanceof TemporalAccessor ) { return ( TemporalAccessor ) value ; } else if ( value instanceof Date ) { return LocalDateTime . ofInstant ( ( ( Date ) value ) . toInstant ( ) , timeZone . toZoneId ( ) ) ; } else if ( value instanceof Calendar ) { return LocalDateTime . ofInstant ( ( ( Calendar ) value ) . toInstant ( ) , timeZone . toZoneId ( ) ) ; } else if ( value instanceof Number ) { return LocalDateTime . ofInstant ( Instant . ofEpochMilli ( ( ( Number ) value ) . longValue ( ) ) , timeZone . toZoneId ( ) ) ; } else { throw valueNotAFormattableObject ( value , tagInfo ) ; } }


public static StorageExt getLocalStorage() {
    if (localStorage == null && Storage.isLocalStorageSupported()) {
      localStorage = new StorageExt(Storage.getLocalStorageIfSupported());
    }
    return localStorage;
  }

public static StorageExt getLocalStorage ( ) { if ( localStorage == null && Storage . isLocalStorageSupported ( ) ) { localStorage = new StorageExt ( Storage . getLocalStorageIfSupported ( ) ) ; } return localStorage ; }

Returns a Local Storage.

@return the localStorage instance, or null if Web Storage is NOT supported.


public static StorageExt getSessionStorage() {
    if (sessionStorage == null && Storage.isSessionStorageSupported()) {
      sessionStorage = new StorageExt(Storage.getSessionStorageIfSupported());
    }
    return sessionStorage;
  }

public static StorageExt getSessionStorage ( ) { if ( sessionStorage == null && Storage . isSessionStorageSupported ( ) ) { sessionStorage = new StorageExt ( Storage . getSessionStorageIfSupported ( ) ) ; } return sessionStorage ; }

Returns a Session Storage.

@return the sessionStorage instance, or null if Web Storage is NOT supported.


public void clear() {
    storage.clear();
    cache.clear();
    fireEvent(StorageChangeEvent.ChangeType.CLEAR, null, null, null, null, null);
  }

public void clear ( ) { storage . clear ( ) ; cache . clear ( ) ; fireEvent ( StorageChangeEvent . ChangeType . CLEAR , null , null , null , null , null ) ; }

Removes all items in the Storage, and its cache if activated

@see W3C Web
Storage - Storage.clear()

Removes all items in the Storage and its cache if activated


public <T> boolean containsKey(StorageKey<T> key) {
    return storage.getItem(key.name()) != null;
  }

public < T > boolean containsKey ( StorageKey < T > key ) { return storage . getItem ( key . name ( ) ) != null ; }

Test if this storage contains a value for the specified key.

<p>
{@link StorageKeyFactory} is preferred to get a {@link StorageKey} instance for primitive types.
</p>

@param key the key whose presence in this storage is to be tested
@param <T> the type of stored value
@return <tt>true</tt> if this storage contains a value for the specified key.

Test if this storage contains a value for the specified key .


public <T> void put(StorageKey<T> key, T value) throws SerializationException, StorageQuotaExceededException {
    if(value == null){
      throw new NullPointerException();
    }
    try {
      String data = StorageUtils.serialize(key.getClazz(), value);
      // Update store and cache
      String oldData = storage.getItem(key.name());
      storage.setItem(key.name(), data);
      T oldValue = cache.put(key, value);
      fireEvent(StorageChangeEvent.ChangeType.PUT, key, value, oldValue, data, oldData);
    } catch (JavaScriptException e) {
      String msg = e.getMessage();
      if (msg != null && msg.contains("QUOTA") && msg.contains("DOM")) {
        throw new StorageQuotaExceededException(key, e);
      }
      throw e;
    }
  }

public
<
T
>
void
put
(
StorageKey
<
T
>
key
,
T
value
)
throws
SerializationException
,
StorageQuotaExceededException
{
if
(
value
==
)
{
throw
new
NullPointerException
(
)
;
}
try
{
String
data
=
StorageUtils
.
serialize
(
key
.
getClazz
(
)
,
value
)
;
// Update store and cache
String
oldData
=
storage
.
getItem
(
key
.
name
(
)
)
;
storage
.
setItem
(
key
.
name
(
)
,
data
)
;
T
oldValue
=
cache
.
put
(
key
,
value
)
;
fireEvent
(
StorageChangeEvent
.
ChangeType
.
PUT
,
key
,
value
,
oldValue
,
data
,
oldData
)
;
}
catch
(
JavaScriptException
e
)
{
String
msg
=
e
.
getMessage
(
)
;
if
(
msg
!=
&&
msg
.
contains
(
"QUOTA"
)
&&
msg
.
contains
(
"DOM"
)
)
{
throw
new
StorageQuotaExceededException
(
key
,
e
)
;
}
throw
e
;
}
}

Store the specified value with the specified key in this storage.

Note: null value is not allowed.

If the storage previously contained a mapping for the key, the old
value is replaced.

{@link StorageKeyFactory} is preferred to get a {@link StorageKey} instance for primitive types.

@param key key with which the specified value is to be associated
@param value value to be associated with the specified key
@throws SerializationException
@throws StorageQuotaExceededException

Store the specified value with the specified key in this storage .


public <T extends Serializable> void remove(StorageKey<T> key) {
    String data = storage.getItem(key.name());
    storage.removeItem(key.name());
    T value = cache.remove(key);
    fireEvent(StorageChangeEvent.ChangeType.REMOVE, key, null, value, null, data);
  }

public < T extends Serializable > void remove ( StorageKey < T > key ) { String data = storage . getItem ( key . name ( ) ) ; storage . removeItem ( key . name ( ) ) ; T value = cache . remove ( key ) ; fireEvent ( StorageChangeEvent . ChangeType . REMOVE , key , null , value , null , data ) ; }

Removes the record for the specified key from this storage if present.

<p>
{@link StorageKeyFactory} is preferred to get a {@link StorageKey} instance for primitive types
</p>

@param key key whose mapping is to be removed from the map
@param <T> the type of stored value

Removes the record for the specified key from this storage if present .


@Deprecated
  public static <T> StorageKey<T> objectKey(String keyName){
    return new StorageKey<>(keyName, Object.class);
  }

@ Deprecated public static < T > StorageKey < T > objectKey ( String keyName ) { return new StorageKey <> ( keyName , Object . class ) ; }

Returns non-primitive type value's storage key.

@param keyName name of storage key
@param <T> type of value
@return non-primitive type value's storage key
@deprecated use {@link #isSerializableKey(String)} or {@link #serializableKey(String)} instead

Returns non - primitive type value s storage key .


public static <T extends IsSerializable> StorageKey<T> isSerializableKey(String keyName){
      return new StorageKey<>(keyName, IsSerializable.class);
  }

public static < T extends IsSerializable > StorageKey < T > isSerializableKey ( String keyName ) { return new StorageKey <> ( keyName , IsSerializable . class ) ; }

Returns IsSerializable type value's storage key.

@param keyName name of storage key
@param <T> type of value
@return IsSerializable type value's storage key

Returns IsSerializable type value s storage key .


public static <T extends Serializable> StorageKey<T> serializableKey(String keyName){
      return new StorageKey<>(keyName, Serializable.class);
  }

public static < T extends Serializable > StorageKey < T > serializableKey ( String keyName ) { return new StorageKey <> ( keyName , Serializable . class ) ; }

Returns Serializable type value's storage key.

@param keyName name of storage key
@param <T> type of value
@return Serializable type value's storage key

Returns Serializable type value s storage key .


private void obtainSize(@NonNull final TypedArray typedArray) {
        Size defaultSize = Size.NORMAL;
        size = Size.fromValue(
                typedArray.getInt(R.styleable.FloatingActionButton_size, defaultSize.getValue()));
    }

private void obtainSize ( @ NonNull final TypedArray typedArray ) { Size defaultSize = Size . NORMAL ; size = Size . fromValue ( typedArray . getInt ( R . styleable . FloatingActionButton_size , defaultSize . getValue ( ) ) ) ; }

Obtains the floating action button's size from a specific typed array.

@param typedArray
The typed array, the color should be obtained from, as an instance of the class
{@link TypedArray}. The typed array may not be null

Obtains the floating action button s size from a specific typed array .


private void obtainColor(@NonNull final TypedArray typedArray) {
        int defaultColor = ThemeUtil.getColor(getContext(), R.attr.colorAccent);
        color = typedArray.getColor(R.styleable.FloatingActionButton_android_color, defaultColor);
    }

private void obtainColor ( @ NonNull final TypedArray typedArray ) { int defaultColor = ThemeUtil . getColor ( getContext ( ) , R . attr . colorAccent ) ; color = typedArray . getColor ( R . styleable . FloatingActionButton_android_color , defaultColor ) ; }

Obtains the floating action button's color from a specific typed array.

@param typedArray
The typed array, the color should be obtained from, as an instance of the class
{@link TypedArray}. The typed array may not be null

Obtains the floating action button s color from a specific typed array .


private void obtainActivatedColor(@NonNull final TypedArray typedArray) {
        int defaultActivatedColor = getControlActivatedColor();
        activatedColor = typedArray
                .getColor(R.styleable.FloatingActionButton_activatedColor, defaultActivatedColor);
    }

private void obtainActivatedColor ( @ NonNull final TypedArray typedArray ) { int defaultActivatedColor = getControlActivatedColor ( ) ; activatedColor = typedArray . getColor ( R . styleable . FloatingActionButton_activatedColor , defaultActivatedColor ) ; }

Obtains the floating action button's activated color from a specific typed array.

@param typedArray
The typed array, the activated color should be obtained from, as an instance of the
class {@link TypedArray}. The typed array may not be null

Obtains the floating action button s activated color from a specific typed array .


private void obtainPressedColor(@NonNull final TypedArray typedArray) {
        int defaultPressedColor = getControlHighlightColor();
        pressedColor = typedArray
                .getColor(R.styleable.FloatingActionButton_pressedColor, defaultPressedColor);
    }

private void obtainPressedColor ( @ NonNull final TypedArray typedArray ) { int defaultPressedColor = getControlHighlightColor ( ) ; pressedColor = typedArray . getColor ( R . styleable . FloatingActionButton_pressedColor , defaultPressedColor ) ; }

Obtains the floating action button's pressed color from a specific typed array.

@param typedArray
The typed array, the pressed color should be obtained from, as an instance of the
class {@link TypedArray}. The typed array may not be null

Obtains the floating action button s pressed color from a specific typed array .


private void obtainDisabledColor(@NonNull final TypedArray typedArray) {
        int defaultDisabledColor =
                ContextCompat.getColor(getContext(), R.color.floating_action_button_disabled_color);
        disabledColor = typedArray
                .getColor(R.styleable.FloatingActionButton_disabledColor, defaultDisabledColor);
    }

private void obtainDisabledColor ( @ NonNull final TypedArray typedArray ) { int defaultDisabledColor = ContextCompat . getColor ( getContext ( ) , R . color . floating_action_button_disabled_color ) ; disabledColor = typedArray . getColor ( R . styleable . FloatingActionButton_disabledColor , defaultDisabledColor ) ; }

Obtains the floating action button's disabled color from a specific typed array.

@param typedArray
The typed array, the disabled color should be obtained from, as an instance of the
class {@link TypedArray}. The typed array may not be null

Obtains the floating action button s disabled color from a specific typed array .


private void obtainIcon(@NonNull final TypedArray typedArray) {
        Drawable icon = typedArray.getDrawable(R.styleable.FloatingActionButton_android_icon);
        setIcon(icon);
    }

private void obtainIcon ( @ NonNull final TypedArray typedArray ) { Drawable icon = typedArray . getDrawable ( R . styleable . FloatingActionButton_android_icon ) ; setIcon ( icon ) ; }

Obtains the floating action button's icon from a specific typed array.

@param typedArray
The typed array, the ripple color should be obtained from, as an instance of the
class {@link TypedArray}. The typed array may not be null

Obtains the floating action button s icon from a specific typed array .


private void obtainVisibilityAnimationDuration(@NonNull final TypedArray typedArray) {
        int defaultAnimationDuration = getResources()
                .getInteger(R.integer.floating_action_button_visibility_animation_duration);
        int duration = typedArray
                .getInteger(R.styleable.FloatingActionButton_visibilityAnimationDuration,
                        defaultAnimationDuration);
        setVisibilityAnimationDuration(duration);
    }

Obtains the duration of the animation, which may be used to changed the visibility of the
floating action button, from a specific typed array.

@param typedArray
The typed array, the animation duration should be obtained from, as an instance of
the class {@link TypedArray}. The typed array may not be null

Obtains the duration of the animation which may be used to changed the visibility of the floating action button from a specific typed array .


private void adaptShadow() {
        if (getSize() == Size.NORMAL) {
            setBackgroundResource(R.drawable.floating_action_button_shadow_normal);
        } else if (getSize() == Size.SMALL) {
            setBackgroundResource(R.drawable.floating_action_button_shadow_small);
        } else {
            setBackgroundResource(R.drawable.floating_action_button_shadow_large);
        }
    }

private void adaptShadow ( ) { if ( getSize ( ) == Size . NORMAL ) { setBackgroundResource ( R . drawable . floating_action_button_shadow_normal ) ; } else if ( getSize ( ) == Size . SMALL ) { setBackgroundResource ( R . drawable . floating_action_button_shadow_small ) ; } else { setBackgroundResource ( R . drawable . floating_action_button_shadow_large ) ; } }

Adapts the shadow of the floating action button, depending on its size.

Adapts the shadow of the floating action button depending on its size .


private void adaptImageButtonSize() {
        int pixelSize = getPixelSize();
        LayoutParams layoutParams = (LayoutParams) imageButton.getLayoutParams();
        layoutParams.width = pixelSize;
        layoutParams.height = pixelSize;
        imageButton.setLayoutParams(layoutParams);
        imageButton.requestLayout();
    }

private void adaptImageButtonSize ( ) { int pixelSize = getPixelSize ( ) ; LayoutParams layoutParams = ( LayoutParams ) imageButton . getLayoutParams ( ) ; layoutParams . width = pixelSize ; layoutParams . height = pixelSize ; imageButton . setLayoutParams ( layoutParams ) ; imageButton . requestLayout ( ) ; }

Adapts the size of the image button, which is used to show the floating image button's
background and icon, depending on the floating button's size.

Adapts the size of the image button which is used to show the floating image button s background and icon depending on the floating button s size .


@SuppressLint("NewApi")
    private void adaptImageButtonBackground() {
        Drawable background = createStateListBackgroundDrawable();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Drawable rippleDrawable = new RippleDrawable(
                    new ColorStateList(new int[][]{{}}, new int[]{getPressedColor()}), background,
                    null);
            ViewUtil.setBackground(imageButton, rippleDrawable);
        } else {
            ViewUtil.setBackground(imageButton, background);
        }
    }

@ SuppressLint ( "NewApi" ) private void adaptImageButtonBackground ( ) { Drawable background = createStateListBackgroundDrawable ( ) ; if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . LOLLIPOP ) { Drawable rippleDrawable = new RippleDrawable ( new ColorStateList ( new int [ ] [ ] { { } } , new int [ ] { getPressedColor ( ) } ) , background , null ) ; ViewUtil . setBackground ( imageButton , rippleDrawable ) ; } else { ViewUtil . setBackground ( imageButton , background ) ; } }

Adapts the background of the image button, which is used to show the floating image button's
background and icon, depending on the floating button's colors.

Adapts the background of the image button which is used to show the floating image button s background and icon depending on the floating button s colors .


private Drawable createStateListBackgroundDrawable() {
        StateListDrawable drawable = new StateListDrawable();

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            drawable.addState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed},
                    createPressedBackgroundDrawable());
        }

        drawable.addState(new int[]{android.R.attr.state_enabled, android.R.attr.state_activated},
                createActivatedBackgroundDrawable());
        drawable.addState(new int[]{android.R.attr.state_enabled},
                createBackgroundDrawable(getColor()));
        drawable.addState(new int[]{}, createDisabledBackgroundDrawable());
        return drawable;
    }

private Drawable createStateListBackgroundDrawable ( ) { StateListDrawable drawable = new StateListDrawable ( ) ; if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . LOLLIPOP ) { drawable . addState ( new int [ ] { android . R . attr . state_enabled , android . R . attr . state_pressed } , createPressedBackgroundDrawable ( ) ) ; } drawable . addState ( new int [ ] { android . R . attr . state_enabled , android . R . attr . state_activated } , createActivatedBackgroundDrawable ( ) ) ; drawable . addState ( new int [ ] { android . R . attr . state_enabled } , createBackgroundDrawable ( getColor ( ) ) ) ; drawable . addState ( new int [ ] { } , createDisabledBackgroundDrawable ( ) ) ; return drawable ; }

Creates and returns a state list drawable, which can be used as the floating action button
background and adapts the background color depending on the button's current state.

@return The drawable, which has been created, as an instance of the class {@link Drawable}

Creates and returns a state list drawable which can be used as the floating action button background and adapts the background color depending on the button s current state .


private Drawable createActivatedBackgroundDrawable() {
        Drawable drawable = createBackgroundDrawable(getColor());
        Drawable hoverDrawable = createBackgroundDrawable(getActivatedColor());
        return new LayerDrawable(new Drawable[]{drawable, hoverDrawable});
    }

private Drawable createActivatedBackgroundDrawable ( ) { Drawable drawable = createBackgroundDrawable ( getColor ( ) ) ; Drawable hoverDrawable = createBackgroundDrawable ( getActivatedColor ( ) ) ; return new LayerDrawable ( new Drawable [ ] { drawable , hoverDrawable } ) ; }

Creates and returns a drawable, which can be used as the floating action button's background,
when it is activated.

@return The drawable, which has been created, as an instance of the class {@link Drawable}

Creates and returns a drawable which can be used as the floating action button s background when it is activated .


private Drawable createPressedBackgroundDrawable() {
        Drawable drawable = createBackgroundDrawable(getColor());
        Drawable hoverDrawable = createBackgroundDrawable(getPressedColor());
        return new LayerDrawable(new Drawable[]{drawable, hoverDrawable});
    }

private Drawable createPressedBackgroundDrawable ( ) { Drawable drawable = createBackgroundDrawable ( getColor ( ) ) ; Drawable hoverDrawable = createBackgroundDrawable ( getPressedColor ( ) ) ; return new LayerDrawable ( new Drawable [ ] { drawable , hoverDrawable } ) ; }

Creates and returns a drawable, which can be used as the floating action button's background,
when it is pressed.

@return The drawable, which has been created, as an instance of the class {@link Drawable}

Creates and returns a drawable which can be used as the floating action button s background when it is pressed .


private Drawable createDisabledBackgroundDrawable() {
        Drawable drawable = createBackgroundDrawable(getColor());
        Drawable hoverDrawable = createBackgroundDrawable(getDisabledColor());
        return new LayerDrawable(new Drawable[]{drawable, hoverDrawable});
    }

private Drawable createDisabledBackgroundDrawable ( ) { Drawable drawable = createBackgroundDrawable ( getColor ( ) ) ; Drawable hoverDrawable = createBackgroundDrawable ( getDisabledColor ( ) ) ; return new LayerDrawable ( new Drawable [ ] { drawable , hoverDrawable } ) ; }

Creates and returns a drawable, which can be used as the floating action button's background,
when it is disabled.

@return The drawable, which has been created, as an instance of the class {@link Drawable}

Creates and returns a drawable which can be used as the floating action button s background when it is disabled .


private Drawable createBackgroundDrawable(@ColorInt final int color) {
        OvalShape shape = new OvalShape();
        ShapeDrawable drawable = new ShapeDrawable(shape);
        drawable.getPaint().setColor(color);
        return drawable;
    }

private Drawable createBackgroundDrawable ( @ ColorInt final int color ) { OvalShape shape = new OvalShape ( ) ; ShapeDrawable drawable = new ShapeDrawable ( shape ) ; drawable . getPaint ( ) . setColor ( color ) ; return drawable ; }

Creates and returns a drawable with a specific color, which can be used as the floating
action button's background.

@param color
The color of the background as an {@link Integer} value
@return The drawable, which has been created, as an instance of the class {@link Drawable}

Creates and returns a drawable with a specific color which can be used as the floating action button s background .


private int getPixelSize() {
        if (getSize() == Size.NORMAL) {
            return getResources().getDimensionPixelSize(R.dimen.floating_action_button_size_normal);
        } else if (getSize() == Size.SMALL) {
            return getResources().getDimensionPixelSize(R.dimen.floating_action_button_size_small);
        } else {
            return getResources().getDimensionPixelSize(R.dimen.floating_action_button_size_large);
        }
    }

private int getPixelSize ( ) { if ( getSize ( ) == Size . NORMAL ) { return getResources ( ) . getDimensionPixelSize ( R . dimen . floating_action_button_size_normal ) ; } else if ( getSize ( ) == Size . SMALL ) { return getResources ( ) . getDimensionPixelSize ( R . dimen . floating_action_button_size_small ) ; } else { return getResources ( ) . getDimensionPixelSize ( R . dimen . floating_action_button_size_large ) ; } }

Returns the size of the floating action button in pixels, depending on its current size.

@return The size of the floating action button in pixels as an {@link Integer} value

Returns the size of the floating action button in pixels depending on its current size .


private void animateVisibility(final int visibility, final long duration) {
        if (visibilityAnimator != null) {
            visibilityAnimator.cancel();
        }

        AnimatorListener listener = createVisibilityAnimatorListener(visibility);
        float targetScale = visibility == View.VISIBLE ? 1 : 0;
        long animationDuration = Math.round(Math.abs(getScaleX() - targetScale) * duration);
        Interpolator interpolator = new AccelerateDecelerateInterpolator();
        visibilityAnimator =
                animate().setInterpolator(interpolator).scaleX(targetScale).scaleY(targetScale)
                        .setDuration(animationDuration).setListener(listener);
    }

private void animateVisibility ( final int visibility , final long duration ) { if ( visibilityAnimator != null ) { visibilityAnimator . cancel ( ) ; } AnimatorListener listener = createVisibilityAnimatorListener ( visibility ) ; float targetScale = visibility == View . VISIBLE ? 1 : 0 ; long animationDuration = Math . round ( Math . abs ( getScaleX ( ) - targetScale ) * duration ) ; Interpolator interpolator = new AccelerateDecelerateInterpolator ( ) ; visibilityAnimator = animate ( ) . setInterpolator ( interpolator ) . scaleX ( targetScale ) . scaleY ( targetScale ) . setDuration ( animationDuration ) . setListener ( listener ) ; }

Animates changing the visibility of the floating action button.

@param visibility
The visibility, which should be set, as an {@link Integer} value. The visibility may
be View.VISIBLE, View.INVISIBLE or View.GONE
@param duration
The duration of the animation in milliseconds as a {@link Long} value

Animates changing the visibility of the floating action button .


private AnimatorListener createVisibilityAnimatorListener(final int visibility) {
        return new AnimatorListener() {

            @Override
            public void onAnimationStart(final Animator animation) {
                if (visibility == View.VISIBLE) {
                    FloatingActionButton.super.setVisibility(visibility);
                }
            }

            @Override
            public void onAnimationRepeat(final Animator animation) {

            }

            @Override
            public void onAnimationEnd(final Animator animation) {
                FloatingActionButton.super.setVisibility(visibility);
                visibilityAnimator = null;
            }

            @Override
            public void onAnimationCancel(final Animator animation) {
                visibilityAnimator = null;
            }

        };
    }

private AnimatorListener createVisibilityAnimatorListener ( final int visibility ) { return new AnimatorListener ( ) { @ Override public void onAnimationStart ( final Animator animation ) { if ( visibility == View . VISIBLE ) { FloatingActionButton . super . setVisibility ( visibility ) ; } } @ Override public void onAnimationRepeat ( final Animator animation ) { } @ Override public void onAnimationEnd ( final Animator animation ) { FloatingActionButton . super . setVisibility ( visibility ) ; visibilityAnimator = null ; } @ Override public void onAnimationCancel ( final Animator animation ) { visibilityAnimator = null ; } } ; }

Creates and returns a listener, which allows to adapt the visibility of the floating action
button, depending on the progress of an animation, which is used to change the visibility.

@param visibility
The visibility, which is set by the observed animation, as an {@link Integer} value.
The visibility may be View.VISIBLE, View.INVISIBLE or
View.GONE
@return The listener, which has been created, as an instance of the type {@link
AnimatorListener}

Creates and returns a listener which allows to adapt the visibility of the floating action button depending on the progress of an animation which is used to change the visibility .


public final void setSize(@NonNull final Size size) {
        Condition.INSTANCE.ensureNotNull(size, "The size may not be null");
        this.size = size;
        adaptShadow();
        adaptImageButtonSize();
        requestLayout();
    }

public
final
void
setSize
(
@
NonNull
final
Size
size
)
{
Condition
.
INSTANCE
.
ensureNotNull
(
size
,
"The size may not be null"
)
;
this
.
size
=
size
;
adaptShadow
(
)
;
adaptImageButtonSize
(
)
;
requestLayout
(
)
;
}

Sets the floating action button's size.

@param size
The size, which should be set, as a value of the enum {@link Size}. The size must
either be NORMAL or SMALL

Sets the floating action button s size .


private void obtainThickness(@NonNull final TypedArray typedArray) {
        int defaultThickness = getContext().getResources()
                .getDimensionPixelSize(R.dimen.circular_progress_bar_thickness_normal);
        thickness = typedArray
                .getDimensionPixelSize(R.styleable.CircularProgressBar_android_thickness,
                        defaultThickness);
    }

private void obtainThickness ( @ NonNull final TypedArray typedArray ) { int defaultThickness = getContext ( ) . getResources ( ) . getDimensionPixelSize ( R . dimen . circular_progress_bar_thickness_normal ) ; thickness = typedArray . getDimensionPixelSize ( R . styleable . CircularProgressBar_android_thickness , defaultThickness ) ; }

Obtains the progress bar's thickness from a specific typed array.

@param typedArray
The typed array, the thickness should be obtained from, as an instance of the class
{@link TypedArray}. The typed array may not be null

Obtains the progress bar s thickness from a specific typed array .


private void initializePaint() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(getThickness());
        paint.setColor(getColor());
    }

private void initializePaint ( ) { paint = new Paint ( ) ; paint . setAntiAlias ( true ) ; paint . setStyle ( Paint . Style . STROKE ) ; paint . setStrokeWidth ( getThickness ( ) ) ; paint . setColor ( getColor ( ) ) ; }

Initializes the paint, which is used for drawing.

Initializes the paint which is used for drawing .


private void initializeAngleAnimator() {
        angleAnimator = ObjectAnimator.ofFloat(this, createAngleProperty(), MAX_DEGREES);
        angleAnimator.setInterpolator(new LinearInterpolator());
        angleAnimator.setDuration(ANGLE_ANIMATION_DURATION);
        angleAnimator.setRepeatMode(ValueAnimator.RESTART);
        angleAnimator.setRepeatCount(ValueAnimator.INFINITE);
    }

private void initializeAngleAnimator ( ) { angleAnimator = ObjectAnimator . ofFloat ( this , createAngleProperty ( ) , MAX_DEGREES ) ; angleAnimator . setInterpolator ( new LinearInterpolator ( ) ) ; angleAnimator . setDuration ( ANGLE_ANIMATION_DURATION ) ; angleAnimator . setRepeatMode ( ValueAnimator . RESTART ) ; angleAnimator . setRepeatCount ( ValueAnimator . INFINITE ) ; }


private Property<CircularProgressDrawable, Float> createAngleProperty() {
        return new Property<CircularProgressDrawable, Float>(Float.class, "angle") {

            @Override
            public Float get(final CircularProgressDrawable object) {
                return currentGlobalAngle;
            }

            @Override
            public void set(final CircularProgressDrawable object, final Float value) {
                currentGlobalAngle = value;
                invalidateSelf();
            }

        };
    }

private Property < CircularProgressDrawable , Float > createAngleProperty ( ) { return new Property < CircularProgressDrawable , Float > ( Float . class , "angle" ) { @ Override public Float get ( final CircularProgressDrawable object ) { return currentGlobalAngle ; } @ Override public void set ( final CircularProgressDrawable object , final Float value ) { currentGlobalAngle = value ; invalidateSelf ( ) ; } } ; }

Creates and returns a property, which allows to animate the global angle of the progress
drawable.

@return The property, which has been created, as an instance of the class {@link Property}

Creates and returns a property which allows to animate the global angle of the progress drawable .


private void initializeSweepAnimator() {
        sweepAnimator = ObjectAnimator
                .ofFloat(this, createSweepProperty(), MAX_DEGREES - MIN_SWEEP_ANGLE * 2);
        sweepAnimator.setInterpolator(new DecelerateInterpolator());
        sweepAnimator.setDuration(SWEEP_ANIMATION_DURATION);
        sweepAnimator.setRepeatMode(ValueAnimator.RESTART);
        sweepAnimator.setRepeatCount(ValueAnimator.INFINITE);
        sweepAnimator.addListener(createSweepAnimatorListener());
    }

private void initializeSweepAnimator ( ) { sweepAnimator = ObjectAnimator . ofFloat ( this , createSweepProperty ( ) , MAX_DEGREES - MIN_SWEEP_ANGLE * 2 ) ; sweepAnimator . setInterpolator ( new DecelerateInterpolator ( ) ) ; sweepAnimator . setDuration ( SWEEP_ANIMATION_DURATION ) ; sweepAnimator . setRepeatMode ( ValueAnimator . RESTART ) ; sweepAnimator . setRepeatCount ( ValueAnimator . INFINITE ) ; sweepAnimator . addListener ( createSweepAnimatorListener ( ) ) ; }


private Property<CircularProgressDrawable, Float> createSweepProperty() {
        return new Property<CircularProgressDrawable, Float>(Float.class, "arc") {

            @Override
            public Float get(final CircularProgressDrawable object) {
                return currentSweepAngle;
            }

            @Override
            public void set(final CircularProgressDrawable object, final Float value) {
                currentSweepAngle = value;
                invalidateSelf();
            }

        };
    }

private Property < CircularProgressDrawable , Float > createSweepProperty ( ) { return new Property < CircularProgressDrawable , Float > ( Float . class , "arc" ) { @ Override public Float get ( final CircularProgressDrawable object ) { return currentSweepAngle ; } @ Override public void set ( final CircularProgressDrawable object , final Float value ) { currentSweepAngle = value ; invalidateSelf ( ) ; } } ; }

Creates and returns a property, which allows to animate the sweep angle of the progress
drawable.

@return The property, which has been created, as an instance of the class {@link Property}

Creates and returns a property which allows to animate the sweep angle of the progress drawable .