/* * 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.entity.machine.pool; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.LocationRegistry; import org.apache.brooklyn.api.location.LocationSpec; import org.apache.brooklyn.api.location.LocationResolver.EnableableLocationResolver; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.core.location.BasicLocationRegistry; import org.apache.brooklyn.core.location.LocationPropertiesFromBrooklynProperties; import org.apache.brooklyn.core.location.dynamic.DynamicLocation; import org.apache.brooklyn.core.location.internal.LocationInternal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.text.KeyValueParser; import org.apache.brooklyn.util.text.Strings; public class ServerPoolLocationResolver implements EnableableLocationResolver { private static final Logger LOG = LoggerFactory.getLogger(ServerPoolLocationResolver.class); private static final String PREFIX = "pool"; public static final String POOL_SPEC = PREFIX + ":%s"; private static final Pattern PATTERN = Pattern.compile("("+PREFIX+"|"+PREFIX.toUpperCase()+")" + ":([a-zA-Z0-9]+)" + // pool Id "(:\\((.*)\\))?$"); // arguments, e.g. displayName private static final Set<String> ACCEPTABLE_ARGS = ImmutableSet.of("name", "displayName"); private ManagementContext managementContext; @Override public boolean isEnabled() { return true; } @Override public void init(ManagementContext managementContext) { this.managementContext = checkNotNull(managementContext, "managementContext"); } @Override public String getPrefix() { return PREFIX; } @Override public boolean accepts(String spec, LocationRegistry registry) { return BasicLocationRegistry.isResolverPrefixForSpec(this, spec, true); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry) { if (LOG.isDebugEnabled()) { LOG.debug("Resolving location '" + spec + "' with flags " + Joiner.on(",").withKeyValueSeparator("=").join(locationFlags)); } String namedLocation = (String) locationFlags.get(LocationInternal.NAMED_SPEC_NAME.getName()); Matcher matcher = PATTERN.matcher(spec); if (!matcher.matches()) { String m = String.format("Invalid location '%s'; must specify either %s:entityId or %s:entityId:(key=argument)", spec, PREFIX, PREFIX); throw new IllegalArgumentException(m); } String argsPart = matcher.group(4); Map<String, String> argsMap = (argsPart != null) ? KeyValueParser.parseMap(argsPart) : Collections.<String,String>emptyMap(); String displayNamePart = argsMap.get("displayName"); String namePart = argsMap.get("name"); if (!ACCEPTABLE_ARGS.containsAll(argsMap.keySet())) { Set<String> illegalArgs = Sets.difference(argsMap.keySet(), ACCEPTABLE_ARGS); throw new IllegalArgumentException("Invalid location '"+spec+"'; illegal args "+illegalArgs+"; acceptable args are "+ACCEPTABLE_ARGS); } if (argsMap.containsKey("displayName") && Strings.isEmpty(displayNamePart)) { throw new IllegalArgumentException("Invalid location '"+spec+"'; if displayName supplied then value must be non-empty"); } if (argsMap.containsKey("name") && Strings.isEmpty(namePart)) { throw new IllegalArgumentException("Invalid location '"+spec+"'; if name supplied then value must be non-empty"); } Map<String, Object> filteredProperties = new LocationPropertiesFromBrooklynProperties() .getLocationProperties(PREFIX, namedLocation, registry.getProperties()); MutableMap<String, Object> flags = MutableMap.<String, Object>builder() .putAll(filteredProperties) .putAll(locationFlags) .build(); String poolId = matcher.group(2); if (Strings.isBlank(poolId)) { throw new IllegalArgumentException("Invalid location '"+spec+"'; pool's entity id must be non-empty"); } final String displayName = displayNamePart != null ? displayNamePart : "Server Pool " + poolId; final String locationName = namePart != null ? namePart : "serverpool-" + poolId; Entity pool = managementContext.getEntityManager().getEntity(poolId); LocationSpec<ServerPoolLocation> locationSpec = LocationSpec.create(ServerPoolLocation.class) .configure(flags) .configure(DynamicLocation.OWNER, pool) .configure(LocationInternal.NAMED_SPEC_NAME, locationName) .displayName(displayName); return managementContext.getLocationManager().createLocation(locationSpec); } }