Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
atlas
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
dataplatform
atlas
Commits
20608f02
Commit
20608f02
authored
Feb 04, 2016
by
Shwetha GS
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ATLAS-372 Expose entity deletion through REST API (dkantor via shwethags)
parent
d2b9b99f
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
358 additions
and
24 deletions
+358
-24
AtlasClient.java
client/src/main/java/org/apache/atlas/AtlasClient.java
+19
-0
EntityNotification.java
.../apache/atlas/notification/entity/EntityNotification.java
+1
-0
NotificationEntityChangeListener.java
...notification/entity/NotificationEntityChangeListener.java
+6
-0
release-log.txt
release-log.txt
+1
-0
MetadataRepository.java
.../java/org/apache/atlas/repository/MetadataRepository.java
+1
-1
GraphBackedMetadataRepository.java
...atlas/repository/graph/GraphBackedMetadataRepository.java
+4
-6
TypedInstanceToGraphMapper.java
...he/atlas/repository/graph/TypedInstanceToGraphMapper.java
+25
-5
DefaultMetadataService.java
...ava/org/apache/atlas/services/DefaultMetadataService.java
+22
-0
TestUtils.java
repository/src/test/java/org/apache/atlas/TestUtils.java
+7
-5
GraphBackedMetadataRepositoryDeleteEntitiesTest.java
...raph/GraphBackedMetadataRepositoryDeleteEntitiesTest.java
+8
-4
DefaultMetadataServiceTest.java
.../org/apache/atlas/service/DefaultMetadataServiceTest.java
+130
-0
EntityChangeListener.java
.../java/org/apache/atlas/listener/EntityChangeListener.java
+8
-0
MetadataService.java
.../main/java/org/apache/atlas/services/MetadataService.java
+9
-0
EntityResource.java
...n/java/org/apache/atlas/web/resources/EntityResource.java
+34
-3
EntityJerseyResourceIT.java
...rg/apache/atlas/web/resources/EntityJerseyResourceIT.java
+83
-0
No files found.
client/src/main/java/org/apache/atlas/AtlasClient.java
View file @
20608f02
...
...
@@ -166,6 +166,8 @@ public class AtlasClient {
UPDATE_ENTITY
(
BASE_URI
+
URI_ENTITY
,
HttpMethod
.
PUT
,
Response
.
Status
.
OK
),
UPDATE_ENTITY_PARTIAL
(
BASE_URI
+
URI_ENTITY
,
HttpMethod
.
POST
,
Response
.
Status
.
OK
),
LIST_ENTITIES
(
BASE_URI
+
URI_ENTITY
,
HttpMethod
.
GET
,
Response
.
Status
.
OK
),
DELETE_ENTITIES
(
BASE_URI
+
URI_ENTITY
,
HttpMethod
.
DELETE
,
Response
.
Status
.
OK
),
//Trait operations
ADD_TRAITS
(
BASE_URI
+
URI_ENTITY
,
HttpMethod
.
POST
,
Response
.
Status
.
CREATED
),
...
...
@@ -379,6 +381,23 @@ public class AtlasClient {
}
/**
* Delete the specified entities from the repository
*
* @param guids guids of entities to delete
* @return List of deleted entity guids
* @throws AtlasServiceException
*/
public
List
<
String
>
deleteEntities
(
String
...
guids
)
throws
AtlasServiceException
{
API
api
=
API
.
DELETE_ENTITIES
;
WebResource
resource
=
getResource
(
api
);
for
(
String
guid
:
guids
)
{
resource
=
resource
.
queryParam
(
GUID
.
toLowerCase
(),
guid
);
}
JSONObject
jsonResponse
=
callAPIWithResource
(
API
.
DELETE_ENTITIES
,
resource
);
return
extractResults
(
jsonResponse
,
GUID
);
}
/**
* Get an entity given the entity id
* @param guid entity id
* @return result object
...
...
notification/src/main/java/org/apache/atlas/notification/entity/EntityNotification.java
View file @
20608f02
...
...
@@ -33,6 +33,7 @@ public interface EntityNotification {
enum
OperationType
{
ENTITY_CREATE
,
ENTITY_UPDATE
,
ENTITY_DELETE
,
TRAIT_ADD
,
TRAIT_DELETE
}
...
...
notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
View file @
20608f02
...
...
@@ -76,9 +76,15 @@ public class NotificationEntityChangeListener implements EntityChangeListener {
notifyOfEntityEvent
(
Collections
.
singleton
(
entity
),
EntityNotification
.
OperationType
.
TRAIT_DELETE
);
}
@Override
public
void
onEntitiesDeleted
(
Collection
<
ITypedReferenceableInstance
>
entities
)
throws
AtlasException
{
notifyOfEntityEvent
(
entities
,
EntityNotification
.
OperationType
.
ENTITY_DELETE
);
}
// ----- helper methods -------------------------------------------------
// send notification of entity change
private
void
notifyOfEntityEvent
(
Collection
<
ITypedReferenceableInstance
>
entityDefinitions
,
EntityNotification
.
OperationType
operationType
)
throws
AtlasException
{
...
...
release-log.txt
View file @
20608f02
...
...
@@ -7,6 +7,7 @@ ATLAS-409 Atlas will not import avro tables with schema read from a file (dosset
ATLAS-379 Create sqoop and falcon metadata addons (venkatnrangan,bvellanki,sowmyaramesh via shwethags)
ALL CHANGES:
ATLAS-372 Expose entity deletion through REST API (dkantor via shwethags)
ATLAS-452 Exceptions while running HiveHookIT#testAlterTableRename (shwethags)
ATLAS-388 UI : On creating Tag, the page to be reset for creating new Tag (Anilg via shwethags)
ATLAS-199 webapp build fails (grunt + tests) (sanjayp via shwethags)
...
...
repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
View file @
20608f02
...
...
@@ -110,7 +110,7 @@ public interface MetadataRepository {
* @return guids of deleted entities
* @throws RepositoryException
*/
List
<
String
>
deleteEntities
(
String
...
guids
)
throws
RepositoryException
;
TypeUtils
.
Pair
<
List
<
String
>,
List
<
ITypedReferenceableInstance
>>
deleteEntities
(
List
<
String
>
guids
)
throws
RepositoryException
;
// Trait management functions
...
...
repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
View file @
20608f02
...
...
@@ -30,16 +30,13 @@ import org.apache.atlas.GraphTransaction;
import
org.apache.atlas.repository.Constants
;
import
org.apache.atlas.repository.MetadataRepository
;
import
org.apache.atlas.repository.RepositoryException
;
import
org.apache.atlas.repository.graph.TypedInstanceToGraphMapper.Operation
;
import
org.apache.atlas.typesystem.ITypedReferenceableInstance
;
import
org.apache.atlas.typesystem.ITypedStruct
;
import
org.apache.atlas.typesystem.exception.EntityExistsException
;
import
org.apache.atlas.typesystem.exception.EntityNotFoundException
;
import
org.apache.atlas.typesystem.persistence.Id
;
import
org.apache.atlas.typesystem.types.AttributeInfo
;
import
org.apache.atlas.typesystem.types.ClassType
;
import
org.apache.atlas.typesystem.types.IDataType
;
import
org.apache.atlas.typesystem.types.TraitType
;
import
org.apache.atlas.typesystem.types.TypeSystem
;
import
org.apache.atlas.typesystem.types.TypeUtils
;
import
org.slf4j.Logger
;
...
...
@@ -316,9 +313,9 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
@Override
@GraphTransaction
public
List
<
String
>
deleteEntities
(
String
...
guids
)
throws
RepositoryException
{
public
TypeUtils
.
Pair
<
List
<
String
>,
List
<
ITypedReferenceableInstance
>>
deleteEntities
(
List
<
String
>
guids
)
throws
RepositoryException
{
if
(
guids
==
null
||
guids
.
length
==
0
)
{
if
(
guids
==
null
||
guids
.
size
()
==
0
)
{
throw
new
IllegalArgumentException
(
"guids must be non-null and non-empty"
);
}
...
...
@@ -341,6 +338,7 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
throw
new
RepositoryException
(
e
);
}
}
return
instanceToGraphMapper
.
getDeletedEntities
();
return
new
TypeUtils
.
Pair
<>(
instanceToGraphMapper
.
getDeletedEntityGuids
(),
instanceToGraphMapper
.
getDeletedEntities
());
}
}
repository/src/main/java/org/apache/atlas/repository/graph/TypedInstanceToGraphMapper.java
View file @
20608f02
...
...
@@ -61,8 +61,8 @@ public final class TypedInstanceToGraphMapper {
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
TypedInstanceToGraphMapper
.
class
);
private
final
Map
<
Id
,
Vertex
>
idToVertexMap
=
new
HashMap
<>();
private
final
TypeSystem
typeSystem
=
TypeSystem
.
getInstance
();
private
final
List
<
String
>
deletedEntit
ie
s
=
new
ArrayList
<>();
private
final
List
<
String
>
deletedEntit
yGuid
s
=
new
ArrayList
<>();
private
final
List
<
ITypedReferenceableInstance
>
deletedEntities
=
new
ArrayList
<>();
private
final
GraphToTypedInstanceMapper
graphToTypedInstanceMapper
;
private
static
final
GraphHelper
graphHelper
=
GraphHelper
.
getInstance
();
...
...
@@ -688,7 +688,8 @@ public final class TypedInstanceToGraphMapper {
// Remove any underlying structs and composite entities owned by this entity.
mapInstanceToVertex
(
typedInstance
,
instanceVertex
,
classType
.
fieldMapping
().
fields
,
false
,
Operation
.
DELETE
);
deletedEntities
.
add
(
id
.
_getId
());
deletedEntityGuids
.
add
(
id
.
_getId
());
deletedEntities
.
add
(
typedInstance
);
}
/**
...
...
@@ -728,12 +729,31 @@ public final class TypedInstanceToGraphMapper {
/**
* Get the IDs of entities that have been deleted.
* Get the
GU
IDs of entities that have been deleted.
*
* @return
*/
List
<
String
>
getDeletedEntities
()
{
List
<
String
>
getDeletedEntityGuids
()
{
if
(
deletedEntityGuids
.
size
()
==
0
)
{
return
Collections
.
emptyList
();
}
else
{
return
Collections
.
unmodifiableList
(
deletedEntityGuids
);
}
}
/**
* Get the entities that have been deleted.
*
* @return
*/
List
<
ITypedReferenceableInstance
>
getDeletedEntities
()
{
if
(
deletedEntities
.
size
()
==
0
)
{
return
Collections
.
emptyList
();
}
else
{
return
Collections
.
unmodifiableList
(
deletedEntities
);
}
}
}
repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
View file @
20608f02
...
...
@@ -21,6 +21,7 @@ package org.apache.atlas.services;
import
com.google.common.base.Preconditions
;
import
com.google.common.collect.ImmutableList
;
import
com.google.inject.Provider
;
import
org.apache.atlas.AtlasClient
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.classification.InterfaceAudience
;
...
...
@@ -54,6 +55,7 @@ import org.apache.atlas.typesystem.types.StructTypeDefinition;
import
org.apache.atlas.typesystem.types.TraitType
;
import
org.apache.atlas.typesystem.types.TypeSystem
;
import
org.apache.atlas.typesystem.types.TypeUtils
;
import
org.apache.atlas.typesystem.types.TypeUtils.Pair
;
import
org.apache.atlas.typesystem.types.ValueConversionException
;
import
org.apache.atlas.typesystem.types.utils.TypesUtil
;
import
org.apache.atlas.utils.ParamChecker
;
...
...
@@ -65,6 +67,7 @@ import org.slf4j.LoggerFactory;
import
javax.inject.Inject
;
import
javax.inject.Singleton
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.HashMap
;
...
...
@@ -680,4 +683,23 @@ public class DefaultMetadataService implements MetadataService {
public
void
unregisterListener
(
EntityChangeListener
listener
)
{
entityChangeListeners
.
remove
(
listener
);
}
/* (non-Javadoc)
* @see org.apache.atlas.services.MetadataService#deleteEntities(java.lang.String)
*/
@Override
public
List
<
String
>
deleteEntities
(
List
<
String
>
deleteCandidateGuids
)
throws
AtlasException
{
ParamChecker
.
notEmpty
(
deleteCandidateGuids
,
"delete candidate guids cannot be empty"
);
Pair
<
List
<
String
>,
List
<
ITypedReferenceableInstance
>>
deleteEntitiesResult
=
repository
.
deleteEntities
(
deleteCandidateGuids
);
if
(
deleteEntitiesResult
.
right
.
size
()
>
0
)
{
onEntitiesDeleted
(
deleteEntitiesResult
.
right
);
}
return
deleteEntitiesResult
.
left
;
}
private
void
onEntitiesDeleted
(
List
<
ITypedReferenceableInstance
>
entities
)
throws
AtlasException
{
for
(
EntityChangeListener
listener
:
entityChangeListeners
)
{
listener
.
onEntitiesDeleted
(
entities
);
}
}
}
repository/src/test/java/org/apache/atlas/TestUtils.java
View file @
20608f02
...
...
@@ -23,6 +23,7 @@ import com.thinkaurelius.titan.core.TitanGraph;
import
com.tinkerpop.blueprints.Edge
;
import
com.tinkerpop.blueprints.Vertex
;
import
com.tinkerpop.blueprints.util.io.graphson.GraphSONWriter
;
import
org.apache.atlas.repository.graph.GraphHelper
;
import
org.apache.atlas.typesystem.ITypedReferenceableInstance
;
import
org.apache.atlas.typesystem.Referenceable
;
...
...
@@ -187,6 +188,7 @@ public final class TestUtils {
public
static
final
String
DATABASE_TYPE
=
"hive_database"
;
public
static
final
String
DATABASE_NAME
=
"foo"
;
public
static
final
String
TABLE_TYPE
=
"hive_table"
;
public
static
final
String
COLUMN_TYPE
=
"column_type"
;
public
static
final
String
TABLE_NAME
=
"bar"
;
public
static
final
String
CLASSIFICATION
=
"classification"
;
public
static
final
String
PII
=
"PII"
;
...
...
@@ -220,7 +222,7 @@ public final class TestUtils {
EnumTypeDefinition
enumTypeDefinition
=
new
EnumTypeDefinition
(
"tableType"
,
values
);
HierarchicalTypeDefinition
<
ClassType
>
columnsDefinition
=
createClassTypeDef
(
"column_type"
,
ImmutableList
.<
String
>
of
(),
createClassTypeDef
(
COLUMN_TYPE
,
ImmutableList
.<
String
>
of
(),
createRequiredAttrDef
(
"name"
,
DataTypes
.
STRING_TYPE
),
createRequiredAttrDef
(
"type"
,
DataTypes
.
STRING_TYPE
));
...
...
@@ -228,7 +230,7 @@ public final class TestUtils {
new
AttributeDefinition
[]{
createRequiredAttrDef
(
"name"
,
DataTypes
.
STRING_TYPE
),});
AttributeDefinition
[]
attributeDefinitions
=
new
AttributeDefinition
[]{
new
AttributeDefinition
(
"cols"
,
String
.
format
(
"array<%s>"
,
"column_type"
),
new
AttributeDefinition
(
"cols"
,
String
.
format
(
"array<%s>"
,
COLUMN_TYPE
),
Multiplicity
.
OPTIONAL
,
true
,
null
),
new
AttributeDefinition
(
"location"
,
DataTypes
.
STRING_TYPE
.
getName
(),
Multiplicity
.
OPTIONAL
,
false
,
null
),
...
...
@@ -256,7 +258,7 @@ public final class TestUtils {
null
),
new
AttributeDefinition
(
"sd"
,
STORAGE_DESC_TYPE
,
Multiplicity
.
REQUIRED
,
true
,
null
),
new
AttributeDefinition
(
"columns"
,
DataTypes
.
arrayTypeName
(
"column_type"
),
new
AttributeDefinition
(
"columns"
,
DataTypes
.
arrayTypeName
(
COLUMN_TYPE
),
Multiplicity
.
OPTIONAL
,
true
,
null
),
new
AttributeDefinition
(
"parameters"
,
new
DataTypes
.
MapType
(
DataTypes
.
STRING_TYPE
,
DataTypes
.
STRING_TYPE
).
getName
(),
Multiplicity
.
OPTIONAL
,
false
,
null
),};
...
...
@@ -277,7 +279,7 @@ public final class TestUtils {
String
.
format
(
"array<%s>"
,
DataTypes
.
STRING_TYPE
.
getName
()),
Multiplicity
.
OPTIONAL
,
false
,
null
),
// array of classes
new
AttributeDefinition
(
"columns"
,
String
.
format
(
"array<%s>"
,
"column_type"
),
new
AttributeDefinition
(
"columns"
,
String
.
format
(
"array<%s>"
,
COLUMN_TYPE
),
Multiplicity
.
OPTIONAL
,
true
,
null
),
// array of structs
new
AttributeDefinition
(
"partitions"
,
String
.
format
(
"array<%s>"
,
"partition_struct_type"
),
...
...
@@ -289,7 +291,7 @@ public final class TestUtils {
//map of classes -
new
AttributeDefinition
(
"columnsMap"
,
DataTypes
.
mapTypeName
(
DataTypes
.
STRING_TYPE
.
getName
(),
"column_type"
),
COLUMN_TYPE
),
Multiplicity
.
OPTIONAL
,
true
,
null
),
//map of structs
new
AttributeDefinition
(
"partitionsMap"
,
...
...
repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepositoryDeleteEntitiesTest.java
View file @
20608f02
...
...
@@ -21,6 +21,7 @@ package org.apache.atlas.repository.graph;
import
com.thinkaurelius.titan.core.TitanGraph
;
import
com.thinkaurelius.titan.core.util.TitanCleanup
;
import
com.tinkerpop.blueprints.Vertex
;
import
org.apache.atlas.RepositoryMetadataModule
;
import
org.apache.atlas.TestUtils
;
import
org.apache.atlas.discovery.graph.GraphBackedDiscoveryService
;
...
...
@@ -32,6 +33,7 @@ import org.apache.atlas.typesystem.exception.EntityNotFoundException;
import
org.apache.atlas.typesystem.types.ClassType
;
import
org.apache.atlas.typesystem.types.Multiplicity
;
import
org.apache.atlas.typesystem.types.TypeSystem
;
import
org.apache.atlas.typesystem.types.TypeUtils.Pair
;
import
org.testng.Assert
;
import
org.testng.annotations.AfterClass
;
import
org.testng.annotations.BeforeClass
;
...
...
@@ -39,7 +41,9 @@ import org.testng.annotations.Guice;
import
org.testng.annotations.Test
;
import
javax.inject.Inject
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
/**
...
...
@@ -114,8 +118,8 @@ public class GraphBackedMetadataRepositoryDeleteEntitiesTest {
vertexCount
=
countVertices
(
Constants
.
ENTITY_TYPE_PROPERTY_KEY
,
"SecurityClearance"
);
Assert
.
assertEquals
(
vertexCount
,
1
);
List
<
String
>
deletedEntities
=
repositoryService
.
deleteEntities
(
hrDeptGuid
);
Assert
.
assertTrue
(
deletedEntities
.
contains
(
hrDeptGuid
));
Pair
<
List
<
String
>,
List
<
ITypedReferenceableInstance
>>
deletedEntities
=
repositoryService
.
deleteEntities
(
Arrays
.
asList
(
hrDeptGuid
)
);
Assert
.
assertTrue
(
deletedEntities
.
left
.
contains
(
hrDeptGuid
));
// Verify Department entity and its contained Person entities were deleted.
verifyEntityDoesNotExist
(
hrDeptGuid
);
...
...
@@ -145,8 +149,8 @@ public class GraphBackedMetadataRepositoryDeleteEntitiesTest {
ITypedReferenceableInstance
employee
=
(
ITypedReferenceableInstance
)
listValue
;
String
employeeGuid
=
employee
.
getId
().
_getId
();
List
<
String
>
deletedEntities
=
repositoryService
.
deleteEntities
(
employeeGuid
);
Assert
.
assertTrue
(
deletedEntities
.
contains
(
employeeGuid
));
Pair
<
List
<
String
>,
List
<
ITypedReferenceableInstance
>>
deletedEntities
=
repositoryService
.
deleteEntities
(
Arrays
.
asList
(
employeeGuid
)
);
Assert
.
assertTrue
(
deletedEntities
.
left
.
contains
(
employeeGuid
));
verifyEntityDoesNotExist
(
employeeGuid
);
}
...
...
repository/src/test/java/org/apache/atlas/service/DefaultMetadataServiceTest.java
View file @
20608f02
...
...
@@ -22,14 +22,20 @@ import com.google.common.collect.ImmutableList;
import
com.google.inject.Inject
;
import
com.thinkaurelius.titan.core.TitanGraph
;
import
com.thinkaurelius.titan.core.util.TitanCleanup
;
import
org.apache.atlas.AtlasClient
;
import
org.apache.atlas.typesystem.exception.TypeNotFoundException
;
import
org.apache.atlas.typesystem.exception.EntityNotFoundException
;
import
org.apache.atlas.utils.ParamChecker
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.RepositoryMetadataModule
;
import
org.apache.atlas.TestUtils
;
import
org.apache.atlas.listener.EntityChangeListener
;
import
org.apache.atlas.repository.graph.GraphProvider
;
import
org.apache.atlas.services.MetadataService
;
import
org.apache.atlas.typesystem.IReferenceableInstance
;
import
org.apache.atlas.typesystem.IStruct
;
import
org.apache.atlas.typesystem.ITypedReferenceableInstance
;
import
org.apache.atlas.typesystem.Referenceable
;
import
org.apache.atlas.typesystem.Struct
;
import
org.apache.atlas.typesystem.TypesDef
;
...
...
@@ -49,6 +55,7 @@ import org.testng.annotations.Test;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.List
;
...
...
@@ -152,6 +159,12 @@ public class DefaultMetadataServiceTest {
return
entity
;
}
private
Referenceable
createColumnEntity
()
{
Referenceable
entity
=
new
Referenceable
(
TestUtils
.
COLUMN_TYPE
);
entity
.
set
(
"name"
,
RandomStringUtils
.
randomAlphanumeric
(
10
));
entity
.
set
(
"type"
,
"VARCHAR(32)"
);
return
entity
;
}
@Test
public
void
testCreateEntityWithUniqueAttribute
()
throws
Exception
{
//name is the unique attribute
...
...
@@ -685,4 +698,121 @@ public class DefaultMetadataServiceTest {
//expected
}
}
@Test
public
void
testDeleteEntities
()
throws
Exception
{
// Create 2 table entities, each with 3 composite column entities
Referenceable
dbEntity
=
createDBEntity
();
String
dbGuid
=
createInstance
(
dbEntity
);
Id
dbId
=
new
Id
(
dbGuid
,
0
,
TestUtils
.
DATABASE_TYPE
);
Referenceable
table1Entity
=
createTableEntity
(
dbId
);
Referenceable
table2Entity
=
createTableEntity
(
dbId
);
Referenceable
col1
=
createColumnEntity
();
Referenceable
col2
=
createColumnEntity
();
Referenceable
col3
=
createColumnEntity
();
table1Entity
.
set
(
"columns"
,
ImmutableList
.
of
(
col1
,
col2
,
col3
));
table2Entity
.
set
(
"columns"
,
ImmutableList
.
of
(
col1
,
col2
,
col3
));
createInstance
(
table1Entity
);
createInstance
(
table2Entity
);
// Retrieve the table entities from the repository,
// to get their guids and the composite column guids.
String
entityJson
=
metadataService
.
getEntityDefinition
(
TestUtils
.
TABLE_TYPE
,
"name"
,
(
String
)
table1Entity
.
get
(
"name"
));
Assert
.
assertNotNull
(
entityJson
);
table1Entity
=
InstanceSerialization
.
fromJsonReferenceable
(
entityJson
,
true
);
Object
val
=
table1Entity
.
get
(
"columns"
);
Assert
.
assertTrue
(
val
instanceof
List
);
List
<
IReferenceableInstance
>
table1Columns
=
(
List
<
IReferenceableInstance
>)
val
;
entityJson
=
metadataService
.
getEntityDefinition
(
TestUtils
.
TABLE_TYPE
,
"name"
,
(
String
)
table2Entity
.
get
(
"name"
));
Assert
.
assertNotNull
(
entityJson
);
table2Entity
=
InstanceSerialization
.
fromJsonReferenceable
(
entityJson
,
true
);
val
=
table2Entity
.
get
(
"columns"
);
Assert
.
assertTrue
(
val
instanceof
List
);
List
<
IReferenceableInstance
>
table2Columns
=
(
List
<
IReferenceableInstance
>)
val
;
// Register an EntityChangeListener to verify the notification mechanism
// is working for deleteEntities().
DeleteEntitiesChangeListener
listener
=
new
DeleteEntitiesChangeListener
();
metadataService
.
registerListener
(
listener
);
// Delete the table entities. The deletion should cascade
// to their composite columns.
JSONArray
deleteCandidateGuids
=
new
JSONArray
();
deleteCandidateGuids
.
put
(
table1Entity
.
getId
().
_getId
());
deleteCandidateGuids
.
put
(
table2Entity
.
getId
().
_getId
());
List
<
String
>
deletedGuids
=
metadataService
.
deleteEntities
(
Arrays
.
asList
(
table1Entity
.
getId
().
_getId
(),
table2Entity
.
getId
().
_getId
()));
// Verify that deleteEntities() response has guids for tables and their composite columns.
Assert
.
assertTrue
(
deletedGuids
.
contains
(
table1Entity
.
getId
().
_getId
()));
Assert
.
assertTrue
(
deletedGuids
.
contains
(
table2Entity
.
getId
().
_getId
()));
for
(
IReferenceableInstance
column
:
table1Columns
)
{
Assert
.
assertTrue
(
deletedGuids
.
contains
(
column
.
getId
().
_getId
()));
}
for
(
IReferenceableInstance
column
:
table2Columns
)
{
Assert
.
assertTrue
(
deletedGuids
.
contains
(
column
.
getId
().
_getId
()));
}
// Verify that tables and their composite columns have been deleted from the repository.
for
(
String
guid
:
deletedGuids
)
{
try
{
metadataService
.
getEntityDefinition
(
guid
);
Assert
.
fail
(
EntityNotFoundException
.
class
.
getSimpleName
()
+
" expected but not thrown. The entity with guid "
+
guid
+
" still exists in the repository after being deleted."
);
}
catch
(
EntityNotFoundException
e
)
{
// The entity does not exist in the repository, so deletion was successful.
}
}
// Verify that the listener was notified about the deleted entities.
Collection
<
ITypedReferenceableInstance
>
deletedEntitiesFromListener
=
listener
.
getDeletedEntities
();
Assert
.
assertNotNull
(
deletedEntitiesFromListener
);
Assert
.
assertEquals
(
deletedEntitiesFromListener
.
size
(),
deletedGuids
.
size
());
List
<
String
>
deletedGuidsFromListener
=
new
ArrayList
<>(
deletedGuids
.
size
());
for
(
ITypedReferenceableInstance
deletedEntity
:
deletedEntitiesFromListener
)
{
deletedGuidsFromListener
.
add
(
deletedEntity
.
getId
().
_getId
());
}
Assert
.
assertEquals
(
deletedGuidsFromListener
,
deletedGuids
);
}
private
static
class
DeleteEntitiesChangeListener
implements
EntityChangeListener
{
private
Collection
<
ITypedReferenceableInstance
>
deletedEntities_
;
@Override
public
void
onEntitiesAdded
(
Collection
<
ITypedReferenceableInstance
>
entities
)
throws
AtlasException
{
}
@Override
public
void
onEntitiesUpdated
(
Collection
<
ITypedReferenceableInstance
>
entities
)
throws
AtlasException
{
}
@Override
public
void
onTraitAdded
(
ITypedReferenceableInstance
entity
,
IStruct
trait
)
throws
AtlasException
{
}
@Override
public
void
onTraitDeleted
(
ITypedReferenceableInstance
entity
,
String
traitName
)
throws
AtlasException
{
}
@Override
public
void
onEntitiesDeleted
(
Collection
<
ITypedReferenceableInstance
>
entities
)
throws
AtlasException
{
deletedEntities_
=
entities
;
}
public
Collection
<
ITypedReferenceableInstance
>
getDeletedEntities
()
{
return
deletedEntities_
;
}
}
}
server-api/src/main/java/org/apache/atlas/listener/EntityChangeListener.java
View file @
20608f02
...
...
@@ -66,4 +66,12 @@ public interface EntityChangeListener {
* @throws AtlasException if the listener notification fails
*/
void
onTraitDeleted
(
ITypedReferenceableInstance
entity
,
String
traitName
)
throws
AtlasException
;
/**
* This is upon deleting entities from the repository.
*
* @param entities the deleted entities
* @throws AtlasException
*/
void
onEntitiesDeleted
(
Collection
<
ITypedReferenceableInstance
>
entities
)
throws
AtlasException
;
}
server-api/src/main/java/org/apache/atlas/services/MetadataService.java
View file @
20608f02
...
...
@@ -175,6 +175,15 @@ public interface MetadataService {
void
deleteTrait
(
String
guid
,
String
traitNameToBeDeleted
)
throws
AtlasException
;
/**
* Delete the specified entities from the repository
*
* @param guids entity guids to be deleted
* @return List of guids for deleted entities
* @throws AtlasException
*/
List
<
String
>
deleteEntities
(
List
<
String
>
guids
)
throws
AtlasException
;
/**
* Register a listener for entity change.
*
* @param listener the listener to register
...
...
webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
View file @
20608f02
...
...
@@ -21,14 +21,14 @@ package org.apache.atlas.web.resources;
import
com.google.common.base.Preconditions
;
import
org.apache.atlas.AtlasClient
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.services.MetadataService
;
import
org.apache.atlas.typesystem.Referenceable
;
import
org.apache.atlas.typesystem.exception.EntityExistsException
;
import
org.apache.atlas.typesystem.exception.EntityNotFoundException
;
import
org.apache.atlas.typesystem.exception.TypeNotFoundException
;
import
org.apache.atlas.utils.ParamChecker
;
import
org.apache.atlas.services.MetadataService
;
import
org.apache.atlas.typesystem.Referenceable
;
import
org.apache.atlas.typesystem.json.InstanceSerialization
;
import
org.apache.atlas.typesystem.types.ValueConversionException
;
import
org.apache.atlas.utils.ParamChecker
;
import
org.apache.atlas.web.util.Servlets
;
import
org.apache.commons.lang.StringUtils
;
import
org.codehaus.jettison.json.JSONArray
;
...
...
@@ -312,6 +312,37 @@ public class EntityResource {
}
/**
* Delete entities from the repository
*
* @param guids deletion candidate guids
* @param request
* @return response payload as json
*/
@DELETE
@Consumes
(
Servlets
.
JSON_MEDIA_TYPE
)
@Produces
(
Servlets
.
JSON_MEDIA_TYPE
)
public
Response
deleteEntities
(
@QueryParam
(
"guid"
)
List
<
String
>
guids
,
@Context
HttpServletRequest
request
)
{
try
{
List
<
String
>
deletedGuids
=
metadataService
.
deleteEntities
(
guids
);
JSONObject
response
=
new
JSONObject
();
response
.
put
(
AtlasClient
.
REQUEST_ID
,
Servlets
.
getRequestId
());
JSONArray
guidArray
=
new
JSONArray
(
deletedGuids
.
size
());
for
(
String
guid
:
deletedGuids
)
{
guidArray
.
put
(
guid
);
}
response
.
put
(
AtlasClient
.
GUID
,
guidArray
);
return
Response
.
ok
(
response
).
build
();
}
catch
(
AtlasException
|
IllegalArgumentException
e
)
{
LOG
.
error
(
"Unable to delete entities {}"
,
guids
,
e
);
throw
new
WebApplicationException
(
Servlets
.
getErrorResponse
(
e
,
Response
.
Status
.
BAD_REQUEST
));
}
catch
(
Throwable
e
)
{
LOG
.
error
(
"Unable to delete entities {}"
,
guids
,
e
);
throw
new
WebApplicationException
(
Servlets
.
getErrorResponse
(
e
,
Response
.
Status
.
INTERNAL_SERVER_ERROR
));
}
}
/**
* Fetch the complete definition of an entity given its GUID.
*
* @param guid GUID for the entity
...
...
webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
View file @
20608f02
...
...
@@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList;
import
com.google.inject.Inject
;
import
com.sun.jersey.api.client.ClientResponse
;
import
com.sun.jersey.api.client.WebResource
;
import
org.apache.atlas.AtlasClient
;
import
org.apache.atlas.AtlasServiceException
;
import
org.apache.atlas.notification.NotificationConsumer
;
...
...
@@ -58,6 +59,7 @@ import org.testng.annotations.Test;
import
javax.ws.rs.HttpMethod
;
import
javax.ws.rs.core.Response
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
...
...
@@ -698,4 +700,85 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
Assert
.
assertTrue
(
refs
.
get
(
0
).
equalsContents
(
columns
.
get
(
0
)));
Assert
.
assertTrue
(
refs
.
get
(
1
).
equalsContents
(
columns
.
get
(
1
)));
}
@Test
public
void
testDeleteEntitiesViaRestApi
()
throws
Exception
{
// Create 2 database entities
Referenceable
db1
=
new
Referenceable
(
DATABASE_TYPE
);
db1
.
set
(
"name"
,
randomString
());
db1
.
set
(
"description"
,
randomString
());
Id
db1Id
=
createInstance
(
db1
);
Referenceable
db2
=
new
Referenceable
(
DATABASE_TYPE
);
db2
.
set
(
"name"
,
randomString
());
db2
.
set
(
"description"
,
randomString
());
Id
db2Id
=
createInstance
(
db2
);
// Delete the database entities
ClientResponse
clientResponse
=
service
.
path
(
ENTITIES
).
queryParam
(
AtlasClient
.
GUID
.
toLowerCase
(),
db1Id
.
_getId
()).
queryParam
(
AtlasClient
.
GUID
.
toLowerCase
(),
db2Id
.
_getId
()).
accept
(
Servlets
.
JSON_MEDIA_TYPE
).
type
(
Servlets
.
JSON_MEDIA_TYPE
).
method
(
HttpMethod
.
DELETE
,
ClientResponse
.
class
);
Assert
.
assertEquals
(
clientResponse
.
getStatus
(),
Response
.
Status
.
OK
.
getStatusCode
());
// Verify that response has guids for both database entities
JSONObject
response
=
new
JSONObject
(
clientResponse
.
getEntity
(
String
.
class
));
final
String
deletedGuidsJson
=
response
.
getString
(
AtlasClient
.
GUID
);
Assert
.
assertNotNull
(
deletedGuidsJson
);
JSONArray
guidsArray
=
new
JSONArray
(
deletedGuidsJson
);
Assert
.
assertEquals
(
guidsArray
.
length
(),
2
);
List
<
String
>
deletedGuidsList
=
new
ArrayList
<>(
2
);
for
(
int
index
=
0
;
index
<
guidsArray
.
length
();
index
++)
{
deletedGuidsList
.
add
(
guidsArray
.
getString
(
index
));
}
Assert
.
assertTrue
(
deletedGuidsList
.
contains
(
db1Id
.
_getId
()));
Assert
.
assertTrue
(
deletedGuidsList
.
contains
(
db2Id
.
_getId
()));
// Verify entities were deleted from the repository.
for
(
String
guid
:
deletedGuidsList
)
{
try
{
serviceClient
.
getEntity
(
guid
);
Assert
.
fail
(
AtlasServiceException
.
class
.
getSimpleName
()
+
" was expected but not thrown. The entity with guid "
+
guid
+
" still exists in the repository after being deleted."
);
}
catch
(
AtlasServiceException
e
)
{
Assert
.
assertTrue
(
e
.
getMessage
().
contains
(
Integer
.
toString
(
Response
.
Status
.
NOT_FOUND
.
getStatusCode
())));
}
}
}
@Test
public
void
testDeleteEntitiesViaClientApi
()
throws
Exception
{
// Create 2 database entities
Referenceable
db1
=
new
Referenceable
(
DATABASE_TYPE
);
db1
.
set
(
"name"
,
randomString
());
db1
.
set
(
"description"
,
randomString
());
Id
db1Id
=
createInstance
(
db1
);
Referenceable
db2
=
new
Referenceable
(
DATABASE_TYPE
);
db2
.
set
(
"name"
,
randomString
());
db2
.
set
(
"description"
,
randomString
());
Id
db2Id
=
createInstance
(
db2
);
// Delete the database entities
List
<
String
>
deletedGuidsList
=
serviceClient
.
deleteEntities
(
db1Id
.
_getId
(),
db2Id
.
_getId
());
// Verify that deleteEntities() response has database entity guids
Assert
.
assertEquals
(
deletedGuidsList
.
size
(),
2
);
Assert
.
assertTrue
(
deletedGuidsList
.
contains
(
db1Id
.
_getId
()));
Assert
.
assertTrue
(
deletedGuidsList
.
contains
(
db2Id
.
_getId
()));
// Verify entities were deleted from the repository.
for
(
String
guid
:
deletedGuidsList
)
{
try
{
serviceClient
.
getEntity
(
guid
);
Assert
.
fail
(
AtlasServiceException
.
class
.
getSimpleName
()
+
" was expected but not thrown. The entity with guid "
+
guid
+
" still exists in the repository after being deleted."
);
}
catch
(
AtlasServiceException
e
)
{
Assert
.
assertTrue
(
e
.
getMessage
().
contains
(
Integer
.
toString
(
Response
.
Status
.
NOT_FOUND
.
getStatusCode
())));
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment