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
5f248157
Commit
5f248157
authored
8 years ago
by
Shwetha GS
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ATLAS-683 Refactor local type-system cache with cache provider interface (vmadugun via shwethags)
parent
440bd2ae
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
911 additions
and
83 deletions
+911
-83
.gitignore
.gitignore
+2
-0
ApplicationProperties.java
...src/main/java/org/apache/atlas/ApplicationProperties.java
+12
-3
atlas-application.properties
distro/src/conf/atlas-application.properties
+5
-0
release-log.txt
release-log.txt
+1
-0
RepositoryMetadataModule.java
.../main/java/org/apache/atlas/RepositoryMetadataModule.java
+5
-1
TypeSystem.java
...in/java/org/apache/atlas/typesystem/types/TypeSystem.java
+124
-76
DefaultTypeCacheProvider.java
...tlas/typesystem/types/cache/DefaultTypeCacheProvider.java
+229
-0
ITypeCacheProvider.java
...ache/atlas/typesystem/types/cache/ITypeCacheProvider.java
+137
-0
ApplicationPropertiesTest.java
...test/java/org/apache/atlas/ApplicationPropertiesTest.java
+12
-2
TypeSystemTest.java
...ava/org/apache/atlas/typesystem/types/TypeSystemTest.java
+1
-1
DefaultTypeCacheProviderTest.java
.../typesystem/types/cache/DefaultTypeCacheProviderTest.java
+383
-0
No files found.
.gitignore
View file @
5f248157
...
@@ -60,7 +60,9 @@ distro/hbase/*.tar.gz
...
@@ -60,7 +60,9 @@ distro/hbase/*.tar.gz
#solr package downloaded
#solr package downloaded
distro/solr/*.tgz
distro/solr/*.tgz
# Scala-IDE specific
.cache-main
.cache-main
.cache-tests
# emacs files
# emacs files
*#
*#
...
...
This diff is collapsed.
Click to expand it.
common/src/main/java/org/apache/atlas/ApplicationProperties.java
View file @
5f248157
...
@@ -92,13 +92,22 @@ public final class ApplicationProperties extends PropertiesConfiguration {
...
@@ -92,13 +92,22 @@ public final class ApplicationProperties extends PropertiesConfiguration {
return
inConf
.
subset
(
prefix
);
return
inConf
.
subset
(
prefix
);
}
}
public
static
Class
getClass
(
String
propertyName
,
String
defaultValue
)
{
public
static
Class
getClass
(
String
propertyName
,
String
defaultValue
,
Class
assignableClass
)
throws
AtlasException
{
try
{
try
{
Configuration
configuration
=
get
();
Configuration
configuration
=
get
();
String
propertyValue
=
configuration
.
getString
(
propertyName
,
defaultValue
);
String
propertyValue
=
configuration
.
getString
(
propertyName
,
defaultValue
);
return
Class
.
forName
(
propertyValue
);
Class
<?>
clazz
=
Class
.
forName
(
propertyValue
);
if
(
assignableClass
==
null
||
assignableClass
.
isAssignableFrom
(
clazz
))
{
return
clazz
;
}
else
{
String
message
=
"Class "
+
clazz
.
getName
()
+
" specified in property "
+
propertyName
+
" is not assignable to class "
+
assignableClass
.
getName
();
LOG
.
error
(
message
);
throw
new
AtlasException
(
message
);
}
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
throw
new
Runtime
Exception
(
e
);
throw
new
Atlas
Exception
(
e
);
}
}
}
}
}
}
This diff is collapsed.
Click to expand it.
distro/src/conf/atlas-application.properties
View file @
5f248157
...
@@ -122,3 +122,8 @@ atlas.login.credentials.file=${sys:atlas.home}/conf/users-credentials.properties
...
@@ -122,3 +122,8 @@ atlas.login.credentials.file=${sys:atlas.home}/conf/users-credentials.properties
#########POLICY FILE PATH #########
#########POLICY FILE PATH #########
atlas.auth.policy.file
=
${sys:atlas.home}/conf/policy-store.txt
atlas.auth.policy.file
=
${sys:atlas.home}/conf/policy-store.txt
######### Type Cache Provider Implementation ########
# A type cache provider class which implements
# org.apache.atlas.typesystem.types.cache.ITypeCacheProvider.
# The default is DefaultTypeCacheProvider which is a local in-memory type cache.
#atlas.typesystem.cache.provider=
This diff is collapsed.
Click to expand it.
release-log.txt
View file @
5f248157
...
@@ -21,6 +21,7 @@ ATLAS-409 Atlas will not import avro tables with schema read from a file (dosset
...
@@ -21,6 +21,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)
ATLAS-379 Create sqoop and falcon metadata addons (venkatnrangan,bvellanki,sowmyaramesh via shwethags)
ALL CHANGES:
ALL CHANGES:
ATLAS-683 Refactor local type-system cache with cache provider interface (vmadugun via shwethags)
ATLAS-802 New look UI to show Business Catalog functionalities (kevalbhatt18 via yhemanth)
ATLAS-802 New look UI to show Business Catalog functionalities (kevalbhatt18 via yhemanth)
ATLAS-658 Improve Lineage with Backbone porting (kevalbhatt18 via yhemanth)
ATLAS-658 Improve Lineage with Backbone porting (kevalbhatt18 via yhemanth)
ATLAS-491 Business Catalog / Taxonomy (jspeidel via yhemanth)
ATLAS-491 Business Catalog / Taxonomy (jspeidel via yhemanth)
...
...
This diff is collapsed.
Click to expand it.
repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
View file @
5f248157
...
@@ -111,7 +111,11 @@ public class RepositoryMetadataModule extends com.google.inject.AbstractModule {
...
@@ -111,7 +111,11 @@ public class RepositoryMetadataModule extends com.google.inject.AbstractModule {
private
static
final
String
DELETE_HANDLER_IMPLEMENTATION_PROPERTY
=
"atlas.DeleteHandler.impl"
;
private
static
final
String
DELETE_HANDLER_IMPLEMENTATION_PROPERTY
=
"atlas.DeleteHandler.impl"
;
private
Class
<?
extends
DeleteHandler
>
getDeleteHandler
()
{
private
Class
<?
extends
DeleteHandler
>
getDeleteHandler
()
{
try
{
return
ApplicationProperties
.
getClass
(
DELETE_HANDLER_IMPLEMENTATION_PROPERTY
,
return
ApplicationProperties
.
getClass
(
DELETE_HANDLER_IMPLEMENTATION_PROPERTY
,
SoftDeleteHandler
.
class
.
getName
());
SoftDeleteHandler
.
class
.
getName
(),
DeleteHandler
.
class
);
}
catch
(
AtlasException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
}
}
}
This diff is collapsed.
Click to expand it.
typesystem/src/main/java/org/apache/atlas/typesystem/types/TypeSystem.java
View file @
5f248157
...
@@ -18,19 +18,6 @@
...
@@ -18,19 +18,6 @@
package
org
.
apache
.
atlas
.
typesystem
.
types
;
package
org
.
apache
.
atlas
.
typesystem
.
types
;
import
com.google.common.collect.ArrayListMultimap
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.ImmutableSet
;
import
com.google.common.collect.Multimap
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.classification.InterfaceAudience
;
import
org.apache.atlas.typesystem.TypesDef
;
import
org.apache.atlas.typesystem.exception.TypeExistsException
;
import
org.apache.atlas.typesystem.exception.TypeNotFoundException
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
javax.inject.Singleton
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Constructor
;
import
java.text.SimpleDateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
...
@@ -41,10 +28,27 @@ import java.util.Set;
...
@@ -41,10 +28,27 @@ import java.util.Set;
import
java.util.TimeZone
;
import
java.util.TimeZone
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
javax.inject.Singleton
;
import
org.apache.atlas.ApplicationProperties
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.classification.InterfaceAudience
;
import
org.apache.atlas.typesystem.TypesDef
;
import
org.apache.atlas.typesystem.exception.TypeExistsException
;
import
org.apache.atlas.typesystem.exception.TypeNotFoundException
;
import
org.apache.atlas.typesystem.types.cache.DefaultTypeCacheProvider
;
import
org.apache.atlas.typesystem.types.cache.ITypeCacheProvider
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.ImmutableSet
;
@Singleton
@Singleton
@InterfaceAudience
.
Private
@InterfaceAudience
.
Private
public
class
TypeSystem
{
public
class
TypeSystem
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
TypeSystem
.
class
);
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
TypeSystem
.
class
);
private
static
final
String
CACHE_PROVIDER_CLASS_PROPERTY
=
"atlas.typesystem.cache.provider"
;
private
static
final
TypeSystem
INSTANCE
=
new
TypeSystem
();
private
static
final
TypeSystem
INSTANCE
=
new
TypeSystem
();
private
static
ThreadLocal
<
SimpleDateFormat
>
dateFormat
=
new
ThreadLocal
<
SimpleDateFormat
>()
{
private
static
ThreadLocal
<
SimpleDateFormat
>
dateFormat
=
new
ThreadLocal
<
SimpleDateFormat
>()
{
...
@@ -56,15 +60,9 @@ public class TypeSystem {
...
@@ -56,15 +60,9 @@ public class TypeSystem {
}
}
};
};
private
Map
<
String
,
IDataType
>
types
;
private
ITypeCacheProvider
typeCache
;
private
IdType
idType
;
private
IdType
idType
;
private
Map
<
String
,
IDataType
>
coreTypes
;
/**
* An in-memory copy of type categories vs types for convenience.
*/
private
Multimap
<
DataTypes
.
TypeCategory
,
String
>
typeCategoriesToTypeNamesMap
;
private
ImmutableList
<
String
>
coreTypes
;
public
TypeSystem
()
{
public
TypeSystem
()
{
initialize
();
initialize
();
...
@@ -78,69 +76,111 @@ public class TypeSystem {
...
@@ -78,69 +76,111 @@ public class TypeSystem {
* This is only used for testing purposes. Not intended for public use.
* This is only used for testing purposes. Not intended for public use.
*/
*/
@InterfaceAudience
.
Private
@InterfaceAudience
.
Private
public
void
reset
()
{
public
TypeSystem
reset
()
{
typeCache
.
clear
();
// clear all entries in cache
initialize
();
initialize
();
return
this
;
}
}
private
void
initialize
()
{
private
void
initialize
()
{
types
=
new
ConcurrentHashMap
<>();
typeCategoriesToTypeNamesMap
=
ArrayListMultimap
.
create
(
DataTypes
.
TypeCategory
.
values
().
length
,
10
);
initCacheProvider
();
coreTypes
=
new
ConcurrentHashMap
<>();
registerPrimitiveTypes
();
registerPrimitiveTypes
();
registerCoreTypes
();
registerCoreTypes
();
coreTypes
=
ImmutableList
.
copyOf
(
types
.
keySet
());
}
/**
* Ideally a cache provider should have been injected in the TypeSystemProvider,
* but a singleton of TypeSystem is constructed privately within the class so that
* clients of TypeSystem would never instantiate a TypeSystem object directly in
* their code. As soon as a client makes a call to TypeSystem.getInstance(), they
* should have the singleton ready for consumption. To enable such an access pattern,
* it kind of becomes imperative to initialize the cache provider within the
* TypeSystem constructor (bypassing the GUICE way of injecting a cache provider)
*/
private
void
initCacheProvider
()
{
// read the pluggable cache provider from Atlas configuration
final
String
defaultCacheProvider
=
DefaultTypeCacheProvider
.
class
.
getName
();
Class
cacheProviderClass
;
try
{
cacheProviderClass
=
ApplicationProperties
.
getClass
(
CACHE_PROVIDER_CLASS_PROPERTY
,
defaultCacheProvider
,
ITypeCacheProvider
.
class
);
}
catch
(
AtlasException
e
)
{
throw
new
RuntimeException
(
"Error getting type cache provider implementation class"
,
e
);
}
try
{
typeCache
=
(
ITypeCacheProvider
)
cacheProviderClass
.
newInstance
();
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Error creating instance of type cache provider implementation class "
+
cacheProviderClass
.
getName
(),
e
);
}
}
}
public
ImmutableList
<
String
>
getCoreTypes
()
{
public
ImmutableList
<
String
>
getCoreTypes
()
{
return
coreTypes
;
return
ImmutableList
.
copyOf
(
coreTypes
.
keySet
())
;
}
}
public
ImmutableList
<
String
>
getTypeNames
()
{
public
ImmutableList
<
String
>
getTypeNames
()
throws
AtlasException
{
List
<
String
>
typeNames
=
new
ArrayList
<>(
types
.
keySet
());
List
<
String
>
typeNames
=
new
ArrayList
<>(
typeCache
.
getAllTypeNames
());
typeNames
.
removeAll
(
getCoreTypes
());
return
ImmutableList
.
copyOf
(
typeNames
);
return
ImmutableList
.
copyOf
(
typeNames
);
}
}
public
ImmutableList
<
String
>
getTypeNamesByCategory
(
DataTypes
.
TypeCategory
typeCategory
)
{
public
ImmutableList
<
String
>
getTypeNamesByCategory
(
DataTypes
.
TypeCategory
typeCategory
)
throws
AtlasException
{
return
ImmutableList
.
copyOf
(
typeCa
tegoriesToTypeNamesMap
.
get
(
typeCategory
));
return
ImmutableList
.
copyOf
(
typeCa
che
.
getTypeNames
(
typeCategory
));
}
}
private
void
registerPrimitiveTypes
()
{
private
void
registerPrimitiveTypes
()
{
types
.
put
(
DataTypes
.
BOOLEAN_TYPE
.
getName
(),
DataTypes
.
BOOLEAN_TYPE
);
types
.
put
(
DataTypes
.
BYTE_TYPE
.
getName
(),
DataTypes
.
BYTE_TYPE
);
types
.
put
(
DataTypes
.
SHORT_TYPE
.
getName
(),
DataTypes
.
SHORT_TYPE
);
types
.
put
(
DataTypes
.
INT_TYPE
.
getName
(),
DataTypes
.
INT_TYPE
);
types
.
put
(
DataTypes
.
LONG_TYPE
.
getName
(),
DataTypes
.
LONG_TYPE
);
types
.
put
(
DataTypes
.
FLOAT_TYPE
.
getName
(),
DataTypes
.
FLOAT_TYPE
);
types
.
put
(
DataTypes
.
DOUBLE_TYPE
.
getName
(),
DataTypes
.
DOUBLE_TYPE
);
types
.
put
(
DataTypes
.
BIGINTEGER_TYPE
.
getName
(),
DataTypes
.
BIGINTEGER_TYPE
);
types
.
put
(
DataTypes
.
BIGDECIMAL_TYPE
.
getName
(),
DataTypes
.
BIGDECIMAL_TYPE
);
types
.
put
(
DataTypes
.
DATE_TYPE
.
getName
(),
DataTypes
.
DATE_TYPE
);
types
.
put
(
DataTypes
.
STRING_TYPE
.
getName
(),
DataTypes
.
STRING_TYPE
);
typeCategoriesToTypeNamesMap
.
putAll
(
DataTypes
.
TypeCategory
.
PRIMITIVE
,
types
.
keySet
());
coreTypes
.
put
(
DataTypes
.
BOOLEAN_TYPE
.
getName
(),
DataTypes
.
BOOLEAN_TYPE
);
coreTypes
.
put
(
DataTypes
.
BYTE_TYPE
.
getName
(),
DataTypes
.
BYTE_TYPE
);
coreTypes
.
put
(
DataTypes
.
SHORT_TYPE
.
getName
(),
DataTypes
.
SHORT_TYPE
);
coreTypes
.
put
(
DataTypes
.
INT_TYPE
.
getName
(),
DataTypes
.
INT_TYPE
);
coreTypes
.
put
(
DataTypes
.
LONG_TYPE
.
getName
(),
DataTypes
.
LONG_TYPE
);
coreTypes
.
put
(
DataTypes
.
FLOAT_TYPE
.
getName
(),
DataTypes
.
FLOAT_TYPE
);
coreTypes
.
put
(
DataTypes
.
DOUBLE_TYPE
.
getName
(),
DataTypes
.
DOUBLE_TYPE
);
coreTypes
.
put
(
DataTypes
.
BIGINTEGER_TYPE
.
getName
(),
DataTypes
.
BIGINTEGER_TYPE
);
coreTypes
.
put
(
DataTypes
.
BIGDECIMAL_TYPE
.
getName
(),
DataTypes
.
BIGDECIMAL_TYPE
);
coreTypes
.
put
(
DataTypes
.
DATE_TYPE
.
getName
(),
DataTypes
.
DATE_TYPE
);
coreTypes
.
put
(
DataTypes
.
STRING_TYPE
.
getName
(),
DataTypes
.
STRING_TYPE
);
}
}
/*
/*
* The only core OOB type we will define is the Struct to represent the Identity of an Instance.
* The only core OOB type we will define is the Struct to represent the Identity of an Instance.
*/
*/
private
void
registerCoreTypes
()
{
private
void
registerCoreTypes
()
{
idType
=
new
IdType
();
idType
=
new
IdType
();
coreTypes
.
put
(
idType
.
getStructType
().
getName
(),
idType
.
getStructType
());
}
}
public
IdType
getIdType
()
{
public
IdType
getIdType
()
{
return
idType
;
return
idType
;
}
}
public
boolean
isRegistered
(
String
typeName
)
{
public
boolean
isRegistered
(
String
typeName
)
throws
AtlasException
{
return
types
.
containsKey
(
typeName
);
return
isCoreType
(
typeName
)
||
typeCache
.
has
(
typeName
);
}
protected
boolean
isCoreType
(
String
typeName
)
{
return
coreTypes
.
containsKey
(
typeName
);
}
}
public
<
T
>
T
getDataType
(
Class
<
T
>
cls
,
String
name
)
throws
AtlasException
{
public
<
T
>
T
getDataType
(
Class
<
T
>
cls
,
String
name
)
throws
AtlasException
{
if
(
types
.
containsKey
(
name
))
{
if
(
isCoreType
(
name
))
{
return
cls
.
cast
(
coreTypes
.
get
(
name
));
}
if
(
typeCache
.
has
(
name
))
{
try
{
try
{
return
cls
.
cast
(
type
s
.
get
(
name
));
return
cls
.
cast
(
type
Cache
.
get
(
name
));
}
catch
(
ClassCastException
cce
)
{
}
catch
(
ClassCastException
cce
)
{
throw
new
AtlasException
(
cce
);
throw
new
AtlasException
(
cce
);
}
}
...
@@ -285,13 +325,12 @@ public class TypeSystem {
...
@@ -285,13 +325,12 @@ public class TypeSystem {
public
EnumType
defineEnumType
(
EnumTypeDefinition
eDef
)
throws
AtlasException
{
public
EnumType
defineEnumType
(
EnumTypeDefinition
eDef
)
throws
AtlasException
{
assert
eDef
.
name
!=
null
;
assert
eDef
.
name
!=
null
;
if
(
types
.
containsKey
(
eDef
.
name
))
{
if
(
isRegistered
(
eDef
.
name
))
{
throw
new
AtlasException
(
String
.
format
(
"Redefinition of type %s not supported"
,
eDef
.
name
));
throw
new
AtlasException
(
String
.
format
(
"Redefinition of type %s not supported"
,
eDef
.
name
));
}
}
EnumType
eT
=
new
EnumType
(
this
,
eDef
.
name
,
eDef
.
description
,
eDef
.
enumValues
);
EnumType
eT
=
new
EnumType
(
this
,
eDef
.
name
,
eDef
.
description
,
eDef
.
enumValues
);
types
.
put
(
eDef
.
name
,
eT
);
typeCache
.
put
(
eT
);
typeCategoriesToTypeNamesMap
.
put
(
DataTypes
.
TypeCategory
.
ENUM
,
eDef
.
name
);
return
eT
;
return
eT
;
}
}
...
@@ -329,17 +368,14 @@ public class TypeSystem {
...
@@ -329,17 +368,14 @@ public class TypeSystem {
*
*
* This step should be called only after the types have been committed to the backend stores successfully.
* This step should be called only after the types have been committed to the backend stores successfully.
* @param typesAdded newly added types.
* @param typesAdded newly added types.
* @throws AtlasException
*/
*/
public
void
commitTypes
(
Map
<
String
,
IDataType
>
typesAdded
)
{
public
void
commitTypes
(
Map
<
String
,
IDataType
>
typesAdded
)
throws
AtlasException
{
for
(
Map
.
Entry
<
String
,
IDataType
>
typeEntry
:
typesAdded
.
entrySet
())
{
for
(
Map
.
Entry
<
String
,
IDataType
>
typeEntry
:
typesAdded
.
entrySet
())
{
String
typeName
=
typeEntry
.
getKey
();
String
typeName
=
typeEntry
.
getKey
();
IDataType
type
=
typeEntry
.
getValue
();
IDataType
type
=
typeEntry
.
getValue
();
//Add/replace the new type in the typesystem
//Add/replace the new type in the typesystem
types
.
put
(
typeName
,
type
);
typeCache
.
put
(
type
);
// ArrayListMultiMap allows duplicates - we want to avoid this during re-activation.
if
(!
typeCategoriesToTypeNamesMap
.
containsEntry
(
type
.
getTypeCategory
(),
typeName
))
{
typeCategoriesToTypeNamesMap
.
put
(
type
.
getTypeCategory
(),
typeName
);
}
}
}
}
}
...
@@ -372,10 +408,12 @@ public class TypeSystem {
...
@@ -372,10 +408,12 @@ public class TypeSystem {
}
}
private
IDataType
dataType
(
String
name
)
throws
AtlasException
{
private
IDataType
dataType
(
String
name
)
throws
AtlasException
{
if
(
transientTypes
.
containsKey
(
name
))
{
if
(
transientTypes
.
containsKey
(
name
))
{
return
transientTypes
.
get
(
name
);
return
transientTypes
.
get
(
name
);
}
}
return
TypeSystem
.
this
.
types
.
get
(
name
);
return
TypeSystem
.
this
.
getDataType
(
IDataType
.
class
,
name
);
}
}
/*
/*
...
@@ -386,7 +424,7 @@ public class TypeSystem {
...
@@ -386,7 +424,7 @@ public class TypeSystem {
private
void
validateAndSetupShallowTypes
(
boolean
update
)
throws
AtlasException
{
private
void
validateAndSetupShallowTypes
(
boolean
update
)
throws
AtlasException
{
for
(
EnumTypeDefinition
eDef
:
enumDefs
)
{
for
(
EnumTypeDefinition
eDef
:
enumDefs
)
{
assert
eDef
.
name
!=
null
;
assert
eDef
.
name
!=
null
;
if
(!
update
&&
(
transientTypes
.
containsKey
(
eDef
.
name
)
||
types
.
containsKey
(
eDef
.
name
)))
{
if
(!
update
&&
(
transientTypes
.
containsKey
(
eDef
.
name
)
||
isRegistered
(
eDef
.
name
)))
{
throw
new
AtlasException
(
String
.
format
(
"Redefinition of type %s not supported"
,
eDef
.
name
));
throw
new
AtlasException
(
String
.
format
(
"Redefinition of type %s not supported"
,
eDef
.
name
));
}
}
...
@@ -396,7 +434,7 @@ public class TypeSystem {
...
@@ -396,7 +434,7 @@ public class TypeSystem {
for
(
StructTypeDefinition
sDef
:
structDefs
)
{
for
(
StructTypeDefinition
sDef
:
structDefs
)
{
assert
sDef
.
typeName
!=
null
;
assert
sDef
.
typeName
!=
null
;
if
(!
update
&&
(
transientTypes
.
containsKey
(
sDef
.
typeName
)
||
types
.
containsKey
(
sDef
.
typeName
)))
{
if
(!
update
&&
(
transientTypes
.
containsKey
(
sDef
.
typeName
)
||
isRegistered
(
sDef
.
typeName
)))
{
throw
new
TypeExistsException
(
String
.
format
(
"Cannot redefine type %s"
,
sDef
.
typeName
));
throw
new
TypeExistsException
(
String
.
format
(
"Cannot redefine type %s"
,
sDef
.
typeName
));
}
}
StructType
sT
=
new
StructType
(
this
,
sDef
.
typeName
,
sDef
.
typeDescription
,
sDef
.
attributeDefinitions
.
length
);
StructType
sT
=
new
StructType
(
this
,
sDef
.
typeName
,
sDef
.
typeDescription
,
sDef
.
attributeDefinitions
.
length
);
...
@@ -407,7 +445,7 @@ public class TypeSystem {
...
@@ -407,7 +445,7 @@ public class TypeSystem {
for
(
HierarchicalTypeDefinition
<
TraitType
>
traitDef
:
traitDefs
)
{
for
(
HierarchicalTypeDefinition
<
TraitType
>
traitDef
:
traitDefs
)
{
assert
traitDef
.
typeName
!=
null
;
assert
traitDef
.
typeName
!=
null
;
if
(!
update
&&
if
(!
update
&&
(
transientTypes
.
containsKey
(
traitDef
.
typeName
)
||
types
.
containsKey
(
traitDef
.
typeName
)))
{
(
transientTypes
.
containsKey
(
traitDef
.
typeName
)
||
isRegistered
(
traitDef
.
typeName
)))
{
throw
new
TypeExistsException
(
String
.
format
(
"Cannot redefine type %s"
,
traitDef
.
typeName
));
throw
new
TypeExistsException
(
String
.
format
(
"Cannot redefine type %s"
,
traitDef
.
typeName
));
}
}
TraitType
tT
=
new
TraitType
(
this
,
traitDef
.
typeName
,
traitDef
.
typeDescription
,
traitDef
.
superTypes
,
TraitType
tT
=
new
TraitType
(
this
,
traitDef
.
typeName
,
traitDef
.
typeDescription
,
traitDef
.
superTypes
,
...
@@ -419,7 +457,7 @@ public class TypeSystem {
...
@@ -419,7 +457,7 @@ public class TypeSystem {
for
(
HierarchicalTypeDefinition
<
ClassType
>
classDef
:
classDefs
)
{
for
(
HierarchicalTypeDefinition
<
ClassType
>
classDef
:
classDefs
)
{
assert
classDef
.
typeName
!=
null
;
assert
classDef
.
typeName
!=
null
;
if
(!
update
&&
if
(!
update
&&
(
transientTypes
.
containsKey
(
classDef
.
typeName
)
||
types
.
containsKey
(
classDef
.
typeName
)))
{
(
transientTypes
.
containsKey
(
classDef
.
typeName
)
||
isRegistered
(
classDef
.
typeName
)))
{
throw
new
TypeExistsException
(
String
.
format
(
"Cannot redefine type %s"
,
classDef
.
typeName
));
throw
new
TypeExistsException
(
String
.
format
(
"Cannot redefine type %s"
,
classDef
.
typeName
));
}
}
...
@@ -582,11 +620,11 @@ public class TypeSystem {
...
@@ -582,11 +620,11 @@ public class TypeSystem {
* Step 5:
* Step 5:
* - Validate that the update can be done
* - Validate that the update can be done
*/
*/
private
void
validateUpdateIsPossible
()
throws
TypeUpdateException
{
private
void
validateUpdateIsPossible
()
throws
TypeUpdateException
,
AtlasException
{
//If the type is modified, validate that update can be done
//If the type is modified, validate that update can be done
for
(
IDataType
newType
:
transientTypes
.
values
())
{
for
(
IDataType
newType
:
transientTypes
.
values
())
{
if
(
TypeSystem
.
this
.
types
.
containsKey
(
newType
.
getName
()))
{
if
(
TypeSystem
.
this
.
isRegistered
(
newType
.
getName
()))
{
IDataType
oldType
=
TypeSystem
.
this
.
type
s
.
get
(
newType
.
getName
());
IDataType
oldType
=
TypeSystem
.
this
.
type
Cache
.
get
(
newType
.
getName
());
oldType
.
validateUpdate
(
newType
);
oldType
.
validateUpdate
(
newType
);
}
}
}
}
...
@@ -600,7 +638,7 @@ public class TypeSystem {
...
@@ -600,7 +638,7 @@ public class TypeSystem {
}
}
@Override
@Override
public
ImmutableList
<
String
>
getTypeNames
()
{
public
ImmutableList
<
String
>
getTypeNames
()
throws
AtlasException
{
Set
<
String
>
typeNames
=
transientTypes
.
keySet
();
Set
<
String
>
typeNames
=
transientTypes
.
keySet
();
typeNames
.
addAll
(
TypeSystem
.
this
.
getTypeNames
());
typeNames
.
addAll
(
TypeSystem
.
this
.
getTypeNames
());
return
ImmutableList
.
copyOf
(
typeNames
);
return
ImmutableList
.
copyOf
(
typeNames
);
...
@@ -644,17 +682,17 @@ public class TypeSystem {
...
@@ -644,17 +682,17 @@ public class TypeSystem {
@Override
@Override
public
StructType
defineStructType
(
String
name
,
boolean
errorIfExists
,
AttributeDefinition
...
attrDefs
)
public
StructType
defineStructType
(
String
name
,
boolean
errorIfExists
,
AttributeDefinition
...
attrDefs
)
throws
AtlasException
{
throws
AtlasException
{
throw
new
AtlasException
(
"Internal Error: define type called on TrasientTypeSystem"
);
throw
new
AtlasException
(
"Internal Error: define type called on Tra
n
sientTypeSystem"
);
}
}
@Override
@Override
public
TraitType
defineTraitType
(
HierarchicalTypeDefinition
traitDef
)
throws
AtlasException
{
public
TraitType
defineTraitType
(
HierarchicalTypeDefinition
traitDef
)
throws
AtlasException
{
throw
new
AtlasException
(
"Internal Error: define type called on TrasientTypeSystem"
);
throw
new
AtlasException
(
"Internal Error: define type called on Tra
n
sientTypeSystem"
);
}
}
@Override
@Override
public
ClassType
defineClassType
(
HierarchicalTypeDefinition
<
ClassType
>
classDef
)
throws
AtlasException
{
public
ClassType
defineClassType
(
HierarchicalTypeDefinition
<
ClassType
>
classDef
)
throws
AtlasException
{
throw
new
AtlasException
(
"Internal Error: define type called on TrasientTypeSystem"
);
throw
new
AtlasException
(
"Internal Error: define type called on Tra
n
sientTypeSystem"
);
}
}
@Override
@Override
...
@@ -662,7 +700,7 @@ public class TypeSystem {
...
@@ -662,7 +700,7 @@ public class TypeSystem {
ImmutableList
<
StructTypeDefinition
>
structDefs
,
ImmutableList
<
StructTypeDefinition
>
structDefs
,
ImmutableList
<
HierarchicalTypeDefinition
<
TraitType
>>
traitDefs
,
ImmutableList
<
HierarchicalTypeDefinition
<
TraitType
>>
traitDefs
,
ImmutableList
<
HierarchicalTypeDefinition
<
ClassType
>>
classDefs
)
throws
AtlasException
{
ImmutableList
<
HierarchicalTypeDefinition
<
ClassType
>>
classDefs
)
throws
AtlasException
{
throw
new
AtlasException
(
"Internal Error: define type called on TrasientTypeSystem"
);
throw
new
AtlasException
(
"Internal Error: define type called on Tra
n
sientTypeSystem"
);
}
}
@Override
@Override
...
@@ -686,13 +724,22 @@ public class TypeSystem {
...
@@ -686,13 +724,22 @@ public class TypeSystem {
}
}
@Override
@Override
public
void
commitTypes
(
Map
<
String
,
IDataType
>
typesAdded
)
{
public
void
commitTypes
(
Map
<
String
,
IDataType
>
typesAdded
)
throws
AtlasException
{
TypeSystem
.
this
.
commitTypes
(
typesAdded
);
TypeSystem
.
this
.
commitTypes
(
typesAdded
);
}
}
public
Map
<
String
,
IDataType
>
getTypesAdded
()
{
public
Map
<
String
,
IDataType
>
getTypesAdded
()
{
return
new
HashMap
<>(
transientTypes
);
return
new
HashMap
<>(
transientTypes
);
}
}
/**
* The core types do not change and they are registered
* once in the main type system.
*/
@Override
public
ImmutableList
<
String
>
getCoreTypes
()
{
return
TypeSystem
.
this
.
getCoreTypes
();
}
}
}
public
class
IdType
{
public
class
IdType
{
...
@@ -700,6 +747,8 @@ public class TypeSystem {
...
@@ -700,6 +747,8 @@ public class TypeSystem {
private
static
final
String
TYPENAME_ATTRNAME
=
"typeName"
;
private
static
final
String
TYPENAME_ATTRNAME
=
"typeName"
;
private
static
final
String
TYP_NAME
=
"__IdType"
;
private
static
final
String
TYP_NAME
=
"__IdType"
;
private
StructType
type
;
private
IdType
()
{
private
IdType
()
{
AttributeDefinition
idAttr
=
AttributeDefinition
idAttr
=
new
AttributeDefinition
(
ID_ATTRNAME
,
DataTypes
.
STRING_TYPE
.
getName
(),
Multiplicity
.
REQUIRED
,
false
,
new
AttributeDefinition
(
ID_ATTRNAME
,
DataTypes
.
STRING_TYPE
.
getName
(),
Multiplicity
.
REQUIRED
,
false
,
...
@@ -712,16 +761,14 @@ public class TypeSystem {
...
@@ -712,16 +761,14 @@ public class TypeSystem {
infos
[
0
]
=
new
AttributeInfo
(
TypeSystem
.
this
,
idAttr
,
null
);
infos
[
0
]
=
new
AttributeInfo
(
TypeSystem
.
this
,
idAttr
,
null
);
infos
[
1
]
=
new
AttributeInfo
(
TypeSystem
.
this
,
typNmAttr
,
null
);
infos
[
1
]
=
new
AttributeInfo
(
TypeSystem
.
this
,
typNmAttr
,
null
);
StructType
type
=
new
StructType
(
TypeSystem
.
this
,
TYP_NAME
,
null
,
infos
);
type
=
new
StructType
(
TypeSystem
.
this
,
TYP_NAME
,
null
,
infos
);
TypeSystem
.
this
.
types
.
put
(
TYP_NAME
,
type
);
}
catch
(
AtlasException
me
)
{
}
catch
(
AtlasException
me
)
{
throw
new
RuntimeException
(
me
);
throw
new
RuntimeException
(
me
);
}
}
}
}
public
StructType
getStructType
()
throws
AtlasException
{
public
StructType
getStructType
()
{
return
getDataType
(
StructType
.
class
,
TYP_NAME
)
;
return
type
;
}
}
public
String
getName
()
{
public
String
getName
()
{
...
@@ -738,4 +785,5 @@ public class TypeSystem {
...
@@ -738,4 +785,5 @@ public class TypeSystem {
}
}
public
static
final
String
ID_STRUCT_ID_ATTRNAME
=
IdType
.
ID_ATTRNAME
;
public
static
final
String
ID_STRUCT_ID_ATTRNAME
=
IdType
.
ID_ATTRNAME
;
public
static
final
String
ID_STRUCT_TYP_NAME
=
IdType
.
TYP_NAME
;
}
}
This diff is collapsed.
Click to expand it.
typesystem/src/main/java/org/apache/atlas/typesystem/types/cache/DefaultTypeCacheProvider.java
0 → 100644
View file @
5f248157
/**
* 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
.
atlas
.
typesystem
.
types
.
cache
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.concurrent.ConcurrentHashMap
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.typesystem.types.ClassType
;
import
org.apache.atlas.typesystem.types.DataTypes.TypeCategory
;
import
org.apache.atlas.typesystem.types.EnumType
;
import
org.apache.atlas.typesystem.types.IDataType
;
import
org.apache.atlas.typesystem.types.StructType
;
import
org.apache.atlas.typesystem.types.TraitType
;
import
com.google.inject.Singleton
;
/**
* Caches the types in-memory within the same process space.
*/
@Singleton
@SuppressWarnings
(
"rawtypes"
)
public
class
DefaultTypeCacheProvider
implements
ITypeCacheProvider
{
private
Map
<
String
,
IDataType
>
types_
=
new
ConcurrentHashMap
<>();
/*
* (non-Javadoc)
* @see
* org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#has(java.lang
* .String)
*/
@Override
public
boolean
has
(
String
typeName
)
throws
AtlasException
{
return
types_
.
containsKey
(
typeName
);
}
/* (non-Javadoc)
* @see org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#has(org.
* apache.atlas.typesystem.types.DataTypes.TypeCategory, java.lang.String)
*/
@Override
public
boolean
has
(
TypeCategory
typeCategory
,
String
typeName
)
throws
AtlasException
{
assertValidTypeCategory
(
typeCategory
);
return
has
(
typeName
);
}
private
void
assertValidTypeCategory
(
TypeCategory
typeCategory
)
throws
AtlasException
{
// there might no need of 'typeCategory' in this implementation for
// certain API, but for a distributed cache, it might help for the
// implementers to partition the types per their category
// while persisting so that look can be efficient
if
(
typeCategory
==
null
)
{
throw
new
AtlasException
(
"Category of the types to be filtered is null."
);
}
boolean
validTypeCategory
=
typeCategory
.
equals
(
TypeCategory
.
CLASS
)
||
typeCategory
.
equals
(
TypeCategory
.
TRAIT
)
||
typeCategory
.
equals
(
TypeCategory
.
ENUM
)
||
typeCategory
.
equals
(
TypeCategory
.
STRUCT
);
if
(!
validTypeCategory
)
{
throw
new
AtlasException
(
"Category of the types should be one of CLASS "
+
"| TRAIT | ENUM | STRUCT."
);
}
}
/*
* (non-Javadoc)
* @see
* org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#get(java.lang
* .String)
*/
@Override
public
IDataType
get
(
String
typeName
)
throws
AtlasException
{
return
types_
.
get
(
typeName
);
}
/* (non-Javadoc)
* @see org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#get(org.apache.
* atlas.typesystem.types.DataTypes.TypeCategory, java.lang.String)
*/
@Override
public
IDataType
get
(
TypeCategory
typeCategory
,
String
typeName
)
throws
AtlasException
{
assertValidTypeCategory
(
typeCategory
);
return
get
(
typeName
);
}
/*
* (non-Javadoc)
* @see
* org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#getNames(org
* .apache.atlas.typesystem.types.DataTypes.TypeCategory)
*/
@Override
public
Collection
<
String
>
getTypeNames
(
TypeCategory
typeCategory
)
throws
AtlasException
{
assertValidTypeCategory
(
typeCategory
);
List
<
String
>
typeNames
=
new
ArrayList
<>();
for
(
Entry
<
String
,
IDataType
>
typeEntry
:
types_
.
entrySet
())
{
String
name
=
typeEntry
.
getKey
();
IDataType
type
=
typeEntry
.
getValue
();
if
(
type
.
getTypeCategory
().
equals
(
typeCategory
))
{
typeNames
.
add
(
name
);
}
}
return
typeNames
;
}
/*
* (non-Javadoc)
* @see
* org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#getAllNames()
*/
@Override
public
Collection
<
String
>
getAllTypeNames
()
throws
AtlasException
{
return
types_
.
keySet
();
}
/*
* (non-Javadoc)
* @see
* org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#put(org.apache
* .atlas.typesystem.types.IDataType)
*/
@Override
public
void
put
(
IDataType
type
)
throws
AtlasException
{
assertValidType
(
type
);
types_
.
put
(
type
.
getName
(),
type
);
}
private
void
assertValidType
(
IDataType
type
)
throws
AtlasException
{
if
(
type
==
null
)
{
throw
new
AtlasException
(
"type is null."
);
}
boolean
validTypeCategory
=
(
type
instanceof
ClassType
)
||
(
type
instanceof
TraitType
)
||
(
type
instanceof
EnumType
)
||
(
type
instanceof
StructType
);
if
(!
validTypeCategory
)
{
throw
new
AtlasException
(
"Category of the types should be one of ClassType | "
+
"TraitType | EnumType | StructType."
);
}
}
/*
* (non-Javadoc)
* @see
* org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#putAll(java
* .util.Collection)
*/
@Override
public
void
putAll
(
Collection
<
IDataType
>
types
)
throws
AtlasException
{
for
(
IDataType
type
:
types
)
{
assertValidType
(
type
);
types_
.
put
(
type
.
getName
(),
type
);
}
}
/*
* (non-Javadoc)
* @see
* org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#remove(java
* .lang.String)
*/
@Override
public
void
remove
(
String
typeName
)
throws
AtlasException
{
types_
.
remove
(
typeName
);
}
/* (non-Javadoc)
* @see org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#remove(org.
* apache.atlas.typesystem.types.DataTypes.TypeCategory, java.lang.String)
*/
@Override
public
void
remove
(
TypeCategory
typeCategory
,
String
typeName
)
throws
AtlasException
{
assertValidTypeCategory
(
typeCategory
);
remove
(
typeName
);
}
/*
* (non-Javadoc)
* @see org.apache.atlas.typesystem.types.cache.ITypeCacheProvider#clear()
*/
@Override
public
void
clear
()
{
types_
.
clear
();
}
}
This diff is collapsed.
Click to expand it.
typesystem/src/main/java/org/apache/atlas/typesystem/types/cache/ITypeCacheProvider.java
0 → 100644
View file @
5f248157
/**
* 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
.
atlas
.
typesystem
.
types
.
cache
;
import
java.util.Collection
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.typesystem.types.DataTypes
;
import
org.apache.atlas.typesystem.types.IDataType
;
/**
* The types are cached to allow faster lookup when type info is needed during
* creation/updation of entities, DSL query translation/execution.
* Implementations of this can chose to plugin a distributed cache provider
* or an in-memory cache synched across nodes in an Altas cluster. <br>
* <br>
* Type entries in the cache can be one of ... <br>
* {@link org.apache.atlas.typesystem.types.ClassType} <br>
* {@link org.apache.atlas.typesystem.types.TraitType} <br>
* {@link org.apache.atlas.typesystem.types.StructType} <br>
* {@link org.apache.atlas.typesystem.types.EnumType}
*/
@SuppressWarnings
(
"rawtypes"
)
public
interface
ITypeCacheProvider
{
/**
* @param typeName
* @return true if the type exists in cache, false otherwise.
* @throws AtlasException
*/
boolean
has
(
String
typeName
)
throws
AtlasException
;
/**
* @param typeCategory Non-null category of type. The category can be one of
* TypeCategory.CLASS | TypeCategory.TRAIT | TypeCategory.STRUCT | TypeCategory.ENUM.
* @param typeName
* @return true if the type of given category exists in cache, false otherwise.
* @throws AtlasException
*/
boolean
has
(
DataTypes
.
TypeCategory
typeCategory
,
String
typeName
)
throws
AtlasException
;
/**
* @param name The name of the type.
* @return returns non-null type if cached, otherwise null
* @throws AtlasException
*/
public
IDataType
get
(
String
typeName
)
throws
AtlasException
;
/**
* @param typeCategory Non-null category of type. The category can be one of
* TypeCategory.CLASS | TypeCategory.TRAIT | TypeCategory.STRUCT | TypeCategory.ENUM.
* @param typeName
* @return returns non-null type (of the specified category) if cached, otherwise null
* @throws AtlasException
*/
public
IDataType
get
(
DataTypes
.
TypeCategory
typeCategory
,
String
typeName
)
throws
AtlasException
;
/**
* @param typeCategory The category of types to filter the returned types. Cannot be null.
* The category can be one of TypeCategory.CLASS | TypeCategory.TRAIT |
* TypeCategory.STRUCT | TypeCategory.ENUM.
* @return
* @throws AtlasException
*/
Collection
<
String
>
getTypeNames
(
DataTypes
.
TypeCategory
typeCategory
)
throws
AtlasException
;
/**
* This is a convenience API to get the names of all types.
*
* @see ITypeCacheProvider#getTypeNames(org.apache.atlas.typesystem.types.DataTypes.TypeCategory)
* @return
* @throws AtlasException
*/
Collection
<
String
>
getAllTypeNames
()
throws
AtlasException
;
/**
* @param type The type to be added to the cache. The type should not be
* null, otherwise throws NullPointerException. <br>
* Type entries in the cache can be one of ... <br>
* {@link org.apache.atlas.typesystem.types.ClassType} <br>
* {@link org.apache.atlas.typesystem.types.TraitType} <br>
* {@link org.apache.atlas.typesystem.types.StructType} <br>
* {@link org.apache.atlas.typesystem.types.EnumType}
* @throws AtlasException
*/
void
put
(
IDataType
type
)
throws
AtlasException
;
/**
* @param types The types to be added to the cache. The type should not be
* null, otherwise throws NullPointerException. <br>
* Type entries in the cache can be one of ... <br>
* {@link org.apache.atlas.typesystem.types.ClassType} <br>
* {@link org.apache.atlas.typesystem.types.TraitType} <br>
* {@link org.apache.atlas.typesystem.types.StructType} <br>
* {@link org.apache.atlas.typesystem.types.EnumType}
* @throws AtlasException
*/
void
putAll
(
Collection
<
IDataType
>
types
)
throws
AtlasException
;
/**
* @param typeName Name of the type to be removed from the cache. If type
* exists, it will be removed, otherwise does nothing.
* @throws AtlasException
*/
void
remove
(
String
typeName
)
throws
AtlasException
;
/**
* @param typeCategory Non-null category of type. The category can be one of
* TypeCategory.CLASS | TypeCategory.TRAIT | TypeCategory.STRUCT | TypeCategory.ENUM.
* @param typeName Name of the type to be removed from the cache. If type
* exists, it will be removed, otherwise does nothing.
* @throws AtlasException
*/
void
remove
(
DataTypes
.
TypeCategory
typeCategory
,
String
typeName
)
throws
AtlasException
;
/**
* Clear the type cache
*
*/
void
clear
();
}
This diff is collapsed.
Click to expand it.
typesystem/src/test/java/org/apache/atlas/ApplicationPropertiesTest.java
View file @
5f248157
...
@@ -19,6 +19,7 @@ package org.apache.atlas;
...
@@ -19,6 +19,7 @@ package org.apache.atlas;
import
org.apache.atlas.typesystem.types.TypeSystem
;
import
org.apache.atlas.typesystem.types.TypeSystem
;
import
org.apache.commons.configuration.Configuration
;
import
org.apache.commons.configuration.Configuration
;
import
org.testng.Assert
;
import
org.testng.annotations.Test
;
import
org.testng.annotations.Test
;
import
static
org
.
testng
.
Assert
.
assertEquals
;
import
static
org
.
testng
.
Assert
.
assertEquals
;
...
@@ -58,11 +59,20 @@ public class ApplicationPropertiesTest {
...
@@ -58,11 +59,20 @@ public class ApplicationPropertiesTest {
@Test
@Test
public
void
testGetClass
()
throws
Exception
{
public
void
testGetClass
()
throws
Exception
{
//read from atlas-application.properties
//read from atlas-application.properties
Class
cls
=
ApplicationProperties
.
getClass
(
"atlas.TypeSystem.impl"
,
ApplicationProperties
.
class
.
getName
());
Class
cls
=
ApplicationProperties
.
getClass
(
"atlas.TypeSystem.impl"
,
ApplicationProperties
.
class
.
getName
()
,
TypeSystem
.
class
);
assertEquals
(
cls
.
getName
(),
TypeSystem
.
class
.
getName
());
assertEquals
(
cls
.
getName
(),
TypeSystem
.
class
.
getName
());
//default value
//default value
cls
=
ApplicationProperties
.
getClass
(
"atlas.TypeSystem2.impl"
,
TypeSystem
.
class
.
getName
());
cls
=
ApplicationProperties
.
getClass
(
"atlas.TypeSystem2.impl"
,
TypeSystem
.
class
.
getName
()
,
TypeSystem
.
class
);
assertEquals
(
cls
.
getName
(),
TypeSystem
.
class
.
getName
());
assertEquals
(
cls
.
getName
(),
TypeSystem
.
class
.
getName
());
//incompatible assignTo class, should throw AtlasException
try
{
cls
=
ApplicationProperties
.
getClass
(
"atlas.TypeSystem.impl"
,
ApplicationProperties
.
class
.
getName
(),
ApplicationProperties
.
class
);
Assert
.
fail
(
AtlasException
.
class
.
getSimpleName
()
+
" was expected but none thrown."
);
}
catch
(
AtlasException
e
)
{
// good
}
}
}
}
}
This diff is collapsed.
Click to expand it.
typesystem/src/test/java/org/apache/atlas/typesystem/types/TypeSystemTest.java
View file @
5f248157
...
@@ -209,7 +209,7 @@ public class TypeSystemTest extends BaseTest {
...
@@ -209,7 +209,7 @@ public class TypeSystemTest extends BaseTest {
}
}
@Test
@Test
public
void
testTypeNamesAreNotDuplicated
()
{
public
void
testTypeNamesAreNotDuplicated
()
throws
Exception
{
TypeSystem
typeSystem
=
getTypeSystem
();
TypeSystem
typeSystem
=
getTypeSystem
();
ImmutableList
<
String
>
traitNames
=
typeSystem
.
getTypeNamesByCategory
(
DataTypes
.
TypeCategory
.
TRAIT
);
ImmutableList
<
String
>
traitNames
=
typeSystem
.
getTypeNamesByCategory
(
DataTypes
.
TypeCategory
.
TRAIT
);
int
numTraits
=
traitNames
.
size
();
int
numTraits
=
traitNames
.
size
();
...
...
This diff is collapsed.
Click to expand it.
typesystem/src/test/java/org/apache/atlas/typesystem/types/cache/DefaultTypeCacheProviderTest.java
0 → 100644
View file @
5f248157
/**
* 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
.
atlas
.
typesystem
.
types
.
cache
;
import
static
org
.
testng
.
Assert
.
assertEquals
;
import
static
org
.
testng
.
Assert
.
assertFalse
;
import
static
org
.
testng
.
Assert
.
assertNotNull
;
import
static
org
.
testng
.
Assert
.
assertNull
;
import
static
org
.
testng
.
Assert
.
assertTrue
;
import
static
org
.
testng
.
Assert
.
fail
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.AtlasException
;
import
org.apache.atlas.typesystem.types.ClassType
;
import
org.apache.atlas.typesystem.types.DataTypes
;
import
org.apache.atlas.typesystem.types.DataTypes.TypeCategory
;
import
org.apache.atlas.typesystem.types.EnumType
;
import
org.apache.atlas.typesystem.types.EnumValue
;
import
org.apache.atlas.typesystem.types.IDataType
;
import
org.apache.atlas.typesystem.types.StructType
;
import
org.apache.atlas.typesystem.types.TraitType
;
import
org.apache.atlas.typesystem.types.TypeSystem
;
import
org.apache.atlas.typesystem.types.utils.TypesUtil
;
import
org.testng.annotations.BeforeClass
;
import
org.testng.annotations.BeforeMethod
;
import
org.testng.annotations.Test
;
import
com.google.common.collect.ImmutableSet
;
/**
* Tests functional behavior of {@link DefaultTypeCacheProvider}
*/
@SuppressWarnings
(
"rawtypes"
)
public
class
DefaultTypeCacheProviderTest
{
private
String
CLASSTYPE_CUSTOMER
=
"Customer"
;
private
String
STRUCTTYPE_ADDRESS
=
"Address"
;
private
String
TRAITTYPE_PRIVILEGED
=
"Privileged"
;
private
String
ENUMTYPE_SHIPPING
=
"Shipping"
;
private
String
UNKNOWN_TYPE
=
"UndefinedType"
;
private
ClassType
customerType
;
private
StructType
addressType
;
private
TraitType
privilegedTrait
;
private
EnumType
shippingEnum
;
private
DefaultTypeCacheProvider
cacheProvider
;
@BeforeClass
public
void
onetimeSetup
()
throws
Exception
{
// init TypeSystem
TypeSystem
ts
=
TypeSystem
.
getInstance
().
reset
();
// Customer ClassType
customerType
=
ts
.
defineClassType
(
TypesUtil
.
createClassTypeDef
(
CLASSTYPE_CUSTOMER
,
ImmutableSet
.<
String
>
of
(),
TypesUtil
.
createRequiredAttrDef
(
"name"
,
DataTypes
.
STRING_TYPE
),
TypesUtil
.
createRequiredAttrDef
(
"id"
,
DataTypes
.
LONG_TYPE
)));
// Address StructType
addressType
=
ts
.
defineStructType
(
STRUCTTYPE_ADDRESS
,
true
,
TypesUtil
.
createRequiredAttrDef
(
"first line"
,
DataTypes
.
STRING_TYPE
),
TypesUtil
.
createOptionalAttrDef
(
"second line"
,
DataTypes
.
STRING_TYPE
),
TypesUtil
.
createRequiredAttrDef
(
"city"
,
DataTypes
.
STRING_TYPE
),
TypesUtil
.
createRequiredAttrDef
(
"pincode"
,
DataTypes
.
INT_TYPE
));
// Privileged TraitType
privilegedTrait
=
ts
.
defineTraitType
(
TypesUtil
.
createTraitTypeDef
(
TRAITTYPE_PRIVILEGED
,
ImmutableSet
.<
String
>
of
(),
TypesUtil
.
createRequiredAttrDef
(
"category"
,
DataTypes
.
INT_TYPE
)));
// Shipping EnumType
shippingEnum
=
ts
.
defineEnumType
(
TypesUtil
.
createEnumTypeDef
(
ENUMTYPE_SHIPPING
,
new
EnumValue
(
"Domestic"
,
1
),
new
EnumValue
(
"International"
,
2
)));
}
@BeforeMethod
public
void
eachTestSetup
()
throws
Exception
{
cacheProvider
=
new
DefaultTypeCacheProvider
();
cacheProvider
.
put
(
customerType
);
cacheProvider
.
put
(
addressType
);
cacheProvider
.
put
(
privilegedTrait
);
cacheProvider
.
put
(
shippingEnum
);
}
@Test
public
void
testCacheGetType
()
throws
Exception
{
IDataType
custType
=
cacheProvider
.
get
(
CLASSTYPE_CUSTOMER
);
verifyType
(
custType
,
CLASSTYPE_CUSTOMER
,
ClassType
.
class
);
IDataType
addrType
=
cacheProvider
.
get
(
STRUCTTYPE_ADDRESS
);
verifyType
(
addrType
,
STRUCTTYPE_ADDRESS
,
StructType
.
class
);
IDataType
privTrait
=
cacheProvider
.
get
(
TRAITTYPE_PRIVILEGED
);
verifyType
(
privTrait
,
TRAITTYPE_PRIVILEGED
,
TraitType
.
class
);
IDataType
shippingEnum
=
cacheProvider
.
get
(
ENUMTYPE_SHIPPING
);
verifyType
(
shippingEnum
,
ENUMTYPE_SHIPPING
,
EnumType
.
class
);
assertNull
(
cacheProvider
.
get
(
UNKNOWN_TYPE
));
}
@Test
public
void
testCacheGetTypeByCategory
()
throws
Exception
{
IDataType
custType
=
cacheProvider
.
get
(
TypeCategory
.
CLASS
,
CLASSTYPE_CUSTOMER
);
verifyType
(
custType
,
CLASSTYPE_CUSTOMER
,
ClassType
.
class
);
IDataType
addrType
=
cacheProvider
.
get
(
TypeCategory
.
STRUCT
,
STRUCTTYPE_ADDRESS
);
verifyType
(
addrType
,
STRUCTTYPE_ADDRESS
,
StructType
.
class
);
IDataType
privTrait
=
cacheProvider
.
get
(
TypeCategory
.
TRAIT
,
TRAITTYPE_PRIVILEGED
);
verifyType
(
privTrait
,
TRAITTYPE_PRIVILEGED
,
TraitType
.
class
);
IDataType
shippingEnum
=
cacheProvider
.
get
(
TypeCategory
.
ENUM
,
ENUMTYPE_SHIPPING
);
verifyType
(
shippingEnum
,
ENUMTYPE_SHIPPING
,
EnumType
.
class
);
assertNull
(
cacheProvider
.
get
(
UNKNOWN_TYPE
));
}
private
void
verifyType
(
IDataType
actualType
,
String
expectedName
,
Class
<?
extends
IDataType
>
typeClass
)
{
assertNotNull
(
actualType
,
"The "
+
expectedName
+
" type not in cache"
);
assertTrue
(
typeClass
.
isInstance
(
actualType
));
assertEquals
(
actualType
.
getName
(),
expectedName
,
"The type name does not match"
);
}
@Test
public
void
testCacheHasType
()
throws
Exception
{
assertTrue
(
cacheProvider
.
has
(
CLASSTYPE_CUSTOMER
));
assertTrue
(
cacheProvider
.
has
(
STRUCTTYPE_ADDRESS
));
assertTrue
(
cacheProvider
.
has
(
TRAITTYPE_PRIVILEGED
));
assertTrue
(
cacheProvider
.
has
(
ENUMTYPE_SHIPPING
));
assertFalse
(
cacheProvider
.
has
(
UNKNOWN_TYPE
));
}
@Test
public
void
testCacheHasTypeByCategory
()
throws
Exception
{
assertTrue
(
cacheProvider
.
has
(
TypeCategory
.
CLASS
,
CLASSTYPE_CUSTOMER
));
assertTrue
(
cacheProvider
.
has
(
TypeCategory
.
STRUCT
,
STRUCTTYPE_ADDRESS
));
assertTrue
(
cacheProvider
.
has
(
TypeCategory
.
TRAIT
,
TRAITTYPE_PRIVILEGED
));
assertTrue
(
cacheProvider
.
has
(
TypeCategory
.
ENUM
,
ENUMTYPE_SHIPPING
));
assertFalse
(
cacheProvider
.
has
(
UNKNOWN_TYPE
));
}
@Test
public
void
testCacheGetAllTypeNames
()
throws
Exception
{
List
<
String
>
allTypeNames
=
new
ArrayList
<
String
>(
cacheProvider
.
getAllTypeNames
());
Collections
.
sort
(
allTypeNames
);
final
int
EXPECTED_TYPE_COUNT
=
4
;
assertEquals
(
allTypeNames
.
size
(),
EXPECTED_TYPE_COUNT
,
"Total number of types does not match."
);
assertEquals
(
STRUCTTYPE_ADDRESS
,
allTypeNames
.
get
(
0
));
assertEquals
(
CLASSTYPE_CUSTOMER
,
allTypeNames
.
get
(
1
));
assertEquals
(
TRAITTYPE_PRIVILEGED
,
allTypeNames
.
get
(
2
));
assertEquals
(
ENUMTYPE_SHIPPING
,
allTypeNames
.
get
(
3
));
}
@Test
public
void
testCacheGetTypeNamesByCategory
()
throws
Exception
{
List
<
String
>
classTypes
=
new
ArrayList
<
String
>(
cacheProvider
.
getTypeNames
(
TypeCategory
.
CLASS
));
final
int
EXPECTED_CLASSTYPE_COUNT
=
1
;
assertEquals
(
classTypes
.
size
(),
EXPECTED_CLASSTYPE_COUNT
);
assertEquals
(
CLASSTYPE_CUSTOMER
,
classTypes
.
get
(
0
));
List
<
String
>
structTypes
=
new
ArrayList
<
String
>(
cacheProvider
.
getTypeNames
(
TypeCategory
.
STRUCT
));
final
int
EXPECTED_STRUCTTYPE_COUNT
=
1
;
assertEquals
(
structTypes
.
size
(),
EXPECTED_STRUCTTYPE_COUNT
);
assertEquals
(
STRUCTTYPE_ADDRESS
,
structTypes
.
get
(
0
));
List
<
String
>
traitTypes
=
new
ArrayList
<
String
>(
cacheProvider
.
getTypeNames
(
TypeCategory
.
TRAIT
));
final
int
EXPECTED_TRAITTYPE_COUNT
=
1
;
assertEquals
(
traitTypes
.
size
(),
EXPECTED_TRAITTYPE_COUNT
);
assertEquals
(
TRAITTYPE_PRIVILEGED
,
traitTypes
.
get
(
0
));
List
<
String
>
enumTypes
=
new
ArrayList
<
String
>(
cacheProvider
.
getTypeNames
(
TypeCategory
.
ENUM
));
final
int
EXPECTED_ENUMTYPE_COUNT
=
1
;
assertEquals
(
enumTypes
.
size
(),
EXPECTED_ENUMTYPE_COUNT
);
assertEquals
(
ENUMTYPE_SHIPPING
,
enumTypes
.
get
(
0
));
}
@Test
public
void
testCacheBulkInsert
()
throws
Exception
{
List
<
IDataType
>
allTypes
=
new
ArrayList
<>();
allTypes
.
add
(
customerType
);
allTypes
.
add
(
addressType
);
allTypes
.
add
(
privilegedTrait
);
allTypes
.
add
(
shippingEnum
);
// create a new cache provider instead of using the one setup for every method call
cacheProvider
=
new
DefaultTypeCacheProvider
();
cacheProvider
.
putAll
(
allTypes
);
IDataType
custType
=
cacheProvider
.
get
(
CLASSTYPE_CUSTOMER
);
verifyType
(
custType
,
CLASSTYPE_CUSTOMER
,
ClassType
.
class
);
IDataType
addrType
=
cacheProvider
.
get
(
STRUCTTYPE_ADDRESS
);
verifyType
(
addrType
,
STRUCTTYPE_ADDRESS
,
StructType
.
class
);
IDataType
privTrait
=
cacheProvider
.
get
(
TRAITTYPE_PRIVILEGED
);
verifyType
(
privTrait
,
TRAITTYPE_PRIVILEGED
,
TraitType
.
class
);
IDataType
shippingEnum
=
cacheProvider
.
get
(
ENUMTYPE_SHIPPING
);
verifyType
(
shippingEnum
,
ENUMTYPE_SHIPPING
,
EnumType
.
class
);
}
@Test
public
void
testCacheRemove
()
throws
Exception
{
cacheProvider
.
remove
(
CLASSTYPE_CUSTOMER
);
assertNull
(
cacheProvider
.
get
(
CLASSTYPE_CUSTOMER
));
assertFalse
(
cacheProvider
.
has
(
CLASSTYPE_CUSTOMER
));
assertTrue
(
cacheProvider
.
getTypeNames
(
TypeCategory
.
CLASS
).
isEmpty
());
final
int
EXPECTED_TYPE_COUNT
=
3
;
assertEquals
(
cacheProvider
.
getAllTypeNames
().
size
(),
EXPECTED_TYPE_COUNT
);
}
@Test
public
void
testCacheRemoveByCategory
()
throws
Exception
{
cacheProvider
.
remove
(
TypeCategory
.
CLASS
,
CLASSTYPE_CUSTOMER
);
assertNull
(
cacheProvider
.
get
(
CLASSTYPE_CUSTOMER
));
assertFalse
(
cacheProvider
.
has
(
CLASSTYPE_CUSTOMER
));
assertTrue
(
cacheProvider
.
getTypeNames
(
TypeCategory
.
CLASS
).
isEmpty
());
final
int
EXPECTED_TYPE_COUNT
=
3
;
assertEquals
(
cacheProvider
.
getAllTypeNames
().
size
(),
EXPECTED_TYPE_COUNT
);
}
@Test
public
void
testCacheClear
()
throws
Exception
{
cacheProvider
.
clear
();
assertNull
(
cacheProvider
.
get
(
CLASSTYPE_CUSTOMER
));
assertFalse
(
cacheProvider
.
has
(
CLASSTYPE_CUSTOMER
));
assertNull
(
cacheProvider
.
get
(
STRUCTTYPE_ADDRESS
));
assertFalse
(
cacheProvider
.
has
(
STRUCTTYPE_ADDRESS
));
assertNull
(
cacheProvider
.
get
(
TRAITTYPE_PRIVILEGED
));
assertFalse
(
cacheProvider
.
has
(
TRAITTYPE_PRIVILEGED
));
assertNull
(
cacheProvider
.
get
(
ENUMTYPE_SHIPPING
));
assertFalse
(
cacheProvider
.
has
(
ENUMTYPE_SHIPPING
));
assertTrue
(
cacheProvider
.
getTypeNames
(
TypeCategory
.
CLASS
).
isEmpty
());
assertTrue
(
cacheProvider
.
getTypeNames
(
TypeCategory
.
STRUCT
).
isEmpty
());
assertTrue
(
cacheProvider
.
getTypeNames
(
TypeCategory
.
TRAIT
).
isEmpty
());
assertTrue
(
cacheProvider
.
getTypeNames
(
TypeCategory
.
ENUM
).
isEmpty
());
assertTrue
(
cacheProvider
.
getAllTypeNames
().
isEmpty
());
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testPutTypeWithNullType
()
throws
Exception
{
cacheProvider
.
put
(
null
);
fail
(
"Null type should be not allowed in 'put'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testPutTypeWithInvalidType
()
throws
Exception
{
cacheProvider
.
put
(
DataTypes
.
BOOLEAN_TYPE
);
fail
(
"type should only be an instance of ClassType | EnumType | StructType | TraitType in 'put'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testGetTypeWithNullCategory
()
throws
Exception
{
cacheProvider
.
get
(
null
,
CLASSTYPE_CUSTOMER
);
fail
(
"Null TypeCategory should be not allowed in 'get'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testGetTypeWithInvalidCategory
()
throws
Exception
{
cacheProvider
.
get
(
TypeCategory
.
PRIMITIVE
,
DataTypes
.
BOOLEAN_TYPE
.
getName
());
fail
(
"TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'get'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheHasTypeWithNullCategory
()
throws
Exception
{
cacheProvider
.
has
(
null
,
CLASSTYPE_CUSTOMER
);
fail
(
"Null TypeCategory should be not allowed in 'has'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheHasTypeWithInvalidCategory
()
throws
Exception
{
cacheProvider
.
has
(
TypeCategory
.
PRIMITIVE
,
DataTypes
.
BOOLEAN_TYPE
.
getName
());
fail
(
"TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'has'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheGetTypeNamesByNullCategory
()
throws
Exception
{
cacheProvider
.
getTypeNames
(
null
);
fail
(
"Null TypeCategory should be not allowed in 'getNames'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheGetTypeNamesByInvalidCategory
()
throws
Exception
{
cacheProvider
.
getTypeNames
(
TypeCategory
.
PRIMITIVE
);
fail
(
"TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'getNames'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheBulkInsertWithNullType
()
throws
Exception
{
List
<
IDataType
>
allTypes
=
new
ArrayList
<>();
allTypes
.
add
(
null
);
// create a new cache provider instead of using the one setup for every method call
cacheProvider
=
new
DefaultTypeCacheProvider
();
cacheProvider
.
putAll
(
allTypes
);
fail
(
"Null type should be not allowed in 'putAll'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheBulkInsertWithInvalidType
()
throws
Exception
{
List
<
IDataType
>
allTypes
=
new
ArrayList
<>();
allTypes
.
add
(
DataTypes
.
BOOLEAN_TYPE
);
// create a new cache provider instead of using the one setup for every method call
cacheProvider
=
new
DefaultTypeCacheProvider
();
cacheProvider
.
putAll
(
allTypes
);
fail
(
"type should only one of ClassType | EnumType | StructType | TraitType in 'putAll'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheRemoveByNullCategory
()
throws
Exception
{
cacheProvider
.
remove
(
null
,
CLASSTYPE_CUSTOMER
);
fail
(
"Null type should be not allowed in 'remove'"
);
}
@Test
(
expectedExceptions
=
AtlasException
.
class
)
public
void
testCacheRemoveByInvalidCategory
()
throws
Exception
{
cacheProvider
.
remove
(
TypeCategory
.
PRIMITIVE
,
DataTypes
.
BOOLEAN_TYPE
.
getName
());
fail
(
"TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'remove'"
);
}
}
This diff is collapsed.
Click to expand it.
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