/*
* Copyright 2014 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.runtime.manager.impl.deploy;
import java.util.Collection;
import java.util.List;
import java.util.Stack;
import org.kie.internal.runtime.conf.BuilderHandler;
import org.kie.internal.runtime.conf.DeploymentDescriptor;
import org.kie.internal.runtime.conf.DeploymentDescriptorBuilder;
import org.kie.internal.runtime.conf.MergeMode;
import org.kie.internal.runtime.conf.NamedObjectModel;
import org.kie.internal.runtime.conf.ObjectModel;
public class DeploymentDescriptorMerger {
public DeploymentDescriptor merge(List<DeploymentDescriptor> descriptorHierarchy, MergeMode mode) {
if (descriptorHierarchy == null || descriptorHierarchy.isEmpty()) {
throw new IllegalArgumentException("Descriptor hierarchy list cannot be empty");
}
if (descriptorHierarchy.size() == 1) {
return descriptorHierarchy.get(0);
}
Stack<DeploymentDescriptor> stack = new Stack<DeploymentDescriptor>();
stack.addAll(descriptorHierarchy);
if (mode == null) {
mode = MergeMode.MERGE_COLLECTIONS;
}
while (stack.size() > 1) {
DeploymentDescriptor master = stack.pop();
DeploymentDescriptor slave = stack.pop();
DeploymentDescriptor desc = merge(master, slave, mode);
// add merged one to be next iteration slave
stack.push(desc);
}
// last element from the stack is the one that contains all merged descriptors
return stack.pop();
}
public DeploymentDescriptor merge(DeploymentDescriptor master, DeploymentDescriptor slave, MergeMode mode) {
if (master == null || slave == null) {
throw new IllegalArgumentException("Descriptors to merge must be provided");
}
DeploymentDescriptor merged = null;
DeploymentDescriptorBuilder builder = master.getBuilder();
builder.setBuildHandler(new MergeModeBuildHandler(mode));
switch (mode) {
case KEEP_ALL:
// do nothing as master wins
merged = master;
break;
case OVERRIDE_ALL:
// do nothing as slave wins
merged = slave;
break;
case OVERRIDE_EMPTY:
builder.auditMode(slave.getAuditMode());
builder.auditPersistenceUnit(slave.getAuditPersistenceUnit());
builder.persistenceMode(slave.getPersistenceMode());
builder.persistenceUnit(slave.getPersistenceUnit());
builder.runtimeStrategy(slave.getRuntimeStrategy());
builder.setConfiguration(slave.getConfiguration());
builder.setEnvironmentEntries(slave.getEnvironmentEntries());
builder.setEventListeners(slave.getEventListeners());
builder.setGlobals(slave.getGlobals());
builder.setMarshalingStrategies(slave.getMarshallingStrategies());
builder.setTaskEventListeners(slave.getTaskEventListeners());
builder.setWorkItemHandlers(slave.getWorkItemHandlers());
builder.setRequiredRoles(slave.getRequiredRoles());
builder.setClasses(slave.getClasses());
builder.setLimitSerializationClasses(slave.getLimitSerializationClasses());
merged = builder.get();
break;
case MERGE_COLLECTIONS:
builder.auditMode(slave.getAuditMode());
builder.auditPersistenceUnit(slave.getAuditPersistenceUnit());
builder.persistenceMode(slave.getPersistenceMode());
builder.persistenceUnit(slave.getPersistenceUnit());
builder.runtimeStrategy(slave.getRuntimeStrategy());
for (ObjectModel model : slave.getEventListeners()) {
builder.addEventListener(model);
}
for (ObjectModel model : slave.getMarshallingStrategies()) {
builder.addMarshalingStrategy(model);
}
for (ObjectModel model : slave.getTaskEventListeners()) {
builder.addTaskEventListener(model);
}
for (NamedObjectModel model : slave.getConfiguration()) {
builder.addConfiguration(model);
}
for (NamedObjectModel model : slave.getEnvironmentEntries()) {
builder.addEnvironmentEntry(model);
}
for (NamedObjectModel model : slave.getGlobals()) {
builder.addGlobal(model);
}
for (NamedObjectModel model : slave.getWorkItemHandlers()) {
builder.addWorkItemHandler(model);
}
for (String requiredRole : slave.getRequiredRoles()) {
builder.addRequiredRole(requiredRole);
}
for (String clazz : slave.getClasses()) {
builder.addClass(clazz);
}
Boolean slaveLimit = slave.getLimitSerializationClasses();
Boolean masterLimit = master.getLimitSerializationClasses();
if( slaveLimit != null && masterLimit != null &&
(!slaveLimit || !masterLimit) ) {
builder.setLimitSerializationClasses(false);
}
merged = builder.get();
break;
default:
break;
}
return merged;
}
private class MergeModeBuildHandler implements BuilderHandler {
private MergeMode mode;
MergeModeBuildHandler(MergeMode mode) {
this.mode = mode;
}
@Override
public boolean accepted(Object value) {
boolean accepted = false;
switch (mode) {
case OVERRIDE_ALL:
accepted = true;
break;
case OVERRIDE_EMPTY:
if (!isEmpty(value)) {
accepted = true;
}
break;
case MERGE_COLLECTIONS:
if (!isEmpty(value)) {
accepted = true;
}
break;
default:
break;
}
return accepted;
}
protected boolean isEmpty(Object value) {
if (value == null) {
return true;
}
if (value instanceof String) {
return ((String) value).isEmpty();
}
if (value instanceof Collection<?>) {
return ((Collection<?>) value).isEmpty();
}
return false;
}
}
}