/*
* 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.location;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.location.LocationSpec;
import org.apache.brooklyn.api.location.MachineLocation;
import org.apache.brooklyn.api.mgmt.LocationManager;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.location.internal.LocationInternal;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.yaml.Yamls;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableList;
public class Locations {
private static final Logger log = LoggerFactory.getLogger(Locations.class);
public static final LocationsFilter USE_FIRST_LOCATION = new LocationsFilter() {
private static final long serialVersionUID = 3100091615409115890L;
@Override
public List<Location> filterForContext(List<Location> locations, Object context) {
if (locations.size()<=1) return locations;
return ImmutableList.of(locations.get(0));
}
};
public interface LocationsFilter extends Serializable {
public List<Location> filterForContext(List<Location> locations, Object context);
}
/** as {@link Machines#findUniqueMachineLocation(Iterable)} */
public static Maybe<MachineLocation> findUniqueMachineLocation(Iterable<? extends Location> locations) {
return Machines.findUniqueMachineLocation(locations);
}
/** as {@link Machines#findUniqueSshMachineLocation(Iterable)} */
public static Maybe<SshMachineLocation> findUniqueSshMachineLocation(Iterable<? extends Location> locations) {
return Machines.findUniqueMachineLocation(locations, SshMachineLocation.class);
}
/** if no locations are supplied, returns locations on the entity, or in the ancestors, until it finds a non-empty set,
* or ultimately the empty set if no locations are anywhere */
public static Collection<? extends Location> getLocationsCheckingAncestors(Collection<? extends Location> locations, Entity entity) {
// look in ancestors if location not set here
Entity ancestor = entity;
while ((locations==null || locations.isEmpty()) && ancestor!=null) {
locations = ancestor.getLocations();
ancestor = ancestor.getParent();
}
return locations;
}
public static boolean isManaged(Location loc) {
ManagementContext mgmt = ((LocationInternal)loc).getManagementContext();
return (mgmt != null) && mgmt.isRunning() && mgmt.getLocationManager().isManaged(loc);
}
public static void unmanage(Location loc) {
if (isManaged(loc)) {
ManagementContext mgmt = ((LocationInternal)loc).getManagementContext();
mgmt.getLocationManager().unmanage(loc);
}
}
/**
* Registers the given location (and all its children) with the management context.
* @throws IllegalStateException if the parent location is not already managed
*
* @since 0.6.0 (added only for backwards compatibility, where locations are being created directly; previously in {@link Entities}).
* @deprecated in 0.6.0; use {@link LocationManager#createLocation(LocationSpec)} instead.
*/
public static void manage(Location loc, ManagementContext managementContext) {
if (!managementContext.getLocationManager().isManaged(loc)) {
log.warn("Deprecated use of unmanaged location ("+loc+"); will be managed automatically now but not supported in future versions");
// FIXME this occurs MOST OF THE TIME e.g. including BrooklynLauncher.location(locationString)
// not sure what is the recommend way to convert from locationString to locationSpec, or the API we want to expose;
// deprecating some of the LocationRegistry methods seems sensible?
log.debug("Stack trace for location of: Deprecated use of unmanaged location; will be managed automatically now but not supported in future versions", new Exception("TRACE for: Deprecated use of unmanaged location"));
managementContext.getLocationManager().manage(loc);
}
}
public static Location coerce(ManagementContext mgmt, Object rawO) {
if (rawO==null)
return null;
if (rawO instanceof Location)
return (Location)rawO;
Object raw = rawO;
if (raw instanceof String)
raw = Yamls.parseAll((String)raw).iterator().next();
String name;
Map<?, ?> flags = null;
if (raw instanceof Map) {
// for yaml, take the key, and merge with locationFlags
Map<?,?> tm = ((Map<?,?>)raw);
if (tm.size()!=1) {
throw new IllegalArgumentException("Location "+rawO+" is invalid; maps must have only one key, being the location spec string");
}
name = (String) tm.keySet().iterator().next();
flags = (Map<?, ?>) tm.values().iterator().next();
} else if (raw instanceof String) {
name = (String)raw;
} else {
throw new IllegalArgumentException("Location "+rawO+" is invalid; can only parse strings or maps");
}
return mgmt.getLocationRegistry().resolve(name, flags);
}
public static Collection<? extends Location> coerceToCollection(ManagementContext mgmt, Object rawO) {
if (rawO==null) return null;
Object raw = rawO;
if (raw instanceof Collection) {
List<Location> result = MutableList.<Location>of();
for (Object o: (Collection<?>)raw)
result.add(coerce(mgmt, o));
return result;
}
if (raw instanceof String) {
raw = Yamls.parseAll((String)raw).iterator().next();
if (raw instanceof Collection)
return coerceToCollection(mgmt, raw);
}
return Collections.singletonList( coerce(mgmt, raw) );
}
}