/* * 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.core.mgmt.rebind.dto; import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento; import org.apache.brooklyn.core.BrooklynVersion; import org.apache.brooklyn.core.config.Sanitizer; import com.google.common.base.Objects; import com.google.common.base.Objects.ToStringHelper; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; public abstract class AbstractMemento implements Memento, Serializable { private static final long serialVersionUID = -8091049282749284567L; protected static abstract class Builder<B extends Builder<?>> { protected String brooklynVersion = BrooklynVersion.get(); protected String id; protected String type; protected Class<?> typeClass; protected String displayName; protected String catalogItemId; protected Map<String, Object> customFields = Maps.newLinkedHashMap(); protected List<Object> tags = Lists.newArrayList(); protected Map<String,Set<String>> relations = Maps.newLinkedHashMap(); // only supported for EntityAdjuncts protected String uniqueTag; @SuppressWarnings("unchecked") protected B self() { return (B) this; } @SuppressWarnings("deprecation") public B from(Memento other) { brooklynVersion = other.getBrooklynVersion(); id = other.getId(); type = other.getType(); typeClass = other.getTypeClass(); displayName = other.getDisplayName(); catalogItemId = other.getCatalogItemId(); customFields.putAll(other.getCustomFields()); tags.addAll(other.getTags()); relations.putAll(other.getRelations()); uniqueTag = other.getUniqueTag(); return self(); } /** * @deprecated since 0.7.0; use config/attributes so generic persistence will work, rather than requiring "custom fields" */ @Deprecated public B customFields(Map<String,?> vals) { customFields.putAll(vals); return self(); } } private String brooklynVersion; private String type; private String id; private String displayName; private String catalogItemId; private List<Object> tags; private Map<String,Set<String>> relations; // for EntityAdjuncts; not used for entity private String uniqueTag; private transient Class<?> typeClass; // for de-serialization protected AbstractMemento() { } // Trusts the builder to not mess around with mutability after calling build() protected AbstractMemento(Builder<?> builder) { brooklynVersion = builder.brooklynVersion; id = builder.id; type = builder.type; typeClass = builder.typeClass; displayName = builder.displayName; catalogItemId = builder.catalogItemId; setCustomFields(builder.customFields); tags = toPersistedList(builder.tags); relations = toPersistedMap(builder.relations); uniqueTag = builder.uniqueTag; } // "fields" is not included as a field here, so that it is serialized after selected subclass fields // but the method declared here simplifies how it is connected in via builder etc protected abstract void setCustomFields(Map<String, Object> fields); @Override public void injectTypeClass(Class<?> clazz) { this.typeClass = clazz; } @Override public Class<?> getTypeClass() { return typeClass; } @Override public String getBrooklynVersion() { return brooklynVersion; } @Override public String getId() { return id; } @Override public String getType() { return type; } @Override public String getDisplayName() { return displayName; } @Override public String getCatalogItemId() { return catalogItemId; } @Override public List<Object> getTags() { return fromPersistedList(tags); } @Override public Map<String,Set<String>> getRelations() { return fromPersistedMap(relations); } @Override public String getUniqueTag() { return uniqueTag; } @Deprecated @Override public Object getCustomField(String name) { if (getCustomFields()==null) return null; return getCustomFields().get(name); } @Deprecated @Override public abstract Map<String, ? extends Object> getCustomFields(); @Override public String toString() { return Objects.toStringHelper(this).add("type", getType()).add("id", getId()).toString(); } @Override public String toVerboseString() { return newVerboseStringHelper().toString(); } protected ToStringHelper newVerboseStringHelper() { return Objects.toStringHelper(this).add("id", getId()).add("type", getType()) .add("displayName", getDisplayName()) .add("tags", getTags()) .add("relations", getRelations()) .add("customFields", Sanitizer.sanitize(getCustomFields())); } protected <T> List<T> fromPersistedList(List<T> l) { if (l==null) return Collections.emptyList(); return Collections.unmodifiableList(l); } protected <T> List<T> toPersistedList(List<T> l) { if (l==null || l.isEmpty()) return null; return l; } protected <T> Set<T> fromPersistedSet(Set<T> l) { if (l==null) return Collections.emptySet(); return Collections.unmodifiableSet(l); } protected <T> Set<T> toPersistedSet(Set<T> l) { if (l==null || l.isEmpty()) return null; return l; } protected <K,V> Map<K,V> fromPersistedMap(Map<K,V> m) { if (m==null) return Collections.emptyMap(); return Collections.unmodifiableMap(m); } protected <K,V> Map<K,V> toPersistedMap(Map<K,V> m) { if (m==null || m.isEmpty()) return null; return m; } protected <K,V> Multimap<K,V> fromPersistedMultimap(Multimap<K,V> m) { if (m==null) return ImmutableMultimap.of(); return ImmutableMultimap.copyOf(m); } protected <K,V> Multimap<K,V> toPersistedMultimap(Multimap<K,V> m) { if (m==null || m.isEmpty()) return null; return m; } }