33
33
import java .util .stream .Collectors ;
34
34
import java .util .stream .StreamSupport ;
35
35
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 ;
36
41
import org .springframework .dao .DataAccessException ;
37
42
import org .springframework .dao .support .PersistenceExceptionTranslator ;
38
43
import org .springframework .data .domain .Persistable ;
39
44
import 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 ;
40
49
41
50
import com .arangodb .ArangoCollection ;
42
51
import com .arangodb .ArangoCursor ;
81
90
* @author Christian Lechner
82
91
* @author Reşat SABIQ
83
92
*/
84
- public class ArangoTemplate implements ArangoOperations , CollectionCallback {
93
+ public class ArangoTemplate implements ArangoOperations , CollectionCallback , ApplicationContextAware {
94
+
95
+ private static final SpelExpressionParser PARSER = new SpelExpressionParser ();
85
96
86
97
private volatile ArangoDBVersion version ;
87
98
private final PersistenceExceptionTranslator exceptionTranslator ;
88
99
private final ArangoConverter converter ;
89
100
private final ArangoDB arango ;
90
- private volatile ArangoDatabase database ;
91
101
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 ;
93
107
94
108
public ArangoTemplate (final ArangoDB arango , final String database ) {
95
109
this (arango , database , null );
@@ -105,32 +119,26 @@ public ArangoTemplate(final ArangoDB arango, final String database, final Arango
105
119
this .arango = arango ._setCursorInitializer (
106
120
new com .arangodb .springframework .core .template .ArangoCursorInitializer (converter ));
107
121
this .databaseName = database ;
122
+ this .databaseExpression = PARSER .parseExpression (databaseName , ParserContext .TEMPLATE_EXPRESSION );
108
123
this .converter = converter ;
109
124
this .exceptionTranslator = exceptionTranslator ;
125
+ this .context = new StandardEvaluationContext ();
110
126
// set concurrency level to 1 as writes are very rare compared to reads
111
127
collectionCache = new ConcurrentHashMap <>(8 , 0.9f , 1 );
128
+ databaseCache = new ConcurrentHashMap <>(8 , 0.9f , 1 );
112
129
version = null ;
113
130
}
114
131
115
132
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 );
128
137
if (!db .exists ()) {
129
138
db .create ();
130
139
}
131
- database = db ;
132
140
return db ;
133
- }
141
+ });
134
142
}
135
143
136
144
private DataAccessException translateExceptionIfPossible (final RuntimeException exception ) {
@@ -157,16 +165,23 @@ private ArangoCollection _collection(
157
165
final ArangoPersistentEntity <?> persistentEntity ,
158
166
final CollectionCreateOptions options ) {
159
167
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 ;
170
185
}
171
186
172
187
private static void ensureCollectionIndexes (
@@ -656,18 +671,15 @@ public boolean exists(final Object id, final Class<?> entityClass) throws DataAc
656
671
657
672
@ Override
658
673
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 ();
664
675
try {
665
676
db .drop ();
666
677
} catch (final ArangoDBException e ) {
667
678
throw translateExceptionIfPossible (e );
668
679
}
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 ));
671
683
}
672
684
673
685
@ Override
@@ -709,4 +721,11 @@ public ArangoConverter getConverter() {
709
721
return this .converter ;
710
722
}
711
723
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
+
712
731
}
0 commit comments