/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.jcr;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import javax.jcr.Binary;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.NodeTypeTemplate;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.nodetype.PropertyDefinitionTemplate;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.modeshape.jcr.api.value.DateTime;
import org.modeshape.jcr.value.ValueFactory;
public class JcrSingleValuePropertyTest extends MultiUseAbstractTest {
private org.modeshape.jcr.api.Property prop;
private byte[] binaryValue;
private DateTime dateValue;
private double doubleValue;
private long longValue;
private String stringValue;
private boolean booleanValue;
private String nameValue;
private String pathValue;
private ValueFactory<String> stringFactory;
protected AbstractJcrNode cars;
protected AbstractJcrNode altima;
/**
* Initialize the expensive activities, and in particular the RepositoryNodeTypeManager instance.
*
* @throws Exception
*/
@BeforeClass
public static void beforeAll() throws Exception {
MultiUseAbstractTest.beforeAll();
// Import the node types and the data ...
registerNodeTypes("cars.cnd");
importContent("/", "io/cars-system-view-with-uuids.xml", ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
// Now define a namespace we'll use in the tests ...
session.getWorkspace().getNamespaceRegistry().registerNamespace("acme", "http://example.com");
NodeTypeManager mgr = session.getWorkspace().getNodeTypeManager();
// Define the node definition that will have all the different kinds of properties ...
NodeTypeTemplate nodeType = mgr.createNodeTypeTemplate();
nodeType.setMixin(true);
nodeType.setName("mixinWithAllPropTypes");
@SuppressWarnings( "unchecked" )
List<PropertyDefinitionTemplate> propDefns = nodeType.getPropertyDefinitionTemplates();
// Add a property for each type ...
PropertyDefinitionTemplate binaryDefn = mgr.createPropertyDefinitionTemplate();
binaryDefn.setName("binaryProperty");
binaryDefn.setRequiredType(PropertyType.BINARY);
propDefns.add(binaryDefn);
PropertyDefinitionTemplate booleanDefn = mgr.createPropertyDefinitionTemplate();
booleanDefn.setName("booleanProperty");
booleanDefn.setRequiredType(PropertyType.BOOLEAN);
propDefns.add(booleanDefn);
PropertyDefinitionTemplate dateDefn = mgr.createPropertyDefinitionTemplate();
dateDefn.setName("dateProperty");
dateDefn.setRequiredType(PropertyType.DATE);
propDefns.add(dateDefn);
PropertyDefinitionTemplate doubleDefn = mgr.createPropertyDefinitionTemplate();
doubleDefn.setName("doubleProperty");
doubleDefn.setRequiredType(PropertyType.DOUBLE);
propDefns.add(doubleDefn);
PropertyDefinitionTemplate longDefn = mgr.createPropertyDefinitionTemplate();
longDefn.setName("longProperty");
longDefn.setRequiredType(PropertyType.LONG);
propDefns.add(longDefn);
PropertyDefinitionTemplate nameDefn = mgr.createPropertyDefinitionTemplate();
nameDefn.setName("nameProperty");
nameDefn.setRequiredType(PropertyType.NAME);
propDefns.add(nameDefn);
PropertyDefinitionTemplate pathDefn = mgr.createPropertyDefinitionTemplate();
pathDefn.setName("pathProperty");
pathDefn.setRequiredType(PropertyType.PATH);
propDefns.add(pathDefn);
PropertyDefinitionTemplate refDefn = mgr.createPropertyDefinitionTemplate();
refDefn.setName("referenceProperty");
refDefn.setRequiredType(PropertyType.REFERENCE);
propDefns.add(refDefn);
PropertyDefinitionTemplate stringDefn = mgr.createPropertyDefinitionTemplate();
stringDefn.setName("stringProperty");
stringDefn.setRequiredType(PropertyType.STRING);
propDefns.add(stringDefn);
PropertyDefinitionTemplate undefinedDefn = mgr.createPropertyDefinitionTemplate();
undefinedDefn.setName("undefinedProperty");
undefinedDefn.setRequiredType(PropertyType.UNDEFINED);
propDefns.add(undefinedDefn);
// Add the node type ...
mgr.registerNodeType(nodeType, true);
}
@Override
@Before
public void beforeEach() throws Exception {
super.beforeEach();
stringFactory = session.stringFactory();
binaryValue = "This is a binary value".getBytes();
dateValue = session.dateFactory().create();
doubleValue = 3.14159d;
longValue = 100L;
booleanValue = true;
stringValue = "stringValue";
nameValue = "acme:SomeName";
pathValue = "/Cars/Hybrid/Toyota Highlander/acme:SomethingElse";
// Add the mixin to the 'Cars' node ...
cars = session.getNode("/Cars");
cars.addMixin("mixinWithAllPropTypes");
altima = session.getNode("/Cars/Hybrid/Nissan Altima");
altima.addMixin("mix:referenceable");
// Set each property ...
cars.setProperty("booleanProperty", booleanValue);
cars.setProperty("dateProperty", dateValue.toCalendar());
cars.setProperty("doubleProperty", doubleValue);
cars.setProperty("binaryProperty", new ByteArrayInputStream(binaryValue));
cars.setProperty("longProperty", longValue);
cars.setProperty("referenceProperty", altima);
cars.setProperty("stringProperty", stringValue);
cars.setProperty("pathProperty", pathValue);
cars.setProperty("nameProperty", nameValue);
cars.setProperty("undefinedProperty", "100");
}
@Test
public void shouldIndicateHasSingleValue() throws Exception {
prop = cars.getProperty("booleanProperty");
PropertyDefinition def = prop.getDefinition();
assertThat(def.isMultiple(), is(false));
}
@Test
public void shouldProvideBoolean() throws Exception {
prop = cars.getProperty("booleanProperty");
assertThat(prop.getBoolean(), is(booleanValue));
assertThat(prop.getAs(Boolean.class), is(booleanValue));
assertThat(prop.getType(), is(PropertyType.BOOLEAN));
assertThat(prop.getString(), is(stringFactory.create(booleanValue)));
assertThat(prop.getLength(), is((long)stringFactory.create(booleanValue).length()));
checkValue(prop);
}
@Test
public void shouldProvideDate() throws Exception {
prop = cars.getProperty("dateProperty");
// see ModeShape-527 for reasons asserts are commented
// assertThat(prop.getDate(), is(dateValue.toCalendar()));
assertThat(prop.getLong(), is(dateValue.getMilliseconds()));
// assertThat(prop.getString(), is(stringFactory.create(dateValue)));
assertThat(prop.getType(), is(PropertyType.DATE));
// assertThat(prop.getLength(), is((long)stringFactory.create(dateValue).length()));
assertThat(prop.getAs(DateTime.class), notNullValue());
checkValue(prop);
}
@Test
public void shouldProvideNode() throws Exception {
prop = cars.getProperty("referenceProperty");
assertThat(prop.getNode(), is((Node)altima));
assertThat(prop.getAs(Node.class), is((Node)altima));
NodeIterator nodeIterator = prop.getAs(NodeIterator.class);
assertThat(nodeIterator.getSize(), is(1l));
assertThat(nodeIterator.nextNode(), is((Node)altima));
assertThat(prop.getType(), is(PropertyType.REFERENCE));
assertThat(prop.getString(), is(altima.getIdentifier()));
assertThat(prop.getLength(), is((long) altima.getIdentifier().length()));
checkValue(prop);
}
@Test
public void shouldProvideDouble() throws Exception {
prop = cars.getProperty("doubleProperty");
assertThat(prop.getDouble(), is(doubleValue));
assertThat(prop.getAs(Double.class), is(doubleValue));
assertThat(prop.getString(), is(stringFactory.create(doubleValue)));
assertThat(prop.getType(), is(PropertyType.DOUBLE));
assertThat(prop.getLength(), is((long)stringFactory.create(doubleValue).length()));
checkValue(prop);
}
@Test
public void shouldProvideLong() throws Exception {
prop = cars.getProperty("longProperty");
assertThat(prop.getLong(), is(longValue));
assertThat(prop.getAs(Long.class), is(longValue));
assertThat(prop.getString(), is(stringFactory.create(longValue)));
assertThat(prop.getType(), is(PropertyType.LONG));
assertThat(prop.getLength(), is((long)stringFactory.create(longValue).length()));
checkValue(prop);
}
@SuppressWarnings( "deprecation" )
@Test
public void shouldProvideStream() throws Exception {
prop = cars.getProperty("binaryProperty");
assertThat(prop.getType(), is(PropertyType.BINARY));
InputStream stream = prop.getStream();
try {
assertThat(stream, notNullValue());
} finally {
if (stream != null) {
stream.close();
}
}
stream = prop.getAs(InputStream.class);
try {
assertThat(stream, notNullValue());
} finally {
if (stream != null) {
stream.close();
}
}
assertThat(prop.getString(), is(stringFactory.create(binaryValue)));
assertThat(prop.getLength(), is((long)binaryValue.length)); // note this value!!
checkValue(prop);
}
@Test
public void shouldProvideBinary() throws Exception {
prop = cars.getProperty("binaryProperty");
assertThat(prop.getType(), is(PropertyType.BINARY));
Binary binary = prop.getBinary();
InputStream stream = binary.getStream();
try {
assertThat(stream, notNullValue());
} finally {
if (stream != null) {
stream.close();
}
}
assertThat(prop.getAs(Binary.class), notNullValue());
assertThat(prop.getAs(org.modeshape.jcr.api.Binary.class), notNullValue());
assertThat(prop.getString(), is(stringFactory.create(binaryValue)));
assertThat(prop.getLength(), is((long)binaryValue.length)); // note this value!!
assertThat(binary.getSize(), is((long)binaryValue.length)); // note this value!!
checkValue(prop);
}
@Test
public void shouldProvideString() throws Exception {
prop = cars.getProperty("stringProperty");
assertThat(prop.getString(), is(stringValue));
assertThat(prop.getAs(String.class), is(stringValue));
assertThat(prop.getType(), is(PropertyType.STRING));
assertThat(prop.getLength(), is((long)stringValue.length()));
checkValue(prop);
}
@Test
public void shouldAllowNameValue() throws Exception {
prop = cars.getProperty("nameProperty");
assertThat(prop.getType(), is(PropertyType.NAME));
assertThat(prop.getString(), is(nameValue));
assertThat(prop.getAs(String.class), is(nameValue));
assertThat(prop.getLength(), is((long)nameValue.length()));
// Change the namespace registry ...
session.setNamespacePrefix("acme2", "http://example.com");
assertThat(prop.getString(), is("acme2:SomeName"));
checkValue(prop);
}
@Test
public void shouldAllowPathValue() throws Exception {
prop = cars.getProperty("pathProperty");
assertThat(prop.getType(), is(PropertyType.PATH));
assertThat(prop.getString(), is(pathValue));
assertThat(prop.getAs(String.class), is(pathValue));
// Change the namespace registry ...
session.setNamespacePrefix("acme2", "http://example.com");
assertThat(prop.getString(), is("/Cars/Hybrid/Toyota Highlander/acme2:SomethingElse"));
checkValue(prop);
}
public void checkValue( Property prop ) throws Exception {
// Should provide a value and not multiple values ...
Value val = prop.getValue();
assertThat(val, notNullValue());
assertThat(prop.getDefinition(), notNullValue());
// Should not allow multiple-value methods ...
try {
prop.getValues();
fail("Should not be able to call 'getValues()' on a single-value property");
} catch (ValueFormatException e) {
// expected
}
try {
prop.getLengths();
fail("Should not be able to call 'getValues()' on a single-value property");
} catch (ValueFormatException e) {
// expected
}
}
}