/* 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.camunda.bpm.engine.impl.variable.serializer;

import javax.xml.bind.DatatypeConverter;
import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.impl.util.StringUtil;
import org.camunda.bpm.engine.variable.impl.value.UntypedValueImpl;
import org.camunda.bpm.engine.variable.type.SerializableValueType;
import org.camunda.bpm.engine.variable.value.SerializableValue;
import org.camunda.bpm.engine.variable.value.TypedValue;

/**
 * @author Roman Smirnov
 *
 */
public abstract class AbstractSerializableValueSerializer<T extends SerializableValue> extends AbstractTypedValueSerializer<T> {

  protected String serializationDataFormat;

  public AbstractSerializableValueSerializer(SerializableValueType type, String serializationDataFormat) {
    super(type);
    this.serializationDataFormat = serializationDataFormat;
  }

  public String getSerializationDataformat() {
    return serializationDataFormat;
  }

  public void writeValue(T value, ValueFields valueFields) {

    String serializedStringValue = value.getValueSerialized();
    byte[] serializedByteValue = null;

    if(value.isDeserialized()) {
      Object objectToSerialize = value.getValue();
      if(objectToSerialize != null) {
        // serialize to byte array
        try {
          serializedByteValue = serializeToByteArray(objectToSerialize);
          serializedStringValue = getSerializedStringValue(serializedByteValue);
        } catch(Exception e) {
          throw new ProcessEngineException("Cannot serialize object in variable '"+valueFields.getName()+"': "+e.getMessage(), e);
        }
      }
    }
    else {
      if (serializedStringValue != null) {
        serializedByteValue = getSerializedBytesValue(serializedStringValue);
      }
    }

    // write value and type to fields.
    writeToValueFields(value, valueFields, serializedByteValue);

    // update the ObjectValue to keep it consistent with value fields.
    updateTypedValue(value, serializedStringValue);
  }

  public T readValue(ValueFields valueFields, boolean deserializeObjectValue) {

    byte[] serializedByteValue = readSerializedValueFromFields(valueFields);
    String serializedStringValue = getSerializedStringValue(serializedByteValue);

    if(deserializeObjectValue) {
      Object deserializedObject = null;
      if(serializedByteValue != null) {
        try {
          deserializedObject = deserializeFromByteArray(serializedByteValue, valueFields);
        } catch (Exception e) {
          throw new ProcessEngineException("Cannot deserialize object in variable '"+valueFields.getName()+"': "+e.getMessage(), e);
        }
      }
      T value = createDeserializedValue(deserializedObject, serializedStringValue, valueFields);
      return value;
    }
    else {
      return createSerializedValue(serializedStringValue, valueFields);
    }
  }

  protected abstract T createDeserializedValue(Object deserializedObject, String serializedStringValue, ValueFields valueFields);

  protected abstract T createSerializedValue(String serializedStringValue, ValueFields valueFields);

  protected abstract void writeToValueFields(T value, ValueFields valueFields, byte[] serializedValue);

  protected abstract void updateTypedValue(T value, String serializedStringValue);

  protected byte[] readSerializedValueFromFields(ValueFields valueFields) {
    return valueFields.getByteArrayValue();
  }

  protected String getSerializedStringValue(byte[] serializedByteValue) {
    if(serializedByteValue != null) {
      if(!isSerializationTextBased()) {
        return DatatypeConverter.printBase64Binary(serializedByteValue);
      }
      return StringUtil.fromBytes(serializedByteValue);
    }
    else {
      return null;
    }
  }

  protected byte[] getSerializedBytesValue(String serializedStringValue) {
    if(serializedStringValue != null) {
      byte[] serializedByteValue = null;
      if (!isSerializationTextBased()) {
        serializedByteValue = DatatypeConverter.parseBase64Binary(serializedStringValue);
      } else {
        serializedByteValue = StringUtil.toByteArray(serializedStringValue);
      }
      return serializedByteValue;
    }
    else {
      return null;
    }
  }

  protected boolean canWriteValue(TypedValue typedValue) {

    if (!(typedValue instanceof SerializableValue) && !(typedValue instanceof UntypedValueImpl)) {
      return false;
    }

    if (typedValue instanceof SerializableValue) {
      SerializableValue serializableValue = (SerializableValue) typedValue;
      String requestedDataFormat = serializableValue.getSerializationDataFormat();
      if (!serializableValue.isDeserialized()) {
        // serialized object => dataformat must match
        return serializationDataFormat.equals(requestedDataFormat);
      } else {
        final boolean canSerialize = typedValue.getValue() == null || canSerializeValue(typedValue.getValue());
        return canSerialize && (requestedDataFormat == null || serializationDataFormat.equals(requestedDataFormat));
      }
    } else {
      return typedValue.getValue() == null || canSerializeValue(typedValue.getValue());
    }

  }


  /**
   * return true if this serializer is able to serialize the provided object.
   *
   * @param value the object to test (guaranteed to be a non-null value)
   * @return true if the serializer can handle the object.
   */
  protected abstract boolean canSerializeValue(Object value);

  // methods to be implemented by subclasses ////////////

  /**
   * Implementations must return a byte[] representation of the provided object.
   * The object is guaranteed not to be null.
   *
   * @param deserializedObject the object to serialize
   * @return the byte array value of the object
   * @throws exception in case the object cannot be serialized
   */
  protected abstract byte[] serializeToByteArray(Object deserializedObject) throws Exception;

  /**
   * Deserialize the object from a byte array.
   *
   * @param object the object to deserialize
   * @param valueFields the value fields
   * @return the deserialized object
   * @throws exception in case the object cannot be deserialized
   */
  protected abstract Object deserializeFromByteArray(byte[] object, ValueFields valueFields) throws Exception;

  /**
   * Return true if the serialization is text based. Return false otherwise
   *
   */
  protected abstract boolean isSerializationTextBased();

}

@@ -622,49 +622,8 @@
 ort 
-javax.xml.bind.DatatypeConverter;%0Aimport 
 org.
@@ -663,16 +663,86 @@
 xception
+;%0Aimport org.camunda.bpm.engine.impl.digest._apacheCommonsCodec.Base64
 ;%0Aimport
@@ -4158,50 +4158,49 @@
     
-return DatatypeConverter.printBase64Binary
+serializedByteValue = Base64.encodeBase64
 (ser
@@ -4479,20 +4479,61 @@
 Value = 
-null
+StringUtil.toByteArray(serializedStringValue)
 ;%0A      
@@ -4601,43 +4601,27 @@
 e = 
-DatatypeConverter.pars
+Base64.decod
 eBase64
-Binary
 (ser
@@ -4631,106 +4631,12 @@
 ized
-StringValue);%0A      %7D else %7B%0A        serializedByteValue = StringUtil.toByteArray(serializedString
+Byte
 Valu

Use DatatypeConverter instead of apacheCommons