/*
* 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.rest.transform;
import java.net.URI;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.location.LocationDefinition;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.core.config.Sanitizer;
import org.apache.brooklyn.core.location.BasicLocationDefinition;
import org.apache.brooklyn.core.location.LocationConfigKeys;
import org.apache.brooklyn.core.location.internal.LocationInternal;
import org.apache.brooklyn.rest.domain.LocationSummary;
import org.apache.brooklyn.rest.util.WebResourceUtils;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.text.Strings;
import com.google.common.collect.ImmutableMap;
public class LocationTransformer {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(LocationTransformer.LocationDetailLevel.class);
public static enum LocationDetailLevel { NONE, LOCAL_EXCLUDING_SECRET, FULL_EXCLUDING_SECRET, FULL_INCLUDING_SECRET }
/** @deprecated since 0.7.0 use method taking management context and detail specifier */
@Deprecated
public static LocationSummary newInstance(String id, org.apache.brooklyn.rest.domain.LocationSpec locationSpec) {
return newInstance(null, id, locationSpec, LocationDetailLevel.LOCAL_EXCLUDING_SECRET);
}
@SuppressWarnings("deprecation")
public static LocationSummary newInstance(ManagementContext mgmt, String id, org.apache.brooklyn.rest.domain.LocationSpec locationSpec, LocationDetailLevel level) {
// TODO: Remove null checks on mgmt when newInstance(String, LocationSpec) is deleted
Map<String, ?> config = locationSpec.getConfig();
if (mgmt != null && (level==LocationDetailLevel.FULL_EXCLUDING_SECRET || level==LocationDetailLevel.FULL_INCLUDING_SECRET)) {
LocationDefinition ld = new BasicLocationDefinition(id, locationSpec.getName(), locationSpec.getSpec(), locationSpec.getConfig());
Location ll = mgmt.getLocationRegistry().resolve(ld, false, null).orNull();
if (ll!=null) config = ((LocationInternal)ll).config().getBag().getAllConfig();
} else if (level==LocationDetailLevel.LOCAL_EXCLUDING_SECRET) {
// get displayName
if (!config.containsKey(LocationConfigKeys.DISPLAY_NAME.getName()) && mgmt!=null) {
LocationDefinition ld = new BasicLocationDefinition(id, locationSpec.getName(), locationSpec.getSpec(), locationSpec.getConfig());
Location ll = mgmt.getLocationRegistry().resolve(ld, false, null).orNull();
if (ll!=null) {
Map<String, Object> configExtra = ((LocationInternal)ll).config().getBag().getAllConfig();
if (configExtra.containsKey(LocationConfigKeys.DISPLAY_NAME.getName())) {
ConfigBag configNew = ConfigBag.newInstance(config);
configNew.configure(LocationConfigKeys.DISPLAY_NAME, (String)configExtra.get(LocationConfigKeys.DISPLAY_NAME.getName()));
config = configNew.getAllConfig();
}
}
}
}
return new LocationSummary(
id,
locationSpec.getName(),
locationSpec.getSpec(),
null,
copyConfig(config, level),
ImmutableMap.of("self", URI.create("/v1/locations/" + id)));
}
/** @deprecated since 0.7.0 use method taking management context and detail specifier */
@Deprecated
public static LocationSummary newInstance(LocationDefinition l) {
return newInstance(null, l, LocationDetailLevel.LOCAL_EXCLUDING_SECRET);
}
public static LocationSummary newInstance(ManagementContext mgmt, LocationDefinition l, LocationDetailLevel level) {
// TODO: Can remove null checks on mgmt when newInstance(LocationDefinition) is deleted
Map<String, Object> config = l.getConfig();
if (mgmt != null && (level==LocationDetailLevel.FULL_EXCLUDING_SECRET || level==LocationDetailLevel.FULL_INCLUDING_SECRET)) {
Location ll = mgmt.getLocationRegistry().resolve(l, false, null).orNull();
if (ll!=null) config = ((LocationInternal)ll).config().getBag().getAllConfig();
} else if (level==LocationDetailLevel.LOCAL_EXCLUDING_SECRET) {
// get displayName
if (mgmt != null && !config.containsKey(LocationConfigKeys.DISPLAY_NAME.getName())) {
Location ll = mgmt.getLocationRegistry().resolve(l, false, null).orNull();
if (ll!=null) {
Map<String, Object> configExtra = ((LocationInternal)ll).config().getBag().getAllConfig();
if (configExtra.containsKey(LocationConfigKeys.DISPLAY_NAME.getName())) {
ConfigBag configNew = ConfigBag.newInstance(config);
configNew.configure(LocationConfigKeys.DISPLAY_NAME, (String)configExtra.get(LocationConfigKeys.DISPLAY_NAME.getName()));
config = configNew.getAllConfig();
}
}
}
}
return new LocationSummary(
l.getId(),
l.getName(),
l.getSpec(),
null,
copyConfig(config, level),
ImmutableMap.of("self", URI.create("/v1/locations/" + l.getId())));
}
private static Map<String, ?> copyConfig(Map<String,?> entries, LocationDetailLevel level) {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
if (level!=LocationDetailLevel.NONE) {
for (Map.Entry<String,?> entry : entries.entrySet()) {
if (level==LocationDetailLevel.FULL_INCLUDING_SECRET || !Sanitizer.IS_SECRET_PREDICATE.apply(entry.getKey())) {
builder.put(entry.getKey(), WebResourceUtils.getValueForDisplay(entry.getValue(), true, false));
}
}
}
return builder.build();
}
public static LocationSummary newInstance(ManagementContext mgmt, Location l, LocationDetailLevel level) {
String spec = null;
String specId = null;
Location lp = l;
while (lp!=null && (spec==null || specId==null)) {
// walk parent locations
// TODO not sure this is the best strategy, or if it's needed, as the spec config is inherited anyway...
if (spec==null) {
Maybe<Object> originalSpec = ((LocationInternal)lp).config().getRaw(LocationInternal.ORIGINAL_SPEC);
if (originalSpec.isPresent())
spec = Strings.toString(originalSpec.get());
}
if (specId==null) {
LocationDefinition ld = null;
// prefer looking it up by name as this loads the canonical definition
if (spec!=null) ld = mgmt.getLocationRegistry().getDefinedLocationByName(spec);
if (ld==null && spec!=null && spec.startsWith("named:"))
ld = mgmt.getLocationRegistry().getDefinedLocationByName(Strings.removeFromStart(spec, "named:"));
if (ld==null) ld = mgmt.getLocationRegistry().getDefinedLocationById(lp.getId());
if (ld!=null) {
if (spec==null) spec = ld.getSpec();
specId = ld.getId();
}
}
lp = lp.getParent();
}
if (specId==null && spec!=null) {
// fall back to attempting to lookup it
Location ll = mgmt.getLocationRegistry().resolve(spec, false, null).orNull();
if (ll!=null) specId = ll.getId();
}
Map<String, Object> configOrig;
if (level == LocationDetailLevel.LOCAL_EXCLUDING_SECRET) {
configOrig = MutableMap.copyOf(((LocationInternal)l).config().getLocalBag().getAllConfig());
} else {
configOrig = MutableMap.copyOf(((LocationInternal)l).config().getBag().getAllConfig());
}
if (level==LocationDetailLevel.LOCAL_EXCLUDING_SECRET) {
// for LOCAL, also get the display name
if (!configOrig.containsKey(LocationConfigKeys.DISPLAY_NAME.getName())) {
Map<String, Object> configExtra = ((LocationInternal)l).config().getBag().getAllConfig();
if (configExtra.containsKey(LocationConfigKeys.DISPLAY_NAME.getName()))
configOrig.put(LocationConfigKeys.DISPLAY_NAME.getName(), configExtra.get(LocationConfigKeys.DISPLAY_NAME.getName()));
}
}
Map<String, ?> config = level==LocationDetailLevel.NONE ? null : copyConfig(configOrig, level);
return new LocationSummary(
l.getId(),
l.getDisplayName(),
spec,
l.getClass().getName(),
config,
MutableMap.of("self", URI.create("/v1/locations/" + l.getId()))
.addIfNotNull("parent", l.getParent()!=null ? URI.create("/v1/locations/"+l.getParent().getId()) : null)
.addIfNotNull("spec", specId!=null ? URI.create("/v1/locations/"+specId) : null)
.asUnmodifiable() );
}
}