/* * Copyright © 2016 Cask Data, Inc. * * Licensed 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 co.cask.cdap.data2.metadata.system; import co.cask.cdap.api.plugin.PluginClass; import co.cask.cdap.data2.metadata.dataset.MetadataDataset; import co.cask.cdap.data2.metadata.indexer.SchemaIndexer; import co.cask.cdap.data2.metadata.store.MetadataStore; import co.cask.cdap.proto.Id; import co.cask.cdap.proto.metadata.MetadataScope; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; /** * A class to write {@link MetadataScope#SYSTEM} metadata for an {@link Id.NamespacedId entity}. */ public abstract class AbstractSystemMetadataWriter implements SystemMetadataWriter { protected static final String SCHEMA_FIELD_PROPERTY_PREFIX = "schema"; protected static final String PLUGIN_KEY_PREFIX = "plugin"; protected static final String PLUGIN_VERSION_KEY_PREFIX = "plugin-version"; protected static final String TTL_KEY = "ttl"; protected static final String DESCRIPTION = "description"; protected static final String CREATION_TIME = "creation-time"; // The following system properties should not get removed on metadata update // since they are not part of entity properties protected static final Set<String> PRESERVE_PROPERTIES = ImmutableSet.of(CREATION_TIME, DESCRIPTION); private final MetadataStore metadataStore; private final Id.NamespacedId entityId; public AbstractSystemMetadataWriter(MetadataStore metadataStore, Id.NamespacedId entityId) { this.metadataStore = metadataStore; this.entityId = entityId; } /** * Define the {@link MetadataScope#SYSTEM system} metadata properties to add for this entity. * * @return A {@link Map} of properties to add to this {@link Id.NamespacedId entity} in {@link MetadataScope#SYSTEM} */ protected abstract Map<String, String> getSystemPropertiesToAdd(); /** * Define the {@link MetadataScope#SYSTEM system} tags to add for this entity. * * @return an array of tags to add to this {@link Id.NamespacedId entity} in {@link MetadataScope#SYSTEM} */ protected abstract String[] getSystemTagsToAdd(); /** * Define the {@link MetadataScope#SYSTEM system} schema to add for this entity. * * @return the schema as a {@link String} */ @Nullable protected String getSchemaToAdd() { return null; } /** * Updates the {@link MetadataScope#SYSTEM} metadata for this {@link Id.NamespacedId entity}. */ @Override public void write() { // Delete existing system metadata before writing new metadata Set<String> existingProperties = metadataStore.getProperties(MetadataScope.SYSTEM, entityId).keySet(); Sets.SetView<String> removeProperties = Sets.difference(existingProperties, PRESERVE_PROPERTIES); if (!removeProperties.isEmpty()) { String[] propertiesArray = removeProperties.toArray(new String[removeProperties.size()]); metadataStore.removeProperties(MetadataScope.SYSTEM, entityId, propertiesArray); } metadataStore.removeTags(MetadataScope.SYSTEM, entityId); // Now add the new metadata Map<String, String> properties = getSystemPropertiesToAdd(); if (properties.size() > 0) { metadataStore.setProperties(MetadataScope.SYSTEM, entityId, properties); } String[] tags = getSystemTagsToAdd(); if (tags.length > 0) { metadataStore.addTags(MetadataScope.SYSTEM, entityId, tags); } // if there is schema property then set that while providing schema indexer if (!Strings.isNullOrEmpty(getSchemaToAdd())) { metadataStore.setProperties(MetadataScope.SYSTEM, entityId, ImmutableMap.of(SCHEMA_FIELD_PROPERTY_PREFIX, getSchemaToAdd()), new SchemaIndexer()); } } protected void addPlugin(PluginClass pluginClass, @Nullable String version, ImmutableMap.Builder<String, String> properties) { String name = pluginClass.getName(); String type = pluginClass.getType(); // Need both name and type in the key because two plugins of different types could have the same name. // However, the composite of name + type is guaranteed to be unique properties.put( PLUGIN_KEY_PREFIX + MetadataDataset.KEYVALUE_SEPARATOR + name + MetadataDataset.KEYVALUE_SEPARATOR + type, name + MetadataDataset.KEYVALUE_SEPARATOR + type ); if (version != null) { properties.put( PLUGIN_VERSION_KEY_PREFIX + MetadataDataset.KEYVALUE_SEPARATOR + name + MetadataDataset.KEYVALUE_SEPARATOR + type, name + MetadataDataset.KEYVALUE_SEPARATOR + version ); } } }