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.jcr;
25
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.math.BigDecimal;
29 import java.net.URI;
30 import java.util.Calendar;
31 import javax.jcr.Node;
32 import javax.jcr.PropertyType;
33 import javax.jcr.RepositoryException;
34 import javax.jcr.Value;
35 import javax.jcr.ValueFormatException;
36 import net.jcip.annotations.NotThreadSafe;
37 import org.modeshape.common.SystemFailureException;
38 import org.modeshape.common.util.IoUtil;
39 import org.modeshape.graph.property.Binary;
40 import org.modeshape.graph.property.BinaryFactory;
41 import org.modeshape.graph.property.DateTime;
42 import org.modeshape.graph.property.DateTimeFactory;
43 import org.modeshape.graph.property.Name;
44 import org.modeshape.graph.property.NameFactory;
45 import org.modeshape.graph.property.Path;
46 import org.modeshape.graph.property.PathFactory;
47 import org.modeshape.graph.property.ValueFactories;
48
49
50
51
52 @NotThreadSafe
53 final class JcrValue implements Value, org.modeshape.jcr.api.Value {
54
55 static final JcrValue[] EMPTY_ARRAY = new JcrValue[] {};
56
57 private final SessionCache sessionCache;
58 private final ValueFactories valueFactories;
59 private final int type;
60 private final Object value;
61 private InputStream asStream = null;
62
63 JcrValue( ValueFactories valueFactories,
64 SessionCache sessionCache,
65 int type,
66 Object value ) {
67 assert valueFactories != null;
68 assert type == PropertyType.BINARY || type == PropertyType.BOOLEAN || type == PropertyType.DATE
69 || type == PropertyType.DECIMAL || type == PropertyType.DOUBLE || type == PropertyType.LONG
70 || type == PropertyType.NAME || type == PropertyType.PATH || type == PropertyType.REFERENCE
71 || type == PropertyType.WEAKREFERENCE || type == PropertyType.STRING || type == PropertyType.URI : "Unxpected PropertyType: "
72 + PropertyType.nameFromValue(type)
73 + " for value "
74 + (value == null ? "null" : ("\""
75 + value + "\""));
76
77
78
79
80 assert value != null;
81
82 this.valueFactories = valueFactories;
83 this.sessionCache = sessionCache;
84 this.type = type;
85 this.value = value instanceof JcrBinary ? ((JcrBinary)value).binary() : value;
86 }
87
88 JcrValue( ValueFactories valueFactories,
89 SessionCache sessionCache,
90 Value value ) throws RepositoryException {
91 assert value != null;
92
93 this.valueFactories = valueFactories;
94 this.sessionCache = sessionCache;
95 this.type = value.getType();
96 this.value = valueToType(this.type, value);
97 }
98
99 private ValueFormatException createValueFormatException( Class<?> type ) {
100 return new ValueFormatException(JcrI18n.cannotConvertValue.text(value.getClass().getSimpleName(), type.getSimpleName()));
101 }
102
103 private ValueFormatException createValueFormatException( org.modeshape.graph.property.ValueFormatException vfe ) {
104 return new ValueFormatException(vfe);
105 }
106
107
108
109
110
111
112
113 final Object value() {
114 return value;
115 }
116
117
118
119
120
121
122 final SessionCache sessionCache() {
123 return sessionCache;
124 }
125
126
127
128
129
130
131 public boolean getBoolean() throws ValueFormatException {
132 try {
133 boolean convertedValue = valueFactories.getBooleanFactory().create(value);
134 return convertedValue;
135 } catch (RuntimeException error) {
136 throw createValueFormatException(boolean.class);
137 }
138 }
139
140
141
142
143
144
145 public Calendar getDate() throws ValueFormatException {
146 try {
147 Calendar convertedValue = valueFactories.getDateFactory().create(value).toCalendar();
148 return convertedValue;
149 } catch (RuntimeException error) {
150 throw createValueFormatException(Calendar.class);
151 }
152 }
153
154
155
156
157
158
159 @Override
160 public BigDecimal getDecimal() throws ValueFormatException, RepositoryException {
161 try {
162 BigDecimal convertedValue = valueFactories.getDecimalFactory().create(value);
163 return convertedValue;
164 } catch (RuntimeException error) {
165 throw createValueFormatException(double.class);
166 }
167 }
168
169
170
171
172
173
174 public double getDouble() throws ValueFormatException {
175 try {
176 double convertedValue = valueFactories.getDoubleFactory().create(value);
177 return convertedValue;
178 } catch (RuntimeException error) {
179 throw createValueFormatException(double.class);
180 }
181 }
182
183 long getLength() throws RepositoryException {
184 if (type == PropertyType.BINARY) {
185 return valueFactories.getBinaryFactory().create(value).getSize();
186 }
187 return getString().length();
188 }
189
190
191
192
193
194
195 public long getLong() throws ValueFormatException {
196 try {
197 long convertedValue = valueFactories.getLongFactory().create(value);
198 return convertedValue;
199 } catch (RuntimeException error) {
200 throw createValueFormatException(long.class);
201 }
202 }
203
204
205
206
207
208
209 public InputStream getStream() throws ValueFormatException {
210 try {
211 if (asStream == null) {
212 Binary binary = valueFactories.getBinaryFactory().create(value);
213 asStream = new SelfClosingInputStream(binary);
214 }
215 return asStream;
216 } catch (RuntimeException error) {
217 throw createValueFormatException(InputStream.class);
218 }
219 }
220
221
222
223
224
225
226 public javax.jcr.Binary getBinary() throws RepositoryException {
227 try {
228 Binary binary = valueFactories.getBinaryFactory().create(value);
229 return new JcrBinary(binary);
230 } catch (RuntimeException error) {
231 throw createValueFormatException(InputStream.class);
232 }
233 }
234
235
236
237
238
239
240 public String getString() throws ValueFormatException {
241 try {
242 String convertedValue = valueFactories.getStringFactory().create(value);
243 return convertedValue;
244 } catch (RuntimeException error) {
245 throw createValueFormatException(String.class);
246 }
247 }
248
249
250
251
252
253
254 public int getType() {
255 return type;
256 }
257
258
259
260
261
262
263 @Override
264 public int hashCode() {
265
266 return value.hashCode();
267 }
268
269
270
271
272
273
274 @Override
275 public boolean equals( Object obj ) {
276 if (obj == this) return true;
277 if (obj instanceof JcrValue) {
278 JcrValue that = (JcrValue)obj;
279 if (this.type != that.type) return false;
280 try {
281 switch (this.type) {
282 case PropertyType.STRING:
283 return this.getString().equals(that.getString());
284 case PropertyType.BINARY:
285 BinaryFactory binaryFactory = valueFactories.getBinaryFactory();
286 Binary thisValue = binaryFactory.create(this.value);
287 Binary thatValue = binaryFactory.create(that.value);
288 return thisValue.equals(thatValue);
289 case PropertyType.BOOLEAN:
290 return this.getBoolean() == that.getBoolean();
291 case PropertyType.DOUBLE:
292 return this.getDouble() == that.getDouble();
293 case PropertyType.LONG:
294 return this.getLong() == that.getLong();
295 case PropertyType.DECIMAL:
296 return getDecimal().equals(that.getDecimal());
297 case PropertyType.DATE:
298 DateTimeFactory dateFactory = valueFactories.getDateFactory();
299 DateTime thisDateValue = dateFactory.create(this.value);
300 DateTime thatDateValue = dateFactory.create(that.value);
301 return thisDateValue.equals(thatDateValue);
302 case PropertyType.PATH:
303 PathFactory pathFactory = valueFactories.getPathFactory();
304 Path thisPathValue = pathFactory.create(this.value);
305 Path thatPathValue = pathFactory.create(that.value);
306 return thisPathValue.equals(thatPathValue);
307 case PropertyType.NAME:
308 NameFactory nameFactory = valueFactories.getNameFactory();
309 Name thisNameValue = nameFactory.create(this.value);
310 Name thatNameValue = nameFactory.create(that.value);
311 return thisNameValue.equals(thatNameValue);
312 case PropertyType.REFERENCE:
313 case PropertyType.WEAKREFERENCE:
314 return this.getString().equals(that.getString());
315 default:
316 throw new SystemFailureException(JcrI18n.invalidPropertyType.text(this.type));
317 }
318 } catch (RepositoryException e) {
319 return false;
320 }
321
322 }
323 if (obj instanceof Value) {
324 Value that = (Value)obj;
325 if (this.type != that.getType()) return false;
326 try {
327 switch (this.type) {
328 case PropertyType.STRING:
329 return this.getString().equals(that.getString());
330 case PropertyType.BINARY:
331 return IoUtil.isSame(this.getStream(), that.getBinary().getStream());
332 case PropertyType.BOOLEAN:
333 return this.getBoolean() == that.getBoolean();
334 case PropertyType.DOUBLE:
335 return this.getDouble() == that.getDouble();
336 case PropertyType.LONG:
337 return this.getLong() == that.getLong();
338 case PropertyType.DECIMAL:
339 return this.getDecimal().equals(that.getDecimal());
340 case PropertyType.DATE:
341 return this.getDate().equals(that.getDate());
342 case PropertyType.PATH:
343 return this.getString().equals(that.getString());
344 case PropertyType.NAME:
345 return this.getString().equals(that.getString());
346 case PropertyType.REFERENCE:
347 return this.getString().equals(that.getString());
348 default:
349 throw new SystemFailureException(JcrI18n.invalidPropertyType.text(this.type));
350 }
351 } catch (IOException e) {
352 return false;
353 } catch (RepositoryException e) {
354 return false;
355 }
356
357 }
358 return false;
359 }
360
361 private JcrValue withTypeAndValue( int type,
362 Object value ) {
363 return new JcrValue(this.valueFactories, this.sessionCache, type, value);
364 }
365
366
367
368
369
370
371
372
373
374
375 JcrValue asType( int type ) throws ValueFormatException {
376 if (type == this.type) {
377 return this.withTypeAndValue(this.type, this.value);
378 }
379
380 Object value = this.value;
381 switch (type) {
382 case PropertyType.BOOLEAN:
383
384
385 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY) {
386 throw createValueFormatException(boolean.class);
387 }
388 try {
389 return this.withTypeAndValue(type, valueFactories.getBooleanFactory().create(value));
390 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
391 throw createValueFormatException(vfe);
392 }
393
394 case PropertyType.DATE:
395 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.DOUBLE
396 && this.type != PropertyType.LONG) {
397 throw createValueFormatException(Calendar.class);
398 }
399 try {
400 return this.withTypeAndValue(type, valueFactories.getDateFactory().create(value));
401 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
402 throw createValueFormatException(vfe);
403 }
404
405 case PropertyType.NAME:
406 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.PATH) {
407 throw createValueFormatException(Name.class);
408 }
409 try {
410 return this.withTypeAndValue(type, valueFactories.getNameFactory().create(value));
411 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
412 throw createValueFormatException(vfe);
413 }
414
415 case PropertyType.PATH:
416 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.NAME) {
417 throw createValueFormatException(Path.class);
418 }
419 try {
420 return this.withTypeAndValue(type, valueFactories.getPathFactory().create(value));
421 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
422 throw createValueFormatException(vfe);
423 }
424
425 case PropertyType.REFERENCE:
426 case PropertyType.WEAKREFERENCE:
427 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY) {
428 throw createValueFormatException(Node.class);
429 }
430 try {
431 return this.withTypeAndValue(type, valueFactories.getReferenceFactory().create(value));
432 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
433 throw createValueFormatException(vfe);
434 }
435 case PropertyType.DOUBLE:
436 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.LONG
437 && this.type != PropertyType.DATE) {
438 throw createValueFormatException(double.class);
439 }
440 try {
441 return this.withTypeAndValue(type, valueFactories.getDoubleFactory().create(value));
442 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
443 throw createValueFormatException(vfe);
444 }
445 case PropertyType.LONG:
446 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.DOUBLE
447 && this.type != PropertyType.DATE) {
448 throw createValueFormatException(long.class);
449 }
450 try {
451 return this.withTypeAndValue(type, valueFactories.getLongFactory().create(value));
452 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
453 throw createValueFormatException(vfe);
454 }
455 case PropertyType.DECIMAL:
456 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.DOUBLE
457 && this.type != PropertyType.LONG && this.type != PropertyType.DATE) {
458 throw createValueFormatException(BigDecimal.class);
459 }
460 try {
461 return this.withTypeAndValue(type, valueFactories.getDecimalFactory().create(value));
462 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
463 throw createValueFormatException(vfe);
464 }
465 case PropertyType.URI:
466 if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.URI) {
467 throw createValueFormatException(URI.class);
468 }
469 try {
470 return this.withTypeAndValue(type, valueFactories.getUriFactory().create(value));
471 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
472 throw createValueFormatException(vfe);
473 }
474
475
476 case PropertyType.BINARY:
477 try {
478 return this.withTypeAndValue(type, valueFactories.getBinaryFactory().create(value));
479 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
480 throw createValueFormatException(vfe);
481 }
482 case PropertyType.STRING:
483 try {
484 return this.withTypeAndValue(type, valueFactories.getStringFactory().create(value));
485 } catch (org.modeshape.graph.property.ValueFormatException vfe) {
486 throw createValueFormatException(vfe);
487 }
488 case PropertyType.UNDEFINED:
489 return this.withTypeAndValue(this.type, this.value);
490
491 default:
492 assert false : "Unexpected JCR property type " + type;
493
494 throw new IllegalStateException("Invalid property type " + type);
495 }
496 }
497
498 protected Object valueToType( int type,
499 Value value ) throws RepositoryException {
500 switch (type) {
501 case PropertyType.BOOLEAN:
502 return valueFactories.getBooleanFactory().create(value.getBoolean());
503 case PropertyType.DATE:
504 return valueFactories.getDateFactory().create(value.getDate());
505 case PropertyType.NAME:
506 return valueFactories.getNameFactory().create(value.getString());
507 case PropertyType.PATH:
508 return valueFactories.getPathFactory().create(value.getString());
509 case PropertyType.REFERENCE:
510 case PropertyType.WEAKREFERENCE:
511 return valueFactories.getReferenceFactory().create(value.getString());
512 case PropertyType.DOUBLE:
513 return valueFactories.getDoubleFactory().create(value.getDouble());
514 case PropertyType.LONG:
515 return valueFactories.getLongFactory().create(value.getLong());
516 case PropertyType.DECIMAL:
517 return valueFactories.getDecimalFactory().create(value.getDecimal());
518 case PropertyType.URI:
519 return valueFactories.getUriFactory().create(value.getString());
520 case PropertyType.BINARY:
521 return valueFactories.getBinaryFactory().create(value.getBinary());
522 case PropertyType.STRING:
523 return valueFactories.getStringFactory().create(value.getString());
524 case PropertyType.UNDEFINED:
525 return value.getString();
526
527 default:
528 assert false : "Unexpected JCR property type " + type;
529
530 throw new IllegalStateException("Invalid property type " + type);
531 }
532 }
533
534 @Override
535 public String toString() {
536 return (value == null ? "null" : value.toString()) + " (" + PropertyType.nameFromValue(type) + ")";
537 }
538 }