diff --git a/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttp.java b/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttp.java index 10948824c41..b7236e2595d 100644 --- a/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttp.java +++ b/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttp.java @@ -50,13 +50,13 @@ import org.apache.hop.core.vfs.HopVfs; import org.apache.hop.core.xml.XmlHandler; import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.HopMetadataProperty; import org.apache.hop.metadata.api.IHopMetadataProvider; import org.apache.hop.resource.ResourceEntry; import org.apache.hop.resource.ResourceEntry.ResourceType; import org.apache.hop.resource.ResourceReference; import org.apache.hop.workflow.WorkflowMeta; import org.apache.hop.workflow.action.ActionBase; -import org.apache.hop.workflow.action.IAction; import org.apache.hop.workflow.action.validator.ActionValidatorUtils; import org.apache.hop.workflow.action.validator.AndValidator; import org.w3c.dom.Node; @@ -72,8 +72,7 @@ documentationUrl = "/workflow/actions/http.html") @Getter @Setter -public class ActionHttp extends ActionBase implements Cloneable, IAction { - public static final String SPACES = " "; +public class ActionHttp extends ActionBase { private static final Class PKG = ActionHttp.class; private static final String CONST_URL_FIELDNAME = "URL"; @@ -86,171 +85,103 @@ public class ActionHttp extends ActionBase implements Cloneable, IAction { public static final String CONST_HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts"; // Base info + @HopMetadataProperty(key = "url") private String url; + @HopMetadataProperty(key = "targetfilename") private String targetFilename; + @HopMetadataProperty(key = "file_appended") private boolean fileAppended; + @HopMetadataProperty(key = "date_time_added") private boolean dateTimeAdded; + @HopMetadataProperty(key = "targetfilename_extension") private String targetFilenameExtension; // Send file content to server? + @HopMetadataProperty(key = "uploadfilename") private String uploadFilename; // The fieldname that contains the URL // Get it from a previous pipeline with Result. + @HopMetadataProperty(key = "url_fieldname") private String urlFieldname; + + @HopMetadataProperty(key = "upload_fieldname") private String uploadFieldname; + + @HopMetadataProperty(key = "dest_fieldname") private String destinationFieldname; + @HopMetadataProperty(key = "run_every_row") private boolean runForEveryRow; + @HopMetadataProperty(key = "ignore_ssl") private boolean ignoreSsl; // Proxy settings + @HopMetadataProperty(key = "proxy_host") private String proxyHostname; + @HopMetadataProperty(key = "proxy_port") private String proxyPort; + @HopMetadataProperty(key = "non_proxy_hosts") private String nonProxyHosts; + @HopMetadataProperty(key = "username") private String username; + @HopMetadataProperty(key = "password", password = true) private String password; - private boolean addfilenameresult; - - private String[] headerName; + @HopMetadataProperty(key = "addfilenameresult") + private boolean addFilenameResult; - private String[] headerValue; + @HopMetadataProperty(key = "header", groupKey = "headers") + private List
headers; public ActionHttp(String n) { super(n, ""); url = null; - addfilenameresult = true; + addFilenameResult = true; } public ActionHttp() { this(""); } - private void allocate(int nrHeaders) { - headerName = new String[nrHeaders]; - headerValue = new String[nrHeaders]; - } - - @Override - public Object clone() { - ActionHttp je = (ActionHttp) super.clone(); - if (headerName != null) { - int nrHeaders = headerName.length; - je.allocate(nrHeaders); - System.arraycopy(headerName, 0, je.headerName, 0, nrHeaders); - System.arraycopy(headerValue, 0, je.headerValue, 0, nrHeaders); - } - return je; - } - - @Override - public String getXml() { - StringBuilder retval = new StringBuilder(300); - - retval.append(super.getXml()); - retval.append(SPACES).append(XmlHandler.addTagValue("url", url)); - retval.append(SPACES).append(XmlHandler.addTagValue("targetfilename", targetFilename)); - retval.append(SPACES).append(XmlHandler.addTagValue("file_appended", fileAppended)); - retval.append(SPACES).append(XmlHandler.addTagValue("date_time_added", dateTimeAdded)); - retval - .append(SPACES) - .append(XmlHandler.addTagValue("targetfilename_extension", targetFilenameExtension)); - retval.append(SPACES).append(XmlHandler.addTagValue("uploadfilename", uploadFilename)); - - retval.append(SPACES).append(XmlHandler.addTagValue("run_every_row", runForEveryRow)); - retval.append(SPACES).append(XmlHandler.addTagValue("ignore_ssl", ignoreSsl)); - retval.append(SPACES).append(XmlHandler.addTagValue("url_fieldname", urlFieldname)); - retval.append(SPACES).append(XmlHandler.addTagValue("upload_fieldname", uploadFieldname)); - retval.append(SPACES).append(XmlHandler.addTagValue("dest_fieldname", destinationFieldname)); - - retval.append(SPACES).append(XmlHandler.addTagValue("username", username)); - retval - .append(SPACES) - .append( - XmlHandler.addTagValue("password", Encr.encryptPasswordIfNotUsingVariables(password))); - - retval.append(SPACES).append(XmlHandler.addTagValue("proxy_host", proxyHostname)); - retval.append(SPACES).append(XmlHandler.addTagValue("proxy_port", proxyPort)); - retval.append(SPACES).append(XmlHandler.addTagValue("non_proxy_hosts", nonProxyHosts)); - retval.append(SPACES).append(XmlHandler.addTagValue("addfilenameresult", addfilenameresult)); - retval.append(" ").append(Const.CR); - if (headerName != null) { - for (int i = 0; i < headerName.length; i++) { - retval.append("
").append(Const.CR); - retval.append(" ").append(XmlHandler.addTagValue("header_name", headerName[i])); - retval.append(" ").append(XmlHandler.addTagValue("header_value", headerValue[i])); - retval.append("
").append(Const.CR); - } - } - retval.append("
").append(Const.CR); - - return retval.toString(); - } - + /** + * @deprecated keep for backwards compatibility + * @param entrynode the top-level XML node + * @param metadataProvider The metadataProvider to optionally load from. + * @param variables + * @throws HopXmlException + */ @Override + @Deprecated(since = "2.13") public void loadXml(Node entrynode, IHopMetadataProvider metadataProvider, IVariables variables) throws HopXmlException { try { - super.loadXml(entrynode); - url = XmlHandler.getTagValue(entrynode, "url"); - targetFilename = XmlHandler.getTagValue(entrynode, "targetfilename"); - fileAppended = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, "file_appended")); - dateTimeAdded = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, "date_time_added")); + super.loadXml(entrynode, metadataProvider, variables); + // Keep targetFilenameExtension = Const.NVL( XmlHandler.getTagValue(entrynode, "targetfilename_extension"), XmlHandler.getTagValue(entrynode, "targetfilename_extention")); - - uploadFilename = XmlHandler.getTagValue(entrynode, "uploadfilename"); - - urlFieldname = XmlHandler.getTagValue(entrynode, "url_fieldname"); - uploadFieldname = XmlHandler.getTagValue(entrynode, "upload_fieldname"); - destinationFieldname = XmlHandler.getTagValue(entrynode, "dest_fieldname"); - runForEveryRow = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, "run_every_row")); - ignoreSsl = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, "ignore_ssl")); - - username = XmlHandler.getTagValue(entrynode, "username"); - password = - Encr.decryptPasswordOptionallyEncrypted(XmlHandler.getTagValue(entrynode, "password")); - - proxyHostname = XmlHandler.getTagValue(entrynode, "proxy_host"); - proxyPort = XmlHandler.getTagValue(entrynode, "proxy_port"); - nonProxyHosts = XmlHandler.getTagValue(entrynode, "non_proxy_hosts"); - addfilenameresult = - "Y" - .equalsIgnoreCase( - Const.NVL(XmlHandler.getTagValue(entrynode, "addfilenameresult"), "Y")); - Node headers = XmlHandler.getSubNode(entrynode, "headers"); - - // How many field headerName? - int nrHeaders = XmlHandler.countNodes(headers, "header"); - allocate(nrHeaders); - for (int i = 0; i < nrHeaders; i++) { - Node fnode = XmlHandler.getSubNodeByNr(headers, "header", i); - headerName[i] = XmlHandler.getTagValue(fnode, "header_name"); - headerValue[i] = XmlHandler.getTagValue(fnode, "header_value"); - } } catch (HopXmlException xe) { throw new HopXmlException("Unable to load action of type 'HTTP' from XML node", xe); } } public boolean isAddFilenameToResult() { - return addfilenameresult; + return addFilenameResult; } public void setAddFilenameToResult(boolean addfilenameresult) { - this.addfilenameresult = addfilenameresult; + this.addFilenameResult = addfilenameresult; } /** @@ -381,20 +312,22 @@ protected PasswordAuthentication getPasswordAuthentication() { } // if we have HTTP headers, add them - if (!Utils.isEmpty(headerName)) { + if (headers != null && !headers.isEmpty()) { if (isDebug()) { logDebug(BaseMessages.getString(PKG, "ActionHTTP.Log.HeadersProvided")); } - for (int j = 0; j < headerName.length; j++) { - if (!Utils.isEmpty(headerValue[j])) { - connection.setRequestProperty(resolve(headerName[j]), resolve(headerValue[j])); + for (int j = 0; j < headers.size(); j++) { + if (!Utils.isEmpty(headers.get(i).getHeaderValue())) { + connection.setRequestProperty( + resolve(headers.get(i).getHeaderName()), + resolve(headers.get(i).getHeaderValue())); if (isDebug()) { logDebug( BaseMessages.getString( PKG, "ActionHTTP.Log.HeaderSet", - resolve(headerName[j]), - resolve(headerValue[j]))); + resolve(headers.get(i).getHeaderName()), + resolve(headers.get(i).getHeaderValue()))); } } } @@ -454,7 +387,7 @@ protected PasswordAuthentication getPasswordAuthentication() { BaseMessages.getString( PKG, "ActionHTTP.Log.FinisedWritingReply", bytesRead, realTargetFile)); - if (addfilenameresult) { + if (addFilenameResult) { // Add to the result files... ResultFile resultFile = new ResultFile( @@ -561,4 +494,15 @@ public void check( remarks, AndValidator.putValidators(ActionValidatorUtils.integerValidator())); } + + @Getter + @Setter + public static final class Header { + + @HopMetadataProperty(key = "header_name") + private String headerName; + + @HopMetadataProperty(key = "header_value") + private String headerValue; + } } diff --git a/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttpDialog.java b/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttpDialog.java index dc9d33a1772..c8c8b763651 100644 --- a/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttpDialog.java +++ b/plugins/actions/http/src/main/java/org/apache/hop/workflow/actions/http/ActionHttpDialog.java @@ -17,6 +17,8 @@ package org.apache.hop.workflow.actions.http; +import java.util.ArrayList; +import java.util.List; import org.apache.hop.core.Const; import org.apache.hop.core.HttpProtocol; import org.apache.hop.core.Props; @@ -291,9 +293,9 @@ public IAction open() { private void setupHeaderTable( ModifyListener lsMod, int margin, CTabItem wHeadersTab, Composite wHeadersComp) { int rows = - action.getHeaderName() == null + action.getHeaders() == null ? 1 - : (action.getHeaderName().length == 0 ? 0 : action.getHeaderName().length); + : (action.getHeaders().size() == 0 ? 0 : action.getHeaders().size()); ColumnInfo[] colinf = new ColumnInfo[] { @@ -885,9 +887,14 @@ public void getData() { wProxyServer.setText(Const.NVL(action.getProxyHostname(), "")); wProxyPort.setText(Const.NVL(action.getProxyPort(), "")); wNonProxyHosts.setText(Const.NVL(action.getNonProxyHosts(), "")); + String[] headerNames = new String[action.getHeaders().size()]; + String[] headerValues = new String[action.getHeaders().size()]; + + for (int i = 0; i < action.getHeaders().size(); i++) { + headerNames[i] = action.getHeaders().get(i).getHeaderName(); + headerValues[i] = action.getHeaders().get(i).getHeaderValue(); + } - String[] headerNames = action.getHeaderName(); - String[] headerValues = action.getHeaderValue(); if (headerNames != null) { for (int i = 0; i < headerNames.length; i++) { TableItem ti = wHeaders.table.getItem(i); @@ -944,32 +951,19 @@ private void ok() { action.setDateTimeAdded(wRunEveryRow.getSelection() ? false : wDateTimeAdded.getSelection()); action.setTargetFilenameExtension(wRunEveryRow.getSelection() ? "" : wTargetExt.getText()); action.setAddFilenameToResult(wAddFilenameToResult.getSelection()); - - int nrItems = wHeaders.nrNonEmpty(); - int nr = 0; - for (int i = 0; i < nrItems; i++) { - String arg = wHeaders.getNonEmpty(i).getText(1); - if (arg != null && arg.length() != 0) { - nr++; - } - } - String[] headerNames = new String[nr]; - String[] headerValues = new String[nr]; - - nr = 0; - for (int i = 0; i < nrItems; i++) { + List headers = new ArrayList<>(); + for (int i = 0; i < wHeaders.nrNonEmpty(); i++) { String varname = wHeaders.getNonEmpty(i).getText(1); String varvalue = wHeaders.getNonEmpty(i).getText(2); + ActionHttp.Header header = new ActionHttp.Header(); if (varname != null && varname.length() != 0) { - headerNames[nr] = varname; - headerValues[nr] = varvalue; - nr++; + header.setHeaderName(varname); + header.setHeaderValue(varvalue); } + headers.add(header); } - action.setHeaderName(headerNames); - action.setHeaderValue(headerValues); - + action.setHeaders(headers); dispose(); } } diff --git a/plugins/actions/http/src/test/java/org/apache/hop/workflow/actions/http/ActionHttpLoadSaveTest.java b/plugins/actions/http/src/test/java/org/apache/hop/workflow/actions/http/ActionHttpLoadSaveTest.java index 4ec5333d03f..dc928bd9905 100644 --- a/plugins/actions/http/src/test/java/org/apache/hop/workflow/actions/http/ActionHttpLoadSaveTest.java +++ b/plugins/actions/http/src/test/java/org/apache/hop/workflow/actions/http/ActionHttpLoadSaveTest.java @@ -17,57 +17,62 @@ package org.apache.hop.workflow.actions.http; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import org.apache.hop.junit.rules.RestoreHopEngineEnvironment; -import org.apache.hop.pipeline.transforms.loadsave.validator.ArrayLoadSaveValidator; -import org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidator; -import org.apache.hop.pipeline.transforms.loadsave.validator.StringLoadSaveValidator; -import org.apache.hop.workflow.action.loadsave.WorkflowActionLoadSaveTestSupport; -import org.junit.ClassRule; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class ActionHttpLoadSaveTest extends WorkflowActionLoadSaveTestSupport { - @ClassRule public static RestoreHopEngineEnvironment env = new RestoreHopEngineEnvironment(); +import org.apache.hop.core.Const; +import org.apache.hop.core.encryption.Encr; +import org.apache.hop.core.encryption.TwoWayPasswordEncoderPluginType; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.plugins.PluginRegistry; +import org.apache.hop.core.util.EnvUtil; +import org.apache.hop.workflow.action.ActionSerializationTestUtil; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; - @Override - protected Class getActionClass() { - return ActionHttp.class; +class ActionHttpLoadSaveTest { + + @BeforeAll + static void beforeClass() throws HopException { + PluginRegistry.addPluginType(TwoWayPasswordEncoderPluginType.getInstance()); + PluginRegistry.init(); + String passwordEncoderPluginID = + Const.NVL(EnvUtil.getSystemProperty(Const.HOP_PASSWORD_ENCODER_PLUGIN), "Hop"); + Encr.init(passwordEncoderPluginID); } - @Override - protected List listAttributes() { - return Arrays.asList( - "url", - "targetFilename", - "fileAppended", - "dateTimeAdded", - "targetFilenameExtension", - "uploadFilename", - "runForEveryRow", - "urlFieldname", - "uploadFieldname", - "destinationFieldname", - "username", - "password", - "proxyHostname", - "proxyPort", - "nonProxyHosts", - "addFilenameToResult", - "headerName", - "headerValue"); + @Test + void testSerialization() throws Exception { + ActionHttp meta = + ActionSerializationTestUtil.testSerialization("/http-action.xml", ActionHttp.class); + + assertEquals("url", meta.getUrl()); + assertEquals("/target/file.csv", meta.getTargetFilename()); + assertEquals("/tmp/file.csv", meta.getUploadFilename()); + assertEquals("username", meta.getUsername()); + assertEquals("proxy", meta.getProxyHostname()); + assertEquals("8080", meta.getProxyPort()); + assertEquals(2, meta.getHeaders().size()); + assertTrue(meta.isIgnoreSsl()); + assertFalse(meta.isRunForEveryRow()); } - @Override - protected Map> createAttributeValidatorsMap() { - Map> validators = new HashMap<>(); - int entries = new Random().nextInt(20) + 1; - validators.put( - "headerName", new ArrayLoadSaveValidator<>(new StringLoadSaveValidator(), entries)); - validators.put( - "headerValue", new ArrayLoadSaveValidator<>(new StringLoadSaveValidator(), entries)); - return validators; + @Test + void testClone() throws Exception { + ActionHttp meta = + ActionSerializationTestUtil.testSerialization("/http-action.xml", ActionHttp.class); + + ActionHttp clone = (ActionHttp) meta.clone(); + + assertEquals(clone.getUrl(), meta.getUrl()); + assertEquals(clone.getTargetFilename(), meta.getTargetFilename()); + assertEquals(clone.getUploadFilename(), meta.getUploadFilename()); + assertEquals(clone.getUsername(), meta.getUsername()); + assertEquals(clone.getProxyHostname(), meta.getProxyHostname()); + assertEquals(clone.getProxyPort(), meta.getProxyPort()); + assertEquals(clone.getHeaders().size(), meta.getHeaders().size()); + assertEquals(clone.isIgnoreSsl(), meta.isIgnoreSsl()); + assertEquals(clone.isRunForEveryRow(), meta.isRunForEveryRow()); } } diff --git a/plugins/actions/http/src/test/resources/http-action.xml b/plugins/actions/http/src/test/resources/http-action.xml new file mode 100644 index 00000000000..cfdd7373e5c --- /dev/null +++ b/plugins/actions/http/src/test/resources/http-action.xml @@ -0,0 +1,55 @@ + + + + HTTP + + HTTP + + url + /target/file.csv + N + N + + /tmp/file.csv + N + Y + + + + username + Encrypted 2be98afc86aa7f2e4bb18bd63c99dbdde + proxy + 8080 + + Y + +
+ accept + header1 +
+
+ accept-charset + header2 +
+
+ N + 800 + 528 + +
\ No newline at end of file