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.jbosscache;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.ByteArrayOutputStream;
28 import java.io.IOException;
29 import java.io.ObjectInputStream;
30 import java.io.ObjectOutputStream;
31 import java.util.Enumeration;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Hashtable;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.UUID;
39 import javax.naming.BinaryRefAddr;
40 import javax.naming.Context;
41 import javax.naming.InitialContext;
42 import javax.naming.NamingException;
43 import javax.naming.RefAddr;
44 import javax.naming.Reference;
45 import javax.naming.Referenceable;
46 import javax.naming.StringRefAddr;
47 import javax.naming.spi.ObjectFactory;
48 import net.jcip.annotations.GuardedBy;
49 import net.jcip.annotations.ThreadSafe;
50 import org.jboss.cache.Cache;
51 import org.jboss.cache.CacheFactory;
52 import org.jboss.cache.DefaultCacheFactory;
53 import org.jboss.cache.config.ConfigurationException;
54 import org.modeshape.common.annotation.Category;
55 import org.modeshape.common.annotation.Description;
56 import org.modeshape.common.annotation.Label;
57 import org.modeshape.common.i18n.I18n;
58 import org.modeshape.common.util.HashCode;
59 import org.modeshape.common.util.Logger;
60 import org.modeshape.common.util.StringUtil;
61 import org.modeshape.graph.ModeShapeLexicon;
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 import org.modeshape.graph.connector.base.BaseRepositorySource;
69 import org.modeshape.graph.connector.base.Connection;
70 import org.modeshape.graph.observe.Observer;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 @ThreadSafe
88 public class JBossCacheSource implements BaseRepositorySource, ObjectFactory {
89
90 private static final long serialVersionUID = 2L;
91
92
93
94 public static final int DEFAULT_RETRY_LIMIT = 0;
95 public static final String DEFAULT_UUID_PROPERTY_NAME = ModeShapeLexicon.UUID.getString();
96
97
98
99
100 public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default";
101
102
103
104
105 public static final boolean DEFAULT_UPDATES_ALLOWED = true;
106
107 protected static final String ROOT_NODE_UUID = "rootNodeUuid";
108 protected static final String SOURCE_NAME = "sourceName";
109 protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
110 protected static final String CACHE_CONFIGURATION_NAME = "cacheConfigurationName";
111 protected static final String CACHE_FACTORY_JNDI_NAME = "cacheFactoryJndiName";
112 protected static final String CACHE_JNDI_NAME = "cacheJndiName";
113 protected static final String RETRY_LIMIT = "retryLimit";
114 protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
115 protected static final String PREDEFINED_WORKSPACE_NAMES = "predefinedWorkspaceNames";
116 protected static final String ALLOW_CREATING_WORKSPACES = "allowCreatingWorkspaces";
117 protected static final String UPDATES_ALLOWED = "updatesAllowed";
118
119 @Description( i18n = JBossCacheConnectorI18n.class, value = "namePropertyDescription" )
120 @Label( i18n = JBossCacheConnectorI18n.class, value = "namePropertyLabel" )
121 @Category( i18n = JBossCacheConnectorI18n.class, value = "namePropertyCategory" )
122 private volatile String name;
123
124 @Description( i18n = JBossCacheConnectorI18n.class, value = "rootNodeUuidPropertyDescription" )
125 @Label( i18n = JBossCacheConnectorI18n.class, value = "rootNodeUuidPropertyLabel" )
126 @Category( i18n = JBossCacheConnectorI18n.class, value = "rootNodeUuidPropertyCategory" )
127 private volatile UUID rootNodeUuid = UUID.randomUUID();
128
129 @Description( i18n = JBossCacheConnectorI18n.class, value = "cacheConfigurationNamePropertyDescription" )
130 @Label( i18n = JBossCacheConnectorI18n.class, value = "cacheConfigurationNamePropertyLabel" )
131 @Category( i18n = JBossCacheConnectorI18n.class, value = "cacheConfigurationNamePropertyCategory" )
132 private volatile String cacheConfigurationName;
133
134 @Description( i18n = JBossCacheConnectorI18n.class, value = "cacheFactoryJndiNamePropertyDescription" )
135 @Label( i18n = JBossCacheConnectorI18n.class, value = "cacheFactoryJndiNamePropertyLabel" )
136 @Category( i18n = JBossCacheConnectorI18n.class, value = "cacheFactoryrJndiNamePropertyCategory" )
137 private volatile String cacheFactoryJndiName;
138
139 @Description( i18n = JBossCacheConnectorI18n.class, value = "cacheJndiNamePropertyDescription" )
140 @Label( i18n = JBossCacheConnectorI18n.class, value = "cacheJndiNamePropertyLabel" )
141 @Category( i18n = JBossCacheConnectorI18n.class, value = "cacheJndiNamePropertyCategory" )
142 private volatile String cacheJndiName;
143
144 @Description( i18n = JBossCacheConnectorI18n.class, value = "retryLimitPropertyDescription" )
145 @Label( i18n = JBossCacheConnectorI18n.class, value = "retryLimitPropertyLabel" )
146 @Category( i18n = JBossCacheConnectorI18n.class, value = "retryLimitPropertyCategory" )
147 private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
148
149 @Description( i18n = JBossCacheConnectorI18n.class, value = "defaultWorkspaceNamePropertyDescription" )
150 @Label( i18n = JBossCacheConnectorI18n.class, value = "defaultWorkspaceNamePropertyLabel" )
151 @Category( i18n = JBossCacheConnectorI18n.class, value = "defaultWorkspaceNamePropertyCategory" )
152 private volatile String defaultWorkspace;
153
154 @Description( i18n = JBossCacheConnectorI18n.class, value = "predefinedWorkspacesPropertyDescription" )
155 @Label( i18n = JBossCacheConnectorI18n.class, value = "predefinedWorkspacesPropertyLabel" )
156 @Category( i18n = JBossCacheConnectorI18n.class, value = "predefinedWorkspacesPropertyCategory" )
157 private volatile String[] predefinedWorkspaces = new String[] {};
158
159 @Description( i18n = JBossCacheConnectorI18n.class, value = "updatesAllowedPropertyDescription" )
160 @Label( i18n = JBossCacheConnectorI18n.class, value = "updatesAllowedPropertyLabel" )
161 @Category( i18n = JBossCacheConnectorI18n.class, value = "updatesAllowedPropertyCategory" )
162 private volatile boolean updatesAllowed = DEFAULT_UPDATES_ALLOWED;
163
164 private volatile CachePolicy defaultCachePolicy;
165 private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true, false);
166 private transient JBossCacheRepository repository;
167 private transient Context jndiContext;
168 private transient RepositoryContext repositoryContext;
169 private final Set<String> repositoryNamesForConfigurationNameProblems = new HashSet<String>();
170
171
172
173
174 public JBossCacheSource() {
175 }
176
177
178
179
180
181
182 public void initialize( RepositoryContext context ) throws RepositorySourceException {
183 this.repositoryContext = context;
184 }
185
186
187
188
189 public String getName() {
190 return this.name;
191 }
192
193
194
195
196
197
198 public RepositorySourceCapabilities getCapabilities() {
199 return capabilities;
200 }
201
202
203
204
205
206
207 public int getRetryLimit() {
208 return retryLimit;
209 }
210
211
212
213
214
215
216 public synchronized void setRetryLimit( int limit ) {
217 retryLimit = limit < 0 ? 0 : limit;
218 }
219
220
221
222
223
224
225 public synchronized void setName( String name ) {
226 if (this.name == name || this.name != null && this.name.equals(name)) return;
227 this.name = name;
228 }
229
230
231
232
233
234
235 public CachePolicy getDefaultCachePolicy() {
236 return defaultCachePolicy;
237 }
238
239
240
241
242 public synchronized void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
243 if (this.defaultCachePolicy == defaultCachePolicy || this.defaultCachePolicy != null
244 && this.defaultCachePolicy.equals(defaultCachePolicy)) return;
245 this.defaultCachePolicy = defaultCachePolicy;
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 public String getCacheJndiName() {
265 return cacheJndiName;
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 public synchronized void setCacheJndiName( String cacheJndiName ) {
285 if (this.cacheJndiName == cacheJndiName || this.cacheJndiName != null && this.cacheJndiName.equals(cacheJndiName)) return;
286 this.cacheJndiName = cacheJndiName;
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304 public String getCacheFactoryJndiName() {
305 return cacheFactoryJndiName;
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324 public synchronized void setCacheFactoryJndiName( String jndiName ) {
325 if (this.cacheFactoryJndiName == jndiName || this.cacheFactoryJndiName != null
326 && this.cacheFactoryJndiName.equals(jndiName)) return;
327 this.cacheFactoryJndiName = jndiName;
328 }
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346 public String getCacheConfigurationName() {
347 return cacheConfigurationName;
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366 public synchronized void setCacheConfigurationName( String cacheConfigurationName ) {
367 if (this.cacheConfigurationName == cacheConfigurationName || this.cacheConfigurationName != null
368 && this.cacheConfigurationName.equals(cacheConfigurationName)) return;
369 this.cacheConfigurationName = cacheConfigurationName;
370 }
371
372
373
374
375
376
377
378 public String getRootNodeUuid() {
379 return this.rootNodeUuid.toString();
380 }
381
382
383
384
385
386
387
388 public UUID getRootNodeUuidObject() {
389 return this.rootNodeUuid;
390 }
391
392
393
394
395
396
397
398 public synchronized void setRootNodeUuid( String rootNodeUuid ) {
399 UUID uuid = null;
400 if (rootNodeUuid == null) uuid = UUID.randomUUID();
401 else uuid = UUID.fromString(rootNodeUuid);
402 if (this.rootNodeUuid.equals(uuid)) return;
403 this.rootNodeUuid = uuid;
404 }
405
406
407
408
409
410
411 public String getDefaultWorkspaceName() {
412 return defaultWorkspace;
413 }
414
415
416
417
418
419
420
421 public synchronized void setDefaultWorkspaceName( String nameOfDefaultWorkspace ) {
422 this.defaultWorkspace = nameOfDefaultWorkspace != null ? nameOfDefaultWorkspace : DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
423 }
424
425
426
427
428
429
430
431
432 public synchronized String[] getPredefinedWorkspaceNames() {
433 String[] copy = new String[predefinedWorkspaces.length];
434 System.arraycopy(predefinedWorkspaces, 0, copy, 0, predefinedWorkspaces.length);
435 return copy;
436 }
437
438
439
440
441
442
443
444
445
446 public synchronized void setPredefinedWorkspaceNames( String[] predefinedWorkspaceNames ) {
447 this.predefinedWorkspaces = predefinedWorkspaceNames;
448 }
449
450
451
452
453
454
455
456
457
458
459 @Description( i18n = JBossCacheConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyDescription" )
460 @Label( i18n = JBossCacheConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyLabel" )
461 @Category( i18n = JBossCacheConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyCategory" )
462 public boolean isCreatingWorkspacesAllowed() {
463 return capabilities.supportsCreatingWorkspaces();
464 }
465
466
467
468
469
470
471
472
473
474
475 public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
476 capabilities = new RepositorySourceCapabilities(true, capabilities.supportsUpdates(), false, allowWorkspaceCreation,
477 capabilities.supportsReferences());
478 }
479
480
481
482
483
484
485 @SuppressWarnings( "unchecked" )
486 public synchronized RepositoryConnection getConnection() throws RepositorySourceException {
487 if (getName() == null) {
488 I18n msg = JBossCacheConnectorI18n.propertyIsRequired;
489 throw new RepositorySourceException(getName(), msg.text("name"));
490 }
491 if (this.repository == null) {
492 Context context = getContext();
493 if (context == null) {
494 try {
495 context = new InitialContext();
496 } catch (NamingException err) {
497 throw new RepositorySourceException(name, err);
498 }
499 }
500
501
502 CacheFactory<UUID, JBossCacheNode> cacheFactory = null;
503 String jndiName = getCacheFactoryJndiName();
504 if (jndiName != null && jndiName.trim().length() != 0) {
505 Object object = null;
506 try {
507 object = context.lookup(jndiName);
508 if (object != null) cacheFactory = (CacheFactory<UUID, JBossCacheNode>)object;
509 } catch (ClassCastException err) {
510 I18n msg = JBossCacheConnectorI18n.objectFoundInJndiWasNotCacheFactory;
511 String className = object != null ? object.getClass().getName() : "null";
512 throw new RepositorySourceException(getName(), msg.text(jndiName, this.getName(), className), err);
513 } catch (Throwable err) {
514 if (err instanceof RuntimeException) throw (RuntimeException)err;
515 throw new RepositorySourceException(getName(), err);
516 }
517 }
518 if (cacheFactory == null) cacheFactory = new DefaultCacheFactory<UUID, JBossCacheNode>();
519
520
521 Cache<UUID, JBossCacheNode> cache = createNewCache(cacheFactory, getName());
522 this.repository = new JBossCacheRepository(this, cache);
523 }
524
525 return new Connection<JBossCacheNode, JBossCacheWorkspace>(this, repository);
526 }
527
528
529
530
531
532
533 public synchronized void close() {
534
535 this.repository = null;
536 }
537
538
539
540
541
542
543
544
545
546
547 @GuardedBy( "writeLock" )
548 protected Cache<UUID, JBossCacheNode> createNewCache( CacheFactory<UUID, JBossCacheNode> cacheFactory,
549 String repositoryName ) {
550 assert repositoryName != null;
551 if (cacheFactory == null) return null;
552
553
554 try {
555 return cacheFactory.createCache(repositoryName);
556 } catch (ConfigurationException error) {
557
558 I18n msg = JBossCacheConnectorI18n.workspaceNameWasNotValidConfiguration;
559 Logger.getLogger(getClass()).debug(msg.text(repositoryName, error.getMessage()));
560 }
561
562 if (this.cacheConfigurationName != null) {
563
564 try {
565 return cacheFactory.createCache(getCacheConfigurationName());
566 } catch (ConfigurationException error) {
567
568 if (this.repositoryNamesForConfigurationNameProblems.add(repositoryName)) {
569
570 I18n msg = JBossCacheConnectorI18n.defaultCacheFactoryConfigurationNameWasNotValidConfiguration;
571 Logger.getLogger(getClass()).debug(msg.text(repositoryName));
572 }
573 }
574 }
575
576
577 return cacheFactory.createCache();
578 }
579
580
581
582
583 public RepositoryContext getRepositoryContext() {
584 return repositoryContext;
585 }
586
587 protected Observer getObserver() {
588 return repositoryContext != null ? repositoryContext.getObserver() : null;
589 }
590
591 protected Context getContext() {
592 return this.jndiContext;
593 }
594
595 protected synchronized void setContext( Context context ) {
596 this.jndiContext = context;
597 }
598
599 public boolean areUpdatesAllowed() {
600 return this.updatesAllowed;
601 }
602
603 public void setUpdatesAllowed( boolean updatesAllowed ) {
604 this.updatesAllowed = updatesAllowed;
605 }
606
607
608
609
610 @Override
611 public boolean equals( Object obj ) {
612 if (obj == this) return true;
613 if (obj instanceof JBossCacheSource) {
614 JBossCacheSource that = (JBossCacheSource)obj;
615 if (this.getName() == null) {
616 if (that.getName() != null) return false;
617 } else {
618 if (!this.getName().equals(that.getName())) return false;
619 }
620 return true;
621 }
622 return false;
623 }
624
625 @Override
626 public int hashCode() {
627 return HashCode.compute(getName());
628 }
629
630
631
632
633 public synchronized Reference getReference() {
634 String className = getClass().getName();
635 String factoryClassName = this.getClass().getName();
636 Reference ref = new Reference(className, factoryClassName, null);
637
638 ref.add(new StringRefAddr(SOURCE_NAME, getName()));
639 ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuid().toString()));
640 ref.add(new StringRefAddr(CACHE_JNDI_NAME, getCacheJndiName()));
641 ref.add(new StringRefAddr(CACHE_FACTORY_JNDI_NAME, getCacheFactoryJndiName()));
642 ref.add(new StringRefAddr(CACHE_CONFIGURATION_NAME, getCacheConfigurationName()));
643 ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
644 ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName()));
645 ref.add(new StringRefAddr(UPDATES_ALLOWED, String.valueOf(areUpdatesAllowed())));
646 ref.add(new StringRefAddr(ALLOW_CREATING_WORKSPACES, Boolean.toString(isCreatingWorkspacesAllowed())));
647 String[] workspaceNames = getPredefinedWorkspaceNames();
648 if (workspaceNames != null && workspaceNames.length != 0) {
649 ref.add(new StringRefAddr(PREDEFINED_WORKSPACE_NAMES, StringUtil.combineLines(workspaceNames)));
650 }
651 if (getDefaultCachePolicy() != null) {
652 ByteArrayOutputStream baos = new ByteArrayOutputStream();
653 CachePolicy policy = getDefaultCachePolicy();
654 try {
655 ObjectOutputStream oos = new ObjectOutputStream(baos);
656 oos.writeObject(policy);
657 ref.add(new BinaryRefAddr(DEFAULT_CACHE_POLICY, baos.toByteArray()));
658 } catch (IOException e) {
659 I18n msg = JBossCacheConnectorI18n.errorSerializingCachePolicyInSource;
660 throw new RepositorySourceException(getName(), msg.text(policy.getClass().getName(), getName()), e);
661 }
662 }
663 return ref;
664 }
665
666
667
668
669 public Object getObjectInstance( Object obj,
670 javax.naming.Name name,
671 Context nameCtx,
672 Hashtable<?, ?> environment ) throws Exception {
673 if (obj instanceof Reference) {
674 Map<String, Object> values = new HashMap<String, Object>();
675 Reference ref = (Reference)obj;
676 Enumeration<?> en = ref.getAll();
677 while (en.hasMoreElements()) {
678 RefAddr subref = (RefAddr)en.nextElement();
679 if (subref instanceof StringRefAddr) {
680 String key = subref.getType();
681 Object value = subref.getContent();
682 if (value != null) values.put(key, value.toString());
683 } else if (subref instanceof BinaryRefAddr) {
684 String key = subref.getType();
685 Object value = subref.getContent();
686 if (value instanceof byte[]) {
687
688 ByteArrayInputStream bais = new ByteArrayInputStream((byte[])value);
689 ObjectInputStream ois = new ObjectInputStream(bais);
690 value = ois.readObject();
691 values.put(key, value);
692 }
693 }
694 }
695 String sourceName = (String)values.get(SOURCE_NAME);
696 String rootNodeUuidString = (String)values.get(ROOT_NODE_UUID);
697 String cacheJndiName = (String)values.get(CACHE_JNDI_NAME);
698 String cacheFactoryJndiName = (String)values.get(CACHE_FACTORY_JNDI_NAME);
699 String cacheConfigurationName = (String)values.get(CACHE_CONFIGURATION_NAME);
700 Object defaultCachePolicy = values.get(DEFAULT_CACHE_POLICY);
701 String retryLimit = (String)values.get(RETRY_LIMIT);
702 String defaultWorkspace = (String)values.get(DEFAULT_WORKSPACE);
703 String createWorkspaces = (String)values.get(ALLOW_CREATING_WORKSPACES);
704 String updatesAllowed = (String)values.get(UPDATES_ALLOWED);
705
706 String combinedWorkspaceNames = (String)values.get(PREDEFINED_WORKSPACE_NAMES);
707 String[] workspaceNames = null;
708 if (combinedWorkspaceNames != null) {
709 List<String> paths = StringUtil.splitLines(combinedWorkspaceNames);
710 workspaceNames = paths.toArray(new String[paths.size()]);
711 }
712
713
714 JBossCacheSource source = new JBossCacheSource();
715 if (sourceName != null) source.setName(sourceName);
716 if (rootNodeUuidString != null) source.setRootNodeUuid(rootNodeUuidString);
717 if (cacheJndiName != null) source.setCacheJndiName(cacheJndiName);
718 if (cacheFactoryJndiName != null) source.setCacheFactoryJndiName(cacheFactoryJndiName);
719 if (cacheConfigurationName != null) source.setCacheConfigurationName(cacheConfigurationName);
720 if (defaultCachePolicy instanceof CachePolicy) {
721 source.setDefaultCachePolicy((CachePolicy)defaultCachePolicy);
722 }
723 if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
724 if (defaultWorkspace != null) source.setDefaultWorkspaceName(defaultWorkspace);
725 if (createWorkspaces != null) source.setCreatingWorkspacesAllowed(Boolean.parseBoolean(createWorkspaces));
726 if (workspaceNames != null && workspaceNames.length != 0) source.setPredefinedWorkspaceNames(workspaceNames);
727 if (updatesAllowed != null) source.setUpdatesAllowed(Boolean.valueOf(updatesAllowed));
728 return source;
729 }
730 return null;
731 }
732 }