use of io.cdap.cdap.api.artifact.ArtifactRange in project cdap by cdapio.
the class ArtifactConfigReaderTest method testRead.
@Test
public void testRead() throws IOException, InvalidArtifactException {
ArtifactConfig validConfig = new ArtifactConfig(ImmutableSet.of(new ArtifactRange(NamespaceId.SYSTEM.getNamespace(), "a", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")), new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "b", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0"))), ImmutableSet.of(PluginClass.builder().setName("name").setType("type").setDescription("desc").setClassName("classname").setProperties(ImmutableMap.of("x", new PluginPropertyField("x", "some field", "int", true, false), "y", new PluginPropertyField("y", "some other field", "string", false, false))).build()), ImmutableMap.of("k1", "v1", "k2", "v2"));
File configFile = new File(tmpFolder.newFolder(), "r1-1.0.0.json");
try (BufferedWriter writer = Files.newWriter(configFile, Charsets.UTF_8)) {
writer.write(validConfig.toString());
}
Assert.assertEquals(validConfig, configReader.read(Id.Namespace.DEFAULT, configFile));
}
use of io.cdap.cdap.api.artifact.ArtifactRange in project cdap by cdapio.
the class ArtifactConfigReaderTest method testInvalidParentNamespace.
@Test(expected = InvalidArtifactException.class)
public void testInvalidParentNamespace() throws IOException, InvalidArtifactException {
ArtifactConfig badConfig = new ArtifactConfig(ImmutableSet.of(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "b", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0"))), ImmutableSet.<PluginClass>of(), ImmutableMap.<String, String>of());
File configFile = new File(tmpFolder.newFolder(), "r1-1.0.0.json");
try (BufferedWriter writer = Files.newWriter(configFile, Charsets.UTF_8)) {
writer.write(badConfig.toString());
}
configReader.read(Id.Namespace.SYSTEM, configFile);
}
use of io.cdap.cdap.api.artifact.ArtifactRange in project cdap by cdapio.
the class ArtifactStore method writeMeta.
// write a new artifact snapshot and clean up the old snapshot data
private void writeMeta(StructuredTableContext context, Id.Artifact artifactId, ArtifactData data) throws IOException {
// write to artifact data table
StructuredTable artifactDataTable = getTable(context, StoreDefinition.ArtifactStore.ARTIFACT_DATA_TABLE);
ArtifactCell artifactCell = new ArtifactCell(artifactId);
artifactDataTable.upsert(concatFields(artifactCell.keys, Collections.singleton(Fields.stringField(StoreDefinition.ArtifactStore.ARTIFACT_DATA_FIELD, GSON.toJson(data)))));
ArtifactClasses classes = data.meta.getClasses();
Location artifactLocation = Locations.getLocationFromAbsolutePath(locationFactory, data.getLocationPath());
// write appClass metadata
StructuredTable appTable = getTable(context, StoreDefinition.ArtifactStore.APP_DATA_TABLE);
ArtifactCell artifactkeys = new ArtifactCell(artifactId);
for (ApplicationClass appClass : classes.getApps()) {
// a:{namespace}:{classname}
AppClassKey appClassKey = new AppClassKey(artifactId.getNamespace().toEntityId(), appClass.getClassName());
Field<String> appDataField = Fields.stringField(StoreDefinition.ArtifactStore.APP_DATA_FIELD, GSON.toJson(new AppData(appClass, artifactLocation)));
appTable.upsert(concatFields(appClassKey.keys, artifactkeys.keys, Collections.singleton(appDataField)));
}
// write pluginClass metadata, we loop twice to only access to one table at a time to prevent deadlock
StructuredTable pluginTable = getTable(context, StoreDefinition.ArtifactStore.PLUGIN_DATA_TABLE);
for (PluginClass pluginClass : classes.getPlugins()) {
// write metadata for each artifact this plugin extends
for (ArtifactRange artifactRange : data.meta.getUsableBy()) {
PluginKeyPrefix pluginKey = new PluginKeyPrefix(artifactRange.getNamespace(), artifactRange.getName(), pluginClass.getType(), pluginClass.getName());
Field<String> pluginDataField = Fields.stringField(StoreDefinition.ArtifactStore.PLUGIN_DATA_FIELD, GSON.toJson(new PluginData(pluginClass, artifactLocation, artifactRange)));
pluginTable.upsert(concatFields(pluginKey.keys, artifactkeys.keys, Collections.singleton(pluginDataField)));
}
}
// write universal plugin class metadata
StructuredTable uniPluginTable = getTable(context, StoreDefinition.ArtifactStore.UNIV_PLUGIN_DATA_TABLE);
for (PluginClass pluginClass : classes.getPlugins()) {
// by any other artifact in the same namespace.
if (data.meta.getUsableBy().isEmpty()) {
// Write a special entry for plugin that doesn't have parent, which means any artifact can use it
UniversalPluginKeyPrefix pluginKey = new UniversalPluginKeyPrefix(artifactId.getNamespace().getId(), pluginClass.getType(), pluginClass.getName());
Field<String> pluginDataField = Fields.stringField(StoreDefinition.ArtifactStore.PLUGIN_DATA_FIELD, GSON.toJson(new PluginData(pluginClass, artifactLocation, null)));
uniPluginTable.upsert(concatFields(pluginKey.keys, artifactkeys.keys, Collections.singleton(pluginDataField)));
}
}
}
use of io.cdap.cdap.api.artifact.ArtifactRange in project cdap by cdapio.
the class DefaultArtifactRepository method shouldUpdateSytemArtifact.
private boolean shouldUpdateSytemArtifact(ArtifactDetail currentArtifactDetail, SystemArtifactInfo systemArtifactInfo) {
if (!currentArtifactDetail.getDescriptor().getArtifactId().getVersion().isSnapshot()) {
// if it's not a snapshot, don't bother trying to update it since artifacts are immutable
return false;
}
// For snapshots check if it's different. Artifact update is disruptive, so we spend some cycles
// to check if it's really needed
Set<ArtifactRange> parents = systemArtifactInfo.getConfig().getParents();
if (!Objects.equals(parents, currentArtifactDetail.getMeta().getUsableBy())) {
return true;
}
if (!Objects.equals(systemArtifactInfo.getConfig().getProperties(), currentArtifactDetail.getMeta().getProperties())) {
return true;
}
Set<PluginClass> additionalPlugins = systemArtifactInfo.getConfig().getPlugins();
if (additionalPlugins != null && !currentArtifactDetail.getMeta().getClasses().getPlugins().containsAll(additionalPlugins)) {
return true;
}
try (InputStream stream1 = currentArtifactDetail.getDescriptor().getLocation().getInputStream();
InputStream stream2 = new FileInputStream(systemArtifactInfo.getArtifactFile())) {
return !IOUtils.contentEquals(stream1, stream2);
} catch (IOException e) {
// In case of any IO problems, jsut update it
return true;
}
}
use of io.cdap.cdap.api.artifact.ArtifactRange in project cdap by cdapio.
the class DefaultArtifactRepository method getParentArtifactDescriptors.
/**
* Get {@link ArtifactDescriptor} of parent and grandparent (if any) artifacts for the given artifact.
*
* @param artifactId the id of the artifact for which to find its parent and grandparent {@link ArtifactDescriptor}
* @param parentArtifacts the ranges of parents to find
* @return {@link ArtifactDescriptor} of parent and grandparent (if any) artifacts, in that specific order
* @throws ArtifactRangeNotFoundException if none of the parents could be found
* @throws InvalidArtifactException if one of the parents also has parents
*/
private List<ArtifactDescriptor> getParentArtifactDescriptors(Id.Artifact artifactId, Set<ArtifactRange> parentArtifacts) throws ArtifactRangeNotFoundException, InvalidArtifactException {
List<ArtifactDetail> parents = new ArrayList<>();
for (ArtifactRange parentRange : parentArtifacts) {
parents.addAll(artifactStore.getArtifacts(parentRange, Integer.MAX_VALUE, ArtifactSortOrder.UNORDERED));
}
if (parents.isEmpty()) {
throw new ArtifactRangeNotFoundException(String.format("Artifact %s extends artifacts '%s' that do not exist", artifactId, Joiner.on('/').join(parentArtifacts)));
}
ArtifactDescriptor parentArtifact = null;
ArtifactDescriptor grandparentArtifact = null;
// complicated dependency trees that are hard to manage.
for (ArtifactDetail parent : parents) {
Set<ArtifactRange> grandparentRanges = parent.getMeta().getUsableBy();
for (ArtifactRange grandparentRange : grandparentRanges) {
// if the parent as the child as a parent (cyclic dependency)
if (grandparentRange.getNamespace().equals(artifactId.getNamespace().getId()) && grandparentRange.getName().equals(artifactId.getName()) && grandparentRange.versionIsInRange(artifactId.getVersion())) {
throw new InvalidArtifactException(String.format("Invalid artifact '%s': cyclic dependency. Parent '%s' has artifact '%s' as a parent.", artifactId, parent.getDescriptor().getArtifactId(), artifactId));
}
List<ArtifactDetail> grandparents = artifactStore.getArtifacts(grandparentRange, Integer.MAX_VALUE, ArtifactSortOrder.UNORDERED);
// check that no grandparent has parents
for (ArtifactDetail grandparent : grandparents) {
Set<ArtifactRange> greatGrandparents = grandparent.getMeta().getUsableBy();
if (!greatGrandparents.isEmpty()) {
throw new InvalidArtifactException(String.format("Invalid artifact '%s'. Grandparents of artifacts cannot have parents. Grandparent '%s' has parents.", artifactId, grandparent.getDescriptor().getArtifactId()));
}
// assumes any grandparent will do
if (parentArtifact == null && grandparentArtifact == null) {
grandparentArtifact = grandparent.getDescriptor();
}
}
}
// assumes any parent will do
if (parentArtifact == null) {
parentArtifact = parent.getDescriptor();
}
}
List<ArtifactDescriptor> parentArtifactList = new ArrayList<>();
parentArtifactList.add(parentArtifact);
if (grandparentArtifact != null) {
parentArtifactList.add(grandparentArtifact);
}
return parentArtifactList;
}
Aggregations