/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.jackrabbit.rmi.value; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import javax.jcr.Binary; import javax.jcr.Node; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.ValueFactory; import javax.jcr.ValueFormatException; /** * The <code>SerialValueFactory</code> class is used in the RMI infrastructure * to create serializable <code>Value</code> instances on the client side. * <p> * This class works in conjunction with the implementations of the * <code>javax.jcr.Value</code> interface found in this package. * <p> * This class may be extended to overwrite any of the * <code>createXXXValue</code> methods to create instances of the respective * type of {@link Value} implementation. The * methods of the <code>ValueFactory</code> interface are declared final to * guard against breaking the rules. */ public class SerialValueFactory implements ValueFactory { /** The singleton value factory instance */ private static final SerialValueFactory INSTANCE = new SerialValueFactory(); /** * Returns the <code>ValueFactory</code> instance, which currently is a * singleton instance of this class. * <p> * Future revisions will support some kind of configuration to specify * which concrete class should be used. */ public static final SerialValueFactory getInstance() { return INSTANCE; } /** * Utility method for decorating an array of values. The returned array will * contain serializable value decorators for all the given values. Note that * the contents of the original values will only be copied when the * decorators are serialized. * <p> * If the given array is <code>null</code>, then an empty array is * returned. * * @param values the values to be decorated * @return array of decorated values * @throws RepositoryException if the values can not be serialized */ public static Value[] makeSerialValueArray(Value[] values) throws RepositoryException { List<Value> serials = new ArrayList<Value>(); if (values != null) { for (Value value : values) { if (value != null) { serials.add(makeSerialValue(value)); } } } return serials.toArray(new Value[serials.size()]); } /** * Utility method for decorating a value. Note that the contents of the * original values will only be copied when the decorators are serialized. * Null referenced and already serializable values are passed as-is. * * @param value the value to be decorated, or <code>null</code> * @return the decorated value, or <code>null</code> * @throws RepositoryException if the value can not be serialized */ public static Value makeSerialValue(Value value) throws RepositoryException { // if the value is null or already serializable, just return it if (value == null || value instanceof Serializable) { return value; } else { return INSTANCE.createValue(value); } } /** * Utility method for converting an array of strings to serializable * string values. * <p> * If the given array is <code>null</code>, then an empty array is * returned. * * @param values the string array * @return array of string values */ public static Value[] makeSerialValueArray(String[] values) { List<Value> serials = new ArrayList<Value>(); if (values != null) { for (String value : values) { if (value != null) { serials.add(INSTANCE.createValue(value)); } } } return serials.toArray(new Value[serials.size()]); } /** * Default constructor only visible to extensions of this class. See * class comments for details. */ protected SerialValueFactory() { } /** {@inheritDoc} */ public Value createValue(String value) { return new StringValue(value); } /** {@inheritDoc} */ public final Value createValue(String value, int type) throws ValueFormatException { try { return createValue(new StringValue(value), type); } catch (ValueFormatException e) { throw e; } catch (RepositoryException e) { throw new ValueFormatException( "Unexpected error when creating value: " + value, e); } } private Value createValue(Value value) throws RepositoryException { return createValue(value, value.getType()); } private Value createValue(Value value, int type) throws RepositoryException { switch (type) { case PropertyType.BINARY: Binary binary = value.getBinary(); try { return createValue(binary.getStream()); } finally { binary.dispose(); } case PropertyType.BOOLEAN: return createValue(value.getBoolean()); case PropertyType.DATE: return createValue(value.getDate()); case PropertyType.DECIMAL: return createValue(value.getDecimal()); case PropertyType.DOUBLE: return createValue(value.getDouble()); case PropertyType.LONG: return createValue(value.getLong()); case PropertyType.NAME: return new NameValue(value.getString()); case PropertyType.PATH: return new PathValue(value.getString()); case PropertyType.REFERENCE: return new ReferenceValue(value.getString()); case PropertyType.STRING: return createValue(value.getString()); default: throw new ValueFormatException("Unknown value type " + type); } } /** {@inheritDoc} */ public final Value createValue(long value) { return new LongValue(value); } /** {@inheritDoc} */ public final Value createValue(double value) { return new DoubleValue(value); } /** {@inheritDoc} */ public final Value createValue(boolean value) { return new BooleanValue(value); } /** {@inheritDoc} */ public Value createValue(BigDecimal value) { return new DecimalValue(value); } /** {@inheritDoc} */ public final Value createValue(Calendar value) { return new DateValue(value); } /** {@inheritDoc} */ public final Value createValue(InputStream value) { try { return createValue(createBinary(value)); } catch (RepositoryException e) { throw new RuntimeException("Unable to create a binary value", e); } } /** {@inheritDoc} */ public final Value createValue(Node value) throws RepositoryException { return createValue(value.getUUID(), PropertyType.REFERENCE); } public Binary createBinary(InputStream stream) throws RepositoryException { try { try { return new SerializableBinary(stream); } finally { stream.close(); } } catch (IOException e) { throw new RepositoryException("Unable to read binary stream", e); } } public Value createValue(Binary value) { return new BinaryValue(value); } public Value createValue(Node value, boolean weak) throws RepositoryException { return new ReferenceValue(value.getUUID()); } }