Skip to content

Commit

Permalink
[JBPM-9738] Adding support for headers in WebServiceWorkItemHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
fjtirado committed Aug 12, 2021
1 parent bb94f5c commit a9a70c0
Show file tree
Hide file tree
Showing 4 changed files with 263 additions and 27 deletions.
@@ -0,0 +1,79 @@
/*
* Copyright 2021 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.process.workitem.core.util;

import java.util.HashMap;
import java.util.Map;

public class WorkItemHeaderInfo {

private final String name;
private final Object content;
private final Map<String, Object> params;

public static class Builder {

private final String name;
private Object content;
private Map<String, Object> parameters;

private Builder(String name) {
this.name = name;
this.parameters = new HashMap<>();
}

public static Builder of(String name) {
return new Builder(name);
}

public Builder withContent(Object content) {
this.content = content;
return this;
}

public Builder withParam(String key, Object value) {
parameters.put(key, value);
return this;
}

public WorkItemHeaderInfo build() {
return new WorkItemHeaderInfo(name, content, parameters);
}
}

private WorkItemHeaderInfo(String name, Object content, Map<String, Object> params) {
this.name = name;
this.content = content;
this.params = params;
}

public String getName() {
return name;
}

public Object getContent() {
return content;
}

public Object getParam(String key) {
return params.get(key);
}

@Override
public String toString() {
return "WorkItemHeaderInfo [name=" + name + ", content=" + content + ", params=" + params + "]";
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2021 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.process.workitem.core.util;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.jbpm.process.workitem.core.util.WorkItemHeaderInfo.Builder;
import org.kie.api.runtime.process.WorkItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WorkItemHeaderUtils {

private WorkItemHeaderUtils() {
}

private static final String CONTENT_PREFIX = "HEADER_";
private static final String PARAM_PREFIX = "HEADER_PARAM_";
static final String SEPARATOR_PROP = "org.kie.workitem.ws.header.separator";

private static final Logger logger = LoggerFactory.getLogger(WorkItemHeaderUtils.class);

public static Collection<WorkItemHeaderInfo> getHeaderInfo(WorkItem workItem) {
final String separator = System.getProperty(SEPARATOR_PROP, "_");
Map<String, WorkItemHeaderInfo.Builder> map = new HashMap<>();
for (Entry<String, Object> param : workItem.getParameters().entrySet()) {
String key = param.getKey().toUpperCase();
if (key.startsWith(PARAM_PREFIX)) {
key = param.getKey().substring(PARAM_PREFIX.length());
int indexOf = key.indexOf(separator);
if (indexOf != -1) {
map.computeIfAbsent(key.substring(indexOf + separator.length()), Builder::of)
.withParam(key.substring(0, indexOf), param.getValue());
} else {
logger.warn("Wrong parameter name {}. It expects at least one {} in {}", param.getKey(), separator,
key);
}
} else if (key.startsWith(CONTENT_PREFIX)) {
map.computeIfAbsent(param.getKey().substring(CONTENT_PREFIX.length()), Builder::of)
.withContent(param.getValue());
}
}
return map.values().stream().map(Builder::build).collect(Collectors.toList());
}

}
@@ -0,0 +1,68 @@
/*
* Copyright 2021 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.process.workitem.core.util;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import org.kie.api.runtime.process.WorkItem;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class WorkItemHeaderUtilsTest {

@Test
public void testBuildHeaderList() {
WorkItem workItem = mock(WorkItem.class);
Map<String, Object> map = new HashMap<>();
map.put("HEADER_Pepito_Grillo", "fulanito");
map.put("header_param_NS_Pepito_Grillo", "http://pepito.com");
map.put("mamotreco", "power");
when(workItem.getParameters()).thenReturn(map);
Collection<WorkItemHeaderInfo> headers = WorkItemHeaderUtils.getHeaderInfo(workItem);
assertEquals(1, headers.size());
WorkItemHeaderInfo header = headers.iterator().next();
assertEquals("Pepito_Grillo", header.getName());
assertEquals("fulanito", header.getContent());
assertEquals("http://pepito.com", header.getParam("NS"));
}

@Test
public void testBuildHeaderListWithCustomSeparator() {
System.setProperty(WorkItemHeaderUtils.SEPARATOR_PROP, "//");
try {
WorkItem workItem = mock(WorkItem.class);
Map<String, Object> map = new HashMap<>();
map.put("HEADER_Pepito_Grillo", "fulanito");
map.put("header_param_NS_232//Pepito_Grillo", "http://pepito.com");
map.put("mamotreco", "power");
when(workItem.getParameters()).thenReturn(map);
Collection<WorkItemHeaderInfo> headers = WorkItemHeaderUtils.getHeaderInfo(workItem);
assertEquals(1, headers.size());
WorkItemHeaderInfo header = headers.iterator().next();
assertEquals("Pepito_Grillo", header.getName());
assertEquals("fulanito", header.getContent());
assertEquals("http://pepito.com", header.getParam("NS_232"));
} finally {
System.clearProperty(WorkItemHeaderUtils.SEPARATOR_PROP);
}
}

}
Expand Up @@ -30,6 +30,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.xml.namespace.QName;

Expand All @@ -38,6 +39,8 @@
import org.apache.cxf.endpoint.ClientCallback;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.endpoint.dynamic.DynamicClientFactory;
import org.apache.cxf.headers.Header;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.jaxws.interceptors.HolderInInterceptor;
import org.apache.cxf.jaxws.interceptors.WrapperClassInInterceptor;
Expand All @@ -52,6 +55,8 @@
import org.jbpm.process.workitem.core.util.WidMavenDepends;
import org.jbpm.process.workitem.core.util.WidParameter;
import org.jbpm.process.workitem.core.util.WidResult;
import org.jbpm.process.workitem.core.util.WorkItemHeaderInfo;
import org.jbpm.process.workitem.core.util.WorkItemHeaderUtils;
import org.jbpm.process.workitem.core.util.service.WidAction;
import org.jbpm.process.workitem.core.util.service.WidAuth;
import org.jbpm.process.workitem.core.util.service.WidService;
Expand Down Expand Up @@ -106,7 +111,7 @@ public class WebServiceWorkItemHandler extends AbstractLogOrThrowWorkItemHandler
private final Long defaultJbpmCxfClientConnectionTimeout = Long.parseLong(System.getProperty("org.jbpm.cxf.client.connectionTimeout", "30000"));
private final Long defaultJbpmCxfClientReceiveTimeout = Long.parseLong(System.getProperty("org.jbpm.cxf.client.receiveTimeout", "60000"));

private ConcurrentHashMap<String, Client> clients = new ConcurrentHashMap<String, Client>();
private ConcurrentHashMap<String, Client> clients = new ConcurrentHashMap<>();
private DynamicClientFactory dcf = null;
private KieSession ksession;
private int asyncTimeout = 10;
Expand Down Expand Up @@ -317,6 +322,7 @@ public WebServiceWorkItemHandler(String handlingProcessId,
this.handlingStrategy = handlingStrategy;
}

@Override
public void executeWorkItem(WorkItem workItem,
final WorkItemManager manager) {

Expand Down Expand Up @@ -397,6 +403,7 @@ public void executeWorkItem(WorkItem workItem,
}
new Thread(new Runnable() {

@Override
public void run() {

try {
Expand Down Expand Up @@ -488,15 +495,7 @@ protected Client getWSClient(WorkItem workItem, String interfaceRef) {
String importNamespace = (String) workItem.getParameter("Namespace");
if (importLocation != null && importLocation.trim().length() > 0
&& importNamespace != null && importNamespace.trim().length() > 0) {
Client client = getDynamicClientFactory().createClient(importLocation,
new QName(importNamespace,
interfaceRef),
getInternalClassLoader(),
null);
setClientTimeout(workItem, client);
clients.put(interfaceRef,
client);
return client;
return getClient (workItem, importLocation, importNamespace, interfaceRef);
}

long processInstanceId = ((WorkItemImpl) workItem).getProcessInstanceId();
Expand All @@ -508,26 +507,52 @@ protected Client getWSClient(WorkItem workItem, String interfaceRef) {
for (Bpmn2Import importObj : typedImports) {
if (WSDL_IMPORT_TYPE.equalsIgnoreCase(importObj.getType())) {
try {
client = getDynamicClientFactory().createClient(importObj.getLocation(),
new QName(importObj.getNamespace(),
interfaceRef),
getInternalClassLoader(),
null);
setClientTimeout(workItem, client);
clients.put(interfaceRef,
client);
return client;
} catch (Exception e) {
logger.error("Error when creating WS Client",
e);
continue;
}
}
}
}
return getClient (workItem, importObj.getLocation(), importObj.getNamespace(), interfaceRef);
} catch (Exception e) {
logger.error("Error when creating WS Client", e);
}
}
}
}
}
return null;
}


private Client getClient(WorkItem workItem, String location, String namespace, String interfaceRef) {
Client client = getDynamicClientFactory().createClient(location, new QName(namespace, interfaceRef),
getInternalClassLoader(), null);
setClientTimeout(workItem, client);
Collection<WorkItemHeaderInfo> headers = WorkItemHeaderUtils.getHeaderInfo(workItem);
if (!headers.isEmpty()) {
client.getRequestContext().put(Header.HEADER_LIST,
headers.stream().map(this::buildHeader).collect(Collectors.toList()));
}
clients.put(interfaceRef, client);
return client;
}


private Header buildHeader(WorkItemHeaderInfo header) {
String namespace = (String) header.getParam("NS");
QName name = namespace == null ? new QName(header.getName()) : new QName(namespace, header.getName());
Class<?> contentClass = String.class;
String type = (String) header.getParam("TYPE");
if (type != null) {
try {
contentClass = classLoader.loadClass(type);
} catch (ClassNotFoundException ex) {
logger.warn("Cannot find type {}", type, ex);
}
}
JAXBDataBinding binding = null;
try {
binding = new JAXBDataBinding(contentClass);
} catch (Exception ex) {
logger.warn("Error creating binding for type {}", type, ex);
}
return new Header(name, header.getContent(), binding);
}

private void setClientTimeout(WorkItem workItem, Client client) {
HTTPConduit conduit = (HTTPConduit) client.getConduit();
Expand Down Expand Up @@ -556,6 +581,7 @@ protected synchronized DynamicClientFactory getDynamicClientFactory() {
return this.dcf;
}

@Override
public void abortWorkItem(WorkItem workItem,
WorkItemManager manager) {
// Do nothing, cannot be aborted
Expand Down

0 comments on commit a9a70c0

Please sign in to comment.