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