blob: 26fdaabd23bc52f89d7d74caa440643075954eac [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
//
// 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 adaptorlib;
import java.util.*;
/** Represents a fixed set of validated {@link MetaItem}s. */
public final class Metadata implements Iterable<MetaItem> {
/** Empty convenience instance. */
public static final Metadata EMPTY = new Metadata.Builder().build();
private final Map<String, MetaItem> items;
/**
* Validates that each meta name is unique, there is either
* public-indicator or ACLs and that ACLs values are acceptable.
*/
private Metadata(Map<String, MetaItem> allMeta) {
items = Collections.unmodifiableMap(new TreeMap<String, MetaItem>(allMeta));
checkConsistency(items);
}
@Override
public boolean equals(Object o) {
boolean same = false;
if (null != o && this.getClass().equals(o.getClass())) {
Metadata other = (Metadata) o;
same = items.equals(other.items);
}
return same;
}
@Override
public int hashCode() {
return items.hashCode();
}
@Override
public Iterator<MetaItem> iterator() {
return items.values().iterator();
}
@Override
public String toString() {
return items.values().toString();
}
public Map<String, String> toMap() {
Map<String, String> map = new HashMap<String, String>(items.size() * 2);
for (MetaItem item : this) {
map.put(item.getName(), item.getValue());
}
return map;
}
public boolean isEmpty() {
return size() == 0;
}
public int size() {
return items.size();
}
private static void checkConsistency(Map<String, MetaItem> allMeta) {
checkNandPublicAndAcls(allMeta);
checkBothOrNoneAcls(allMeta);
checkPublicIsBoolean(allMeta);
}
/** Either have public indicator or ACLs, but not both. */
private static void checkNandPublicAndAcls(Map<String, MetaItem> m) {
boolean hasPublicName = m.containsKey("google:ispublic");
boolean hasAcls = m.containsKey("google:aclusers")
|| m.containsKey("google:aclgroups");
if (hasPublicName && hasAcls) {
throw new IllegalArgumentException("has both ispublic and ACLs");
}
}
/** Cannot provide users without groups and vice-versa. */
private static void checkBothOrNoneAcls(Map<String, MetaItem> m) {
boolean hasUserAcls = m.containsKey("google:aclusers");
boolean hasGroupAcls = m.containsKey("google:aclgroups");
if (hasUserAcls && !hasGroupAcls) {
throw new IllegalArgumentException("has users, but not groups");
} else if (hasGroupAcls && !hasUserAcls) {
throw new IllegalArgumentException("has groups, but not users");
} else if (hasGroupAcls && hasUserAcls) {
String userLine = m.get("google:aclusers").getValue().trim();
String groupLine = m.get("google:aclgroups").getValue().trim();
if (userLine.isEmpty() && groupLine.isEmpty()) {
throw new IllegalArgumentException("both users and groups empty");
}
}
}
/** If has public indicator value is acceptable. */
private static void checkPublicIsBoolean(Map<String, MetaItem> m) {
MetaItem item = m.get("google:ispublic");
if (null != item) {
String value = item.getValue();
if (!"true".equals(value) && !"false".equals(value)) {
throw new IllegalArgumentException("ispublic is not true nor false");
}
}
}
/**
* Builder for instances of {@link Metadata}.
*/
public static class Builder {
private Map<String, MetaItem> items = new TreeMap<String, MetaItem>();
/**
* Create new empty builder.
*/
public Builder() {}
/**
* Initialize builder with {@code MetaItems} from {@code iterable}. Useful
* to make tweaked copies of {@link Metadata}.
*/
public Builder(Iterable<MetaItem> iterable) {
for (MetaItem item : iterable) {
items.put(item.getName(), item);
}
}
/**
* Add a new {@code MetaItem} to the builder, replacing any previously-added
* {@code MetaItem} with the same name.
*/
public Builder add(MetaItem item) {
items.put(item.getName(), item);
return this;
}
/**
* Returns a metadata instance that reflects current builder state. It does
* not reset the builder.
*/
public Metadata build() {
return new Metadata(items);
}
}
}