3333import java .util .stream .Collectors ;
3434import java .util .stream .StreamSupport ;
3535
36+ import org .springframework .beans .BeansException ;
37+ import org .springframework .context .ApplicationContext ;
38+ import org .springframework .context .ApplicationContextAware ;
39+ import org .springframework .context .expression .BeanFactoryAccessor ;
40+ import org .springframework .context .expression .BeanFactoryResolver ;
3641import org .springframework .dao .DataAccessException ;
3742import org .springframework .dao .support .PersistenceExceptionTranslator ;
3843import org .springframework .data .domain .Persistable ;
3944import org .springframework .data .mapping .PersistentPropertyAccessor ;
45+ import org .springframework .expression .Expression ;
46+ import org .springframework .expression .ParserContext ;
47+ import org .springframework .expression .spel .standard .SpelExpressionParser ;
48+ import org .springframework .expression .spel .support .StandardEvaluationContext ;
4049
4150import com .arangodb .ArangoCollection ;
4251import com .arangodb .ArangoCursor ;
8190 * @author Christian Lechner
8291 * @author Reşat SABIQ
8392 */
84- public class ArangoTemplate implements ArangoOperations , CollectionCallback {
93+ public class ArangoTemplate implements ArangoOperations , CollectionCallback , ApplicationContextAware {
94+
95+ private static final SpelExpressionParser PARSER = new SpelExpressionParser ();
8596
8697 private volatile ArangoDBVersion version ;
8798 private final PersistenceExceptionTranslator exceptionTranslator ;
8899 private final ArangoConverter converter ;
89100 private final ArangoDB arango ;
90- private volatile ArangoDatabase database ;
91101 private final String databaseName ;
92- private final Map <String , ArangoCollection > collectionCache ;
102+ private final Expression databaseExpression ;
103+ private final Map <String , ArangoDatabase > databaseCache ;
104+ private final Map <CollectionCacheKey , CollectionCacheValue > collectionCache ;
105+
106+ private final StandardEvaluationContext context ;
93107
94108 public ArangoTemplate (final ArangoDB arango , final String database ) {
95109 this (arango , database , null );
@@ -105,32 +119,26 @@ public ArangoTemplate(final ArangoDB arango, final String database, final Arango
105119 this .arango = arango ._setCursorInitializer (
106120 new com .arangodb .springframework .core .template .ArangoCursorInitializer (converter ));
107121 this .databaseName = database ;
122+ this .databaseExpression = PARSER .parseExpression (databaseName , ParserContext .TEMPLATE_EXPRESSION );
108123 this .converter = converter ;
109124 this .exceptionTranslator = exceptionTranslator ;
125+ this .context = new StandardEvaluationContext ();
110126 // set concurrency level to 1 as writes are very rare compared to reads
111127 collectionCache = new ConcurrentHashMap <>(8 , 0.9f , 1 );
128+ databaseCache = new ConcurrentHashMap <>(8 , 0.9f , 1 );
112129 version = null ;
113130 }
114131
115132 private ArangoDatabase db () {
116- // guard against NPE because database can be set to null by dropDatabase() by another thread
117- ArangoDatabase db = database ;
118- if (db != null ) {
119- return db ;
120- }
121- // make sure the database is only created once
122- synchronized (this ) {
123- db = database ;
124- if (db != null ) {
125- return db ;
126- }
127- db = arango .db (databaseName );
133+ final String key = databaseExpression != null ? databaseExpression .getValue (context , String .class )
134+ : databaseName ;
135+ return databaseCache .computeIfAbsent (key , name -> {
136+ final ArangoDatabase db = arango .db (name );
128137 if (!db .exists ()) {
129138 db .create ();
130139 }
131- database = db ;
132140 return db ;
133- }
141+ });
134142 }
135143
136144 private DataAccessException translateExceptionIfPossible (final RuntimeException exception ) {
@@ -157,16 +165,23 @@ private ArangoCollection _collection(
157165 final ArangoPersistentEntity <?> persistentEntity ,
158166 final CollectionCreateOptions options ) {
159167
160- return collectionCache .computeIfAbsent (name , collName -> {
161- final ArangoCollection collection = db ().collection (collName );
162- if (!collection .exists ()) {
163- collection .create (options );
164- }
165- if (persistentEntity != null ) {
166- ensureCollectionIndexes (collection (collection ), persistentEntity );
167- }
168- return collection ;
169- });
168+ final ArangoDatabase db = db ();
169+ final Class <?> entityClass = persistentEntity != null ? persistentEntity .getType () : null ;
170+ final CollectionCacheValue value = collectionCache .computeIfAbsent (new CollectionCacheKey (db .name (), name ),
171+ key -> {
172+ final ArangoCollection collection = db .collection (name );
173+ if (!collection .exists ()) {
174+ collection .create (options );
175+ }
176+ return new CollectionCacheValue (collection );
177+ });
178+ final Collection <Class <?>> entities = value .getEntities ();
179+ final ArangoCollection collection = value .getCollection ();
180+ if (persistentEntity != null && !entities .contains (entityClass )) {
181+ value .addEntityClass (entityClass );
182+ ensureCollectionIndexes (collection (collection ), persistentEntity );
183+ }
184+ return collection ;
170185 }
171186
172187 private static void ensureCollectionIndexes (
@@ -656,18 +671,15 @@ public boolean exists(final Object id, final Class<?> entityClass) throws DataAc
656671
657672 @ Override
658673 public void dropDatabase () throws DataAccessException {
659- // guard against NPE because another thread could also call dropDatabase()
660- ArangoDatabase db = database ;
661- if (db == null ) {
662- db = arango .db (databaseName );
663- }
674+ final ArangoDatabase db = db ();
664675 try {
665676 db .drop ();
666677 } catch (final ArangoDBException e ) {
667678 throw translateExceptionIfPossible (e );
668679 }
669- database = null ;
670- collectionCache .clear ();
680+ databaseCache .remove (db .name ());
681+ collectionCache .keySet ().stream ().filter (key -> key .getDb ().equals (db .name ()))
682+ .forEach (key -> collectionCache .remove (key ));
671683 }
672684
673685 @ Override
@@ -709,4 +721,11 @@ public ArangoConverter getConverter() {
709721 return this .converter ;
710722 }
711723
724+ @ Override
725+ public void setApplicationContext (final ApplicationContext applicationContext ) throws BeansException {
726+ context .setRootObject (applicationContext );
727+ context .setBeanResolver (new BeanFactoryResolver (applicationContext ));
728+ context .addPropertyAccessor (new BeanFactoryAccessor ());
729+ }
730+
712731}
0 commit comments