/*
* 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;
}
}