/*
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* 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.jbpm.services.task.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.drools.core.marshalling.impl.ClassObjectMarshallingStrategyAcceptor;
import org.drools.core.marshalling.impl.MarshallerReaderContext;
import org.drools.core.marshalling.impl.MarshallingConfigurationImpl;
import org.drools.core.marshalling.impl.PersisterHelper;
import org.drools.core.marshalling.impl.ProcessMarshallerWriteContext;
import org.drools.core.marshalling.impl.ProtobufMessages.Header;
import org.drools.core.marshalling.impl.SerializablePlaceholderResolverStrategy;
import org.jbpm.marshalling.impl.JBPMMessages;
import org.jbpm.marshalling.impl.JBPMMessages.Variable;
import org.jbpm.marshalling.impl.JBPMMessages.VariableContainer;
import org.jbpm.marshalling.impl.ProtobufProcessMarshaller;
import org.kie.api.marshalling.ObjectMarshallingStrategy;
import org.kie.api.marshalling.ObjectMarshallingStrategyStore;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.task.model.Status;
import org.kie.api.task.model.Task;
import org.kie.internal.task.api.TaskModelProvider;
import org.kie.internal.task.api.model.AccessType;
import org.kie.internal.task.api.model.ContentData;
import org.kie.internal.task.api.model.FaultData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.Message;
public class ContentMarshallerHelper {
private static final Logger logger = LoggerFactory.getLogger(ContentMarshallerHelper.class);
private static final String SINGLE_VAR_KEY = "_results_";
public static ContentData marshal(Object o, Environment env) {
return marshal(null, o, env);
}
public static ContentData marshal(Task task, Object o, Environment env) {
if (o == null) {
return null;
}
ContentData content = null;
byte[] toByteArray = marshallContent(task, o, env);
content = TaskModelProvider.getFactory().newContentData();
content.setContent(toByteArray);
content.setType(o.getClass().getCanonicalName());
content.setAccessType(AccessType.Inline);
return content;
}
public static FaultData marshalFault(Map<String, Object> fault, Environment env) {
return marshalFault(null, fault, env);
}
public static FaultData marshalFault(Task task, Map<String, Object> fault, Environment env) {
FaultData content = null;
byte[] toByteArray = marshallContent(task, fault, env);
content = TaskModelProvider.getFactory().newFaultData();
content.setContent(toByteArray);
content.setType(fault.getClass().getCanonicalName());
content.setAccessType(AccessType.Inline);
content.setFaultName((String)fault.get("faultName"));
content.setType((String)fault.get("faultType"));
return content;
}
public static Object unmarshall(byte[] content, Environment env) {
return unmarshall(content, env, null);
}
public static Object unmarshall(byte[] content, Environment env, ClassLoader classloader) {
MarshallerReaderContext context = null;
try {
ByteArrayInputStream stream = new ByteArrayInputStream(content);
MarshallingConfigurationImpl marshallingConfigurationImpl = null;
if (env != null) {
marshallingConfigurationImpl = new MarshallingConfigurationImpl((ObjectMarshallingStrategy[]) env.get(EnvironmentName.OBJECT_MARSHALLING_STRATEGIES), false, false);
} else {
marshallingConfigurationImpl = new MarshallingConfigurationImpl(new ObjectMarshallingStrategy[]{new SerializablePlaceholderResolverStrategy(ClassObjectMarshallingStrategyAcceptor.DEFAULT)}, false, false);
}
ObjectMarshallingStrategyStore objectMarshallingStrategyStore = marshallingConfigurationImpl.getObjectMarshallingStrategyStore();
context = new MarshallerReaderContext(stream, null, null, objectMarshallingStrategyStore, null, env);
if (classloader != null) {
context.classLoader = classloader;
} else {
context.classLoader = ContentMarshallerHelper.class.getClassLoader();
}
ExtensionRegistry registry = PersisterHelper.buildRegistry(context, null);
Header _header = PersisterHelper.readFromStreamWithHeaderPreloaded(context, registry);
try {
VariableContainer parseFrom = JBPMMessages.VariableContainer.parseFrom(_header.getPayload(), registry);
Map<String, Object> value = ProtobufProcessMarshaller.unmarshallVariableContainerValue(context, parseFrom);
// in case there was single variable stored return only that variable and not map
if (value.containsKey(SINGLE_VAR_KEY) && value.size() == 1) {
return value.get(SINGLE_VAR_KEY);
}
return value;
} catch (Exception e) {
// backward compatible fallback mechanism to ensure existing data can be read properly
return fallbackParse(context, _header, registry);
}
} catch (Exception ex) {
logger.warn("Exception while unmarshaling content", ex);
}
return null;
}
public static byte[] marshallContent(Object o, Environment env) {
return marshallContent(null, o, env);
}
@SuppressWarnings("unchecked")
public static byte[] marshallContent(Task task, Object o, Environment env) {
ProcessMarshallerWriteContext context;
try {
MarshallingConfigurationImpl marshallingConfigurationImpl = null;
if (env != null) {
marshallingConfigurationImpl = new MarshallingConfigurationImpl((ObjectMarshallingStrategy[]) env.get(EnvironmentName.OBJECT_MARSHALLING_STRATEGIES), false, false);
} else {
marshallingConfigurationImpl = new MarshallingConfigurationImpl(new ObjectMarshallingStrategy[]{new SerializablePlaceholderResolverStrategy(ClassObjectMarshallingStrategyAcceptor.DEFAULT)}, false, false);
}
ObjectMarshallingStrategyStore objectMarshallingStrategyStore = marshallingConfigurationImpl.getObjectMarshallingStrategyStore();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
context = new ProcessMarshallerWriteContext(stream, null, null, null, objectMarshallingStrategyStore, env);
if (task != null) {
context.setTaskId(task.getId());
context.setProcessInstanceId(task.getTaskData().getProcessInstanceId());
context.setWorkItemId(task.getTaskData().getWorkItemId());
// determine state of the task
int taskState = ProcessMarshallerWriteContext.STATE_ACTIVE;
if (task.getTaskData().getStatus() == Status.Completed ||
task.getTaskData().getStatus() == Status.Error ||
task.getTaskData().getStatus() == Status.Exited ||
task.getTaskData().getStatus() == Status.Failed ||
task.getTaskData().getStatus() == Status.Obsolete) {
taskState = ProcessMarshallerWriteContext.STATE_COMPLETED;
}
context.setState(taskState);
}
Map<String, Object> input = null;
if (o instanceof Map) {
input = (Map<String, Object>) o;
} else {
// in case there is only single variable to be stored place it into a map under special key
input = new HashMap<String, Object>();
input.put(SINGLE_VAR_KEY, o);
}
Message marshallVariable = ProtobufProcessMarshaller.marshallVariablesContainer(context, input);
PersisterHelper.writeToStreamWithHeader(context, marshallVariable);
context.close();
return stream.toByteArray();
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object fallbackParse(MarshallerReaderContext context, Header header, ExtensionRegistry registry) throws Exception {
Variable parseFrom = JBPMMessages.Variable.parseFrom(header.getPayload(), registry);
Object value = ProtobufProcessMarshaller.unmarshallVariableValue(context, parseFrom);
if (value instanceof Map) {
Map result = new HashMap();
Map<String, Variable> variablesMap = (Map<String, Variable>) value;
for (String key : variablesMap.keySet()) {
result.put(key, ProtobufProcessMarshaller.unmarshallVariableValue(context, variablesMap.get(key)));
}
return result;
}
return value;
}
}