001/* 002 * This file is part of the JDrupes non-blocking HTTP Codec 003 * Copyright (C) 2017 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Lesser General Public License as published 007 * by the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 013 * License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.httpcodec.types; 020 021import java.util.Collection; 022import java.util.HashSet; 023import java.util.Iterator; 024import java.util.LinkedHashMap; 025import java.util.Optional; 026import java.util.Set; 027import java.util.stream.Collectors; 028import java.util.stream.Stream; 029 030import org.jdrupes.httpcodec.util.ListItemizer; 031 032/** 033 * Represents a list of Cache-Control directives. 034 * 035 * @see "[RFC 7234, 5.2](https://tools.ietf.org/html/rfc7234#section-5.2)" 036 */ 037public class CacheControlDirectives implements Iterable<Directive> { 038 039 private LinkedHashMap<String, Directive> directives; 040 041 /** 042 * Creates a new empty cookie list. 043 */ 044 public CacheControlDirectives() { 045 directives = new LinkedHashMap<>(); 046 } 047 048 /** 049 * Creates a new list with items copied from the existing collection. 050 * 051 * @param existing the existing collection 052 */ 053 public CacheControlDirectives(Collection<Directive> existing) { 054 directives = new LinkedHashMap<>(); 055 for (Directive directive: existing) { 056 directives.put(directive.name(), directive); 057 } 058 } 059 060 /** 061 * Returns the value for the directive with the given name. 062 * 063 * @param name the name 064 * @return the value if a directive with the given name exists 065 */ 066 public Optional<String> valueForName(String name) { 067 return Optional.ofNullable(directives.get(name.toLowerCase())) 068 .flatMap(Directive::value); 069 } 070 071 /** 072 * Adds a directive to the list. If a directive with the same name 073 * already exists, it is replaced (except for `no-cache`). 074 * 075 * The `no-cache` directive is handled specially. If no such directive 076 * exists, it is added. Else, if the new directive has no 077 * arguments, it replaces the existing `no-cache` directive. If both 078 * the existing directive and the new directive specify fields, 079 * the fields are merged. 080 * 081 * @param directive the directive 082 * @return the directives for easy chaining 083 */ 084 public CacheControlDirectives add(Directive directive) { 085 if ("no-cache".equals(directive.name())) { 086 Directive existing = directives.get(directive.name()); 087 if (existing != null) { 088 if (!existing.value().isPresent()) { 089 return this; 090 } 091 if (directive.value().isPresent()) { 092 Set<String> values = new HashSet<>(); 093 new ListItemizer(existing.value().get(), ",") 094 .forEachRemaining(values::add); 095 new ListItemizer(directive.value().get(), ",") 096 .forEachRemaining(values::add); 097 directives.put(directive.name(), 098 new Directive(directive.name(), values.stream() 099 .collect(Collectors.joining(", ")))); 100 return this; 101 } 102 } 103 } 104 directives.remove(directive.name()); 105 directives.put(directive.name(), directive); 106 return this; 107 } 108 109 /** 110 * Removes all directives from the list. 111 * 112 * @return the directives for easy chaining 113 */ 114 public CacheControlDirectives clear() { 115 directives.clear(); 116 return this; 117 } 118 119 public boolean isEmpty() { 120 return directives.isEmpty(); 121 } 122 123 /* (non-Javadoc) 124 * @see java.util.List#iterator() 125 */ 126 @Override 127 public Iterator<Directive> iterator() { 128 return directives.values().iterator(); 129 } 130 131 public Stream<Directive> stream() { 132 return directives.values().stream(); 133 } 134 135 /** 136 * Remove the directive with the given name. 137 * 138 * @param name 139 * @return the directives for easy chaining 140 */ 141 public boolean remove(String name) { 142 return false; 143 } 144 145 public int size() { 146 return directives.size(); 147 } 148 149}