/* * Copyright (C) 2005-2012 BetaCONCEPT Limited * * This file is part of Astroboa. * * Astroboa is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Astroboa is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Astroboa. If not, see <http://www.gnu.org/licenses/>. */ package org.betaconceptframework.astroboa.engine.jcr.util; import java.io.ByteArrayInputStream; import java.util.Calendar; import java.util.List; import javax.jcr.Binary; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.ValueFactory; import javax.jcr.nodetype.PropertyDefinition; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.betaconceptframework.astroboa.api.model.SimpleCmsProperty; import org.betaconceptframework.astroboa.api.model.ValueType; import org.betaconceptframework.astroboa.api.model.exception.CmsException; import org.betaconceptframework.astroboa.model.impl.ItemQName; import org.betaconceptframework.astroboa.util.DateUtils; /** * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ public class JcrValueUtils { /** * Get values from repository AND transform to objects * BINARY data is not processed by this method * @param value * @return * @throws */ public static Object getObjectValue(Value value) throws RepositoryException { if (value == null) return null; switch (value.getType()) { case PropertyType.BOOLEAN: return value.getBoolean(); case PropertyType.DATE: return value.getDate(); case PropertyType.DOUBLE: return value.getDouble(); case PropertyType.LONG: return value.getLong(); case PropertyType.STRING: case PropertyType.PATH: case PropertyType.NAME: case PropertyType.REFERENCE: return value.getString(); case PropertyType.BINARY: Binary binary = null; try { binary = value.getBinary(); if (binary!=null){ return IOUtils.toByteArray(binary.getStream()); } } catch (Exception e) { throw new CmsException(e); } finally{ if (binary!= null){ binary.dispose(); } } default: throw new CmsException("Unsupported value type "+ PropertyType.nameFromValue(value.getType())); } } public static Value[] convertListToValueArray(List values, ValueType valueType, ValueFactory valueFactory) throws RepositoryException { if (CollectionUtils.isEmpty(values)) return getJcrNullForMultiValue(); boolean atLeastOneValueIsNotNull = false; Value[] valueArray = new Value[values.size()]; for (int i=0; i< values.size(); i++){ valueArray[i] = JcrValueUtils.getJcrValue(values.get(i), valueType, valueFactory); if (valueArray[i] != null && valueArray[i] != JcrValueUtils.getJcrNull()){ atLeastOneValueIsNotNull = true; } } //All values in array are null. return null if (!atLeastOneValueIsNotNull){ return getJcrNullForMultiValue(); } return valueArray; } public static Value getJcrValue(SimpleCmsProperty simpleProperty, ValueFactory valueFactory) throws RepositoryException { ValueType valueType = simpleProperty.getValueType(); final Object value = simpleProperty.getSimpleTypeValue(); return getJcrValue(value, valueType, valueFactory); } public static Value getJcrValue(Object value, ValueType valueType, ValueFactory valueFactory) throws RepositoryException { if (valueType == null) throw new CmsException("Undefined property type "); if (value == null) return getJcrNull(); //Return null value in case value is a blank String if (value instanceof String && StringUtils.isBlank((String)value)) return getJcrNull(); switch (valueType) { case Boolean: if (value instanceof String) return getJcrBoolean(Boolean.valueOf((String)value), valueFactory); return getJcrBoolean((Boolean)value, valueFactory); case Double: if (value instanceof String) return getJcrDouble(Double.valueOf((String)value), valueFactory); return getJcrDouble((Double)value, valueFactory); case Date: if (value instanceof String) return getJcrCalendar(DateUtils.fromString((String)value), valueFactory); return getJcrCalendar((Calendar)value, valueFactory); case Long: if (value instanceof String) return getJcrLong(Long.valueOf((String)value), valueFactory); return getJcrLong((Long)value, valueFactory); case String: case ObjectReference: case TopicReference: return getJcrString((String)value, valueFactory); default: throw new CmsException("Undefined property type "+ valueType); } } private static Value getJcrBoolean(Boolean booleanValue, ValueFactory valueFactory) { return valueFactory.createValue(booleanValue); } private static Value getJcrDouble(Double doubleValue, ValueFactory valueFactory) { return valueFactory.createValue(doubleValue); } private static Value getJcrLong(Long longValue, ValueFactory valueFactory) { return valueFactory.createValue(longValue); } /* * Do not forget to call value.getBinary().dispose() after you have done processing this value */ public static Value getJcrBinary(byte[] content, ValueFactory valueFactory) throws RepositoryException { Binary binary = valueFactory.createBinary(new ByteArrayInputStream(content)); return valueFactory.createValue(binary); } private static Value getJcrString(String stringValue, ValueFactory valueFactory) { return valueFactory.createValue(stringValue); } private static Value getJcrCalendar(Calendar date, ValueFactory valueFactory) { return valueFactory.createValue(date); } public static Value getJcrNull() { return (Value) null; } public static Value[] getJcrNullForMultiValue() { //Although it may be better to return an empty array //JCR implementation (Jackrabbit) needs 'null' in order //to complete nullify value for property. return (Value[]) null; } public static void replaceValue(Node node, ItemQName property, Value newValue, Value oldValue, Boolean isPropertyMultivalued) throws RepositoryException { //Node does not have property if (!node.hasProperty(property.getJcrName())) { //New Value is null. Do nothing if (newValue == null) return; //Determine if property is multiple, if this info is not provided if (isPropertyMultivalued == null) { isPropertyMultivalued = propertyIsMultiValued(node, property); } if (isPropertyMultivalued) node.setProperty(property.getJcrName(), new Value[]{newValue}); else node.setProperty(property.getJcrName(), newValue); } else { //Node has property Property jcrProperty = node.getProperty(property.getJcrName()); if (isPropertyMultivalued == null) //Determine by property isPropertyMultivalued = jcrProperty.getDefinition().isMultiple(); if (!isPropertyMultivalued){ if (oldValue == null || ( oldValue != null && oldValue.equals(jcrProperty.getValue())) ){ //Set newValue only if no old value is provided OR //oldValue is provided and it really exists there jcrProperty.setValue(newValue); } } else { Value[] values = jcrProperty.getValues(); //Remove oldValue if (oldValue != null) { int index = ArrayUtils.indexOf(values, oldValue); if (index == ArrayUtils.INDEX_NOT_FOUND) throw new ItemNotFoundException("Value "+ oldValue.getString() + " in property "+ jcrProperty.getPath()); values = (Value[]) ArrayUtils.remove(values, index); } //Add new value if (newValue != null && ! ArrayUtils.contains(values, newValue)) values = (Value[]) ArrayUtils.add(values, newValue); //If at the end values array is empty //remove property if (ArrayUtils.isEmpty(values)){ node.setProperty(property.getJcrName(), JcrValueUtils.getJcrNullForMultiValue()); } else{ node.setProperty(property.getJcrName(), values); } } } } private static boolean propertyIsMultiValued(Node node, ItemQName property) throws RepositoryException { String propertyName = property.getJcrName(); PropertyDefinition[] propertyDefinitions = node.getDefinition().getDeclaringNodeType().getPropertyDefinitions(); for (PropertyDefinition propertyDefinition: propertyDefinitions) { if (propertyDefinition.getName().equals(propertyName)) return propertyDefinition.isMultiple(); } throw new RepositoryException("Unable ot determine if property "+ property.getJcrName() + " in node "+ node.getPath() + " is multivalue or not"); } /** * Adds a value to a property. * @param node * @param property * @param newValue * @param isPropertyMultivalued * @throws RepositoryException */ public static void addValue(Node node, ItemQName property, Value newValue, Boolean isPropertyMultivalued) throws RepositoryException { replaceValue(node, property, newValue, null, isPropertyMultivalued); } /** * @param node * @param property * @param valueToBeRemoved * @param isPropertyMultivalued * @throws RepositoryException */ public static void removeValue(Node node, ItemQName property, Value valueToBeRemoved, Boolean isPropertyMultivalued) throws RepositoryException { replaceValue(node, property, null, valueToBeRemoved, isPropertyMultivalued); } }