This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 546dc444a0 Webservice improvements, fixes #5425 ,#4692, #4277 and
#2673 (#5795)
546dc444a0 is described below
commit 546dc444a020ff77151dcc19d1fa327671788b63
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Wed Oct 8 16:04:39 2025 +0200
Webservice improvements, fixes #5425 ,#4692, #4277 and #2673 (#5795)
* Add option to change statuscode in webservice, fixes #4692
* Add option to include header field in pipeline, fixes #4277
* Add support for binary fields in web service, fixes #5425 fixes #2673
---
.../modules/ROOT/pages/hop-server/web-service.adoc | 8 +-
.../java/org/apache/hop/www/WebServiceServlet.java | 55 +++++++-
.../org/apache/hop/www/service/WebService.java | 144 ++-------------------
.../hop/ui/www/service/WebServiceEditor.java | 52 ++++++++
.../hop/ui/www/service/WebServiceGuiPlugin.java | 2 +
.../www/service/messages/messages_en_US.properties | 3 +
6 files changed, 126 insertions(+), 138 deletions(-)
diff --git
a/docs/hop-user-manual/modules/ROOT/pages/hop-server/web-service.adoc
b/docs/hop-user-manual/modules/ROOT/pages/hop-server/web-service.adoc
index bcf377f536..4c741ea882 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/hop-server/web-service.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/hop-server/web-service.adoc
@@ -54,6 +54,9 @@ Make sure that the pipeline you want to execute is available
on the server.
|Output field
|The output field from which this service will take data from, convert it to a
String and output it
+|Status field
+|The field that contains the status code to be returned by the service,
default status code is `200` if left empty
+
|Content type
|The content type which will get reported by the webService servlet
@@ -61,7 +64,10 @@ Make sure that the pipeline you want to execute is available
on the server.
|Enable this option if you want the executions of the web service pipeline to
be listed in the status of the server.
|Request body content variable
-|This is the name of the variable which at runtime will contain the content of
the request body content. This is useful when doing a POST against the
webservice.
+|This is the name of the variable which at runtime will contain the content of
the request body. This is useful when doing a POST against the webservice.
+
+|Request header content variable
+|This is the name of the variable which at runtime will contain the content of
the request header. This is return a json object containing all headers that
were in the request.
|===
diff --git a/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
b/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
index ed5810a393..3dcc515477 100644
--- a/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
@@ -17,10 +17,13 @@
package org.apache.hop.www;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -36,6 +39,7 @@ import org.apache.hop.core.logging.LoggingObjectType;
import org.apache.hop.core.logging.SimpleLoggingObject;
import org.apache.hop.core.metadata.SerializableMetadataProvider;
import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.IValueMeta;
import org.apache.hop.core.variables.IVariables;
import org.apache.hop.i18n.BaseMessages;
import org.apache.hop.metadata.api.IHopMetadataProvider;
@@ -120,7 +124,9 @@ public class WebServiceServlet extends BaseHttpServlet
implements IHopServerPlug
String transformName = variables.resolve(webService.getTransformName());
String fieldName = variables.resolve(webService.getFieldName());
String contentType = variables.resolve(webService.getContentType());
+ String statusCodeField = variables.resolve(webService.getStatusCode());
String bodyContentVariable =
variables.resolve(webService.getBodyContentVariable());
+ String headerContentVariable =
variables.resolve(webService.getHeaderContentVariable());
String bodyContent = "";
if (StringUtils.isNotEmpty(bodyContentVariable)) {
@@ -129,6 +135,22 @@ public class WebServiceServlet extends BaseHttpServlet
implements IHopServerPlug
bodyContent = out.toString(StandardCharsets.UTF_8);
}
+ String headerContent = "";
+ if (StringUtils.isNotEmpty(headerContentVariable)) {
+ // Create JSON object containing all request headers
+ ObjectMapper objectMapper = new ObjectMapper();
+ ObjectNode headersJson = objectMapper.createObjectNode();
+
+ Enumeration<String> headerNames = request.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String headerName = headerNames.nextElement();
+ String headerValue = request.getHeader(headerName);
+ headersJson.put(headerName, headerValue);
+ }
+
+ headerContent = objectMapper.writeValueAsString(headersJson);
+ }
+
if (StringUtils.isEmpty(contentType)) {
response.setContentType("text/plain");
} else {
@@ -159,6 +181,10 @@ public class WebServiceServlet extends BaseHttpServlet
implements IHopServerPlug
pipeline.setVariable(bodyContentVariable, Const.NVL(bodyContent, ""));
}
+ if (StringUtils.isNotEmpty(headerContentVariable)) {
+ pipeline.setVariable(headerContentVariable, Const.NVL(headerContent,
""));
+ }
+
// Set all the other parameters as variables/parameters...
//
String[] pipelineParameters = pipelineMeta.listParameters();
@@ -205,8 +231,31 @@ public class WebServiceServlet extends BaseHttpServlet
implements IHopServerPlug
public void rowWrittenEvent(IRowMeta rowMeta, Object[] row)
throws HopTransformException {
try {
- String outputString = rowMeta.getString(row, fieldName, "");
-
outputStream.write(outputString.getBytes(StandardCharsets.UTF_8));
+ response.setStatus(rowMeta.getInteger(row, statusCodeField,
200L).intValue());
+
+ // Get the field index and metadata to detect field type
+ int fieldIndex = rowMeta.indexOfValue(fieldName);
+ if (fieldIndex < 0) {
+ throw new HopTransformException("Field '" + fieldName + "'
not found in row");
+ }
+
+ IValueMeta valueMeta = rowMeta.getValueMeta(fieldIndex);
+
+ // Check if field is binary type and handle accordingly
+ byte[] outputData;
+ if (valueMeta.getType() == IValueMeta.TYPE_BINARY) {
+ // Binary output - get raw bytes without encoding conversion
+ outputData = rowMeta.getBinary(row, fieldIndex);
+ if (outputData == null) {
+ outputData = new byte[0];
+ }
+ } else {
+ // Text output - convert to string and encode as UTF-8
+ String outputString = rowMeta.getString(row, fieldName, "");
+ outputData = outputString.getBytes(StandardCharsets.UTF_8);
+ }
+
+ outputStream.write(outputData);
outputStream.flush();
} catch (HopValueException e) {
throw new HopTransformException(
@@ -224,8 +273,6 @@ public class WebServiceServlet extends BaseHttpServlet
implements IHopServerPlug
pipeline.startThreads();
pipeline.waitUntilFinished();
- response.setStatus(HttpServletResponse.SC_OK);
-
} catch (Exception e) {
throw new ServletException("Error producing web service output", e);
}
diff --git a/engine/src/main/java/org/apache/hop/www/service/WebService.java
b/engine/src/main/java/org/apache/hop/www/service/WebService.java
index 21a85451c2..40101ac6c9 100644
--- a/engine/src/main/java/org/apache/hop/www/service/WebService.java
+++ b/engine/src/main/java/org/apache/hop/www/service/WebService.java
@@ -18,6 +18,8 @@
package org.apache.hop.www.service;
+import lombok.Getter;
+import lombok.Setter;
import org.apache.hop.metadata.api.HopMetadata;
import org.apache.hop.metadata.api.HopMetadataBase;
import org.apache.hop.metadata.api.HopMetadataProperty;
@@ -31,6 +33,8 @@ import org.apache.hop.metadata.api.IHopMetadata;
image = "ui/images/webservice.svg",
documentationUrl = "/metadata-types/web-service.html",
hopMetadataPropertyType = HopMetadataPropertyType.SERVER_WEB_SERVICE)
+@Getter
+@Setter
public class WebService extends HopMetadataBase implements IHopMetadata {
@HopMetadataProperty private boolean enabled;
@@ -38,9 +42,11 @@ public class WebService extends HopMetadataBase implements
IHopMetadata {
@HopMetadataProperty private String transformName;
@HopMetadataProperty private String fieldName;
@HopMetadataProperty private String contentType;
+ @HopMetadataProperty private String statusCode;
@HopMetadataProperty private boolean listingStatus;
@HopMetadataProperty private String bodyContentVariable;
@HopMetadataProperty private String runConfigurationName;
+ @HopMetadataProperty private String headerContentVariable;
public WebService() {}
@@ -51,149 +57,21 @@ public class WebService extends HopMetadataBase implements
IHopMetadata {
String transformName,
String fieldName,
String contentType,
+ String statusCode,
boolean listingStatus,
String bodyContentVariable,
- String runConfigurationName) {
+ String runConfigurationName,
+ String headerContentVariable) {
super(name);
this.enabled = enabled;
this.filename = filename;
this.transformName = transformName;
this.fieldName = fieldName;
this.contentType = contentType;
+ this.statusCode = statusCode;
this.listingStatus = listingStatus;
this.bodyContentVariable = bodyContentVariable;
this.runConfigurationName = runConfigurationName;
- }
-
- /**
- * Gets enabled
- *
- * @return value of enabled
- */
- public boolean isEnabled() {
- return enabled;
- }
-
- /**
- * @param enabled The enabled to set
- */
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
-
- /**
- * Gets filename
- *
- * @return value of filename
- */
- public String getFilename() {
- return filename;
- }
-
- /**
- * @param filename The filename to set
- */
- public void setFilename(String filename) {
- this.filename = filename;
- }
-
- /**
- * Gets transformName
- *
- * @return value of transformName
- */
- public String getTransformName() {
- return transformName;
- }
-
- /**
- * @param transformName The transformName to set
- */
- public void setTransformName(String transformName) {
- this.transformName = transformName;
- }
-
- /**
- * Gets fieldName
- *
- * @return value of fieldName
- */
- public String getFieldName() {
- return fieldName;
- }
-
- /**
- * @param fieldName The fieldName to set
- */
- public void setFieldName(String fieldName) {
- this.fieldName = fieldName;
- }
-
- /**
- * Gets contentType
- *
- * @return value of contentType
- */
- public String getContentType() {
- return contentType;
- }
-
- /**
- * @param contentType The contentType to set
- */
- public void setContentType(String contentType) {
- this.contentType = contentType;
- }
-
- /**
- * Gets listingStatus
- *
- * @return value of listingStatus
- */
- public boolean isListingStatus() {
- return listingStatus;
- }
-
- /**
- * @param listingStatus The listingStatus to set
- */
- public void setListingStatus(boolean listingStatus) {
- this.listingStatus = listingStatus;
- }
-
- /**
- * Gets bodyContentVariable
- *
- * @return value of bodyContentVariable
- */
- public String getBodyContentVariable() {
- return bodyContentVariable;
- }
-
- /**
- * Sets bodyContentVariable
- *
- * @param bodyContentVariable value of bodyContentVariable
- */
- public void setBodyContentVariable(String bodyContentVariable) {
- this.bodyContentVariable = bodyContentVariable;
- }
-
- /**
- * Gets runConfigurationName
- *
- * @return value of runConfigurationName
- */
- public String getRunConfigurationName() {
- return runConfigurationName;
- }
-
- /**
- * Sets runConfigurationName
- *
- * @param runConfigurationName value of runConfigurationName
- */
- public void setRunConfigurationName(String runConfigurationName) {
- this.runConfigurationName = runConfigurationName;
+ this.headerContentVariable = headerContentVariable;
}
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceEditor.java
b/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceEditor.java
index 02ee02c856..31eb27e6c5 100644
--- a/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceEditor.java
+++ b/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceEditor.java
@@ -67,9 +67,11 @@ public class WebServiceEditor extends
MetadataEditor<WebService> {
private MetaSelectionLine<PipelineRunConfiguration> wRunConfiguration;
private TextVar wTransform;
private TextVar wField;
+ private TextVar wStatusCode;
private ComboVar wContentType;
private Button wListStatus;
private TextVar wBodyContentVariable;
+ private TextVar wHeaderContentVariable;
public WebServiceEditor(HopGui hopGui, MetadataManager<WebService> manager,
WebService metadata) {
super(hopGui, manager, metadata);
@@ -236,6 +238,25 @@ public class WebServiceEditor extends
MetadataEditor<WebService> {
wField.setLayoutData(fdField);
lastControl = wlField;
+ // Status code field
+ //
+ Label wlStatuscode = new Label(parent, SWT.RIGHT);
+ PropsUi.setLook(wlField);
+ wlStatuscode.setText(BaseMessages.getString(PKG,
"WebServiceEditor.StatusCodeField.Label"));
+ FormData fdlStatusCode = new FormData();
+ fdlStatusCode.left = new FormAttachment(0, 0);
+ fdlStatusCode.right = new FormAttachment(middle, -margin);
+ fdlStatusCode.top = new FormAttachment(lastControl, 2 * margin);
+ wlStatuscode.setLayoutData(fdlStatusCode);
+ wStatusCode = new TextVar(manager.getVariables(), parent, SWT.SINGLE |
SWT.LEFT | SWT.BORDER);
+ PropsUi.setLook(wStatusCode);
+ FormData fdStatuscode = new FormData();
+ fdStatuscode.left = new FormAttachment(middle, 0);
+ fdStatuscode.right = new FormAttachment(100, 0);
+ fdStatuscode.top = new FormAttachment(wlStatuscode, 0, SWT.CENTER);
+ wStatusCode.setLayoutData(fdStatuscode);
+ lastControl = wlStatuscode;
+
// Content type
//
Label wlContentType = new Label(parent, SWT.RIGHT);
@@ -303,6 +324,31 @@ public class WebServiceEditor extends
MetadataEditor<WebService> {
wBodyContentVariable.setLayoutData(fdBodyContentVariable);
lastControl = wlBodyContentVariable;
+ // HeaderContentVariable to read from
+ //
+ Label wlHeaderContentVariable = new Label(parent, SWT.RIGHT);
+ PropsUi.setLook(wlHeaderContentVariable);
+ wlHeaderContentVariable.setText(
+ BaseMessages.getString(PKG,
"WebServiceEditor.HeaderContentVariable.Label"));
+ wlHeaderContentVariable.setToolTipText(
+ BaseMessages.getString(PKG,
"WebServiceEditor.HeaderContentVariable.Tooltip"));
+ FormData fdlHeaderContentVariable = new FormData();
+ fdlHeaderContentVariable.left = new FormAttachment(0, 0);
+ fdlHeaderContentVariable.right = new FormAttachment(middle, -margin);
+ fdlHeaderContentVariable.top = new FormAttachment(lastControl, 2 * margin);
+ wlHeaderContentVariable.setLayoutData(fdlHeaderContentVariable);
+ wHeaderContentVariable =
+ new TextVar(manager.getVariables(), parent, SWT.SINGLE | SWT.LEFT |
SWT.BORDER);
+ wHeaderContentVariable.setToolTipText(
+ BaseMessages.getString(PKG,
"WebServiceEditor.HeaderContentVariable.Tooltip"));
+ PropsUi.setLook(wHeaderContentVariable);
+ FormData fdHeaderContentVariable = new FormData();
+ fdHeaderContentVariable.left = new FormAttachment(middle, 0);
+ fdHeaderContentVariable.right = new FormAttachment(100, 0);
+ fdHeaderContentVariable.top = new FormAttachment(wlHeaderContentVariable,
0, SWT.CENTER);
+ wHeaderContentVariable.setLayoutData(fdHeaderContentVariable);
+ lastControl = wlHeaderContentVariable;
+
setWidgetsContent();
// Add listener to detect change after loading data
@@ -312,9 +358,11 @@ public class WebServiceEditor extends
MetadataEditor<WebService> {
wFilename.addListener(SWT.Modify, modifyListener);
wTransform.addListener(SWT.Modify, modifyListener);
wField.addListener(SWT.Modify, modifyListener);
+ wStatusCode.addListener(SWT.Modify, modifyListener);
wContentType.addListener(SWT.Modify, modifyListener);
wListStatus.addListener(SWT.Selection, modifyListener);
wBodyContentVariable.addListener(SWT.Modify, modifyListener);
+ wHeaderContentVariable.addListener(SWT.Modify, modifyListener);
wRunConfiguration.addListener(SWT.Selection, modifyListener);
}
@@ -416,9 +464,11 @@ public class WebServiceEditor extends
MetadataEditor<WebService> {
wFilename.setText(Const.NVL(ws.getFilename(), ""));
wTransform.setText(Const.NVL(ws.getTransformName(), ""));
wField.setText(Const.NVL(ws.getFieldName(), ""));
+ wStatusCode.setText(Const.NVL(ws.getStatusCode(), ""));
wContentType.setText(Const.NVL(ws.getContentType(), ""));
wListStatus.setSelection(ws.isListingStatus());
wBodyContentVariable.setText(Const.NVL(ws.getBodyContentVariable(), ""));
+ wHeaderContentVariable.setText(Const.NVL(ws.getHeaderContentVariable(),
""));
try {
wRunConfiguration.fillItems();
wRunConfiguration.setText(Const.NVL(ws.getRunConfigurationName(), ""));
@@ -434,9 +484,11 @@ public class WebServiceEditor extends
MetadataEditor<WebService> {
ws.setFilename(wFilename.getText());
ws.setTransformName(wTransform.getText());
ws.setFieldName(wField.getText());
+ ws.setStatusCode(wStatusCode.getText());
ws.setContentType(wContentType.getText());
ws.setListingStatus(wListStatus.getSelection());
ws.setBodyContentVariable(wBodyContentVariable.getText());
+ ws.setHeaderContentVariable(wHeaderContentVariable.getText());
ws.setRunConfigurationName(wRunConfiguration.getText());
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceGuiPlugin.java
b/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceGuiPlugin.java
index 1644dc54fc..654b4a0fe3 100644
--- a/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceGuiPlugin.java
+++ b/ui/src/main/java/org/apache/hop/ui/www/service/WebServiceGuiPlugin.java
@@ -104,8 +104,10 @@ public class WebServiceGuiPlugin {
transformMeta.getName(),
fieldName,
"text/plain",
+ null,
false,
null,
+ null,
null);
manager.newMetadata(webService);
return;
diff --git
a/ui/src/main/resources/org/apache/hop/ui/www/service/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/www/service/messages/messages_en_US.properties
index a3f249bd7c..7c8cb4612e 100644
---
a/ui/src/main/resources/org/apache/hop/ui/www/service/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/www/service/messages/messages_en_US.properties
@@ -18,9 +18,12 @@
WebServiceEditor.BodyContentVariable.Label=Request body content variable
WebServiceEditor.BodyContentVariable.Tooltip=This is the name of the variable
which at runtime will contain the content of the request body content. \nThis
is useful when doing a POST against the webservice.
+WebServiceEditor.HeaderContentVariable.Label=Request header content variable
+WebServiceEditor.HeaderContentVariable.Tooltip=This is the name of the
variable which at runtime will contain the content of the request header
content.
WebServiceEditor.ContentType.Label=Content type
WebServiceEditor.Enabled.Label=Enabled
WebServiceEditor.Field.Label=Output field
+WebServiceEditor.StatusCodeField.Label=Status Code field
WebServiceEditor.Filename.Label=Filename on the server
WebServiceEditor.ListStatus.Label=List status on server
WebServiceEditor.Name.Label=Name