Return-Path: X-Original-To: apmail-brooklyn-commits-archive@minotaur.apache.org Delivered-To: apmail-brooklyn-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 7741F10016 for ; Tue, 18 Aug 2015 15:04:05 +0000 (UTC) Received: (qmail 80966 invoked by uid 500); 18 Aug 2015 15:03:43 -0000 Delivered-To: apmail-brooklyn-commits-archive@brooklyn.apache.org Received: (qmail 80943 invoked by uid 500); 18 Aug 2015 15:03:43 -0000 Mailing-List: contact commits-help@brooklyn.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.incubator.apache.org Delivered-To: mailing list commits@brooklyn.incubator.apache.org Received: (qmail 80934 invoked by uid 99); 18 Aug 2015 15:03:43 -0000 Received: from Unknown (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Aug 2015 15:03:43 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id B4F1ADED1D for ; Tue, 18 Aug 2015 15:03:42 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 1.4 X-Spam-Level: * X-Spam-Status: No, score=1.4 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.381, URIBL_BLOCKED=0.001] autolearn=disabled Received: from mx1-eu-west.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id 21_K9H4ew1tJ for ; Tue, 18 Aug 2015 15:03:35 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-eu-west.apache.org (ASF Mail Server at mx1-eu-west.apache.org) with SMTP id 60EDF25410 for ; Tue, 18 Aug 2015 15:03:13 +0000 (UTC) Received: (qmail 78445 invoked by uid 99); 18 Aug 2015 15:03:11 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Aug 2015 15:03:11 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 26EFEE0419; Tue, 18 Aug 2015 15:03:11 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: hadrian@apache.org To: commits@brooklyn.incubator.apache.org Date: Tue, 18 Aug 2015 15:03:26 -0000 Message-Id: <4ec657023d494e31a21df783659341c2@git.apache.org> In-Reply-To: <8a1c4e07828a430c8c0497ef97ea3865@git.apache.org> References: <8a1c4e07828a430c8c0497ef97ea3865@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [17/64] [abbrv] incubator-brooklyn git commit: BROOKLYN-162 - apply org.apache package prefix to utils-common http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableList.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableList.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableList.java new file mode 100644 index 0000000..4f8206a --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableList.java @@ -0,0 +1,251 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.collections; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableList; + +public class MutableList extends ArrayList { + private static final long serialVersionUID = -5533940507175152491L; + + private static final Logger log = LoggerFactory.getLogger(MutableList.class); + + public static MutableList of() { + return new MutableList(); + } + + public static MutableList of(V v1) { + MutableList result = new MutableList(); + result.add(v1); + return result; + } + + public static MutableList of(V v1, V v2, V ...vv) { + MutableList result = new MutableList(); + result.add(v1); + result.add(v2); + for (V v: vv) result.add(v); + return result; + } + + public static MutableList copyOf(@Nullable Iterable orig) { + return (orig instanceof Collection) + ? new MutableList((Collection)orig) + : orig!=null ? new MutableList(orig) : new MutableList(); + } + + public static MutableList copyOf(Iterator elements) { + if (!elements.hasNext()) { + return of(); + } + return new MutableList.Builder().addAll(elements).build(); + } + + public MutableList() { + } + + public MutableList(Collection source) { + super(source); + } + + public MutableList(Iterable source) { + for (V s : source) { + add(s); + } + } + + /** @deprecated since 0.7.0, use {@link #asImmutableCopy()}, or {@link #asUnmodifiable()} / {@link #asUnmodifiableCopy()} */ @Deprecated + public ImmutableList toImmutable() { + return ImmutableList.copyOf(this); + } + /** creates an {@link ImmutableList} which is a copy of this list. note that the list should not contain nulls. */ + public List asImmutableCopy() { + try { + return ImmutableList.copyOf(this); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + log.warn("Error converting list to Immutable, using unmodifiable instead: "+e, e); + return asUnmodifiableCopy(); + } + } + /** creates a {@link Collections#unmodifiableList(List)} wrapper around this list. the method is efficient, + * as there is no copying, but the returned view might change if the list here is changed. */ + public List asUnmodifiable() { + return Collections.unmodifiableList(this); + } + /** creates a {@link Collections#unmodifiableList(List)} of a copy of this list. + * the returned item is immutable, but unlike {@link #asImmutableCopy()} nulls are permitted. */ + public List asUnmodifiableCopy() { + return Collections.unmodifiableList(MutableList.copyOf(this)); + } + + public static Builder builder() { + return new Builder(); + } + + /** + * @see guava's ImMutableList.Builder + */ + public static class Builder { + final MutableList result = new MutableList(); + + public Builder() {} + + public Builder add(V value) { + result.add(value); + return this; + } + + public Builder add(V value1, V value2, V ...values) { + result.add(value1); + result.add(value2); + for (V v: values) result.add(v); + return this; + } + + public Builder remove(V val) { + result.remove(val); + return this; + } + + public Builder addAll(Iterable iterable) { + if (iterable instanceof Collection) { + result.addAll((Collection) iterable); + } else { + for (V v : iterable) { + result.add(v); + } + } + return this; + } + + public Builder addAll(Iterator iter) { + while (iter.hasNext()) { + add(iter.next()); + } + return this; + } + + public Builder addAll(V[] vals) { + for (V v : vals) { + result.add(v); + } + return this; + } + + public Builder removeAll(Iterable iterable) { + if (iterable instanceof Collection) { + result.removeAll((Collection) iterable); + } else { + for (V v : iterable) { + result.remove(v); + } + } + return this; + } + + public MutableList build() { + return new MutableList(result); + } + + public ImmutableList buildImmutable() { + return ImmutableList.copyOf(result); + } + + public Builder addLists(Iterable ...items) { + for (Iterable item: items) { + addAll(item); + } + return this; + } + } + + /** as {@link List#add(Object)} but fluent style */ + public MutableList append(V item) { + add(item); + return this; + } + + /** as {@link List#add(Object)} but excluding nulls, and fluent style */ + public MutableList appendIfNotNull(V item) { + if (item!=null) add(item); + return this; + } + + /** as {@link List#add(Object)} but accepting multiple, and fluent style */ + public MutableList append(V item1, V item2, V ...items) { + add(item1); + add(item2); + for (V item: items) add(item); + return this; + } + + /** as {@link List#add(Object)} but excluding nulls, accepting multiple, and fluent style */ + public MutableList appendIfNotNull(V item1, V item2, V ...items) { + if (item1!=null) add(item1); + if (item2!=null) add(item2); + for (V item: items) + if (item!=null) add(item); + return this; + } + + /** as {@link List#addAll(Collection)} but fluent style */ + public MutableList appendAll(Iterable items) { + if (items!=null) + for (V item: items) add(item); + return this; + } + /** as {@link List#addAll(Collection)} but fluent style */ + public MutableList appendAll(Iterator items) { + addAll(items); + return this; + } + + public boolean addAll(Iterable setToAdd) { + // copy of parent, but accepting Iterable and null + if (setToAdd==null) return false; + return addAll(setToAdd.iterator()); + } + public boolean addAll(Iterator setToAdd) { + if (setToAdd==null) return false; + boolean modified = false; + while (setToAdd.hasNext()) { + if (add(setToAdd.next())) + modified = true; + } + return modified; + } + + public boolean removeIfNotNull(V item) { + if (item==null) return false; + return remove(item); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableMap.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableMap.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableMap.java new file mode 100644 index 0000000..8ca2652 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableMap.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.collections; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; + +/** Map impl, exposing simple builder operations (add) in a fluent-style API, + * where the final map is mutable. You can also toImmutable. */ +public class MutableMap extends LinkedHashMap { + + private static final long serialVersionUID = -2463168443382874384L; + private static final Logger log = LoggerFactory.getLogger(MutableMap.class); + + public static MutableMap of() { + return new MutableMap(); + } + + public static MutableMap of(K k1, V v1) { + MutableMap result = new MutableMap(); + result.put(k1, v1); + return result; + } + + public static MutableMap of(K k1, V v1, K k2, V v2) { + MutableMap result = new MutableMap(); + result.put(k1, v1); + result.put(k2, v2); + return result; + } + + public static MutableMap of(K k1, V v1, K k2, V v2, K k3, V v3) { + MutableMap result = new MutableMap(); + result.put(k1, v1); + result.put(k2, v2); + result.put(k3, v3); + return result; + } + + public static MutableMap of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4) { + MutableMap result = new MutableMap(); + result.put(k1, v1); + result.put(k2, v2); + result.put(k3, v3); + result.put(k4, v4); + return result; + } + + public static MutableMap of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4,K k5, V v5) { + MutableMap result = new MutableMap(); + result.put(k1, v1); + result.put(k2, v2); + result.put(k3, v3); + result.put(k4, v4); + result.put(k5, v5); + return result; + } + + public static MutableMap of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4,K k5, V v5,K k6,V v6) { + MutableMap result = new MutableMap(); + result.put(k1, v1); + result.put(k2, v2); + result.put(k3, v3); + result.put(k4, v4); + result.put(k5, v5); + result.put(k6, v6); + return result; + } + + public static MutableMap of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4,K k5, V v5,K k6,V v6,K k7,V v7) { + MutableMap result = new MutableMap(); + result.put(k1, v1); + result.put(k2, v2); + result.put(k3, v3); + result.put(k4, v4); + result.put(k5, v5); + result.put(k6, v6); + result.put(k7, v7); + return result; + } + + public static MutableMap copyOf(@Nullable Map orig) { + MutableMap result = new MutableMap(); + if (orig!=null) + result.putAll(orig); + return result; + } + + public MutableMap() {} + @SuppressWarnings("unchecked") + public MutableMap(@SuppressWarnings("rawtypes") Map source) { super(source); } + + /** as {@link #put(Object, Object)} but fluent style */ + public MutableMap add(K key, V value) { + put(key, value); + return this; + } + + /** as {@link #putAll(Map)} but fluent style (and accepting null, ignoring it) */ + public MutableMap add(@Nullable Map m) { + if (m!=null) putAll(m); + return this; + } + + /** as {@link #put(Object, Object)} but excluding null values, and fluent style */ + public MutableMap addIfNotNull(K key, V value) { + if (value!=null) add(key, value); + return this; + } + + public Maybe getMaybe(K key) { + if (containsKey(key)) return Maybe.of(get(key)); + return Maybe.absent("No entry for key '"+key+"' in this map"); + } + + /** @deprecated since 0.7.0, use {@link #asImmutableCopy()}, or {@link #asUnmodifiable()} / {@link #asUnmodifiableCopy()} */ @Deprecated + public ImmutableMap toImmutable() { + return ImmutableMap.copyOf(this); + } + /** as {@link MutableList#asImmutableCopy()} */ + public Map asImmutableCopy() { + try { + return ImmutableMap.copyOf(this); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + log.warn("Error converting list to Immutable, using unmodifiable instead: "+e, e); + return asUnmodifiableCopy(); + } + } + /** as {@link MutableList#asUnmodifiable()} */ + public Map asUnmodifiable() { + return Collections.unmodifiableMap(this); + } + /** as {@link MutableList#asUnmodifiableCopy()} */ + public Map asUnmodifiableCopy() { + return Collections.unmodifiableMap(MutableMap.copyOf(this)); + } + + public static Builder builder() { + return new Builder(); + } + + /** + * @see guava's ImmutableMap.Builder + */ + public static class Builder { + final MutableMap result = new MutableMap(); + + public Builder() {} + + public Builder put(K key, V value) { + result.put(key, value); + return this; + } + + public Builder putIfNotNull(K key, V value) { + if (value!=null) result.put(key, value); + return this; + } + + public Builder putIfAbsent(K key, V value) { + if (!result.containsKey(key)) result.put(key, value); + return this; + } + + public Builder put(Entry entry) { + result.put(entry.getKey(), entry.getValue()); + return this; + } + + public Builder putAll(Map map) { + result.add(map); + return this; + } + + public Builder remove(K key) { + result.remove(key); + return this; + } + + public Builder removeAll(K... keys) { + for (K key : keys) { + result.remove(key); + } + return this; + } + + public Builder removeAll(Iterable keys) { + for (K key : keys) { + result.remove(key); + } + return this; + } + + /** moves the value stored under oldKey to newKey, if there was such a value */ + public Builder renameKey(K oldKey, K newKey) { + if (result.containsKey(oldKey)) { + V oldValue = result.remove(oldKey); + result.put(newKey, oldValue); + } + return this; + } + + public MutableMap build() { + return new MutableMap(result); + } + + public Builder filterValues(Predicate filter) { + for (Iterator iter = result.values().iterator(); iter.hasNext();) { + V val = iter.next(); + if (!filter.apply(val)) iter.remove(); + } + return this; + } + + public Builder filterKeys(Predicate filter) { + for (Iterator iter = result.keySet().iterator(); iter.hasNext();) { + K key = iter.next(); + if (!filter.apply(key)) iter.remove(); + } + return this; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java new file mode 100644 index 0000000..f851305 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.collections; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +public class MutableSet extends LinkedHashSet { + + private static final long serialVersionUID = 2330133488446834595L; + private static final Logger log = LoggerFactory.getLogger(MutableSet.class); + + public static MutableSet of() { + return new MutableSet(); + } + + public static MutableSet of(V v1) { + MutableSet result = new MutableSet(); + result.add(v1); + return result; + } + + public static MutableSet of(V v1, V v2) { + MutableSet result = new MutableSet(); + result.add(v1); + result.add(v2); + return result; + } + + public static MutableSet of(V v1, V v2, V v3, V ...vMore) { + MutableSet result = new MutableSet(); + result.add(v1); + result.add(v2); + result.add(v3); + for (V vi: vMore) result.add(vi); + return result; + } + + public static MutableSet copyOf(@Nullable Iterable orig) { + return orig==null ? new MutableSet() : new MutableSet(orig); + } + + public static MutableSet copyOf(@Nullable Iterator elements) { + if (elements == null || !elements.hasNext()) { + return of(); + } + return new MutableSet.Builder().addAll(elements).build(); + } + + public MutableSet() { + } + + public MutableSet(Iterable source) { + super((source instanceof Collection) ? (Collection)source : Sets.newLinkedHashSet(source)); + } + + /** @deprecated since 0.7.0, use {@link #asImmutableCopy()}, or {@link #asUnmodifiable()} / {@link #asUnmodifiableCopy()} */ @Deprecated + public Set toImmutable() { + // Don't use ImmutableSet as that does not accept nulls + return Collections.unmodifiableSet(Sets.newLinkedHashSet(this)); + } + /** as {@link MutableList#asImmutableCopy()()} */ + public Set asImmutableCopy() { + try { + return ImmutableSet.copyOf(this); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + log.warn("Error converting list to Immutable, using unmodifiable instead: "+e, e); + return asUnmodifiableCopy(); + } + } + /** as {@link MutableList#asUnmodifiable()} */ + public Set asUnmodifiable() { + return Collections.unmodifiableSet(this); + } + /** as {@link MutableList#asUnmodifiableCopy()} */ + public Set asUnmodifiableCopy() { + return Collections.unmodifiableSet(MutableSet.copyOf(this)); + } + + public static Builder builder() { + return new Builder(); + } + + /** + * @see guava's ImmutableSet.Builder + */ + public static class Builder { + final MutableSet result = new MutableSet(); + + public Builder() {} + + public Builder add(V value) { + result.add(value); + return this; + } + + public Builder add(V v1, V v2, V ...values) { + result.add(v1); + result.add(v2); + for (V value: values) result.add(value); + return this; + } + + public Builder remove(V val) { + result.remove(val); + return this; + } + + public Builder addAll(V[] values) { + for (V v : values) { + result.add(v); + } + return this; + } + public Builder addAll(Iterable iterable) { + if (iterable instanceof Collection) { + result.addAll((Collection) iterable); + } else { + for (V v : iterable) { + result.add(v); + } + } + return this; + } + + public Builder addAll(Iterator iter) { + while (iter.hasNext()) { + add(iter.next()); + } + return this; + } + + public Builder removeAll(Iterable iterable) { + if (iterable instanceof Collection) { + result.removeAll((Collection) iterable); + } else { + for (V v : iterable) { + result.remove(v); + } + } + return this; + } + + public MutableSet build() { + return new MutableSet(result); + } + + } + + public boolean addIfNotNull(V e) { + if (e!=null) return add(e); + return false; + } + + public boolean addAll(Iterable setToAdd) { + // copy of parent, but accepting Iterable and null + if (setToAdd==null) return false; + boolean modified = false; + Iterator e = setToAdd.iterator(); + while (e.hasNext()) { + if (add(e.next())) + modified = true; + } + return modified; + } + + /** as {@link #addAll(Collection)} but fluent style and permitting null */ + public MutableSet putAll(Iterable setToAdd) { + if (setToAdd!=null) addAll(setToAdd); + return this; + } + + public boolean removeIfNotNull(V item) { + if (item==null) return false; + return remove(item); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/collections/QuorumCheck.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/QuorumCheck.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/QuorumCheck.java new file mode 100644 index 0000000..44b5fa2 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/QuorumCheck.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.collections; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; + +import org.apache.brooklyn.util.yaml.Yamls; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; + +/** + * For checking if a group/cluster is quorate. That is, whether the group has sufficient + * healthy members. + */ +public interface QuorumCheck { + + /** + * @param sizeHealthy Number of healthy members + * @param totalSize Total number of members one would expect to be healthy (i.e. ignoring stopped members) + * @return Whether this group is healthy + */ + public boolean isQuorate(int sizeHealthy, int totalSize); + + public static class QuorumChecks { + /** + * Checks that all members that should be up are up (i.e. ignores stopped nodes). + */ + public static QuorumCheck all() { + return new NumericQuorumCheck(0, 1.0, false, "all"); + } + /** + * Checks all members that should be up are up, and that there is at least one such member. + */ + public static QuorumCheck allAndAtLeastOne() { + return new NumericQuorumCheck(1, 1.0, false, "allAndAtLeastOne"); + } + /** + * Requires at least one member that should be up is up. + */ + public static QuorumCheck atLeastOne() { + return new NumericQuorumCheck(1, 0.0, false, "atLeastOne"); + } + /** + * Requires at least one member to be up if the total size is non-zero. + * i.e. okay if empty, or if non-empty and something is healthy, but not okay if not-empty and nothing is healthy. + * "Empty" means that no members are supposed to be up (e.g. there may be stopped members). + */ + public static QuorumCheck atLeastOneUnlessEmpty() { + return new NumericQuorumCheck(1, 0.0, true, "atLeastOneUnlessEmpty"); + } + /** + * Always "healthy" + */ + public static QuorumCheck alwaysTrue() { + return new NumericQuorumCheck(0, 0.0, true, "alwaysHealthy"); + } + + public static QuorumCheck newInstance(int minRequiredSize, double minRequiredRatio, boolean allowEmpty) { + return new NumericQuorumCheck(minRequiredSize, minRequiredRatio, allowEmpty); + } + + /** See {@link QuorumChecks#newLinearRange(String,String)} */ + public static QuorumCheck newLinearRange(String range) { + return newLinearRange(range, null); + } + + /** Given a JSON representation of a list of points (where a point is a list of 2 numbers), + * with the points in increasing x-coordinate value, + * this constructs a quorum check which does linear interpolation on those coordinates, + * with extensions to either side. + * The x-coordinate is taken as the total size, and the y-coordinate as the minimum required size. + *

+ * It sounds complicated but it gives a very easy and powerful way to define quorum checks. + * For instance: + *

+ * [[0,0],[1,1]] says that if 0 items are expected, at least 0 is required; + * if 1 is expected, 1 is required; and by extension if 10 are expected, 10 are required. + * In other words, this is the same as {@link #all()}. + *

+ * [[0,1],[1,1],[2,2]] is the same as the previous for x (number expected) greater-than or equal to 1; + * but if 0 is expected, 1 is required, and so it fails when 0 are present. + * In other words, {@link #allAndAtLeastOne()}. + *

+ * [[5,5],[10,10],[100,70],[200,140]] has {@link #all()} behavior up to 10 expected + * (line extended to the left, for less than 5); but then gently tapers off to requiring only 70% at 100 + * (with 30 of 40 = 75% required at that intermediate point along the line [[10,10],[100,70]]); + * and then from 100 onwards it is a straight 70%. + *

+ * The type of linear regression described in the last example is quite useful in practise, + * to be stricter for smaller clusters (or possibly more lax for small values in some cases, + * such as when tolerating dangling references during rebind). + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static QuorumCheck newLinearRange(String range, String name) { + return LinearRangeQuorumCheck.of(name, (Iterable)Iterables.getOnlyElement( Yamls.parseAll(range) )); + } + + private static final List NAMED_CHECKS = MutableList + .of(all(), allAndAtLeastOne(), atLeastOne(), atLeastOneUnlessEmpty(), alwaysTrue()); + + public static QuorumCheck of(String nameOrRange) { + if (nameOrRange==null) return null; + for (QuorumCheck qc: NAMED_CHECKS) { + if (qc instanceof NumericQuorumCheck) { + if (Objects.equal(nameOrRange, ((NumericQuorumCheck)qc).getName())) + return qc; + } + } + return newLinearRange(nameOrRange); + } + } + + public static class NumericQuorumCheck implements QuorumCheck, Serializable { + private static final long serialVersionUID = -5090669237460159621L; + + protected final int minRequiredSize; + protected final double minRequiredRatio; + protected final boolean allowEmpty; + protected final String name; + + public NumericQuorumCheck(int minRequiredSize, double minRequiredRatio, boolean allowEmpty) { + this(minRequiredSize, minRequiredRatio, allowEmpty, null); + } + public NumericQuorumCheck(int minRequiredSize, double minRequiredRatio, boolean allowEmpty, String name) { + this.minRequiredSize = minRequiredSize; + this.minRequiredRatio = minRequiredRatio; + this.allowEmpty = allowEmpty; + this.name = name; + } + + @Override + public boolean isQuorate(int sizeHealthy, int totalSize) { + if (allowEmpty && totalSize==0) return true; + if (sizeHealthy < minRequiredSize) return false; + if (sizeHealthy < totalSize*minRequiredRatio-0.000000001) return false; + return true; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "QuorumCheck["+(name!=null?name+";":"")+"require="+minRequiredSize+","+((int)100*minRequiredRatio)+"%"+(allowEmpty ? "|0" : "")+"]"; + } + } + + /** See {@link QuorumChecks#newLinearRange(String,String)} */ + public static class LinearRangeQuorumCheck implements QuorumCheck, Serializable { + + private static final long serialVersionUID = -6425548115925898645L; + + private static class Point { + final double size, minRequiredAtSize; + public Point(double size, double minRequiredAtSize) { this.size = size; this.minRequiredAtSize = minRequiredAtSize; } + public static Point ofIntegerCoords(Iterable coords) { + Preconditions.checkNotNull(coords==null, "coords"); + Preconditions.checkArgument(Iterables.size(coords)==2, "A point must consist of two coordinates; invalid data: "+coords); + Iterator ci = coords.iterator(); + return new Point(ci.next(), ci.next()); + } + public static List listOfIntegerCoords(Iterable> points) { + MutableList result = MutableList.of(); + for (Iterable point: points) result.add(ofIntegerCoords(point)); + return result.asUnmodifiable(); + } + @Override + public String toString() { + return "("+size+","+minRequiredAtSize+")"; + } + } + + protected final String name; + protected final List points; + + public static LinearRangeQuorumCheck of(String name, Iterable> points) { + return new LinearRangeQuorumCheck(name, Point.listOfIntegerCoords(points)); + } + public static LinearRangeQuorumCheck of(Iterable> points) { + return new LinearRangeQuorumCheck(null, Point.listOfIntegerCoords(points)); + } + + protected LinearRangeQuorumCheck(String name, Iterable points) { + Preconditions.checkArgument(Iterables.size(points)>=2, "At least two points must be supplied for "+name+": "+points); + this.name = name; + this.points = MutableList.copyOf(points).asUnmodifiable(); + // check valid + Point last = null; + for (Point p: points) { + if (last!=null) { + if (p.size <= last.size) throw new IllegalStateException("Points must be supplied in order of increasing totalSize (x coordinate); instead have "+last+" and "+p); + } + } + } + + @Override + public boolean isQuorate(int sizeHealthy, int totalSize) { + Point next = points.get(0); + Point prev = null; + for (int i=1; itotalSize) break; + } + double minRequiredAtSize = (totalSize-prev.size)/(next.size-prev.size) * (next.minRequiredAtSize-prev.minRequiredAtSize) + prev.minRequiredAtSize; + return (sizeHealthy > minRequiredAtSize-0.000000001); + } + + @Override + public String toString() { + return "LinearRangeQuorumCheck["+(name!=null ? name+":" : "")+points+"]"; + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/collections/SetFromLiveMap.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/SetFromLiveMap.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/SetFromLiveMap.java new file mode 100644 index 0000000..085e31d --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/SetFromLiveMap.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.collections; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; + +import com.google.common.annotations.GwtIncompatible; +import com.google.common.collect.Sets; + +/** + * Creates a Set backed by a given map (using the map's {@link Map#keySet()} for the contents of the set). + *

+ * As {@link Collections#newSetFromMap(Map)} and guava's {@link Sets#newSetFromMap(Map)}, but accepts + * a non-empty map. Also supports others modifying the backing map simultaneously, if the backing map + * is a ConcurrentMap. + */ +public class SetFromLiveMap extends AbstractSet implements Set, Serializable { + + public static Set create(Map map) { + return new SetFromLiveMap(map); + } + + private final Map m; // The backing map + private transient Set s; // Its keySet + + SetFromLiveMap(Map map) { + m = map; + s = map.keySet(); + } + + @Override + public void clear() { + m.clear(); + } + + @Override + public int size() { + return m.size(); + } + + @Override + public boolean isEmpty() { + return m.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return m.containsKey(o); + } + + @Override + public boolean remove(Object o) { + return m.remove(o) != null; + } + + @Override + public boolean add(E e) { + return m.put(e, Boolean.TRUE) == null; + } + + @Override + public Iterator iterator() { + return s.iterator(); + } + + @Override + public Object[] toArray() { + return s.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return s.toArray(a); + } + + @Override + public String toString() { + return s.toString(); + } + + @Override + public int hashCode() { + return s.hashCode(); + } + + @Override + public boolean equals(@Nullable Object object) { + return this == object || this.s.equals(object); + } + + @Override + public boolean containsAll(Collection c) { + return s.containsAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return s.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return s.retainAll(c); + } + + // addAll is the only inherited implementation + @GwtIncompatible("not needed in emulated source") + private static final long serialVersionUID = 0; + + @GwtIncompatible("java.io.ObjectInputStream") + private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + s = m.keySet(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimeWindowedList.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimeWindowedList.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimeWindowedList.java new file mode 100644 index 0000000..570c2ed --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimeWindowedList.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.collections; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.brooklyn.util.time.Duration; + +import com.google.common.collect.ImmutableList; + +/** + * Keeps a list of timestamped values that are in the given time-period (millis). + * It also guarantees to keep the given minimum number of values in the list (even if old), + * and to keep the given number of out-of-date values. + * + * For example, this is useful if we want to determine if a metric has been consistently high. + * + * @author aled + */ +public class TimeWindowedList { + private final LinkedList> values = new LinkedList>(); + private volatile Duration timePeriod; + private final int minVals; + private final int minExpiredVals; + + public TimeWindowedList(Duration timePeriod) { + this.timePeriod = timePeriod; + minVals = 0; + minExpiredVals = 0; + } + + /** + * @deprecated since 0.7.0; use {@link #TimeWindowedList(Duration)} + */ + public TimeWindowedList(long timePeriod) { + this(Duration.millis(timePeriod)); + } + + public TimeWindowedList(Map flags) { + if (!flags.containsKey("timePeriod")) throw new IllegalArgumentException("Must define timePeriod"); + timePeriod = Duration.of(flags.get("timePeriod")); + + if (flags.containsKey("minVals")) { + minVals = ((Number)flags.get("minVals")).intValue(); + } else { + minVals = 0; + } + if (flags.containsKey("minExpiredVals")) { + minExpiredVals = ((Number)flags.get("minExpiredVals")).intValue(); + } else { + minExpiredVals = 0; + } + } + + public void setTimePeriod(Duration newTimePeriod) { + timePeriod = newTimePeriod; + } + + public synchronized T getLatestValue() { + return (values.isEmpty()) ? null : values.get(values.size()-1).getValue(); + } + + public List> getValues() { + return getValues(System.currentTimeMillis()); + } + + public synchronized List> getValues(long now) { + pruneValues(now); + return ImmutableList.copyOf(values); + } + + public synchronized List> getValuesInWindow(long now, Duration subTimePeriod) { + long startTime = now - subTimePeriod.toMilliseconds(); + List> result = new LinkedList>(); + TimestampedValue mostRecentExpired = null; + for (TimestampedValue val : values) { + if (val.getTimestamp() < startTime) { + // discard; but remember most recent too-old value so we include that as the "initial" + mostRecentExpired = val; + } else { + result.add(val); + } + } + if (minExpiredVals > 0 && mostRecentExpired != null) { + result.add(0, mostRecentExpired); + } + + if (result.size() < minVals) { + int minIndex = Math.max(0, values.size()-minVals); + return ImmutableList.copyOf(values.subList(minIndex, values.size())); + } else { + return result; + } + } + + public void add(T val) { + add(val, System.currentTimeMillis()); + } + + public synchronized void add(T val, long timestamp) { + values.add(values.size(), new TimestampedValue(val, timestamp)); + pruneValues(timestamp); + } + + public synchronized void pruneValues(long now) { + long startTime = now - timePeriod.toMilliseconds(); + int expiredValsCount = 0; + if (timePeriod.equals(Duration.ZERO)) { + expiredValsCount = values.size(); + } else { + for (TimestampedValue val : values) { + if (val.getTimestamp() < startTime) { + expiredValsCount++; + } else { + break; + } + } + } + int numToPrune = Math.min(expiredValsCount - minExpiredVals, values.size()-minVals); + for (int i = 0; i < numToPrune; i++) { + values.removeFirst(); + } + } + + @Override + public String toString() { + return "timePeriod="+timePeriod+", vals="+values; + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimestampedValue.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimestampedValue.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimestampedValue.java new file mode 100644 index 0000000..0015748 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/TimestampedValue.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.collections; + +import com.google.common.base.Objects; + +public class TimestampedValue { + + private final T value; + private final long timestamp; + + public TimestampedValue(T value, long timestamp) { + this.value = value; + this.timestamp = timestamp; + } + + public T getValue() { + return value; + } + + public long getTimestamp() { + return timestamp; + } + + @Override + public int hashCode() { + return Objects.hashCode(value, timestamp); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof TimestampedValue)) { + return false; + } + TimestampedValue o = (TimestampedValue) other; + return o.getTimestamp() == timestamp && Objects.equal(o.getValue(), value); + } + + @Override + public String toString() { + return "val="+value+"; timestamp="+timestamp; + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/concurrent/CallableFromRunnable.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/concurrent/CallableFromRunnable.java b/utils/common/src/main/java/org/apache/brooklyn/util/concurrent/CallableFromRunnable.java new file mode 100644 index 0000000..72510f6 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/concurrent/CallableFromRunnable.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.concurrent; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; + +import com.google.common.annotations.Beta; + +/** Wraps a Runnable as a Callable. Like {@link Executors#callable(Runnable, Object)} but including the underlying toString. */ +@Beta +public class CallableFromRunnable implements Callable { + + public static CallableFromRunnable newInstance(Runnable task, T result) { + return new CallableFromRunnable(task, result); + } + + private final Runnable task; + private final T result; + + protected CallableFromRunnable(Runnable task, T result) { + this.task = task; + this.result = result; + } + + public T call() { + task.run(); + return result; + } + + @Override + public String toString() { + if (result!=null) + return "CallableFromRunnable["+task+(result!=null ? "->"+result : "")+"]"; + else + return ""+task; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/crypto/AuthorizedKeysParser.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/crypto/AuthorizedKeysParser.java b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/AuthorizedKeysParser.java new file mode 100644 index 0000000..14edabe --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/AuthorizedKeysParser.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.crypto; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.RSAPublicKeySpec; + +import org.apache.brooklyn.util.exceptions.Exceptions; + +import com.google.common.io.BaseEncoding; + +public class AuthorizedKeysParser { + + public static PublicKey decodePublicKey(String keyLine) { + try { + ByteArrayInputStream stream = null; + + // look for the Base64 encoded part of the line to decode + // both ssh-rsa and ssh-dss begin with "AAAA" due to the length bytes + for (String part : keyLine.split(" ")) { + if (part.startsWith("AAAA")) { + stream = new ByteArrayInputStream(BaseEncoding.base64().decode(part)); + break; + } + } + if (stream == null) + throw new IllegalArgumentException("Encoded public key should include phrase beginning AAAA."); + + String type = readType(stream); + if (type.equals("ssh-rsa")) { + BigInteger e = readBigInt(stream, 1); + BigInteger m = readBigInt(stream, 1); + RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e); + return KeyFactory.getInstance("RSA").generatePublic(spec); + } else if (type.equals("ssh-dss")) { + BigInteger p = readBigInt(stream, 1); + BigInteger q = readBigInt(stream, 1); + BigInteger g = readBigInt(stream, 1); + BigInteger y = readBigInt(stream, 1); + DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g); + return KeyFactory.getInstance("DSA").generatePublic(spec); + } else { + throw new IllegalArgumentException("Unknown public key type " + type); + } + + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + throw new IllegalArgumentException("Error parsing authorized_keys/SSH2 format public key: "+e); + } + } + + private static int readInt(InputStream stream) throws IOException { + return ((stream.read() & 0xFF) << 24) | ((stream.read() & 0xFF) << 16) + | ((stream.read() & 0xFF) << 8) | (stream.read() & 0xFF); + } + + private static byte[] readBytesWithLength(InputStream stream, int minLen) throws IOException { + int len = readInt(stream); + if (len100000) + throw new IllegalStateException("Invalid stream header: length "+len); + byte[] result = new byte[len]; + stream.read(result); + return result; + } + + private static void writeInt(OutputStream stream, int v) throws IOException { + for (int shift = 24; shift >= 0; shift -= 8) + stream.write((v >>> shift) & 0xFF); + } + private static void writeBytesWithLength(OutputStream stream, byte[] buf) throws IOException { + writeInt(stream, buf.length); + stream.write(buf); + } + + private static String readType(InputStream stream) throws IOException { return new String(readBytesWithLength(stream, 0)); } + private static BigInteger readBigInt(InputStream stream, int minLen) throws IOException { return new BigInteger(readBytesWithLength(stream, minLen)); } + + public static String encodePublicKey(PublicKey key) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + String type = null; + if (key==null) { + return null; + } else if (key instanceof RSAPublicKey) { + type = "ssh-rsa"; + writeBytesWithLength(out, type.getBytes()); + writeBytesWithLength(out, ((RSAPublicKey)key).getPublicExponent().toByteArray()); + writeBytesWithLength(out, ((RSAPublicKey)key).getModulus().toByteArray()); + } else if (key instanceof DSAPublicKey) { + type = "ssh-dss"; + writeBytesWithLength(out, type.getBytes()); + writeBytesWithLength(out, ((DSAPublicKey)key).getParams().getP().toByteArray()); + writeBytesWithLength(out, ((DSAPublicKey)key).getParams().getQ().toByteArray()); + writeBytesWithLength(out, ((DSAPublicKey)key).getParams().getG().toByteArray()); + writeBytesWithLength(out, ((DSAPublicKey)key).getY().toByteArray()); + } else { + throw new IllegalStateException("Unsupported public key type for encoding: "+key); + } + out.close(); + + return type+" "+BaseEncoding.base64().encode(out.toByteArray()); + } catch (Exception e) { + // shouldn't happen, as it's a byte stream... + throw Exceptions.propagate(e); + } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SecureKeysWithoutBouncyCastle.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SecureKeysWithoutBouncyCastle.java b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SecureKeysWithoutBouncyCastle.java new file mode 100644 index 0000000..b801fb8 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SecureKeysWithoutBouncyCastle.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.crypto; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.NoSuchElementException; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import javax.security.auth.x500.X500Principal; + +import org.apache.brooklyn.util.exceptions.Exceptions; + +/** + * Utility methods for generating and working with keys, with no BC dependencies + */ +public class SecureKeysWithoutBouncyCastle { + + private static KeyPairGenerator defaultKeyPairGenerator = newKeyPairGenerator("RSA", 1024); + + protected SecureKeysWithoutBouncyCastle() {} + + public static KeyPairGenerator newKeyPairGenerator(String algorithm, int bits) { + KeyPairGenerator keyPairGenerator; + try { + keyPairGenerator = KeyPairGenerator.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + throw Exceptions.propagate(e); + } + keyPairGenerator.initialize(bits); + return keyPairGenerator; + } + + public static KeyPair newKeyPair() { + return defaultKeyPairGenerator.generateKeyPair(); + } + + public static KeyPair newKeyPair(String algorithm, int bits) { + return newKeyPairGenerator(algorithm, bits).generateKeyPair(); + } + + /** returns a new keystore, of the default type, and initialized to be empty. + * (everyone always forgets to load(null,null).) */ + public static KeyStore newKeyStore() { + try { + KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); + store.load(null, null); + return store; + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + /** returns keystore of default type read from given source */ + public static KeyStore newKeyStore(InputStream source, String passphrase) { + try { + KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); + store.load(source, passphrase!=null ? passphrase.toCharArray() : new char[0]); + return store; + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + /** see {@link #getTrustManager(KeyStore, Class)}, matching any type */ + public static TrustManager getTrustManager(KeyStore trustStore) { + return getTrustManager(trustStore, null); + } + /** returns the trust manager inferred from trustStore, matching the type (if not null); + * throws exception if there are none, or if there are multiple */ + @SuppressWarnings("unchecked") + public static T getTrustManager(KeyStore trustStore, Class type) { + try { + TrustManagerFactory tmf = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(trustStore); + T result = null; + for (TrustManager tm: tmf.getTrustManagers()) { + if (type==null || type.isInstance(tm)) { + if (result!=null) + throw new IllegalStateException("Multiple trust managers matching "+type+" inferred from "+trustStore); + result = (T)tm; + } + } + if (result!=null) + return result; + throw new NoSuchElementException("No trust manager matching "+type+" can be inferred from "+trustStore); + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + public static X509TrustManager getTrustManager(X509Certificate certificate) { + try { + KeyStore ks = newKeyStore(); + ks.setCertificateEntry("", certificate); + return getTrustManager(ks, X509TrustManager.class); + } catch (KeyStoreException e) { + throw Exceptions.propagate(e); + } + } + + /** converts a certificate to the canonical implementation, commonly sun.security.x509.X509CertImpl, + * which is required in some places -- the Bouncy Castle X509 impl is not accepted + * (e.g. where certs are chained, passed to trust manager) */ + public static X509Certificate getCanonicalImpl(X509Certificate inCert) { + try { + KeyStore store = newKeyStore(); + store.setCertificateEntry("to-canonical", inCert); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + store.store(out, "".toCharArray()); + + KeyStore store2 = KeyStore.getInstance(KeyStore.getDefaultType()); + store2.load(new ByteArrayInputStream(out.toByteArray()), "".toCharArray()); + return (X509Certificate) store2.getCertificate("to-canonical"); + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + public static boolean isCertificateAuthorizedBy(X509Certificate candidate, X509Certificate authority) { + try { + candidate = getCanonicalImpl(candidate); + getTrustManager(authority).checkClientTrusted(new X509Certificate[] { candidate }, "RSA"); + return true; + } catch (CertificateException e) { + return false; + } + } + + public static X500Principal getX500PrincipalWithCommonName(String commonName) { + return new X500Principal("" + "C=None," + "L=None," + "O=None," + "OU=None," + "CN=" + commonName); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SslTrustUtils.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SslTrustUtils.java b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SslTrustUtils.java new file mode 100644 index 0000000..3dd394d --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/SslTrustUtils.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.crypto; + +import java.net.URLConnection; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +public class SslTrustUtils { + + /** configures a connection to accept all certificates, if it is for https */ + public static T trustAll(T connection) { + if (connection instanceof HttpsURLConnection) { + ((HttpsURLConnection)connection).setSSLSocketFactory(TrustingSslSocketFactory.getInstance()); + ((HttpsURLConnection)connection).setHostnameVerifier(ALL_HOSTS_VALID); + } + return connection; + } + + /** trusts all SSL certificates */ + public static final TrustManager TRUST_ALL = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + } + }; + + /** trusts no SSL certificates */ + public static final TrustManager TRUST_NONE = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + throw new java.security.cert.CertificateException("No clients allowed."); + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + throw new java.security.cert.CertificateException("No servers allowed."); + } + }; + + public static class DelegatingTrustManager implements X509TrustManager { + private final X509TrustManager delegate; + public DelegatingTrustManager(X509TrustManager delegate) { + this.delegate = delegate; + } + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + delegate.checkClientTrusted(chain, authType); + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + delegate.checkServerTrusted(chain, authType); + } + @Override + public X509Certificate[] getAcceptedIssuers() { + return delegate.getAcceptedIssuers(); + } + } + + public static final HostnameVerifier ALL_HOSTS_VALID = new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/crypto/TrustingSslSocketFactory.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/crypto/TrustingSslSocketFactory.java b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/TrustingSslSocketFactory.java new file mode 100644 index 0000000..2597035 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/crypto/TrustingSslSocketFactory.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.crypto; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Throwables; + +/** An SSLSocketFactory which trusts all endpoints (ie encryption but no authentication) */ +public class TrustingSslSocketFactory extends SSLSocketFactory { + + private static final Logger logger = LoggerFactory.getLogger(TrustingSslSocketFactory.class); + + private static TrustingSslSocketFactory INSTANCE; + public synchronized static TrustingSslSocketFactory getInstance() { + if (INSTANCE==null) INSTANCE = new TrustingSslSocketFactory(); + return INSTANCE; + } + + private static SSLContext sslContext; + static { + try { + sslContext = SSLContext.getInstance("TLS"); + } catch (Exception e) { + logger.error("Unable to set up SSLContext with TLS. Https activity will likely fail.", e); + } + } + + // no reason this can't be public, but no reason it should be necessary; + // just use getInstance to get the shared INSTANCE + protected TrustingSslSocketFactory() { + super(); + try { + sslContext.init(null, new TrustManager[] { SslTrustUtils.TRUST_ALL }, null); + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { + return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + } + + @Override + public Socket createSocket() throws IOException { + return sslContext.getSocketFactory().createSocket(); + } + + @Override + public String[] getDefaultCipherSuites() { + return sslContext.getSocketFactory().getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return sslContext.getSocketFactory().getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(String arg0, int arg1) throws IOException, UnknownHostException { + return sslContext.getSocketFactory().createSocket(arg0, arg1); + } + + @Override + public Socket createSocket(InetAddress arg0, int arg1) throws IOException { + return sslContext.getSocketFactory().createSocket(arg0, arg1); + } + + @Override + public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) throws IOException, UnknownHostException { + return sslContext.getSocketFactory().createSocket(arg0, arg1, arg2, arg3); + } + + @Override + public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, int arg3) throws IOException { + return sslContext.getSocketFactory().createSocket(arg0, arg1, arg2, arg3); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CompoundRuntimeException.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CompoundRuntimeException.java b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CompoundRuntimeException.java new file mode 100644 index 0000000..bd2ac6c --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CompoundRuntimeException.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.brooklyn.util.exceptions; + +import java.util.Collections; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class CompoundRuntimeException extends RuntimeException { + + private static final long serialVersionUID = 6110995537064639587L; + + private final List causes; + + public CompoundRuntimeException(String message) { + super(message); + this.causes = Collections.emptyList(); + } + + public CompoundRuntimeException(String message, Throwable cause) { + super(message, cause); + this.causes = (cause == null) ? Collections.emptyList() : Collections.singletonList(cause); + } + + public CompoundRuntimeException(Throwable cause) { + super(cause); + this.causes = (cause == null) ? Collections.emptyList() : Collections.singletonList(cause); + } + + public CompoundRuntimeException(String message, Iterable causes) { + this(message, (Iterables.isEmpty(causes) ? null : Iterables.get(causes, 0)), causes); + } + public CompoundRuntimeException(String message, Throwable primaryCauseToReport, Iterable allCauses) { + super(message, primaryCauseToReport); + this.causes = ImmutableList.copyOf(allCauses); + } + + public List getAllCauses() { + return causes; + } +}