1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.modeshape.connector.jcr;
26
27 import java.io.ByteArrayInputStream;
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.io.ObjectOutputStream;
32 import java.util.Enumeration;
33 import java.util.HashMap;
34 import java.util.Hashtable;
35 import java.util.Map;
36 import javax.jcr.Credentials;
37 import javax.jcr.Repository;
38 import javax.jcr.SimpleCredentials;
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.StringRefAddr;
46 import javax.naming.spi.ObjectFactory;
47 import net.jcip.annotations.ThreadSafe;
48 import org.modeshape.common.annotation.Category;
49 import org.modeshape.common.annotation.Description;
50 import org.modeshape.common.annotation.Label;
51 import org.modeshape.common.i18n.I18n;
52 import org.modeshape.graph.cache.CachePolicy;
53 import org.modeshape.graph.connector.RepositoryConnection;
54 import org.modeshape.graph.connector.RepositoryContext;
55 import org.modeshape.graph.connector.RepositorySource;
56 import org.modeshape.graph.connector.RepositorySourceCapabilities;
57 import org.modeshape.graph.connector.RepositorySourceException;
58
59
60
61
62
63
64 @ThreadSafe
65 public class JcrRepositorySource implements RepositorySource, ObjectFactory {
66
67
68
69
70 private static final long serialVersionUID = 1L;
71
72 protected static final String SOURCE_NAME = "sourceName";
73 protected static final String REPOSITORY_JNDI_NAME = "repositoryJndiName";
74 protected static final String USERNAME = "username";
75 protected static final String PASSWORD = "password";
76 protected static final String CREDENTIALS = "credentials";
77 protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
78 protected static final String RETRY_LIMIT = "retryLimit";
79
80
81
82
83 public static final int DEFAULT_RETRY_LIMIT = 0;
84
85
86
87
88 protected static final boolean SUPPORTS_EVENTS = true;
89
90
91
92 protected static final boolean SUPPORTS_SAME_NAME_SIBLINGS = true;
93
94
95
96 protected static final boolean SUPPORTS_UPDATES = true;
97
98
99
100 protected static final boolean SUPPORTS_CREATING_WORKSPACES = false;
101
102
103
104 protected static final boolean SUPPORTS_REFERENCES = false;
105
106 @Description( i18n = JcrConnectorI18n.class, value = "namePropertyDescription" )
107 @Label( i18n = JcrConnectorI18n.class, value = "namePropertyLabel" )
108 @Category( i18n = JcrConnectorI18n.class, value = "namePropertyCategory" )
109 private volatile String name;
110
111 @Description( i18n = JcrConnectorI18n.class, value = "repositoryJndiNamePropertyDescription" )
112 @Label( i18n = JcrConnectorI18n.class, value = "repositoryJndiNamePropertyLabel" )
113 @Category( i18n = JcrConnectorI18n.class, value = "repositoryJndiNamePropertyCategory" )
114 private volatile String repositoryJndiName;
115
116 @Description( i18n = JcrConnectorI18n.class, value = "usernamePropertyDescription" )
117 @Label( i18n = JcrConnectorI18n.class, value = "usernamePropertyLabel" )
118 @Category( i18n = JcrConnectorI18n.class, value = "usernamePropertyCategory" )
119 private volatile String username;
120
121 @Description( i18n = JcrConnectorI18n.class, value = "passwordPropertyDescription" )
122 @Label( i18n = JcrConnectorI18n.class, value = "passwordPropertyLabel" )
123 @Category( i18n = JcrConnectorI18n.class, value = "passwordPropertyCategory" )
124 private volatile String password;
125
126 private volatile Credentials credentials;
127 private volatile CachePolicy defaultCachePolicy;
128
129 @Description( i18n = JcrConnectorI18n.class, value = "retryLimitPropertyDescription" )
130 @Label( i18n = JcrConnectorI18n.class, value = "retryLimitPropertyLabel" )
131 @Category( i18n = JcrConnectorI18n.class, value = "retryLimitPropertyCategory" )
132 private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
133
134 private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(SUPPORTS_SAME_NAME_SIBLINGS,
135 SUPPORTS_UPDATES,
136 SUPPORTS_EVENTS,
137 SUPPORTS_CREATING_WORKSPACES,
138 SUPPORTS_REFERENCES);
139 private transient Repository repository;
140 private transient Context jndiContext;
141 private transient RepositoryContext repositoryContext;
142
143
144
145
146 public JcrRepositorySource() {
147 }
148
149
150
151
152
153
154 public String getName() {
155 return name;
156 }
157
158
159
160
161
162
163 public void setName( String name ) {
164 if (name != null) {
165 name = name.trim();
166 if (name.length() == 0) name = null;
167 }
168 this.name = name;
169 }
170
171
172
173
174
175
176 public RepositorySourceCapabilities getCapabilities() {
177 return capabilities;
178 }
179
180
181
182
183
184
185 @Description( i18n = JcrConnectorI18n.class, value = "updatesAllowedPropertyDescription" )
186 @Label( i18n = JcrConnectorI18n.class, value = "updatesAllowedPropertyLabel" )
187 @Category( i18n = JcrConnectorI18n.class, value = "updatesAllowedPropertyCategory" )
188 public boolean getUpdatesAllowed() {
189 return capabilities.supportsUpdates();
190 }
191
192
193
194
195 public String getRepositoryJndiName() {
196 return repositoryJndiName;
197 }
198
199
200
201
202
203
204 public void setRepositoryJndiName( String repositoryJndiName ) {
205 if (repositoryJndiName != null && repositoryJndiName.trim().length() == 0) repositoryJndiName = null;
206 this.repositoryJndiName = repositoryJndiName;
207 }
208
209
210
211
212
213
214 public String getUsername() {
215 return username;
216 }
217
218
219
220
221 public synchronized void setUsername( String username ) {
222 this.username = username;
223 }
224
225
226
227
228 public String getPassword() {
229 return password;
230 }
231
232
233
234
235 public synchronized void setPassword( String password ) {
236 this.password = password;
237 }
238
239
240
241
242
243
244 public Credentials getCredentials() {
245 return credentials;
246 }
247
248
249
250
251
252
253 public void setCredentials( Credentials credentials ) {
254 this.credentials = credentials;
255 }
256
257
258
259
260
261
262 public CachePolicy getDefaultCachePolicy() {
263 return defaultCachePolicy;
264 }
265
266
267
268
269 public synchronized void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
270 if (this.defaultCachePolicy == defaultCachePolicy || this.defaultCachePolicy != null
271 && this.defaultCachePolicy.equals(defaultCachePolicy)) return;
272 this.defaultCachePolicy = defaultCachePolicy;
273 }
274
275
276
277
278
279
280 public int getRetryLimit() {
281 return retryLimit;
282 }
283
284
285
286
287
288
289 public synchronized void setRetryLimit( int limit ) {
290 retryLimit = limit < 0 ? 0 : limit;
291 }
292
293
294
295
296
297
298 public void initialize( RepositoryContext context ) throws RepositorySourceException {
299 this.repositoryContext = context;
300 }
301
302 protected RepositoryContext getRepositoryContext() {
303 return repositoryContext;
304 }
305
306 protected synchronized Repository getRepository() {
307 return this.repository;
308 }
309
310 protected synchronized void setRepository( Repository repository ) {
311 this.repository = repository;
312 }
313
314 protected synchronized Context getContext() {
315 return this.jndiContext;
316 }
317
318 protected synchronized void setContext( Context context ) {
319 this.jndiContext = context;
320 }
321
322
323
324
325
326
327 public synchronized Reference getReference() {
328 String className = getClass().getName();
329 String factoryClassName = this.getClass().getName();
330 Reference ref = new Reference(className, factoryClassName, null);
331
332 if (getName() != null) {
333 ref.add(new StringRefAddr(SOURCE_NAME, getName()));
334 }
335 ref.add(new StringRefAddr(SOURCE_NAME, getName()));
336 ref.add(new StringRefAddr(REPOSITORY_JNDI_NAME, getRepositoryJndiName()));
337 ref.add(new StringRefAddr(USERNAME, getUsername()));
338 ref.add(new StringRefAddr(PASSWORD, getPassword()));
339 ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
340 if (getCredentials() != null) {
341 ByteArrayOutputStream baos = new ByteArrayOutputStream();
342 Credentials credentials = getCredentials();
343 try {
344 ObjectOutputStream oos = new ObjectOutputStream(baos);
345 oos.writeObject(credentials);
346 ref.add(new BinaryRefAddr(CREDENTIALS, baos.toByteArray()));
347 } catch (IOException e) {
348 I18n msg = JcrConnectorI18n.errorSerializingObjectUsedInSource;
349 throw new RepositorySourceException(getName(), msg.text(credentials.getClass().getName(), getName()), e);
350 }
351 }
352 if (getDefaultCachePolicy() != null) {
353 ByteArrayOutputStream baos = new ByteArrayOutputStream();
354 CachePolicy policy = getDefaultCachePolicy();
355 try {
356 ObjectOutputStream oos = new ObjectOutputStream(baos);
357 oos.writeObject(policy);
358 ref.add(new BinaryRefAddr(DEFAULT_CACHE_POLICY, baos.toByteArray()));
359 } catch (IOException e) {
360 I18n msg = JcrConnectorI18n.errorSerializingObjectUsedInSource;
361 throw new RepositorySourceException(getName(), msg.text(policy.getClass().getName(), getName()), e);
362 }
363 }
364 return ref;
365 }
366
367
368
369
370 public Object getObjectInstance( Object obj,
371 javax.naming.Name name,
372 Context nameCtx,
373 Hashtable<?, ?> environment ) throws Exception {
374 if (obj instanceof Reference) {
375 Map<String, Object> values = new HashMap<String, Object>();
376 Reference ref = (Reference)obj;
377 Enumeration<?> en = ref.getAll();
378 while (en.hasMoreElements()) {
379 RefAddr subref = (RefAddr)en.nextElement();
380 if (subref instanceof StringRefAddr) {
381 String key = subref.getType();
382 Object value = subref.getContent();
383 if (value != null) values.put(key, value.toString());
384 } else if (subref instanceof BinaryRefAddr) {
385 String key = subref.getType();
386 Object value = subref.getContent();
387 if (value instanceof byte[]) {
388
389 ByteArrayInputStream bais = new ByteArrayInputStream((byte[])value);
390 ObjectInputStream ois = new ObjectInputStream(bais);
391 value = ois.readObject();
392 values.put(key, value);
393 }
394 }
395 }
396 String sourceName = (String)values.get(SOURCE_NAME);
397 String repositoryJndiName = (String)values.get(REPOSITORY_JNDI_NAME);
398 String username = (String)values.get(USERNAME);
399 String password = (String)values.get(PASSWORD);
400 String retryLimit = (String)values.get(RETRY_LIMIT);
401 Object credentials = values.get(CREDENTIALS);
402 Object defaultCachePolicy = values.get(DEFAULT_CACHE_POLICY);
403
404
405 JcrRepositorySource source = new JcrRepositorySource();
406 if (sourceName != null) source.setName(sourceName);
407 if (repositoryJndiName != null) source.setRepositoryJndiName(repositoryJndiName);
408 if (username != null) source.setUsername(username);
409 if (password != null) source.setPassword(password);
410 if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
411 if (credentials instanceof Credentials) {
412 source.setCredentials((Credentials)credentials);
413 }
414 if (defaultCachePolicy instanceof CachePolicy) {
415 source.setDefaultCachePolicy((CachePolicy)defaultCachePolicy);
416 }
417 return source;
418 }
419 return null;
420 }
421
422
423
424
425
426
427 public synchronized RepositoryConnection getConnection() throws RepositorySourceException {
428 if (name == null || name.trim().length() == 0) {
429 I18n msg = JcrConnectorI18n.propertyIsRequired;
430 throw new RepositorySourceException(name, msg.text("name"));
431 }
432 if (repositoryJndiName == null || repositoryJndiName.trim().length() == 0) {
433 I18n msg = JcrConnectorI18n.propertyIsRequired;
434 throw new RepositorySourceException(getName(), msg.text("repositoryJndiName"));
435 }
436 if (this.repository == null) {
437 Context context = getContext();
438 if (context == null) {
439 try {
440 context = new InitialContext();
441 } catch (NamingException err) {
442 throw new RepositorySourceException(name, err);
443 }
444 }
445
446
447 Repository repository = null;
448 Object object = null;
449 try {
450 object = context.lookup(repositoryJndiName);
451 if (object != null) repository = (Repository)object;
452 } catch (ClassCastException err) {
453 I18n msg = JcrConnectorI18n.objectFoundInJndiWasNotRepository;
454 String className = object != null ? object.getClass().getName() : "null";
455 throw new RepositorySourceException(getName(), msg.text(repositoryJndiName, this.getName(), className), err);
456 } catch (Throwable err) {
457 if (err instanceof RuntimeException) throw (RuntimeException)err;
458 throw new RepositorySourceException(getName(), err);
459 }
460 if (repository == null) {
461 I18n msg = JcrConnectorI18n.repositoryObjectNotFoundInJndi;
462 throw new RepositorySourceException(getName(), msg.text(repositoryJndiName));
463 }
464 this.repository = repository;
465 }
466 assert this.repository != null;
467
468
469 Credentials credentials = getCredentials();
470 if (credentials == null || (username != null || password != null)) {
471 char[] passwd = this.password != null ? password.toCharArray() : new char[] {};
472 credentials = new SimpleCredentials(username, passwd);
473 }
474
475
476 return new JcrRepositoryConnection(this, repository, credentials);
477 }
478
479
480
481
482
483
484 public void close() {
485
486 this.repositoryContext = null;
487 this.repository = null;
488 }
489 }