|
@@ -0,0 +1,695 @@
|
|
|
+/**
|
|
|
+ * 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.ambari.server.controller.internal;
|
|
|
+
|
|
|
+import com.google.inject.Inject;
|
|
|
+import org.apache.ambari.server.AmbariException;
|
|
|
+import org.apache.ambari.server.DuplicateResourceException;
|
|
|
+import org.apache.ambari.server.ObjectNotFoundException;
|
|
|
+import org.apache.ambari.server.ParentObjectNotFoundException;
|
|
|
+import org.apache.ambari.server.StaticallyInject;
|
|
|
+import org.apache.ambari.server.controller.AmbariManagementController;
|
|
|
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
|
|
|
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
|
|
|
+import org.apache.ambari.server.controller.spi.Predicate;
|
|
|
+import org.apache.ambari.server.controller.spi.Request;
|
|
|
+import org.apache.ambari.server.controller.spi.RequestStatus;
|
|
|
+import org.apache.ambari.server.controller.spi.Resource;
|
|
|
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
|
|
|
+import org.apache.ambari.server.controller.spi.SystemException;
|
|
|
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
|
|
|
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
|
|
|
+import org.apache.ambari.server.orm.dao.ArtifactDAO;
|
|
|
+import org.apache.ambari.server.orm.entities.ArtifactEntity;
|
|
|
+import org.apache.ambari.server.state.Cluster;
|
|
|
+
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.LinkedHashSet;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.TreeMap;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Provider for cluster artifacts.
|
|
|
+ * Artifacts contain an artifact name as the PK and artifact data in the form of
|
|
|
+ * a map which is the content of the artifact.
|
|
|
+ * <p>
|
|
|
+ * An example of an artifact is a kerberos descriptor.
|
|
|
+ */
|
|
|
+//todo: implement ExtendedResourceProvider???
|
|
|
+@StaticallyInject
|
|
|
+public class ArtifactResourceProvider extends AbstractResourceProvider {
|
|
|
+ /**
|
|
|
+ * artifact name
|
|
|
+ */
|
|
|
+ public static final String ARTIFACT_NAME_PROPERTY =
|
|
|
+ PropertyHelper.getPropertyId("Artifacts", "artifact_name");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * artifact data
|
|
|
+ */
|
|
|
+ public static final String ARTIFACT_DATA_PROPERTY = "artifact_data";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * primary key fields
|
|
|
+ */
|
|
|
+ private static Set<String> pkPropertyIds = new HashSet<String>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * map of resource type to fk field
|
|
|
+ */
|
|
|
+ private static Map<Resource.Type, String> keyPropertyIds =
|
|
|
+ new HashMap<Resource.Type, String>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * resource properties
|
|
|
+ */
|
|
|
+ private static Set<String> propertyIds = new HashSet<String>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * map of resource type to type registration
|
|
|
+ */
|
|
|
+ private static final Map<Resource.Type, TypeRegistration> typeRegistrations =
|
|
|
+ new HashMap<Resource.Type, TypeRegistration>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * map of foreign key field to type registration
|
|
|
+ */
|
|
|
+ private static final Map<String, TypeRegistration> typeRegistrationsByFK =
|
|
|
+ new HashMap<String, TypeRegistration>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * map of short foreign key field to type registration
|
|
|
+ */
|
|
|
+ private static final Map<String, TypeRegistration> typeRegistrationsByShortFK =
|
|
|
+ new HashMap<String, TypeRegistration>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * artifact data access object
|
|
|
+ */
|
|
|
+ @Inject
|
|
|
+ private static ArtifactDAO artifactDAO;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * set resource properties, pk and fk's
|
|
|
+ */
|
|
|
+ static {
|
|
|
+ // resource properties
|
|
|
+ propertyIds.add(ARTIFACT_NAME_PROPERTY);
|
|
|
+ propertyIds.add(ARTIFACT_DATA_PROPERTY);
|
|
|
+
|
|
|
+ // pk property
|
|
|
+ pkPropertyIds.add(ARTIFACT_NAME_PROPERTY);
|
|
|
+
|
|
|
+ // key properties
|
|
|
+ keyPropertyIds.put(Resource.Type.Artifact, ARTIFACT_NAME_PROPERTY);
|
|
|
+
|
|
|
+ //todo: external registration
|
|
|
+ // cluster registration
|
|
|
+ ClusterTypeRegistration clusterTypeRegistration = new ClusterTypeRegistration();
|
|
|
+ typeRegistrations.put(clusterTypeRegistration.getType(), clusterTypeRegistration);
|
|
|
+
|
|
|
+ //service registration
|
|
|
+ ServiceTypeRegistration serviceTypeRegistration = new ServiceTypeRegistration();
|
|
|
+ typeRegistrations.put(serviceTypeRegistration.getType(), serviceTypeRegistration);
|
|
|
+
|
|
|
+ //todo: detect resource type and fk name collisions during registration
|
|
|
+ for (TypeRegistration registration: typeRegistrations.values()) {
|
|
|
+ String fkProperty = registration.getFKPropertyName();
|
|
|
+ keyPropertyIds.put(registration.getType(), fkProperty);
|
|
|
+ propertyIds.add(fkProperty);
|
|
|
+
|
|
|
+ typeRegistrationsByFK.put(fkProperty, registration);
|
|
|
+ typeRegistrationsByShortFK.put(registration.getShortFKPropertyName(), registration);
|
|
|
+
|
|
|
+ for (Map.Entry<Resource.Type, String> ancestor : registration.getForeignKeyInfo().entrySet()) {
|
|
|
+ Resource.Type ancestorType = ancestor.getKey();
|
|
|
+ if (! keyPropertyIds.containsKey(ancestorType)) {
|
|
|
+ String ancestorFK = ancestor.getValue();
|
|
|
+ keyPropertyIds.put(ancestorType, ancestorFK);
|
|
|
+ propertyIds.add(ancestorFK);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constructor.
|
|
|
+ *
|
|
|
+ * @param controller management controller
|
|
|
+ */
|
|
|
+ @Inject
|
|
|
+ protected ArtifactResourceProvider(AmbariManagementController controller) {
|
|
|
+ super(propertyIds, keyPropertyIds);
|
|
|
+
|
|
|
+ for (TypeRegistration typeRegistration : typeRegistrations.values()) {
|
|
|
+ typeRegistration.setManagementController(controller);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected Set<String> getPKPropertyIds() {
|
|
|
+ return pkPropertyIds;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public RequestStatus createResources(Request request)
|
|
|
+ throws SystemException,
|
|
|
+ UnsupportedPropertyException,
|
|
|
+ ResourceAlreadyExistsException,
|
|
|
+ NoSuchParentResourceException {
|
|
|
+
|
|
|
+ for (Map<String, Object> properties : request.getProperties()) {
|
|
|
+ createResources(getCreateCommand(properties));
|
|
|
+ }
|
|
|
+ notifyCreate(Resource.Type.Artifact, request);
|
|
|
+
|
|
|
+ return getRequestStatus(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<Resource> getResources(Request request, Predicate predicate)
|
|
|
+ throws SystemException,
|
|
|
+ UnsupportedPropertyException,
|
|
|
+ NoSuchResourceException,
|
|
|
+ NoSuchParentResourceException {
|
|
|
+
|
|
|
+ Set<Map<String, Object>> requestProps = getPropertyMaps(predicate);
|
|
|
+ Set<Resource> resources = new LinkedHashSet<Resource>();
|
|
|
+
|
|
|
+ for (Map<String, Object> props : requestProps) {
|
|
|
+ resources.addAll(getResources(getGetCommand(request, predicate, props)));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (resources.isEmpty() && isInstanceRequest(requestProps)) {
|
|
|
+ throw new NoSuchResourceException(
|
|
|
+ "The requested resource doesn't exist: Artifact not found, " + predicate);
|
|
|
+ }
|
|
|
+ return resources;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public RequestStatus updateResources(Request request, Predicate predicate)
|
|
|
+ throws SystemException,
|
|
|
+ UnsupportedPropertyException,
|
|
|
+ NoSuchResourceException,
|
|
|
+ NoSuchParentResourceException {
|
|
|
+
|
|
|
+ throw new UnsupportedOperationException("Update not currently supported for Artifact resources");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public RequestStatus deleteResources(Predicate predicate)
|
|
|
+ throws SystemException,
|
|
|
+ UnsupportedPropertyException,
|
|
|
+ NoSuchResourceException,
|
|
|
+ NoSuchParentResourceException {
|
|
|
+
|
|
|
+ throw new UnsupportedOperationException("Delete not currently supported for Artifact resources");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a command to create the resource.
|
|
|
+ *
|
|
|
+ * @param properties request properties
|
|
|
+ *
|
|
|
+ * @return a new create command
|
|
|
+ */
|
|
|
+ private Command<Void> getCreateCommand(final Map<String, Object> properties) {
|
|
|
+ return new Command<Void>() {
|
|
|
+ @Override
|
|
|
+ public Void invoke() throws AmbariException {
|
|
|
+ // ensure that parent exists
|
|
|
+ validateParent(properties);
|
|
|
+
|
|
|
+ String artifactName = String.valueOf(properties.get(ARTIFACT_NAME_PROPERTY));
|
|
|
+ TreeMap<String, String> foreignKeyMap = createForeignKeyMap(properties);
|
|
|
+
|
|
|
+ if (artifactDAO.findByNameAndForeignKeys(artifactName, foreignKeyMap) != null) {
|
|
|
+ throw new DuplicateResourceException(String.format(
|
|
|
+ "Attempted to create an artifact which already exists, artifact_name='%s', foreign_keys='%s'",
|
|
|
+ artifactName, getRequestForeignKeys(properties)));
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG.debug("Creating Artifact Resource with name '{}'. Parent information: {}",
|
|
|
+ artifactName, getRequestForeignKeys(properties));
|
|
|
+
|
|
|
+ artifactDAO.create(toEntity(properties));
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a command to get the requested resources.
|
|
|
+ *
|
|
|
+ * @param properties request properties
|
|
|
+ *
|
|
|
+ * @return a new get command
|
|
|
+ */
|
|
|
+ private Command<Set<Resource>> getGetCommand(final Request request,
|
|
|
+ final Predicate predicate,
|
|
|
+ final Map<String, Object> properties) {
|
|
|
+ return new Command<Set<Resource>>() {
|
|
|
+ @Override
|
|
|
+ public Set<Resource> invoke() throws AmbariException {
|
|
|
+ String name = (String) properties.get(ARTIFACT_NAME_PROPERTY);
|
|
|
+ validateParent(properties);
|
|
|
+
|
|
|
+ Set<Resource> matchingResources = new HashSet<Resource>();
|
|
|
+ TreeMap<String, String> foreignKeys = createForeignKeyMap(properties);
|
|
|
+ Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
|
|
|
+ if (name != null) {
|
|
|
+ // find instance using name and foreign keys
|
|
|
+ ArtifactEntity entity = artifactDAO.findByNameAndForeignKeys(name, foreignKeys);
|
|
|
+ if (entity != null) {
|
|
|
+ Resource instance = (toResource(entity, requestPropertyIds));
|
|
|
+ if (predicate.evaluate(instance)) {
|
|
|
+ matchingResources.add(instance);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // find collection using foreign keys only
|
|
|
+ List<ArtifactEntity> results = artifactDAO.findByForeignKeys(foreignKeys);
|
|
|
+ for (ArtifactEntity entity : results) {
|
|
|
+ Resource resource = toResource(entity, requestPropertyIds);
|
|
|
+ if (predicate.evaluate(resource)) {
|
|
|
+ matchingResources.add(resource);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return matchingResources;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Validate that parent resources exist.
|
|
|
+ *
|
|
|
+ * @param properties request properties
|
|
|
+ *
|
|
|
+ * @throws ParentObjectNotFoundException if the parent resource doesn't exist
|
|
|
+ * @throws AmbariException if an error occurred while attempting to validate the parent
|
|
|
+ */
|
|
|
+ private void validateParent(Map<String, Object> properties) throws AmbariException {
|
|
|
+ Resource.Type parentType = getRequestType(properties);
|
|
|
+ if (! typeRegistrations.get(parentType).instanceExists(keyPropertyIds, properties)) {
|
|
|
+ throw new ParentObjectNotFoundException(String.format(
|
|
|
+ "Parent resource doesn't exist: %s", getRequestForeignKeys(properties)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get the type of the parent resource from the request properties.
|
|
|
+ *
|
|
|
+ * @param properties request properties
|
|
|
+ *
|
|
|
+ * @return the parent resource type based on the request properties
|
|
|
+ *
|
|
|
+ * @throws AmbariException if unable to determine the parent resource type
|
|
|
+ */
|
|
|
+ private Resource.Type getRequestType(Map<String, Object> properties) throws AmbariException {
|
|
|
+ Set<String> requestFKs = getRequestForeignKeys(properties).keySet();
|
|
|
+ for (TypeRegistration registration : typeRegistrations.values()) {
|
|
|
+ Collection<String> typeFKs = new HashSet<String>(registration.getForeignKeyInfo().values());
|
|
|
+ typeFKs.add(registration.getFKPropertyName());
|
|
|
+ if (requestFKs.equals(typeFKs)) {
|
|
|
+ return registration.getType();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ throw new AmbariException("Couldn't determine resource type based on request properties");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get a map of foreign key to value for the given request properties.
|
|
|
+ * The foreign key map will only include the foreign key properties which
|
|
|
+ * are included in the request properties. This is useful for reporting
|
|
|
+ * errors back to the user.
|
|
|
+ * .
|
|
|
+ * @param properties request properties
|
|
|
+ *
|
|
|
+ * @return map of foreign key to value for the provided request properties
|
|
|
+ */
|
|
|
+ private Map<String, String> getRequestForeignKeys(Map<String, Object> properties) {
|
|
|
+ Map<String, String> requestFKs = new HashMap<String, String>();
|
|
|
+ for (String property : properties.keySet()) {
|
|
|
+ if (! property.equals(ARTIFACT_NAME_PROPERTY) && ! property.startsWith(ARTIFACT_DATA_PROPERTY)) {
|
|
|
+ requestFKs.put(property, String.valueOf(properties.get(property)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return requestFKs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Convert a map of properties to an artifact entity.
|
|
|
+ *
|
|
|
+ * @param properties property map
|
|
|
+ *
|
|
|
+ * @return new artifact entity
|
|
|
+ */
|
|
|
+ private ArtifactEntity toEntity(Map<String, Object> properties)
|
|
|
+ throws AmbariException {
|
|
|
+
|
|
|
+ String name = (String) properties.get(ARTIFACT_NAME_PROPERTY);
|
|
|
+ if (name == null || name.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("Artifact name must be provided");
|
|
|
+ }
|
|
|
+
|
|
|
+ ArtifactEntity artifact = new ArtifactEntity();
|
|
|
+ artifact.setArtifactName(name);
|
|
|
+ Map<String, Object> dataMap = new HashMap<String, Object>();
|
|
|
+ for (Map.Entry<String, Object> entry : properties.entrySet()) {
|
|
|
+ String key = entry.getKey();
|
|
|
+ //todo: should we handle scalar value?
|
|
|
+ if (key.startsWith(ARTIFACT_DATA_PROPERTY)) {
|
|
|
+ dataMap.put(key.split("/")[1], entry.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ artifact.setArtifactData(dataMap);
|
|
|
+ artifact.setForeignKeys(createForeignKeyMap(properties));
|
|
|
+
|
|
|
+ return artifact;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a map of foreign keys and values which can be persisted.
|
|
|
+ * This map will include the short fk names of the key properties as well
|
|
|
+ * as the 'persist id' representation of the value which is returned
|
|
|
+ * by the type registration.
|
|
|
+ *
|
|
|
+ * @param properties request properties
|
|
|
+ * @return an ordered map of key name to value
|
|
|
+ *
|
|
|
+ * @throws AmbariException an unexpected exception occurred
|
|
|
+ */
|
|
|
+ private TreeMap<String, String> createForeignKeyMap(Map<String, Object> properties) throws AmbariException {
|
|
|
+ TreeMap<String, String> foreignKeys = new TreeMap<String, String>();
|
|
|
+ for (String keyProperty : keyPropertyIds.values()) {
|
|
|
+ if (! keyProperty.equals(ARTIFACT_NAME_PROPERTY)) {
|
|
|
+ String origValue = (String) properties.get(keyProperty);
|
|
|
+ if (origValue != null && ! origValue.isEmpty()) {
|
|
|
+ TypeRegistration typeRegistration = typeRegistrationsByFK.get(keyProperty);
|
|
|
+ foreignKeys.put(typeRegistration.getShortFKPropertyName(), typeRegistration.toPersistId(origValue));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return foreignKeys;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a resource instance from an artifact entity.
|
|
|
+ * This will convert short fk property names to the full property name as well
|
|
|
+ * as converting the value from the 'persist id' representation which is written
|
|
|
+ * to the database.
|
|
|
+ *
|
|
|
+ * @param entity artifact entity
|
|
|
+ * @param requestedIds requested id's
|
|
|
+ *
|
|
|
+ * @return a new resource instance for the given artifact entity
|
|
|
+ */
|
|
|
+ private Resource toResource(ArtifactEntity entity, Set<String> requestedIds) throws AmbariException {
|
|
|
+ Resource resource = new ResourceImpl(Resource.Type.Artifact);
|
|
|
+ setResourceProperty(resource, ARTIFACT_NAME_PROPERTY, entity.getArtifactName(), requestedIds);
|
|
|
+ setResourceProperty(resource, ARTIFACT_DATA_PROPERTY, entity.getArtifactData(), requestedIds);
|
|
|
+
|
|
|
+ for (Map.Entry<String, String> entry : entity.getForeignKeys().entrySet()) {
|
|
|
+ TypeRegistration typeRegistration = typeRegistrationsByShortFK.get(entry.getKey());
|
|
|
+ setResourceProperty(resource, typeRegistration.getFKPropertyName(),
|
|
|
+ typeRegistration.fromPersistId(entry.getValue()), requestedIds);
|
|
|
+ }
|
|
|
+ return resource;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Determine if the request was for an instance resource.
|
|
|
+ *
|
|
|
+ * @param requestProps request properties
|
|
|
+ *
|
|
|
+ * @return true if the request was for a specific instance, false otherwise
|
|
|
+ */
|
|
|
+ private boolean isInstanceRequest(Set<Map<String, Object>> requestProps) {
|
|
|
+ return requestProps.size() == 1 &&
|
|
|
+ requestProps.iterator().next().get(ARTIFACT_NAME_PROPERTY) != null;
|
|
|
+ }
|
|
|
+
|
|
|
+ //todo: when static registration is changed to external registration, this interface
|
|
|
+ //todo: should be extracted as a first class interface.
|
|
|
+ /**
|
|
|
+ * Used to register a dynamic sub-resource with an existing resource type.
|
|
|
+ */
|
|
|
+ public static interface TypeRegistration {
|
|
|
+ /**
|
|
|
+ * Allows the management controller to be set on the registration.
|
|
|
+ * This is called as part of the registration process.
|
|
|
+ * For registrations that need access to the management controller,
|
|
|
+ * they should assign this controller to a member field.
|
|
|
+ *
|
|
|
+ * @param controller management controller
|
|
|
+ */
|
|
|
+ public void setManagementController(AmbariManagementController controller);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get the type of the registering resource.
|
|
|
+ *
|
|
|
+ * @return type of the register resource
|
|
|
+ */
|
|
|
+ public Resource.Type getType();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Full foreign key property name to use in the artifact resource.
|
|
|
+ * At this time, all foreign key properties should be in the "Artifacts" category.
|
|
|
+ *
|
|
|
+ * @return the absolute foreign key property name.
|
|
|
+ * For example: "Artifacts/cluster_name
|
|
|
+ */
|
|
|
+ //todo: use relative property names
|
|
|
+ public String getFKPropertyName();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Shortened foreign key name that is written to the database.
|
|
|
+ * This name doesn't need to be in any category but must be unique
|
|
|
+ * across all registrations.
|
|
|
+ *
|
|
|
+ * @return short fk name. For example: "cluster_name"
|
|
|
+ */
|
|
|
+ public String getShortFKPropertyName();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Convert the foreign key value to a value that is persisted to the database.
|
|
|
+ * In most cases this will be the original value.
|
|
|
+ * <p>
|
|
|
+ * An example of when this will be different is when the fk value value needs
|
|
|
+ * to be converted to the unique id for the resource.
|
|
|
+ * <p>
|
|
|
+ * For example, the cluster_name to the cluster_id.
|
|
|
+ * <p>
|
|
|
+ * This returned value will later be converted back to the normal form via
|
|
|
+ * {@link #fromPersistId(String)}.
|
|
|
+ *
|
|
|
+ * @param value normal form of the fk value used by the api
|
|
|
+ *
|
|
|
+ * @return persist id form of the fk value
|
|
|
+ *
|
|
|
+ * @throws AmbariException if unable to convert the value
|
|
|
+ */
|
|
|
+ public String toPersistId(String value) throws AmbariException;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Convert the persist id form of the foreign key which is written to the database
|
|
|
+ * to the form used by the api. In most cases, this will be the same.
|
|
|
+ * <p>
|
|
|
+ * This method takes the value returned from {@link #toPersistId(String)} and converts
|
|
|
+ * it back to the original value which is used by the api.
|
|
|
+ * <p>
|
|
|
+ * An example of this is the converting the cluster name to the cluster id in
|
|
|
+ * {@link #toPersistId(String)} and then back to the cluster name by this method. The
|
|
|
+ * api always uses the cluster name so we wouldn't want to return the id back as the
|
|
|
+ * value for a cluster_name foreign key.
|
|
|
+ *
|
|
|
+ * @param value persist id form of the fk value
|
|
|
+ *
|
|
|
+ * @return normal form of the fk value used by the api
|
|
|
+ *
|
|
|
+ * @throws AmbariException if unable to convert the value
|
|
|
+ */
|
|
|
+ public String fromPersistId(String value) throws AmbariException;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get a map of ancestor type to foreign key.
|
|
|
+ * <p>
|
|
|
+ * <b>Note: Currently, if a parent resource has also registered the same dynamic resource,
|
|
|
+ * the foreign key name used here has to match the value returned by the parent resource
|
|
|
+ * in {@link #getFKPropertyName()}</b>
|
|
|
+ *
|
|
|
+ * @return map of ancestor type to foreign key
|
|
|
+ */
|
|
|
+ //todo: look at the need to use the same name as specified by ancestors
|
|
|
+ public Map<Resource.Type, String> getForeignKeyInfo();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Determine if the instance identified by the provided properties exists.
|
|
|
+ *
|
|
|
+ * @param keyMap map of resource type to foreign key properties
|
|
|
+ * @param properties request properties
|
|
|
+ *
|
|
|
+ * @return true if the resource instance exists, false otherwise
|
|
|
+ *
|
|
|
+ * @throws AmbariException an exception occurs trying to determine if the instance exists
|
|
|
+ */
|
|
|
+ public boolean instanceExists(Map<Resource.Type, String> keyMap,
|
|
|
+ Map<String, Object> properties) throws AmbariException;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //todo: Registration should be done externally and these implementations should be moved
|
|
|
+ //todo: to a location where the registering resource definition has access to them.
|
|
|
+ /**
|
|
|
+ * Cluster resource registration.
|
|
|
+ */
|
|
|
+ private static class ClusterTypeRegistration implements TypeRegistration {
|
|
|
+ /**
|
|
|
+ * management controller instance
|
|
|
+ */
|
|
|
+ private AmbariManagementController controller = null;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * cluster name property name
|
|
|
+ */
|
|
|
+ private static final String CLUSTER_NAME = PropertyHelper.getPropertyId("Artifacts", "cluster_name");
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setManagementController(AmbariManagementController controller) {
|
|
|
+ this.controller = controller;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Resource.Type getType() {
|
|
|
+ return Resource.Type.Cluster;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getFKPropertyName() {
|
|
|
+ return CLUSTER_NAME;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getShortFKPropertyName() {
|
|
|
+ return "cluster";
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String toPersistId(String value) throws AmbariException {
|
|
|
+ return String.valueOf(controller.getClusters().getCluster(value).getClusterId());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String fromPersistId(String value) throws AmbariException {
|
|
|
+ return controller.getClusters().getClusterById(Long.valueOf(value)).getClusterName();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<Resource.Type, String> getForeignKeyInfo() {
|
|
|
+ return Collections.emptyMap();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean instanceExists(Map<Resource.Type, String> keyMap,
|
|
|
+ Map<String, Object> properties) throws AmbariException {
|
|
|
+ try {
|
|
|
+ String clusterName = String.valueOf(properties.get(CLUSTER_NAME));
|
|
|
+ controller.getClusters().getCluster(clusterName);
|
|
|
+ return true;
|
|
|
+ } catch (ObjectNotFoundException e) {
|
|
|
+ // doesn't exist
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Service resource registration.
|
|
|
+ */
|
|
|
+ private static class ServiceTypeRegistration implements TypeRegistration {
|
|
|
+ /**
|
|
|
+ * management controller instance
|
|
|
+ */
|
|
|
+ private AmbariManagementController controller = null;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * service name property name
|
|
|
+ */
|
|
|
+ private static final String SERVICE_NAME = PropertyHelper.getPropertyId("Artifacts", "service_name");
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setManagementController(AmbariManagementController controller) {
|
|
|
+ this.controller = controller;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Resource.Type getType() {
|
|
|
+ return Resource.Type.Service;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getFKPropertyName() {
|
|
|
+ return SERVICE_NAME;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getShortFKPropertyName() {
|
|
|
+ return "service";
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String toPersistId(String value) {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String fromPersistId(String value) {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<Resource.Type, String> getForeignKeyInfo() {
|
|
|
+ return Collections.singletonMap(Resource.Type.Cluster, "Artifacts/cluster_name");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean instanceExists(Map<Resource.Type, String> keyMap,
|
|
|
+ Map<String, Object> properties) throws AmbariException {
|
|
|
+
|
|
|
+ String clusterName = String.valueOf(properties.get(keyMap.get(Resource.Type.Cluster)));
|
|
|
+ try {
|
|
|
+ Cluster cluster = controller.getClusters().getCluster(clusterName);
|
|
|
+ cluster.getService(String.valueOf(properties.get(SERVICE_NAME)));
|
|
|
+ return true;
|
|
|
+ } catch (ObjectNotFoundException e) {
|
|
|
+ // doesn't exist
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|