1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.connector.store.jpa;
25
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.Enumeration;
31 import java.util.HashMap;
32 import java.util.Hashtable;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Properties;
36 import java.util.UUID;
37 import javax.naming.Context;
38 import javax.naming.InitialContext;
39 import javax.naming.RefAddr;
40 import javax.naming.Reference;
41 import javax.naming.StringRefAddr;
42 import javax.naming.spi.ObjectFactory;
43 import javax.persistence.EntityManager;
44 import javax.persistence.EntityManagerFactory;
45 import javax.sql.DataSource;
46 import net.jcip.annotations.Immutable;
47 import net.jcip.annotations.ThreadSafe;
48 import org.hibernate.SessionFactory;
49 import org.hibernate.ejb.Ejb3Configuration;
50 import org.modeshape.common.annotation.AllowedValues;
51 import org.modeshape.common.annotation.Category;
52 import org.modeshape.common.annotation.Description;
53 import org.modeshape.common.annotation.Label;
54 import org.modeshape.common.i18n.I18n;
55 import org.modeshape.common.util.CheckArg;
56 import org.modeshape.common.util.Logger;
57 import org.modeshape.common.util.StringUtil;
58 import org.modeshape.connector.store.jpa.model.simple.SimpleModel;
59 import org.modeshape.connector.store.jpa.util.StoreOptionEntity;
60 import org.modeshape.connector.store.jpa.util.StoreOptions;
61 import org.modeshape.graph.ExecutionContext;
62 import org.modeshape.graph.cache.CachePolicy;
63 import org.modeshape.graph.connector.RepositoryConnection;
64 import org.modeshape.graph.connector.RepositoryContext;
65 import org.modeshape.graph.connector.RepositorySource;
66 import org.modeshape.graph.connector.RepositorySourceCapabilities;
67 import org.modeshape.graph.connector.RepositorySourceException;
68
69
70
71
72
73
74 @ThreadSafe
75 public class JpaSource implements RepositorySource, ObjectFactory {
76
77 private final Logger LOGGER = Logger.getLogger(JpaSource.class);
78
79
80
81
82
83
84 public static class Models {
85 public static final Model SIMPLE = new SimpleModel();
86 private static final Model[] ALL_ARRAY = new Model[] {SIMPLE};
87 private static final List<Model> MODIFIABLE_MODELS = new ArrayList<Model>(Arrays.asList(ALL_ARRAY));
88 public static final Collection<Model> ALL = Collections.unmodifiableCollection(MODIFIABLE_MODELS);
89 public static final Model DEFAULT = SIMPLE;
90
91 public static boolean addModel( Model model ) {
92 CheckArg.isNotNull(model, "modelName");
93 for (Model existing : MODIFIABLE_MODELS) {
94 if (existing.getName().equals(model.getName())) return false;
95 }
96 return MODIFIABLE_MODELS.add(model);
97 }
98
99 public static Model getModel( String name ) {
100 CheckArg.isNotEmpty(name, "name");
101 name = name.trim();
102 for (Model existing : ALL) {
103 if (existing.getName().equals(name)) return existing;
104 }
105 return null;
106 }
107 }
108
109 protected static final String SOURCE_NAME = "sourceName";
110 protected static final String ROOT_NODE_UUID = "rootNodeUuid";
111 protected static final String DATA_SOURCE_JNDI_NAME = "dataSourceJndiName";
112 protected static final String DIALECT = "dialect";
113 protected static final String USERNAME = "username";
114 protected static final String PASSWORD = "password";
115 protected static final String URL = "url";
116 protected static final String DRIVER_CLASS_NAME = "driverClassName";
117 protected static final String DRIVER_CLASSLOADER_NAME = "driverClassloaderName";
118 protected static final String MAXIMUM_CONNECTIONS_IN_POOL = "maximumConnectionsInPool";
119 protected static final String MINIMUM_CONNECTIONS_IN_POOL = "minimumConnectionsInPool";
120 protected static final String MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS = "maximumConnectionIdleTimeInSeconds";
121 protected static final String MAXIMUM_SIZE_OF_STATEMENT_CACHE = "maximumSizeOfStatementCache";
122 protected static final String NUMBER_OF_CONNECTIONS_TO_BE_ACQUIRED_AS_NEEDED = "numberOfConnectionsToBeAcquiredAsNeeded";
123 protected static final String IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS = "idleTimeInSecondsBeforeTestingConnections";
124 protected static final String CACHE_TIME_TO_LIVE_IN_MILLISECONDS = "cacheTimeToLiveInMilliseconds";
125 protected static final String RETRY_LIMIT = "retryLimit";
126 protected static final String MODEL_NAME = "modelName";
127 protected static final String LARGE_VALUE_SIZE_IN_BYTES = "largeValueSizeInBytes";
128 protected static final String COMPRESS_DATA = "compressData";
129 protected static final String ENFORCE_REFERENTIAL_INTEGRITY = "enforceReferentialIntegrity";
130 protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
131 protected static final String PREDEFINED_WORKSPACE_NAMES = "predefinedWorkspaceNames";
132 protected static final String ALLOW_CREATING_WORKSPACES = "allowCreatingWorkspaces";
133 protected static final String AUTO_GENERATE_SCHEMA = "autoGenerateSchema";
134
135
136
137
138 protected static final boolean SUPPORTS_EVENTS = true;
139
140
141
142 protected static final boolean SUPPORTS_SAME_NAME_SIBLINGS = true;
143
144
145
146 protected static final boolean SUPPORTS_REFERENCES = true;
147
148
149
150
151 public static final boolean DEFAULT_ALLOWS_UPDATES = true;
152
153
154
155 public static final boolean DEFAULT_SHOW_SQL = false;
156
157
158
159 public static final boolean DEFAULT_SUPPORTS_CREATING_WORKSPACES = true;
160
161
162
163
164 public static final String DEFAULT_ROOT_NODE_UUID = "1497b6fe-8c7e-4bbb-aaa2-24f3d4942668";
165
166
167
168
169 public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default";
170
171 private static final int DEFAULT_RETRY_LIMIT = 0;
172 private static final int DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS = 60 * 5;
173 private static final int DEFAULT_MAXIMUM_FETCH_DEPTH = 3;
174 private static final int DEFAULT_MAXIMUM_CONNECTIONS_IN_POOL = 5;
175 private static final int DEFAULT_MINIMUM_CONNECTIONS_IN_POOL = 0;
176 private static final int DEFAULT_MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS = 60 * 10;
177 private static final int DEFAULT_MAXIMUM_NUMBER_OF_STATEMENTS_TO_CACHE = 100;
178 private static final int DEFAULT_NUMBER_OF_CONNECTIONS_TO_ACQUIRE_AS_NEEDED = 1;
179 private static final int DEFAULT_IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS = 60 * 3;
180 private static final int DEFAULT_LARGE_VALUE_SIZE_IN_BYTES = 1 << 10;
181 private static final boolean DEFAULT_COMPRESS_DATA = true;
182 private static final boolean DEFAULT_ENFORCE_REFERENTIAL_INTEGRITY = true;
183
184
185
186
187
188 public static final String DEFAULT_AUTO_GENERATE_SCHEMA = "validate";
189
190
191
192
193 private static final long serialVersionUID = 1L;
194
195 @Description( i18n = JpaConnectorI18n.class, value = "namePropertyDescription" )
196 @Label( i18n = JpaConnectorI18n.class, value = "namePropertyLabel" )
197 @Category( i18n = JpaConnectorI18n.class, value = "namePropertyCategory" )
198 private volatile String name;
199
200 @Description( i18n = JpaConnectorI18n.class, value = "dataSourceJndiNamePropertyDescription" )
201 @Label( i18n = JpaConnectorI18n.class, value = "dataSourceJndiNamePropertyLabel" )
202 @Category( i18n = JpaConnectorI18n.class, value = "dataSourceJndiNamePropertyCategory" )
203 private volatile String dataSourceJndiName;
204
205 @Description( i18n = JpaConnectorI18n.class, value = "dialectPropertyDescription" )
206 @Label( i18n = JpaConnectorI18n.class, value = "dialectPropertyLabel" )
207 @Category( i18n = JpaConnectorI18n.class, value = "dialectPropertyCategory" )
208 private volatile String dialect;
209
210 @Description( i18n = JpaConnectorI18n.class, value = "usernamePropertyDescription" )
211 @Label( i18n = JpaConnectorI18n.class, value = "usernamePropertyLabel" )
212 @Category( i18n = JpaConnectorI18n.class, value = "usernamePropertyCategory" )
213 private volatile String username;
214
215 @Description( i18n = JpaConnectorI18n.class, value = "passwordPropertyDescription" )
216 @Label( i18n = JpaConnectorI18n.class, value = "passwordPropertyLabel" )
217 @Category( i18n = JpaConnectorI18n.class, value = "passwordPropertyCategory" )
218 private volatile String password;
219
220 @Description( i18n = JpaConnectorI18n.class, value = "urlPropertyDescription" )
221 @Label( i18n = JpaConnectorI18n.class, value = "urlPropertyLabel" )
222 @Category( i18n = JpaConnectorI18n.class, value = "urlPropertyCategory" )
223 private volatile String url;
224
225 @Description( i18n = JpaConnectorI18n.class, value = "driverClassNamePropertyDescription" )
226 @Label( i18n = JpaConnectorI18n.class, value = "driverClassNamePropertyLabel" )
227 @Category( i18n = JpaConnectorI18n.class, value = "driverClassNamePropertyCategory" )
228 private volatile String driverClassName;
229
230
231
232
233 private volatile String driverClassloaderName;
234
235 @Description( i18n = JpaConnectorI18n.class, value = "rootNodeUuidPropertyDescription" )
236 @Label( i18n = JpaConnectorI18n.class, value = "rootNodeUuidPropertyLabel" )
237 @Category( i18n = JpaConnectorI18n.class, value = "rootNodeUuidPropertyCategory" )
238 private volatile String rootNodeUuid = DEFAULT_ROOT_NODE_UUID;
239
240 @Description( i18n = JpaConnectorI18n.class, value = "maximumConnectionsInPoolPropertyDescription" )
241 @Label( i18n = JpaConnectorI18n.class, value = "maximumConnectionsInPoolPropertyLabel" )
242 @Category( i18n = JpaConnectorI18n.class, value = "maximumConnectionsInPoolPropertyCategory" )
243 private volatile int maximumConnectionsInPool = DEFAULT_MAXIMUM_CONNECTIONS_IN_POOL;
244
245 @Description( i18n = JpaConnectorI18n.class, value = "minimumConnectionsInPoolPropertyDescription" )
246 @Label( i18n = JpaConnectorI18n.class, value = "minimumConnectionsInPoolPropertyLabel" )
247 @Category( i18n = JpaConnectorI18n.class, value = "minimumConnectionsInPoolPropertyCategory" )
248 private volatile int minimumConnectionsInPool = DEFAULT_MINIMUM_CONNECTIONS_IN_POOL;
249
250 @Description( i18n = JpaConnectorI18n.class, value = "maximumConnectionIdleTimeInSecondsPropertyDescription" )
251 @Label( i18n = JpaConnectorI18n.class, value = "maximumConnectionIdleTimeInSecondsPropertyLabel" )
252 @Category( i18n = JpaConnectorI18n.class, value = "maximumConnectionIdleTimeInSecondsPropertyCategory" )
253 private volatile int maximumConnectionIdleTimeInSeconds = DEFAULT_MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS;
254
255 @Description( i18n = JpaConnectorI18n.class, value = "maximumSizeOfStatementCachePropertyDescription" )
256 @Label( i18n = JpaConnectorI18n.class, value = "maximumSizeOfStatementCachePropertyLabel" )
257 @Category( i18n = JpaConnectorI18n.class, value = "maximumSizeOfStatementCachePropertyCategory" )
258 private volatile int maximumSizeOfStatementCache = DEFAULT_MAXIMUM_NUMBER_OF_STATEMENTS_TO_CACHE;
259
260 @Description( i18n = JpaConnectorI18n.class, value = "numberOfConnectionsToAcquireAsNeededPropertyDescription" )
261 @Label( i18n = JpaConnectorI18n.class, value = "numberOfConnectionsToAcquireAsNeededPropertyLabel" )
262 @Category( i18n = JpaConnectorI18n.class, value = "numberOfConnectionsToAcquireAsNeededPropertyCategory" )
263 private volatile int numberOfConnectionsToAcquireAsNeeded = DEFAULT_NUMBER_OF_CONNECTIONS_TO_ACQUIRE_AS_NEEDED;
264
265 @Description( i18n = JpaConnectorI18n.class, value = "idleTimeInSecondsBeforeTestingConnectionsPropertyDescription" )
266 @Label( i18n = JpaConnectorI18n.class, value = "idleTimeInSecondsBeforeTestingConnectionsPropertyLabel" )
267 @Category( i18n = JpaConnectorI18n.class, value = "idleTimeInSecondsBeforeTestingConnectionsPropertyCategory" )
268 private volatile int idleTimeInSecondsBeforeTestingConnections = DEFAULT_IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS;
269
270 @Description( i18n = JpaConnectorI18n.class, value = "retryLimitPropertyDescription" )
271 @Label( i18n = JpaConnectorI18n.class, value = "retryLimitPropertyLabel" )
272 @Category( i18n = JpaConnectorI18n.class, value = "retryLimitPropertyCategory" )
273 private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
274
275 @Description( i18n = JpaConnectorI18n.class, value = "cacheTimeToLiveInMillisecondsPropertyDescription" )
276 @Label( i18n = JpaConnectorI18n.class, value = "cacheTimeToLiveInMillisecondsPropertyLabel" )
277 @Category( i18n = JpaConnectorI18n.class, value = "cacheTimeToLiveInMillisecondsPropertyCategory" )
278 private volatile int cacheTimeToLiveInMilliseconds = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS * 1000;
279
280 @Description( i18n = JpaConnectorI18n.class, value = "largeValueSizeInBytesPropertyDescription" )
281 @Label( i18n = JpaConnectorI18n.class, value = "largeValueSizeInBytesPropertyLabel" )
282 @Category( i18n = JpaConnectorI18n.class, value = "largeValueSizeInBytesPropertyCategory" )
283 private volatile long largeValueSizeInBytes = DEFAULT_LARGE_VALUE_SIZE_IN_BYTES;
284
285 @Description( i18n = JpaConnectorI18n.class, value = "showSqlPropertyDescription" )
286 @Label( i18n = JpaConnectorI18n.class, value = "showSqlPropertyLabel" )
287 @Category( i18n = JpaConnectorI18n.class, value = "showSqlPropertyCategory" )
288 private volatile boolean showSql = DEFAULT_SHOW_SQL;
289
290 @Description( i18n = JpaConnectorI18n.class, value = "compressDataPropertyDescription" )
291 @Label( i18n = JpaConnectorI18n.class, value = "compressDataPropertyLabel" )
292 @Category( i18n = JpaConnectorI18n.class, value = "compressDataPropertyCategory" )
293 private volatile boolean compressData = DEFAULT_COMPRESS_DATA;
294
295
296
297
298 private volatile boolean referentialIntegrityEnforced = DEFAULT_ENFORCE_REFERENTIAL_INTEGRITY;
299
300 @Description( i18n = JpaConnectorI18n.class, value = "autoGenerateSchemaPropertyDescription" )
301 @Label( i18n = JpaConnectorI18n.class, value = "autoGenerateSchemaPropertyLabel" )
302 @Category( i18n = JpaConnectorI18n.class, value = "autoGenerateSchemaPropertyCategory" )
303 @AllowedValues( {"create", "create-drop", "update", "validate"} )
304 private volatile String autoGenerateSchema = DEFAULT_AUTO_GENERATE_SCHEMA;
305
306 @Description( i18n = JpaConnectorI18n.class, value = "defaultWorkspaceNamePropertyDescription" )
307 @Label( i18n = JpaConnectorI18n.class, value = "defaultWorkspaceNamePropertyLabel" )
308 @Category( i18n = JpaConnectorI18n.class, value = "defaultWorkspaceNamePropertyCategory" )
309 private volatile String defaultWorkspace = DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
310
311 @Description( i18n = JpaConnectorI18n.class, value = "predefinedWorkspacesPropertyDescription" )
312 @Label( i18n = JpaConnectorI18n.class, value = "predefinedWorkspacesPropertyLabel" )
313 @Category( i18n = JpaConnectorI18n.class, value = "predefinedWorkspacesPropertyCategory" )
314 private volatile String[] predefinedWorkspaces = new String[] {};
315
316 private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(
317 SUPPORTS_SAME_NAME_SIBLINGS,
318 DEFAULT_ALLOWS_UPDATES,
319 SUPPORTS_EVENTS,
320 DEFAULT_SUPPORTS_CREATING_WORKSPACES,
321 SUPPORTS_REFERENCES);
322
323 @Description( i18n = JpaConnectorI18n.class, value = "modelNamePropertyDescription" )
324 @Label( i18n = JpaConnectorI18n.class, value = "modelNamePropertyLabel" )
325 @Category( i18n = JpaConnectorI18n.class, value = "modelNamePropertyCategory" )
326 private volatile String modelName;
327 private transient Model model;
328 private transient DataSource dataSource;
329 private transient EntityManagers entityManagers;
330 private transient CachePolicy cachePolicy;
331 private transient RepositoryContext repositoryContext;
332 private transient UUID rootUuid = UUID.fromString(rootNodeUuid);
333
334
335
336
337
338
339 public String getName() {
340 return name;
341 }
342
343 protected Logger getLogger() {
344 return LOGGER;
345 }
346
347
348
349
350
351
352 public void setName( String name ) {
353 if (name != null) {
354 name = name.trim();
355 if (name.length() == 0) name = null;
356 }
357 this.name = name;
358 }
359
360
361
362
363
364
365 public RepositorySourceCapabilities getCapabilities() {
366 return capabilities;
367 }
368
369
370
371
372
373
374 @Description( i18n = JpaConnectorI18n.class, value = "updatesAllowedPropertyDescription" )
375 @Label( i18n = JpaConnectorI18n.class, value = "updatesAllowedPropertyLabel" )
376 @Category( i18n = JpaConnectorI18n.class, value = "updatesAllowedPropertyCategory" )
377 public boolean areUpdatesAllowed() {
378 return capabilities.supportsUpdates();
379 }
380
381
382
383
384
385
386 public synchronized void setAllowsUpdates( boolean allowsUpdates ) {
387 capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), allowsUpdates,
388 capabilities.supportsEvents(), capabilities.supportsCreatingWorkspaces(),
389 capabilities.supportsReferences());
390 }
391
392
393
394
395
396
397 public boolean getShowSql() {
398 return this.showSql;
399 }
400
401
402
403
404
405
406 public synchronized void setShowSql( boolean showSql ) {
407 this.showSql = showSql;
408 }
409
410
411
412
413
414
415
416 public String getAutoGenerateSchema() {
417 return this.autoGenerateSchema;
418 }
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440 public synchronized void setAutoGenerateSchema( String autoGenerateSchema ) {
441 this.autoGenerateSchema = autoGenerateSchema != null ? autoGenerateSchema.trim() : DEFAULT_AUTO_GENERATE_SCHEMA;
442 }
443
444
445
446
447
448
449 public int getRetryLimit() {
450 return retryLimit;
451 }
452
453
454
455
456
457
458 public synchronized void setRetryLimit( int limit ) {
459 if (limit < 0) limit = 0;
460 this.retryLimit = limit;
461 }
462
463
464
465
466
467
468 public int getCacheTimeToLiveInMilliseconds() {
469 return cacheTimeToLiveInMilliseconds;
470 }
471
472
473
474
475
476
477
478 public synchronized void setCacheTimeToLiveInMilliseconds( int cacheTimeToLive ) {
479 if (cacheTimeToLive < 0) cacheTimeToLive = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS;
480 this.cacheTimeToLiveInMilliseconds = cacheTimeToLive;
481 this.cachePolicy = cacheTimeToLiveInMilliseconds > 0 ? new JpaCachePolicy(cacheTimeToLiveInMilliseconds) : null;
482 }
483
484
485
486
487
488
489 public CachePolicy getCachePolicy() {
490 return cachePolicy;
491 }
492
493
494
495
496
497
498 public EntityManagers getEntityManagers() {
499 return entityManagers;
500 }
501
502
503
504
505 public String getRootNodeUuid() {
506 return rootNodeUuid;
507 }
508
509
510
511
512 public UUID getRootUuid() {
513 return rootUuid;
514 }
515
516
517
518
519
520 public void setRootNodeUuid( String rootNodeUuid ) {
521 if (rootNodeUuid != null && rootNodeUuid.trim().length() == 0) rootNodeUuid = DEFAULT_ROOT_NODE_UUID;
522 this.rootUuid = UUID.fromString(rootNodeUuid);
523 this.rootNodeUuid = rootNodeUuid;
524 }
525
526
527
528
529
530
531 public String getDefaultWorkspaceName() {
532 return defaultWorkspace;
533 }
534
535
536
537
538
539
540
541 public synchronized void setDefaultWorkspaceName( String nameOfDefaultWorkspace ) {
542 this.defaultWorkspace = nameOfDefaultWorkspace != null ? nameOfDefaultWorkspace : DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
543 }
544
545
546
547
548
549
550
551
552 public synchronized String[] getPredefinedWorkspaceNames() {
553 String[] copy = new String[predefinedWorkspaces.length];
554 System.arraycopy(predefinedWorkspaces, 0, copy, 0, predefinedWorkspaces.length);
555 return copy;
556 }
557
558
559
560
561
562
563
564
565
566 public synchronized void setPredefinedWorkspaceNames( String[] predefinedWorkspaceNames ) {
567 if (predefinedWorkspaceNames != null && predefinedWorkspaceNames.length == 1) {
568 predefinedWorkspaceNames = predefinedWorkspaceNames[0].split("\\s*,\\s*");
569 }
570 this.predefinedWorkspaces = predefinedWorkspaceNames != null ? predefinedWorkspaceNames : new String[] {};
571 }
572
573
574
575
576
577
578
579
580
581
582 @Description( i18n = JpaConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyDescription" )
583 @Label( i18n = JpaConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyLabel" )
584 @Category( i18n = JpaConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyCategory" )
585 public boolean isCreatingWorkspacesAllowed() {
586 return capabilities.supportsCreatingWorkspaces();
587 }
588
589
590
591
592
593
594
595
596
597
598 public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
599 capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), capabilities.supportsUpdates(),
600 capabilities.supportsEvents(), allowWorkspaceCreation,
601 capabilities.supportsReferences());
602 }
603
604
605
606
607 public String getDialect() {
608 return dialect;
609 }
610
611
612
613
614 public synchronized void setDialect( String dialect ) {
615 if (dialect != null && dialect.trim().length() == 0) dialect = null;
616 this.dialect = dialect;
617 }
618
619
620
621
622 public String getDataSourceJndiName() {
623 return dataSourceJndiName;
624 }
625
626
627
628
629 public void setDataSourceJndiName( String dataSourceJndiName ) {
630 if (dataSourceJndiName != null && dataSourceJndiName.trim().length() == 0) dataSourceJndiName = null;
631 this.dataSourceJndiName = dataSourceJndiName;
632 }
633
634
635
636
637 public String getDriverClassName() {
638 return driverClassName;
639 }
640
641
642
643
644 public synchronized void setDriverClassName( String driverClassName ) {
645 if (driverClassName != null && driverClassName.trim().length() == 0) driverClassName = null;
646 this.driverClassName = driverClassName;
647 }
648
649
650
651
652 public String getDriverClassloaderName() {
653 return driverClassloaderName;
654 }
655
656
657
658
659 public void setDriverClassloaderName( String driverClassloaderName ) {
660 if (driverClassloaderName != null && driverClassloaderName.trim().length() == 0) driverClassloaderName = null;
661 this.driverClassloaderName = driverClassloaderName;
662 }
663
664
665
666
667 public String getUsername() {
668 return username;
669 }
670
671
672
673
674 public synchronized void setUsername( String username ) {
675 this.username = username;
676 }
677
678
679
680
681 public String getPassword() {
682 return password;
683 }
684
685
686
687
688 public synchronized void setPassword( String password ) {
689 this.password = password;
690 }
691
692
693
694
695 public String getUrl() {
696 return url;
697 }
698
699
700
701
702 public synchronized void setUrl( String url ) {
703 if (url != null && url.trim().length() == 0) url = null;
704 this.url = url;
705 }
706
707
708
709
710 public int getMaximumConnectionsInPool() {
711 return maximumConnectionsInPool;
712 }
713
714
715
716
717 public synchronized void setMaximumConnectionsInPool( int maximumConnectionsInPool ) {
718 if (maximumConnectionsInPool < 0) maximumConnectionsInPool = DEFAULT_MAXIMUM_CONNECTIONS_IN_POOL;
719 this.maximumConnectionsInPool = maximumConnectionsInPool;
720 }
721
722
723
724
725 public int getMinimumConnectionsInPool() {
726 return minimumConnectionsInPool;
727 }
728
729
730
731
732 public synchronized void setMinimumConnectionsInPool( int minimumConnectionsInPool ) {
733 if (minimumConnectionsInPool < 0) minimumConnectionsInPool = DEFAULT_MINIMUM_CONNECTIONS_IN_POOL;
734 this.minimumConnectionsInPool = minimumConnectionsInPool;
735 }
736
737
738
739
740 public int getMaximumConnectionIdleTimeInSeconds() {
741 return maximumConnectionIdleTimeInSeconds;
742 }
743
744
745
746
747 public synchronized void setMaximumConnectionIdleTimeInSeconds( int maximumConnectionIdleTimeInSeconds ) {
748 if (maximumConnectionIdleTimeInSeconds < 0) maximumConnectionIdleTimeInSeconds = DEFAULT_MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS;
749 this.maximumConnectionIdleTimeInSeconds = maximumConnectionIdleTimeInSeconds;
750 }
751
752
753
754
755 public int getMaximumSizeOfStatementCache() {
756 return maximumSizeOfStatementCache;
757 }
758
759
760
761
762 public synchronized void setMaximumSizeOfStatementCache( int maximumSizeOfStatementCache ) {
763 if (maximumSizeOfStatementCache < 0) maximumSizeOfStatementCache = DEFAULT_MAXIMUM_NUMBER_OF_STATEMENTS_TO_CACHE;
764 this.maximumSizeOfStatementCache = maximumSizeOfStatementCache;
765 }
766
767
768
769
770 public int getNumberOfConnectionsToAcquireAsNeeded() {
771 return numberOfConnectionsToAcquireAsNeeded;
772 }
773
774
775
776
777 public synchronized void setNumberOfConnectionsToAcquireAsNeeded( int numberOfConnectionsToAcquireAsNeeded ) {
778 if (numberOfConnectionsToAcquireAsNeeded < 0) numberOfConnectionsToAcquireAsNeeded = DEFAULT_NUMBER_OF_CONNECTIONS_TO_ACQUIRE_AS_NEEDED;
779 this.numberOfConnectionsToAcquireAsNeeded = numberOfConnectionsToAcquireAsNeeded;
780 }
781
782
783
784
785 public int getIdleTimeInSecondsBeforeTestingConnections() {
786 return idleTimeInSecondsBeforeTestingConnections;
787 }
788
789
790
791
792 public synchronized void setIdleTimeInSecondsBeforeTestingConnections( int idleTimeInSecondsBeforeTestingConnections ) {
793 if (idleTimeInSecondsBeforeTestingConnections < 0) idleTimeInSecondsBeforeTestingConnections = DEFAULT_IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS;
794 this.idleTimeInSecondsBeforeTestingConnections = idleTimeInSecondsBeforeTestingConnections;
795 }
796
797
798
799
800
801
802
803
804
805 return dataSource;
806 }
807
808
809
810
811
812
813
814
815
816 this.dataSource = dataSource;
817 }
818
819
820
821
822
823
824
825 public String getModel() {
826 return modelName;
827 }
828
829
830
831
832
833
834
835 public synchronized void setModel( String modelName ) {
836 if (modelName != null) {
837 modelName = modelName.trim();
838 if (modelName.length() == 0) modelName = null;
839 }
840 if (modelName == null) {
841 model = null;
842 return;
843 }
844 Model model = Models.getModel(modelName);
845 if (model == null) {
846 StringBuilder sb = new StringBuilder();
847 boolean first = true;
848 for (Model existing : Models.ALL) {
849 if (!first) {
850 first = false;
851 sb.append(", ");
852 }
853 sb.append('"').append(existing.getName()).append('"');
854 }
855 String modelNames = sb.toString();
856 throw new IllegalArgumentException(JpaConnectorI18n.unknownModelName.text(model, modelNames));
857 }
858 this.model = model;
859 this.modelName = modelName;
860 }
861
862
863
864
865 public long getLargeValueSizeInBytes() {
866 return largeValueSizeInBytes;
867 }
868
869
870
871
872 public void setLargeValueSizeInBytes( long largeValueSizeInBytes ) {
873 if (largeValueSizeInBytes < 0) largeValueSizeInBytes = DEFAULT_LARGE_VALUE_SIZE_IN_BYTES;
874 this.largeValueSizeInBytes = largeValueSizeInBytes;
875 }
876
877
878
879
880 public boolean isCompressData() {
881 return compressData;
882 }
883
884
885
886
887 public void setCompressData( boolean compressData ) {
888 this.compressData = compressData;
889 }
890
891
892
893
894 public boolean isReferentialIntegrityEnforced() {
895 return referentialIntegrityEnforced;
896 }
897
898
899
900
901 public void setReferentialIntegrityEnforced( boolean referentialIntegrityEnforced ) {
902 this.referentialIntegrityEnforced = referentialIntegrityEnforced;
903 }
904
905
906
907
908
909
910 public void initialize( RepositoryContext context ) throws RepositorySourceException {
911 this.repositoryContext = context;
912 }
913
914
915
916
917
918
919 public Reference getReference() {
920 String className = getClass().getName();
921 String factoryClassName = this.getClass().getName();
922 Reference ref = new Reference(className, factoryClassName, null);
923
924 ref.add(new StringRefAddr(SOURCE_NAME, getName()));
925 ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuid()));
926 ref.add(new StringRefAddr(DATA_SOURCE_JNDI_NAME, getDataSourceJndiName()));
927 ref.add(new StringRefAddr(DIALECT, getDialect()));
928 ref.add(new StringRefAddr(USERNAME, getUsername()));
929 ref.add(new StringRefAddr(PASSWORD, getPassword()));
930 ref.add(new StringRefAddr(URL, getUrl()));
931 ref.add(new StringRefAddr(DRIVER_CLASS_NAME, getDriverClassName()));
932 ref.add(new StringRefAddr(DRIVER_CLASSLOADER_NAME, getDriverClassloaderName()));
933 ref.add(new StringRefAddr(MAXIMUM_CONNECTIONS_IN_POOL, Integer.toString(getMaximumConnectionsInPool())));
934 ref.add(new StringRefAddr(MINIMUM_CONNECTIONS_IN_POOL, Integer.toString(getMinimumConnectionsInPool())));
935 ref.add(new StringRefAddr(MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS,
936 Integer.toString(getMaximumConnectionIdleTimeInSeconds())));
937 ref.add(new StringRefAddr(MAXIMUM_SIZE_OF_STATEMENT_CACHE, Integer.toString(getMaximumSizeOfStatementCache())));
938 ref.add(new StringRefAddr(NUMBER_OF_CONNECTIONS_TO_BE_ACQUIRED_AS_NEEDED,
939 Integer.toString(getNumberOfConnectionsToAcquireAsNeeded())));
940 ref.add(new StringRefAddr(IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS,
941 Integer.toString(getIdleTimeInSecondsBeforeTestingConnections())));
942 ref.add(new StringRefAddr(CACHE_TIME_TO_LIVE_IN_MILLISECONDS, Integer.toString(getCacheTimeToLiveInMilliseconds())));
943 ref.add(new StringRefAddr(LARGE_VALUE_SIZE_IN_BYTES, Long.toString(getLargeValueSizeInBytes())));
944 ref.add(new StringRefAddr(COMPRESS_DATA, Boolean.toString(isCompressData())));
945 ref.add(new StringRefAddr(ENFORCE_REFERENTIAL_INTEGRITY, Boolean.toString(isReferentialIntegrityEnforced())));
946 ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName()));
947 ref.add(new StringRefAddr(ALLOW_CREATING_WORKSPACES, Boolean.toString(isCreatingWorkspacesAllowed())));
948 ref.add(new StringRefAddr(AUTO_GENERATE_SCHEMA, getAutoGenerateSchema()));
949 String[] workspaceNames = getPredefinedWorkspaceNames();
950 if (workspaceNames != null && workspaceNames.length != 0) {
951 ref.add(new StringRefAddr(PREDEFINED_WORKSPACE_NAMES, StringUtil.combineLines(workspaceNames)));
952 }
953 if (getModel() != null) {
954 ref.add(new StringRefAddr(MODEL_NAME, getModel()));
955 }
956 ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
957 return ref;
958 }
959
960
961
962
963
964
965 public RepositoryContext getRepositoryContext() {
966 return repositoryContext;
967 }
968
969
970
971
972 public Object getObjectInstance( Object obj,
973 javax.naming.Name name,
974 Context nameCtx,
975 Hashtable<?, ?> environment ) throws Exception {
976 if (obj instanceof Reference) {
977 Map<String, String> values = new HashMap<String, String>();
978 Reference ref = (Reference)obj;
979 Enumeration<?> en = ref.getAll();
980 while (en.hasMoreElements()) {
981 RefAddr subref = (RefAddr)en.nextElement();
982 if (subref instanceof StringRefAddr) {
983 String key = subref.getType();
984 Object value = subref.getContent();
985 if (value != null) values.put(key, value.toString());
986 }
987 }
988 String sourceName = values.get(SOURCE_NAME);
989 String rootNodeUuid = values.get(ROOT_NODE_UUID);
990 String dataSourceJndiName = values.get(DATA_SOURCE_JNDI_NAME);
991 String dialect = values.get(DIALECT);
992 String username = values.get(USERNAME);
993 String password = values.get(PASSWORD);
994 String url = values.get(URL);
995 String driverClassName = values.get(DRIVER_CLASS_NAME);
996 String driverClassloaderName = values.get(DRIVER_CLASSLOADER_NAME);
997 String maxConnectionsInPool = values.get(MAXIMUM_CONNECTIONS_IN_POOL);
998 String minConnectionsInPool = values.get(MINIMUM_CONNECTIONS_IN_POOL);
999 String maxConnectionIdleTimeInSec = values.get(MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS);
1000 String maxSizeOfStatementCache = values.get(MAXIMUM_SIZE_OF_STATEMENT_CACHE);
1001 String acquisitionIncrement = values.get(NUMBER_OF_CONNECTIONS_TO_BE_ACQUIRED_AS_NEEDED);
1002 String idleTimeInSeconds = values.get(IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS);
1003 String cacheTtlInMillis = values.get(CACHE_TIME_TO_LIVE_IN_MILLISECONDS);
1004 String modelName = values.get(MODEL_NAME);
1005 String retryLimit = values.get(RETRY_LIMIT);
1006 String largeModelSize = values.get(LARGE_VALUE_SIZE_IN_BYTES);
1007 String compressData = values.get(COMPRESS_DATA);
1008 String refIntegrity = values.get(ENFORCE_REFERENTIAL_INTEGRITY);
1009 String defaultWorkspace = values.get(DEFAULT_WORKSPACE);
1010 String createWorkspaces = values.get(ALLOW_CREATING_WORKSPACES);
1011 String autoGenerateSchema = values.get(AUTO_GENERATE_SCHEMA);
1012
1013 String combinedWorkspaceNames = values.get(PREDEFINED_WORKSPACE_NAMES);
1014 String[] workspaceNames = null;
1015 if (combinedWorkspaceNames != null) {
1016 List<String> paths = StringUtil.splitLines(combinedWorkspaceNames);
1017 workspaceNames = paths.toArray(new String[paths.size()]);
1018 }
1019
1020
1021 JpaSource source = new JpaSource();
1022 if (sourceName != null) source.setName(sourceName);
1023 if (rootNodeUuid != null) source.setRootNodeUuid(rootNodeUuid);
1024 if (dataSourceJndiName != null) source.setDataSourceJndiName(dataSourceJndiName);
1025 if (dialect != null) source.setDialect(dialect);
1026 if (username != null) source.setUsername(username);
1027 if (password != null) source.setPassword(password);
1028 if (url != null) source.setUrl(url);
1029 if (driverClassName != null) source.setDriverClassName(driverClassName);
1030 if (driverClassloaderName != null) source.setDriverClassloaderName(driverClassloaderName);
1031 if (maxConnectionsInPool != null) source.setMaximumConnectionsInPool(Integer.parseInt(maxConnectionsInPool));
1032 if (minConnectionsInPool != null) source.setMinimumConnectionsInPool(Integer.parseInt(minConnectionsInPool));
1033 if (maxConnectionIdleTimeInSec != null) source.setMaximumConnectionIdleTimeInSeconds(Integer.parseInt(maxConnectionIdleTimeInSec));
1034 if (maxSizeOfStatementCache != null) source.setMaximumSizeOfStatementCache(Integer.parseInt(maxSizeOfStatementCache));
1035 if (acquisitionIncrement != null) source.setNumberOfConnectionsToAcquireAsNeeded(Integer.parseInt(acquisitionIncrement));
1036 if (idleTimeInSeconds != null) source.setIdleTimeInSecondsBeforeTestingConnections(Integer.parseInt(idleTimeInSeconds));
1037 if (cacheTtlInMillis != null) source.setCacheTimeToLiveInMilliseconds(Integer.parseInt(cacheTtlInMillis));
1038 if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
1039 if (modelName != null) source.setModel(modelName);
1040 if (largeModelSize != null) source.setLargeValueSizeInBytes(Long.parseLong(largeModelSize));
1041 if (compressData != null) source.setCompressData(Boolean.parseBoolean(compressData));
1042 if (refIntegrity != null) source.setReferentialIntegrityEnforced(Boolean.parseBoolean(refIntegrity));
1043 if (defaultWorkspace != null) source.setDefaultWorkspaceName(defaultWorkspace);
1044 if (createWorkspaces != null) source.setCreatingWorkspacesAllowed(Boolean.parseBoolean(createWorkspaces));
1045 if (workspaceNames != null && workspaceNames.length != 0) source.setPredefinedWorkspaceNames(workspaceNames);
1046 if (autoGenerateSchema != null) source.setAutoGenerateSchema(autoGenerateSchema);
1047 return source;
1048 }
1049 return null;
1050 }
1051
1052
1053
1054
1055
1056
1057 public synchronized RepositoryConnection getConnection() throws RepositorySourceException {
1058 if (this.name == null || this.name.trim().length() == 0) {
1059 throw new RepositorySourceException(JpaConnectorI18n.repositorySourceMustHaveName.text());
1060 }
1061 assert rootNodeUuid != null;
1062 assert rootUuid != null;
1063 if (entityManagers == null) {
1064
1065 Ejb3Configuration configurator = new Ejb3Configuration();
1066
1067
1068 configurator.addAnnotatedClass(StoreOptionEntity.class);
1069
1070
1071 configure(configurator);
1072
1073
1074 if (this.dataSource == null && this.dataSourceJndiName != null) {
1075
1076 try {
1077 Context context = new InitialContext();
1078 dataSource = (DataSource)context.lookup(this.dataSourceJndiName);
1079 } catch (Throwable t) {
1080 Logger.getLogger(getClass())
1081 .error(t, JpaConnectorI18n.errorFindingDataSourceInJndi, name, dataSourceJndiName);
1082 }
1083 }
1084
1085 if (this.dataSource != null) {
1086
1087 configurator.setDataSource(this.dataSource);
1088 } else {
1089
1090 if (this.repositoryContext != null && this.driverClassloaderName != null) {
1091 try {
1092 ExecutionContext context = this.repositoryContext.getExecutionContext();
1093 ClassLoader loader = context.getClassLoader(this.driverClassloaderName);
1094 if (loader != null) {
1095 Thread.currentThread().setContextClassLoader(loader);
1096 }
1097 } catch (Throwable t) {
1098 I18n msg = JpaConnectorI18n.errorSettingContextClassLoader;
1099 Logger.getLogger(getClass()).error(t, msg, name, driverClassloaderName);
1100 }
1101 }
1102
1103 setProperty(configurator, "hibernate.dialect", this.dialect);
1104 setProperty(configurator, "hibernate.connection.driver_class", this.driverClassName);
1105 setProperty(configurator, "hibernate.connection.username", this.username);
1106 setProperty(configurator, "hibernate.connection.password", this.password);
1107 setProperty(configurator, "hibernate.connection.url", this.url);
1108 setProperty(configurator, "hibernate.connection.max_fetch_depth", DEFAULT_MAXIMUM_FETCH_DEPTH);
1109 setProperty(configurator, "hibernate.connection.pool_size", 0);
1110 setProperty(configurator, "hibernate.show_sql", String.valueOf(this.showSql));
1111 }
1112
1113 Logger logger = getLogger();
1114 if (logger.isDebugEnabled()) {
1115 logger.debug("Properties for Hibernate configuration used for ModeShape JPA Source {0}:", getName());
1116 Properties props = configurator.getProperties();
1117 for (Map.Entry<Object, Object> entry : props.entrySet()) {
1118 String propName = entry.getKey().toString();
1119 if (propName.startsWith("hibernate")) {
1120 logger.debug(" {0} = {1}", propName, entry.getValue());
1121 }
1122 }
1123 }
1124
1125 EntityManagerFactory entityManagerFactory = configurator.buildEntityManagerFactory();
1126 try {
1127
1128 EntityManager entityManager = entityManagerFactory.createEntityManager();
1129 try {
1130
1131
1132 StoreOptions options = new StoreOptions(entityManager);
1133 UUID actualUuid = options.getRootNodeUuid();
1134 if (actualUuid != null) {
1135 this.setRootNodeUuid(actualUuid.toString());
1136 } else {
1137 options.setRootNodeUuid(this.rootUuid);
1138 }
1139
1140
1141 String actualModelName = options.getModelName();
1142 if (actualModelName == null) {
1143
1144 if (model == null) setModel(Models.DEFAULT.getName());
1145 assert model != null;
1146 options.setModelName(model);
1147 } else {
1148
1149 try {
1150 setModel(actualModelName);
1151 } catch (Throwable e) {
1152
1153 String msg = JpaConnectorI18n.existingStoreSpecifiesUnknownModel.text(name, actualModelName);
1154 throw new RepositorySourceException(msg);
1155 }
1156 }
1157 } finally {
1158 entityManager.close();
1159 }
1160 } finally {
1161 entityManagerFactory.close();
1162 }
1163
1164
1165 model.configure(configurator);
1166
1167
1168 entityManagers = new EntityManagers(configurator);
1169 }
1170
1171 return model.createConnection(this);
1172 }
1173
1174
1175
1176
1177
1178
1179 public synchronized void close() {
1180 if (entityManagers != null) {
1181 try {
1182
1183
1184 entityManagers.close();
1185 } finally {
1186 entityManagers = null;
1187 }
1188 }
1189 }
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201 protected void configure( Ejb3Configuration configuration ) {
1202
1203 setProperty(configuration, "hibernate.connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");
1204 setProperty(configuration, "hibernate.c3p0.max_size", this.maximumConnectionsInPool);
1205 setProperty(configuration, "hibernate.c3p0.min_size", this.minimumConnectionsInPool);
1206 setProperty(configuration, "hibernate.c3p0.timeout", this.maximumConnectionIdleTimeInSeconds);
1207 setProperty(configuration, "hibernate.c3p0.max_statements", this.maximumSizeOfStatementCache);
1208 setProperty(configuration, "hibernate.c3p0.idle_test_period", this.idleTimeInSecondsBeforeTestingConnections);
1209 setProperty(configuration, "hibernate.c3p0.acquire_increment", this.numberOfConnectionsToAcquireAsNeeded);
1210 setProperty(configuration, "hibernate.c3p0.validate", "false");
1211
1212
1213 setProperty(configuration, "hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
1214
1215
1216
1217 setProperty(configuration, "hibernate.format_sql", "true");
1218 setProperty(configuration, "hibernate.use_sql_comments", "true");
1219 setProperty(configuration, "hibernate.hbm2ddl.auto", this.autoGenerateSchema);
1220 }
1221
1222 protected void setProperty( Ejb3Configuration configurator,
1223 String propertyName,
1224 String propertyValue ) {
1225 assert configurator != null;
1226 assert propertyName != null;
1227 assert propertyName.trim().length() != 0;
1228 if (propertyValue != null) {
1229 configurator.setProperty(propertyName, propertyValue.trim());
1230 }
1231 }
1232
1233 protected void setProperty( Ejb3Configuration configurator,
1234 String propertyName,
1235 int propertyValue ) {
1236 assert configurator != null;
1237 assert propertyName != null;
1238 assert propertyName.trim().length() != 0;
1239 configurator.setProperty(propertyName, Integer.toString(propertyValue));
1240 }
1241
1242 @Immutable
1243
1244 private static final long serialVersionUID = 1L;
1245 private final int ttl;
1246
1247
1248 this.ttl = ttl;
1249 }
1250
1251 public long getTimeToLive() {
1252 return ttl;
1253 }
1254
1255 }
1256
1257 }