com.bazaarvoice.dropwizard.caching.CacheControlConfigurationItem.java Source code

Java tutorial

Introduction

Here is the source code for com.bazaarvoice.dropwizard.caching.CacheControlConfigurationItem.java

Source

/*
 * Copyright 2014 Bazaarvoice, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bazaarvoice.dropwizard.caching;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import io.dropwizard.util.Duration;

import javax.ws.rs.core.CacheControl;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

/**
 * Cache control options to apply to an endpoint.
 */
public class CacheControlConfigurationItem {
    private Optional<String> _group = Optional.absent();
    private Optional<Pattern> _groupRegex = Optional.absent();

    private Optional<Duration> _maxAge = Optional.absent();
    private Optional<Duration> _sharedMaxAge = Optional.absent();
    private Set<CacheControlFlag> _flags = ImmutableSet.of();
    private Set<String> _privateFields = ImmutableSet.of();
    private Set<String> _noCacheFields = ImmutableSet.of();
    private Map<String, String> _cacheExtensions = ImmutableMap.of();

    public Optional<Pattern> getGroupRegex() {
        return _groupRegex;
    }

    @JsonProperty
    public void setGroupRegex(Optional<Pattern> groupRegex) {
        checkNotNull(groupRegex);
        checkState(groupRegex.isPresent() || _group.isPresent(),
                "only one of group or groupRegex can be specified");
        _groupRegex = groupRegex;
    }

    public Optional<String> getGroup() {
        return _group;
    }

    @JsonProperty
    public void setGroup(Optional<String> group) {
        checkNotNull(group);
        checkState(group.isPresent() || _group.isPresent(), "only one of group or groupRegex can be specified");
        _group = group;
    }

    public Optional<Duration> getMaxAge() {
        return _maxAge;
    }

    @JsonProperty
    public void setMaxAge(Optional<Duration> maxAge) {
        checkNotNull(maxAge);
        checkArgument(!maxAge.isPresent() || maxAge.get().getQuantity() >= 0, "maxAge must be >= 0");
        _maxAge = maxAge;
    }

    public Optional<Duration> getSharedMaxAge() {
        return _sharedMaxAge;
    }

    @JsonProperty
    public void setSharedMaxAge(Optional<Duration> sharedMaxAge) {
        checkNotNull(sharedMaxAge);
        checkArgument(!sharedMaxAge.isPresent() || sharedMaxAge.get().getQuantity() >= 0,
                "sharedMaxAge must be >= 0");
        _sharedMaxAge = sharedMaxAge;
    }

    public Set<CacheControlFlag> getFlags() {
        return _flags;
    }

    @JsonProperty
    public void setFlags(Set<CacheControlFlag> flags) {
        checkNotNull(flags);
        checkArgument(!flags.contains(null), "flags must not contain null");
        _flags = ImmutableSet.copyOf(flags);
    }

    public Set<String> getPrivateFields() {
        return _privateFields;
    }

    @JsonProperty("private")
    public void setPrivateFields(Set<String> privateFields) {
        checkNotNull(privateFields);
        checkArgument(!privateFields.contains(null), "privateFields must not contain null");
        _privateFields = ImmutableSet.copyOf(privateFields);
    }

    public Set<String> getNoCacheFields() {
        return _noCacheFields;
    }

    @JsonProperty("noCache")
    public void setNoCacheFields(Set<String> noCacheFields) {
        checkNotNull(noCacheFields);
        checkArgument(!noCacheFields.contains(null), "noCacheFields must not contain null");
        _noCacheFields = ImmutableSet.copyOf(noCacheFields);
    }

    public Map<String, String> getCacheExtensions() {
        return _cacheExtensions;
    }

    @JsonProperty("extensions")
    public void setCacheExtensions(Map<String, String> cacheExtensions) {
        checkNotNull(cacheExtensions);
        _cacheExtensions = ImmutableMap.copyOf(cacheExtensions);
    }

    public CacheControl buildCacheControl() {
        CacheControl cacheControl = new CacheControl();
        cacheControl.setNoTransform(false); // Default is true

        if (_maxAge.isPresent()) {
            cacheControl.setMaxAge((int) _maxAge.get().toSeconds());
        }

        if (_sharedMaxAge.isPresent()) {
            cacheControl.setSMaxAge((int) _maxAge.get().toSeconds());
        }

        if (_privateFields.size() > 0) {
            cacheControl.setPrivate(true);
            cacheControl.getPrivateFields().addAll(_privateFields);
        }

        if (_noCacheFields.size() > 0) {
            cacheControl.setNoCache(true);
            cacheControl.getNoCacheFields().addAll(_noCacheFields);
        }

        for (CacheControlFlag flag : _flags) {
            switch (flag) {
            case NO_CACHE:
                cacheControl.setNoCache(true);
                break;

            case NO_STORE:
                cacheControl.setNoStore(true);
                break;

            case MUST_REVALIDATE:
                cacheControl.setMustRevalidate(true);
                break;

            case PROXY_REVALIDATE:
                cacheControl.setProxyRevalidate(true);
                break;

            case NO_TRANSFORM:
                cacheControl.setNoTransform(true);
                break;

            case PRIVATE:
                cacheControl.setPrivate(true);
                break;

            case PUBLIC:
                // public is not directly supported by the CacheControl object, so use extension map
                cacheControl.getCacheExtension().put("public", "");
                break;

            default:
                checkState(false, "Unhandled cache control flag: " + flag);
                break;
            }
        }

        // Although the docs don't state it explicitly, both null and empty string get converted to a bare directive
        // for cache extensions.
        cacheControl.getCacheExtension().putAll(_cacheExtensions);
        return cacheControl;
    }

    public Predicate<String> buildGroupMatcher() {
        Predicate<String> matcher;

        if (_groupRegex.isPresent()) {
            matcher = regexMatcher(_groupRegex.get());
        } else {
            matcher = groupNameMatcher(_group.or("*"));
        }

        return matcher;
    }

    private static Predicate<String> groupNameMatcher(String name) {
        if (name.equals("*")) {
            return Predicates.alwaysTrue();
        }

        return regexMatcher(Pattern.compile("" + "^" + Joiner.on(".*")
                .join(FluentIterable.from(Splitter.on('*').split(name)).transform(new Function<String, Object>() {
                    public Object apply(String input) {
                        return input.length() == 0 ? input : Pattern.quote(input);
                    }
                })) + "$", Pattern.CASE_INSENSITIVE));
    }

    private static Predicate<String> regexMatcher(final Pattern pattern) {
        return new Predicate<String>() {
            public boolean apply(String input) {
                return pattern.matcher(input).find();
            }
        };
    }
}