/** * Creates a {@link MetadataEntity} representing the given datasetName. To create a {@link MetadataEntity} for a * dataset in a specified namespace please use {@link MetadataEntity#ofDataset(String, String)}. * * @param datasetName the name of the dataset * @return {@link MetadataEntity} representing the dataset name */ public static MetadataEntity ofDataset(String datasetName) { return builder().appendAsType(MetadataEntity.DATASET, datasetName).build(); }
/** * If the MetadataEntity Builder key-value represent an application or artifact which is versioned in CDAP i.e. their * metadata entity representation ends with 'version' rather than 'application' or 'artifact' and the type is also * set to 'version' then for backward compatibility of rest end points return an updated builder which has the * correct type. This is only needed in 5.0 for backward compatibility of the rest endpoint. * From 5.0 and later the rest end point must be called with a query parameter which specify the type of the * metadata entity if the type is not the last key. (CDAP-13678) */ @VisibleForTesting static MetadataEntity.Builder makeBackwardCompatible(MetadataEntity.Builder builder) { MetadataEntity entity = builder.build(); List<MetadataEntity.KeyValue> entityKeyValues = StreamSupport.stream(entity.spliterator(), false) .collect(Collectors.toList()); if (entityKeyValues.size() == 3 && entity.getType().equals(MetadataEntity.VERSION) && (entityKeyValues.get(1).getKey().equals(MetadataEntity.ARTIFACT) || entityKeyValues.get(1).getKey().equals(MetadataEntity.APPLICATION))) { // this is artifact or application so update the builder MetadataEntity.Builder actualEntityBuilder = MetadataEntity.builder(); // namespace actualEntityBuilder.append(entityKeyValues.get(0).getKey(), entityKeyValues.get(0).getValue()); // application or artifact (so append as type) actualEntityBuilder.appendAsType(entityKeyValues.get(1).getKey(), entityKeyValues.get(1).getValue()); // version detail actualEntityBuilder.append(entityKeyValues.get(2).getKey(), entityKeyValues.get(2).getValue()); return actualEntityBuilder; } return builder; }
@Override public MetadataEntity toMetadataEntity() { return MetadataEntity.ofDataset(namespace, dataset); }
/** * @return a {@link String} which describes the {@link MetadataEntity} for a user in plain english. * If the {@link MetadataEntity} represents a known CDAP entity then the description is worded to show relations * in the hierarchy. */ public String getDescription() { return getDescription(new StringBuilder(), getType()); }
/** * Returns a List of {@link KeyValue} till the given splitKey (inclusive) * * @param splitKey the splitKey (inclusive) * @return List of {@link KeyValue} */ public List<MetadataEntity.KeyValue> head(String splitKey) { splitKey = splitKey.toLowerCase(); if (!containsKey(splitKey)) { throw new IllegalArgumentException(String.format("The given key %s does not exists in %s", splitKey, toString())); } List<MetadataEntity.KeyValue> subParts = new ArrayList<>(); for (KeyValue keyValue : this) { subParts.add(keyValue); if (keyValue.getKey().equalsIgnoreCase(splitKey)) { // reached till the key which is inclusive so stop break; } } return subParts; }
@Test public void testSearchOnTypes() throws Exception { MetadataEntity myField1 = MetadataEntity.builder(MetadataEntity.ofDataset(NamespaceId.DEFAULT.getEntityName(), "myDs")) .appendAsType("field", "myField1").build(); MetadataEntity myField2 = MetadataEntity.builder(MetadataEntity.ofDataset(NamespaceId.DEFAULT.getEntityName(), "myDs")) .appendAsType("field", "myField2").build(); final MetadataEntry myFieldEntry1 = new MetadataEntry(myField1, "testKey1", "testValue1"); final MetadataEntry myFieldEntry2 = new MetadataEntry(myField2, "testKey2", "testValue2"); txnl.execute(() -> { dataset.addProperty(myField1, "testKey1", "testValue1"); dataset.addProperty(myField2, "testKey2", "testValue2"); }); // Search for it based on value txnl.execute(() -> { List<MetadataEntry> results = searchByDefaultIndex("default", "field:myField1", ImmutableSet.of(EntityTypeSimpleName.ALL)); Assert.assertEquals(ImmutableList.of(myFieldEntry1), results); // should return both fields results = searchByDefaultIndex("default", "field:myFie*", ImmutableSet.of(EntityTypeSimpleName.ALL)); Assert.assertEquals(ImmutableList.of(myFieldEntry1, myFieldEntry2), results); results = searchByDefaultIndex("default", "field*", ImmutableSet.of(EntityTypeSimpleName.ALL)); Assert.assertEquals(ImmutableList.of(myFieldEntry1, myFieldEntry2), results); }); }
/** * Returns the EntityId represented by the given MetadataEntity. Note: Custom MetadataEntity cannot be converted * into EntityId hence this call is only safe to be called if the MetadataEntity does represent an EntityId and can * actually be converted to an EntityId. * @param metadataEntity the MetadataEntity which needs to be converted to EntityId * @return the EntityId * @throws IllegalArgumentException if the metadataEntity does not represent an EntityId and is a custom * metadataEntity. */ public static <T extends EntityId> T fromMetadataEntity(MetadataEntity metadataEntity) { // check that the type of teh metadata entity is known type EntityType.valueOf(metadataEntity.getType().toUpperCase()); return getSelfOrParentEntityId(metadataEntity); }
private String getDescription(StringBuilder builder, String type) { switch (type) { case MetadataEntity.NAMESPACE: builder.append(String.format("%s: %s", MetadataEntity.NAMESPACE, getValue(MetadataEntity.NAMESPACE))); return builder.toString(); case MetadataEntity.APPLICATION: String description = String.format("%s: %s", MetadataEntity.APPLICATION, getValue(MetadataEntity.APPLICATION)); if (containsKey(MetadataEntity.VERSION)) { description = String.format("%s of %s: %s", description, MetadataEntity.VERSION, getValue(MetadataEntity.VERSION)); return getDescription(builder, MetadataEntity.NAMESPACE); case MetadataEntity.ARTIFACT: builder.append(String.format("%s: %s of %s: %s deployed in ", MetadataEntity.ARTIFACT, getValue(MetadataEntity.ARTIFACT), MetadataEntity.VERSION, getValue(MetadataEntity.VERSION))); return getDescription(builder, MetadataEntity.NAMESPACE); case MetadataEntity.DATASET: builder.append(String.format("%s: %s which exists in ", MetadataEntity.DATASET, getValue(MetadataEntity.DATASET))); return getDescription(builder, MetadataEntity.NAMESPACE); case MetadataEntity.PROGRAM: builder.append(String.format("%s: %s in ", getValue(MetadataEntity.TYPE).toLowerCase(), getValue(MetadataEntity.PROGRAM))); return getDescription(builder, MetadataEntity.APPLICATION); case MetadataEntity.SCHEDULE: builder.append(String.format("%s: %s in ", MetadataEntity.SCHEDULE, getValue(MetadataEntity.SCHEDULE))); return getDescription(builder, MetadataEntity.APPLICATION);
private String addQueryParams(String path, MetadataEntity metadataEntity, @Nullable MetadataScope scope, boolean aggregateRun) { StringBuilder builder = new StringBuilder(path); String prefix = "?"; if (!Iterables.getLast(metadataEntity.getKeys()).equalsIgnoreCase(metadataEntity.getType())) { // if last leaf node is not the entity type specify it through query para builder.append(prefix); builder.append("type="); builder.append(metadataEntity.getType()); prefix = "&"; } // the default value of aggregateRun is true so in the case it is false we need to include it as query param if (!aggregateRun) { builder.append(prefix); builder.append("aggregateRun="); builder.append(false); prefix = "&"; } if (scope == null) { return builder.toString(); } else { builder.append(prefix); builder.append("scope="); builder.append(scope); } return builder.toString(); } }
List<MetadataEntity.KeyValue> extractedParts = metadataEntity.head(entityType.toString()); String version = metadataEntity.containsKey(MetadataEntity.VERSION) ? metadataEntity.getValue(MetadataEntity.VERSION) : ApplicationId.DEFAULT_VERSION; if (entityType == EntityType.APPLICATION) { if (!metadataEntity.containsKey(MetadataEntity.VERSION)) { extractedParts.add(2, new MetadataEntity.KeyValue(MetadataEntity.VERSION, version)); extractedParts = metadataEntity.head(MetadataEntity.VERSION);
@Test public void testPublishing() { generateMetadataUpdates(); // Audit messages for metadata changes List<AuditMessage> actualAuditMessages = new ArrayList<>(); String systemNs = NamespaceId.SYSTEM.getNamespace(); for (AuditMessage auditMessage : auditPublisher.popMessages()) { // Ignore system audit messages if (auditMessage.getType() == AuditType.METADATA_CHANGE) { if (!systemNs.equalsIgnoreCase(auditMessage.getEntity().getValue(MetadataEntity.NAMESPACE))) { actualAuditMessages.add(auditMessage); } } } Assert.assertEquals(expectedAuditMessages, actualAuditMessages); }
public InvalidMetadataException(MetadataEntity metadataEntity, String message) { super(String.format("Unable to set metadata for %s. %s", metadataEntity.getDescription(), message)); this.metadataEntity = metadataEntity; }
/** * Finds a valid known CDAP entity which can be considered as the parent for the MetadataEntity by walking up the * key-value hierarchy of the MetadataEntity * * @param metadataEntity whose EntityType needs to be determined * @return {@link EntityType} of the given metadataEntity */ @Nullable private static EntityType findParentType(MetadataEntity metadataEntity) { List<String> keys = new ArrayList<>(); metadataEntity.getKeys().forEach(keys::add); int curIndex = keys.size() - 1; EntityType entityType = null; while (curIndex >= 0) { try { entityType = EntityType.valueOf(keys.get(curIndex).toUpperCase()); // found a valid entity type; break; } catch (IllegalArgumentException e) { // the current key is not a valid cdap entity type so try up in hierarchy curIndex--; } } return entityType; }
@Test public void testToEntityId() { // should be able to get get an EntityId if Metadata belong to a cdap entity id DatasetId myDs = NamespaceId.DEFAULT.dataset("myDs"); MetadataDataset.Record metadata1 = new MetadataDataset.Record(myDs); Assert.assertEquals(myDs, metadata1.getEntityId()); MetadataEntity metadataEntity = MetadataEntity.builder(MetadataEntity.ofDataset(NamespaceId.DEFAULT.getEntityName(), "myDs")) .appendAsType("field", "myField").build(); MetadataDataset.Record metadata2 = new MetadataDataset.Record(metadataEntity); try { metadata2.getEntityId(); Assert.fail(); } catch (IllegalArgumentException e) { // expected } } }
/** * Returns the EntityId represented by the given MetadataEntity. Note: Custom MetadataEntity cannot be converted * into EntityId hence this call is only safe to be called if the MetadataEntity does represent an EntityId and can * actually be converted to an EntityId. * @param metadataEntity the MetadataEntity which needs to be converted to EntityId * @return the EntityId * @throws IllegalArgumentException if the metadataEntity does not represent an EntityId and is a custom * metadataEntity. */ public static <T extends EntityId> T fromMetadataEntity(MetadataEntity metadataEntity) { // check that the type of teh metadata entity is known type EntityType.valueOf(metadataEntity.getType().toUpperCase()); return getSelfOrParentEntityId(metadataEntity); }