I am using Spring Integration in my project. I am trying to execute a rest service which takes multipart/formdata input parameters. I am using int-http:outbound-gateway to execute rest service. The following is the code:
<int:channel id="PQcreateAttachment-Rest-Channel" />
<int:chain input-channel="PQcreateAttachment-Rest-Channel" output-channel="PQcreateAttachment-StoredProcedure-Router" >
<int:header-filter header-names="accept-encoding"/>
<int:service-activator ref="httpOutboundGatewayHandler" method="buildMultipartHttpOutboundGatewayRequest" />
<int-http:outbound-gateway url-expression="headers.restResourceUrl"
http-method-expression="headers.httpMethod"
extract-request-payload="true"
>
</int-http:outbound-gateway>
<int:service-activator ref="msgHandler" method="buildMessageFromExtSysResponse" />
</int:chain>
But I am getting the following error when I execute the above code.
Caused by: org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.integration.message.GenericMessage] and content type [application/x-java-serialized-object]
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:665)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:481)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:460)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:409)
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:372)
... 121 more
Here is the java code that prepares my multipart request:
public Message<?> buildMultipartHttpOutboundGatewayRequest(Message<?> inMessage) throws Exception{
logger.debug(" ************** buildMultipartHttpOutboundGatewayRequest Start *************************");
String inMsgPayload = (String)inMessage.getPayload();
SOAXml soaXml = parseSOAXml(inMsgPayload);
String restURL = null;
String contentType = null;
String acceptHdr = null;
String userId = null;
String password = null;
String businessAreaName = null;
String typeName = null;
String attachmentLocation = null;
String httpMethod = null;
Message<?> outMessage = null;
MessageHeaders inMsgHdrs = null;
MessageBuilder<?> msgBuild = null;
String authorization = null;
//TODO: File location needs to be changed to standard one
String fileLocation = "C:\\source.xml";
//if we reach here means, it is AWD system
restURL = getAwdSOAService(soaXml);
Document document = XmlParserUtil.convertString2Document(inMsgPayload);
userId = XmlParserUtil.getNodeValue(document,"//userId");
password = XmlParserUtil.getNodeValue(document,"//PQcreateAttachment/password");
businessAreaName = XmlParserUtil.getNodeValue(document,"//businessAreaName");
typeName = XmlParserUtil.getNodeValue(document,"//typeName");
httpMethod = XmlParserUtil.getNodeValue(document,"//METHOD");
attachmentLocation = XmlParserUtil.getNodeValue(document,"//attachmentLocation");
//Construct source xml
//Creating document
Document sourceDocument = DocumentHelper.createDocument();
Element sourceInstance = sourceDocument.addElement("createSourceInstance");
sourceInstance.addAttribute("xmlns", "http://www.dsttechnologies.com/awd/rest/v1");
Element orderItem=sourceInstance.addElement("businessAreaName");
orderItem.setText("SAMPLEBA");
Element orderItemDesc=sourceInstance.addElement("typeName");
orderItemDesc.setText("SAMPLEST");
// create source xml file
XmlParserUtil.createXMLFileUsingDOM4J(sourceDocument, fileLocation);
authorization = getBasicAuthorization(userId,password);
Resource source = new ClassPathResource(fileLocation);
Resource attachment = new ClassPathResource(attachmentLocation);
Map<String, Object> multipartMap = new HashMap<String, Object>();
multipartMap.put("source", source);
multipartMap.put("attachment", attachment);
logger.info("Created multipart request: " + multipartMap);
inMessage = buildMessageForMultipart(multipartMap);
// contentType = csProps.getHttpAwdContentTypeValue();
acceptHdr = csProps.getHttpAwdAcceptTypeValue() ;
// authorization = getBasicAuthorization(soaXml.getUserid(),decriptPassword(soaXml.getPassword()));
inMsgHdrs = inMessage.getHeaders();
msgBuild = MessageBuilder.withPayload(inMessage).copyHeaders(inMsgHdrs);
msgBuild.removeHeader("Content-Encoding");
msgBuild.removeHeader("accept-encoding");
msgBuild.setHeader(csProps.getHttpUrlHdr(), restURL);
msgBuild.setHeader(csProps.getHttpMethodHdr(), httpMethod);
msgBuild.setHeader(csProps.getHttpAuthorizatonHdr(),authorization );
// msgBuild.setHeader(csProps.getHttpContentTypeHdr(), contentType);
// msgBuild.setHeader(csProps.getHttpAcceptTypeHdr(),acceptHdr);
outMessage = msgBuild.build();
logger.debug(" ************** buildHttpOutboundGatewayRequest End*************************");
logger.debug(outMessage);
logger.debug(" ************************************************************************");
return outMessage;
}
Any ideas on what's wrong here?
Your problem is because you wrap one message to another.
What your buildMessageForMultipart(multipartMap); does?
I'm sure the simple map as payload and those header would be enough.
Not sure what is the point to wrap one message to another.
Related
I want testing pagination.
I want add some fake content to my Page mocked class.
How can I?
This is my test (refactoring it from a previous test), I'm using Junit5 and of course I get that No valut at JSON path $.content.lenght() and so on (of course, Page is empty):
/**
* index
*/
#WithMockUser("username")
#Test
void testCanIndex() throws Exception {
var transaction01 = BankAccountTransactionsControllerTest.validBankAccountTransactionsEntity(1L,
new BigDecimal(99.99), "First Transaction");
var transaction02 = BankAccountTransactionsControllerTest.validBankAccountTransactionsEntity(2L,
new BigDecimal(150.00), "Second Transaction");
var result = new ArrayList<BankAccountTransactionsEntity>();
result.add(transaction01);
result.add(transaction02);
Page<BankAccountTransactionsEntity> items = mock(Page.class);
when(bankAccountTransactionsService.index(0, 1, "id", "desc")).thenReturn(items);
mvc.perform(get("/api/v1/bank-account-transactions/")).andExpect(status().isOk())
.andExpect(jsonPath("$.content.length()", is(2))).andExpect(jsonPath("$[0].id", is(1)))
.andExpect(jsonPath("$.content[1].id", is(2))).andExpect(jsonPath("$[0].amount", is(new BigDecimal(99.99))))
.andExpect(jsonPath("$.content[1].amount", is(150)))
.andExpect(jsonPath("$.content[0].purpose", is("First Transaction")))
.andExpect(jsonPath("$.content[1].purpose", is("Second Transaction")))
.andExpect(jsonPath("$.content[0]", Matchers.hasKey("transactionDate")))
.andExpect(jsonPath("$.content[1]", Matchers.hasKey("transactionDate")));
}
Edit
I made a change, calling directly a PageImpl
#Test
void testCanIndex() throws Exception {
var transaction01 = BankAccountTransactionsControllerTest.validBankAccountTransactionsEntity(1L,
new BigDecimal(99.99), "First Transaction");
var transaction02 = BankAccountTransactionsControllerTest.validBankAccountTransactionsEntity(2L,
new BigDecimal(150.00), "Second Transaction");
var result = new ArrayList<BankAccountTransactionsEntity>();
result.add(transaction01);
result.add(transaction02);
Page<BankAccountTransactionsEntity> items = new PageImpl<>(result);
when(bankAccountTransactionsService.index(0, 1, "id", "desc")).thenReturn(items);
mvc.perform(get("/api/v1/bank-account-transactions/")).andExpect(status().isOk())
.andExpect(jsonPath("$.content.length()", is(2)));
}
But body returned is empty
MockHttpServletRequest:
HTTP Method = GET
Request URI = /api/v1/bank-account-transactions/
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.bitbank.controllers.BankAccountTransactionsController
Method = com.bitbank.controllers.BankAccountTransactionsController#index(Integer, Integer, String, String)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
I am trying to connect to servicebus and getting data from it, it seems since I've got the token I must reuse it evertime I make a request what's wrong with this code?here is the error I've got at the last
line The remote server returned an error: (401) Unauthorized.
//sample usage string mydata1 = string.Format(Constants.myData, brfId);
public static readonly myData= "https://sdgsdg.servicebus.windows.net/sgsdg/gdgsg/{0}";
//sample usage - string agendaByBriefingDetailIdURI = string.Format(Constants.myData2 BriefingID, accessCode);
public static readonly string myData2= "https://sdgsg.servicebus.windows.net/sdg/dgsg/{0}/{1}";
string SCOPE = "http://lalalalala.servicebus.windows.net/";
string WRAP_PASSWORD = "lalalalalala"
string WRAP_USERNAME = "lalalala";
string ACS_NAMESPACE = "lalalalala";
WebClient client = new WebClient();
client.BaseAddress = string.Format("https://{0}.accesscontrol.windows.net", ACS_NAMESPACE);
NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", WRAP_USERNAME);
values.Add("wrap_password", WRAP_PASSWORD);
values.Add("wrap_scope", SCOPE);
// WebClient takes care of the URL Encoding
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);
// the raw response from ACS
string response = Encoding.UTF8.GetString(responseBytes);
string token = response.Split('&').Single(x => x.StartsWith("wrap_access_token=", StringComparison.OrdinalIgnoreCase)).Split('=')[1];
string decodedToken = HttpUtility.UrlDecode(token);
string.Format("WRAP access_token=\"{0}\"", HttpUtility.UrlDecode(token));
WebClient webClient = new WebClient();
webClient.Headers["Authorization"] = string.Format("WRAP access_token=\"{0}\"", HttpUtility.UrlDecode(token));
string returnString = webClient.DownloadString(string.Format(mystaticre, 10));
I have a problem when I try to assign a file with folder, the file and folder exist in the system but when I use the method for upload the folder of the file the response it's success but the file not figure into the folder.
I use the method
POST /basic/api/collection/{collection-id}/feed
in the collection-id I change for the folder UUID but don't works.
you know how assign a file to folder?
System.out.println("Uploading " + fileName + " in " + parentFolderName);
Abdera abdera = new Abdera();
Factory factory = abdera.getFactory();
Entry entry = factory.newEntry();
//Entry
entry.setTitle(parentFolderName);
entry.setId(parentFolderUUID);
InputStream in = req.getInputStream();
entry.setContent("application/pdf");
entry.setLanguage("en");
AbderaClient abderaClient = new AbderaClient(abdera);
abderaClient.addCredentials(Utils.configJson.getString("connectionsServerURL"), null, null, new UsernamePasswordCredentials(connectionsUser, connectionsPassword));
//Nonce
String nonceUrl = "https://connectionsww.demos.ibm.com/files/basic/api/nonce";
ClientResponse respNonce = abderaClient.get(nonceUrl);
StringWriter writerNonce = new StringWriter();
IOUtils.copy(respNonce.getInputStream(), writerNonce, "UTF-8");
String nonce = writerNonce.toString();
//Multipart-post options
RequestOptions options = abderaClient.getDefaultRequestOptions();
options.setSlug(parentFolderUUID);
options.setContentType("multipart/mixed");
options.setAcceptLanguage("en");
options.setHeader("X-Update-Nonce", nonce);
fileURL = fileURL + "?X-Update-Nonce=" + nonce;
ClientResponse resp = abderaClient.post(fileURL, entry);
based on the method signature, I think you are missing two items:
One
Content-Type header should be
Content-Type: application/atom+xml
Two payload of itemid (the id there is the id of the file I want in the folder/collection).
<feed xmlns="http://www.w3.org/2005/Atom">
<entry>
<itemId xmlns="urn:ibm.com/td">aca70bd1-0925-42c1-8196-b1c3042178a6</itemId>
</entry>
</feed>
I found the solution for the answer of #Paul, the final code it's there.
Abdera abdera = new Abdera();
Factory factory = abdera.getFactory();
Entry entry = factory.newEntry();
//Entry
entry.setUpdated(new java.util.Date());
entry.setTitle(parentFolderName);
entry.setId(parentFolderUUID);
InputStream in = req.getInputStream();
entry.setContent("application/atom+xml");
entry.setLanguage("en");
AbderaClient abderaClient = new AbderaClient(abdera);
abderaClient.addCredentials(Utils.configJson.getString("connectionsServerURL"), null, null, new UsernamePasswordCredentials(connectionsUser, connectionsPassword));
System.out.println("added abdera client credentials");
//Nonce
String nonceUrl = "https://connectionsww.demos.ibm.com/files/basic/api/nonce";
ClientResponse respNonce = abderaClient.get(nonceUrl);
StringWriter writerNonce = new StringWriter();
IOUtils.copy(respNonce.getInputStream(), writerNonce, "UTF-8");
String nonce = writerNonce.toString();
//Multipart-post options
RequestOptions options = abderaClient.getDefaultRequestOptions();
options.setSlug(parentFolderUUID);
options.setContentType("application/atom+xml");
options.setAcceptLanguage("en");
options.setHeader("itemId", docUUID);
fileURL = fileURL + "?itemId="+docUUID;
System.out.println("fileURL+++++: " + fileURL);
ClientResponse resp = abderaClient.post(fileURL, entry, options);
I want to post some request values alongside the multipart-formdata file contents. In the old API you could use PostFileWithRequest:
[Test]
public void Can_POST_upload_file_using_ServiceClient_with_request()
{
IServiceClient client = new JsonServiceClient(ListeningOn);
var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath());
var request = new FileUpload{CustomerId = 123, CustomerName = "Foo"};
var response = client.PostFileWithRequest<FileUploadResponse>(ListeningOn + "/fileuploads", uploadFile, request);
var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd();
Assert.That(response.FileName, Is.EqualTo(uploadFile.Name));
Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length));
Assert.That(response.Contents, Is.EqualTo(expectedContents));
Assert.That(response.CustomerName, Is.EqualTo("Foo"));
Assert.That(response.CustomerId, Is.EqualTo(123));
}
I can't find any such method in the new API, nor any overrides on client.Post() which suggest that this is still possible. Does anyone know if this is a feature that was dropped?
Update
As #Mythz points out, the feature wasn't dropped. I had made the mistake of not casting the client:
private IRestClient CreateRestClient()
{
return new JsonServiceClient(WebServiceHostUrl);
}
[Test]
public void Can_WebRequest_POST_upload_binary_file_to_save_new_file()
{
var restClient = (JsonServiceClient)CreateRestClient(); // this cast was missing
var fileToUpload = new FileInfo(#"D:/test/test.avi");
var beforeHash = this.Hash(fileToUpload);
var response = restClient.PostFileWithRequest<FilesResponse>("files/UploadedFiles/", fileToUpload, new TestRequest() { Echo = "Test"});
var uploadedFile = new FileInfo(FilesRootDir + "UploadedFiles/test.avi");
var afterHash = this.Hash(uploadedFile);
Assert.That(beforeHas, Is.EqualTo(afterHash));
}
private string Hash(FileInfo file)
{
using (var md5 = MD5.Create())
{
using (var stream = file.OpenRead())
{
var bytes = md5.ComputeHash(stream);
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower();
}
}
}
None of the old API was removed from the C# Service Clients, only new API's were added.
The way you process an uploaded file inside a service also hasn't changed.
I am looking for some suggestion or sample around retrieving images (actual file, not URL), from a picture library using REST API.
Thanks for any input.
Task 1: Getting a List of Image libs on a given site
public static XmlNode GetPicLibListingXML(string imagingServiceURL)
{
Imaging wsImaging = new Imaging();
wsImaging.UseDefaultCredentials = true;
wsImaging.Url = imagingServiceURL;
XmlNode xnPicLibs = wsImaging.ListPictureLibrary();
return xnPicLibs;
}
Sample return XML:
<Library name="{3C1D52F5-5387-490A-9A2D-A9C99A208C00}" title="Tech Images" guid="3c1d52f5-5387-490a-9a2d-a9c99a208c00" url="Tech Images" xmlns="http://schemas.microsoft.com/sharepoint/soap/ois/" />
Task 2: Listing Images in a given library
public static XmlNode GetImageFileListing(string imagingServiceURL, string imageFileLibraryName)
{
Imaging wsImaging = new Imaging();
ImageInfo curImageInfo = new ImageInfo();
wsImaging.UseDefaultCredentials = true;
wsImaging.Url = imagingServiceURL;
XmlNode xnListItems = wsImaging.GetListItems(imageFileLibraryName, "");
return xnListItems;
}
Task 3: Download Image(s)
private const string ATTR_FILENAME = "name";
private const string FILENAMESPACEURI = "http://schemas.microsoft.com/sharepoint/soap/ois/";
public static bool DownloadImageFiles(string imagingServiceURL, string imageFileLibraryName, string[] fileNames, string saveToFolder)
{
Imaging wsImaging = new Imaging();
wsImaging.UseDefaultCredentials = true;
wsImaging.Url = imagingServiceURL;
XmlElement parent = (XmlElement)wsImaging.Download(imageFileLibraryName, string.Empty, fileNames, 0, true);
XmlNodeList files = parent.GetElementsByTagName("File", FILENAMESPACEURI);
foreach (XmlNode file in files)
{
if (Directory.Exists(saveToFolder) == false)
{
Directory.CreateDirectory(saveToFolder);
}
byte[] fileBytes = Convert.FromBase64String(file.InnerText);
using (FileStream fs = File.OpenWrite(saveToFolder + file.Attributes[ATTR_FILENAME].Value))
{
BinaryWriter writer = new BinaryWriter(fs);
writer.Write(fileBytes);
writer.Close();
}
}
return true;
}
Note:
Imaging() class is a web reference to imagining.asmx
The Download call natively returns XML so yo uneed to run it through a conversion to byte
If you need to get a reference on the Imagine web service check this on out on MSDN:
http://msdn.microsoft.com/en-us/library/imaging.imaging.aspx
source:
http://gourangaland.wordpress.com/2008/05/30/using-the-moss-imaging-web-service-to-download-imagesimaging-asmx/