I am trying to integrate Docusign in our Java (Java-11) application.
I am trying to use the JWT flow for the same. After having authorized the app, I could get to the point of creating getting the access token, however when trying to create an envelope and create an embededded request I am seeing the following error :
[2021-07-21 15:00:32.954] [EC2AMAZ-5EFUJD8] [http-nio-8080-exec-2] ERROR c.p.e.h.GovCloudBaseExceptionHandler#handleException:237 - -- handleException() - {}
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/html;charset=utf-8, type=class com.docusign.esign.model.EnvelopeSummary, genericType=class com.docusign.esign.model.EnvelopeSummary.
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:232)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1091)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:834)
at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:363)
at org.glassfish.jersey.client.InboundJaxrsResponse$2.call(InboundJaxrsResponse.java:126)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:229)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestSco
The createEnvelope Method in the following code is throwing the error
void CreateEnvelope()
{
// Create the envelope definition
EnvelopeDefinition envelope = null;
try {
envelope = makeEnvelope("anur.puniyani#teliolabs.com", "Anur");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Call DocuSign to create the envelope
//ApiClient apiClient = createApiClient("", bearerToken);
EnvelopesApi envelopesApi = new EnvelopesApi(apiClient);
EnvelopeSummary envelopeSummary = null ;
try {
envelopeSummary = envelopesApi.createEnvelope("1a9c289e-f63d-4f63-b6cd-5c43af184603", envelope);
} catch (ApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
envelopeId = envelopeSummary.getEnvelopeId();
System.out.println("Envelope ID (&(*&(&( !!!!= "+envelopeId);
}
I used the following base url for the ApiClient constructor : https://account-d.docusign.com
As the one in my App dashboard (demo.docusign.com) did not seem to work for giving permissions and was throwing a page not found error.
Please help me and my colleague are stuck with this since the entire day. We tried contacting support but they don't give API support unless you have the license.
EDIT: I figured out that the basepath you're using is missing /restapi it should be https://demo.docusign.com/restapi. Also I incorrectly said docusign.net when it should be docusign.com
As far as I am aware, there is no class method to create the envelope directly within the EnvelopeDefinition. You will need to specify the various associated portions necessary for the API call to succeed. This portion of code comes from eSignature example 002 in our Launcher. I've made a few small changes to make it work with a single document. You'll need to send this envelope definition to the host "demo.docusign.net" :
package com.docusign.controller.eSignature.examples;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Base64;
import com.docusign.esign.api.EnvelopesApi;
import com.docusign.esign.client.ApiClient;
import com.docusign.esign.client.ApiException;
import com.docusign.esign.model.Document;
import com.docusign.esign.model.EnvelopeDefinition;
import com.docusign.esign.model.EnvelopeSummary;
import com.docusign.esign.model.Recipients;
import com.docusign.esign.model.SignHere;
import com.docusign.esign.model.Signer;
import com.docusign.esign.model.Tabs;
class CreateEnvelope
{
public static void main(String[] args) {
// Create the envelope definition
String accessToken = "eyJ0eXAi......JgAkJuZ8A";
String accountId = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxx";
// Call DocuSign to create the envelope
ApiClient apiClient = new ApiClient("https://demo.docusign.net/restapi");
apiClient.addDefaultHeader("Authorization", "Bearer " + accessToken);
EnvelopesApi envelopesApi = new EnvelopesApi(apiClient);
EnvelopeDefinition envelope = makeEnvelope("anur.puniyani#teliolabs.com", "Anur");
try {
EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envelope);
String envelopeId = envelopeSummary.getEnvelopeId();
System.out.println("Envelope ID = "+envelopeId);
} catch (ApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName) {
// Create a signer recipient to sign the document, identified by name and email
// We set the clientUserId to enable embedded signing for the recipient
Signer signer = new Signer();
signer.setEmail(signerEmail);
signer.setName(signerName);
// signer.clientUserId("1000"); # will not receive docuSign email to sign if client user id is present
signer.recipientId("1");
SignHere signHere = new SignHere();
signHere.setAnchorString("/sn1/");
signHere.setAnchorUnits("pixels");
signHere.setAnchorYOffset("20");
signHere.setAnchorXOffset("10");
Tabs signerTabs = new Tabs();
signerTabs.setSignHereTabs(Arrays.asList(signHere));
// Add the recipient to the envelope object
Recipients recipients = new Recipients();
recipients.setSigners(Arrays.asList(signer));
EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition();
envelopeDefinition.setEmailSubject("Please sign this document");
envelopeDefinition.setRecipients(recipients);
Path path = Paths.get("./path/to/my/code-examples-java/src/main/resources/World_Wide_Corp_lorem.pdf");
byte[] data = null;
try {
data = Files.readAllBytes(path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Document document = new Document();
document.setDocumentBase64(Base64.getEncoder().encodeToString(data));
document.setName("Hello Doc");
document.setFileExtension("pdf");
document.setDocumentId("3");
envelopeDefinition.setDocuments(Arrays.asList(document));
// Request that the envelope be sent by setting |status| to "sent".
// To request that the envelope be created as a draft, set to "created"
envelopeDefinition.setStatus("sent");
return envelopeDefinition;
}
}
This code above comes from the Code example launcher here. A pre-packaged version that has all of your configuration details filled in here on the Quickstart page is also provided.
Related
When working with gRPC, we need to generate the gRPC client and server interfaces from our .proto service definition via protocol buffer compiler (protoc) or using Gradle or Maven protoc build plugin.
Flow now: protobuf file -> java code -> gRPC client.
So, is there any way to skip this step?
How to create a generic gRPC client that can call the server directly from the protobuf file without compile into java code?
Or, is there a way to Generated Code at runtime?
Flow expect: protobuf file -> gRPC client.
I want to build a generic gRPC client system with the input are protobuf files along with description of method, package, message request ... without having to compile again for each protobuf.
Thank you very much.
Protobuf systems really need protoc to be run. However, the generated code could be skipped. Instead of passing something like --java_out and --grpc_java_out to protoc you can pass --descriptor_set_out=FILE which will parse the .proto file into a descriptor file. A descriptor file is a proto-encoded FileDescriptorSet. This is the same basic format as used with the reflection service.
Once you have a descriptor, you can load it a FileDescriptor at a time and create a DynamicMessage.
Then for the gRPC piece, you need to create a gRPC MethodDescriptor.
static MethodDescriptor from(
Descriptors.MethodDescriptor methodDesc
) {
return MethodDescriptor.<DynamicMessage, DynamicMessage>newBuilder()
// UNKNOWN is fine, but the "correct" value can be computed from
// methodDesc.toProto().getClientStreaming()/getServerStreaming()
.setType(getMethodTypeFromDesc(methodDesc))
.setFullMethodName(MethodDescriptor.generateFullMethodName(
serviceDesc.getFullName(), methodDesc.getName()))
.setRequestMarshaller(ProtoUtils.marshaller(
DynamicMessage.getDefaultInstance(methodDesc.getInputType())))
.setResponseMarshaller(ProtoUtils.marshaller(
DynamicMessage.getDefaultInstance(methodDesc.getOutputType())))
.build();
static MethodDescriptor.MethodType getMethodTypeFromDesc(
Descriptors.MethodDescriptor methodDesc
) {
if (!methodDesc.isServerStreaming()
&& !methodDesc.isClientStreaming()) {
return MethodDescriptor.MethodType.UNARY;
} else if (methodDesc.isServerStreaming()
&& !methodDesc.isClientStreaming()) {
return MethodDescriptor.MethodType.SERVER_STREAMING;
} else if (!methodDesc.isServerStreaming()) {
return MethodDescriptor.MethodType.CLIENT_STREAMING);
} else {
return MethodDescriptor.MethodType.BIDI_STREAMING);
}
}
At that point you have everything you need and can call Channel.newCall(method, CallOptions.DEFAULT) in gRPC. You're also free to use ClientCalls to use something more similar to the stub APIs.
So dynamic calls are definitely possible, and is used for things like grpcurl. But it also is not easy and so is generally only done when necessary.
I did it in Java, and the step is:
Call reflection service to get FileDescriptorProto list by method name
Get FileDescriptor of method from FileDescriptorProto list by package name, service name
Get MethodDescriptor from ServiceDescriptor which get from the FileDescriptor
Generate a MethodDescriptor<DynamicMessage, DynamicMessage> by MethodDescriptor
Build request DynamicMessage from content like JSON or others
Call method
Parse response content to JSON from DynamicMessage response
You can reference the full sample in project helloworlde/grpc-java-sample#reflection
And proto is:
syntax = "proto3";
package io.github.helloworlde.grpc;
option go_package = "api;grpc_gateway";
option java_package = "io.github.helloworlde.grpc";
option java_multiple_files = true;
option java_outer_classname = "HelloWorldGrpc";
service HelloService{
rpc SayHello(HelloMessage) returns (HelloResponse){
}
}
message HelloMessage {
string message = 2;
}
message HelloResponse {
string message = 1;
}
Start server for this proto by yourself, and the full code in Java just like:
import com.google.protobuf.ByteString;
import com.google.protobuf.DescriptorProtos;
import com.google.protobuf.Descriptors;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.TypeRegistry;
import com.google.protobuf.util.JsonFormat;
import io.grpc.CallOptions;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.MethodDescriptor;
import io.grpc.protobuf.ProtoUtils;
import io.grpc.reflection.v1alpha.ServerReflectionGrpc;
import io.grpc.reflection.v1alpha.ServerReflectionRequest;
import io.grpc.reflection.v1alpha.ServerReflectionResponse;
import io.grpc.stub.ClientCalls;
import io.grpc.stub.StreamObserver;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
#Slf4j
public class ReflectionCall {
public static void main(String[] args) throws InterruptedException {
// 反射方法的格式只支持 package.service.method 或者 package.service
String methodSymbol = "io.github.helloworlde.grpc.HelloService.SayHello";
String requestContent = "{\"message\": \"Reflection\"}";
// 构建 Channel
ManagedChannel channel = ManagedChannelBuilder.forAddress("127.0.0.1", 9090)
.usePlaintext()
.build();
// 使用 Channel 构建 BlockingStub
ServerReflectionGrpc.ServerReflectionStub reflectionStub = ServerReflectionGrpc.newStub(channel);
// 响应观察器
StreamObserver<ServerReflectionResponse> streamObserver = new StreamObserver<ServerReflectionResponse>() {
#Override
public void onNext(ServerReflectionResponse response) {
try {
// 只需要关注文件描述类型的响应
if (response.getMessageResponseCase() == ServerReflectionResponse.MessageResponseCase.FILE_DESCRIPTOR_RESPONSE) {
List<ByteString> fileDescriptorProtoList = response.getFileDescriptorResponse().getFileDescriptorProtoList();
handleResponse(fileDescriptorProtoList, channel, methodSymbol, requestContent);
} else {
log.warn("未知响应类型: " + response.getMessageResponseCase());
}
} catch (Exception e) {
log.error("处理响应失败: {}", e.getMessage(), e);
}
}
#Override
public void onError(Throwable t) {
}
#Override
public void onCompleted() {
log.info("Complete");
}
};
// 请求观察器
StreamObserver<ServerReflectionRequest> requestStreamObserver = reflectionStub.serverReflectionInfo(streamObserver);
// 构建并发送获取方法文件描述请求
ServerReflectionRequest getFileContainingSymbolRequest = ServerReflectionRequest.newBuilder()
.setFileContainingSymbol(methodSymbol)
.build();
requestStreamObserver.onNext(getFileContainingSymbolRequest);
channel.awaitTermination(10, TimeUnit.SECONDS);
}
/**
* 处理响应
*/
private static void handleResponse(List<ByteString> fileDescriptorProtoList,
ManagedChannel channel,
String methodFullName,
String requestContent) {
try {
// 解析方法和服务名称
String fullServiceName = extraPrefix(methodFullName);
String methodName = extraSuffix(methodFullName);
String packageName = extraPrefix(fullServiceName);
String serviceName = extraSuffix(fullServiceName);
// 根据响应解析 FileDescriptor
Descriptors.FileDescriptor fileDescriptor = getFileDescriptor(fileDescriptorProtoList, packageName, serviceName);
// 查找服务描述
Descriptors.ServiceDescriptor serviceDescriptor = fileDescriptor.getFile().findServiceByName(serviceName);
// 查找方法描述
Descriptors.MethodDescriptor methodDescriptor = serviceDescriptor.findMethodByName(methodName);
// 发起请求
executeCall(channel, fileDescriptor, methodDescriptor, requestContent);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 解析并查找方法对应的文件描述
*/
private static Descriptors.FileDescriptor getFileDescriptor(List<ByteString> fileDescriptorProtoList,
String packageName,
String serviceName) throws Exception {
Map<String, DescriptorProtos.FileDescriptorProto> fileDescriptorProtoMap =
fileDescriptorProtoList.stream()
.map(bs -> {
try {
return DescriptorProtos.FileDescriptorProto.parseFrom(bs);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(DescriptorProtos.FileDescriptorProto::getName, f -> f));
if (fileDescriptorProtoMap.isEmpty()) {
log.error("服务不存在");
throw new IllegalArgumentException("方法的文件描述不存在");
}
// 查找服务对应的 Proto 描述
DescriptorProtos.FileDescriptorProto fileDescriptorProto = findServiceFileDescriptorProto(packageName, serviceName, fileDescriptorProtoMap);
// 获取这个 Proto 的依赖
Descriptors.FileDescriptor[] dependencies = getDependencies(fileDescriptorProto, fileDescriptorProtoMap);
// 生成 Proto 的 FileDescriptor
return Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, dependencies);
}
/**
* 根据包名和服务名查找相应的文件描述
*/
private static DescriptorProtos.FileDescriptorProto findServiceFileDescriptorProto(String packageName,
String serviceName,
Map<String, DescriptorProtos.FileDescriptorProto> fileDescriptorProtoMap) {
for (DescriptorProtos.FileDescriptorProto proto : fileDescriptorProtoMap.values()) {
if (proto.getPackage().equals(packageName)) {
boolean exist = proto.getServiceList()
.stream()
.anyMatch(s -> serviceName.equals(s.getName()));
if (exist) {
return proto;
}
}
}
throw new IllegalArgumentException("服务不存在");
}
/**
* 获取前缀
*/
private static String extraPrefix(String content) {
int index = content.lastIndexOf(".");
return content.substring(0, index);
}
/**
* 获取后缀
*/
private static String extraSuffix(String content) {
int index = content.lastIndexOf(".");
return content.substring(index + 1);
}
/**
* 获取依赖类型
*/
private static Descriptors.FileDescriptor[] getDependencies(DescriptorProtos.FileDescriptorProto proto,
Map<String, DescriptorProtos.FileDescriptorProto> finalDescriptorProtoMap) {
return proto.getDependencyList()
.stream()
.map(finalDescriptorProtoMap::get)
.map(f -> toFileDescriptor(f, getDependencies(f, finalDescriptorProtoMap)))
.toArray(Descriptors.FileDescriptor[]::new);
}
/**
* 将 FileDescriptorProto 转为 FileDescriptor
*/
#SneakyThrows
private static Descriptors.FileDescriptor toFileDescriptor(DescriptorProtos.FileDescriptorProto fileDescriptorProto,
Descriptors.FileDescriptor[] dependencies) {
return Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, dependencies);
}
/**
* 执行方法调用
*/
private static void executeCall(ManagedChannel channel,
Descriptors.FileDescriptor fileDescriptor,
Descriptors.MethodDescriptor originMethodDescriptor,
String requestContent) throws Exception {
// 重新生成 MethodDescriptor
MethodDescriptor<DynamicMessage, DynamicMessage> methodDescriptor = generateMethodDescriptor(originMethodDescriptor);
CallOptions callOptions = CallOptions.DEFAULT;
TypeRegistry registry = TypeRegistry.newBuilder()
.add(fileDescriptor.getMessageTypes())
.build();
// 将请求内容由 JSON 字符串转为相应的类型
JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry);
DynamicMessage.Builder messageBuilder = DynamicMessage.newBuilder(originMethodDescriptor.getInputType());
parser.merge(requestContent, messageBuilder);
DynamicMessage requestMessage = messageBuilder.build();
// 调用,调用方式可以通过 originMethodDescriptor.isClientStreaming() 和 originMethodDescriptor.isServerStreaming() 推断
DynamicMessage response = ClientCalls.blockingUnaryCall(channel, methodDescriptor, callOptions, requestMessage);
// 将响应解析为 JSON 字符串
JsonFormat.Printer printer = JsonFormat.printer()
.usingTypeRegistry(registry)
.includingDefaultValueFields();
String responseContent = printer.print(response);
log.info("响应: {}", responseContent);
}
/**
* 重新生成方法描述
*/
private static MethodDescriptor<DynamicMessage, DynamicMessage> generateMethodDescriptor(Descriptors.MethodDescriptor originMethodDescriptor) {
// 生成方法全名
String fullMethodName = MethodDescriptor.generateFullMethodName(originMethodDescriptor.getService().getFullName(), originMethodDescriptor.getName());
// 请求和响应类型
MethodDescriptor.Marshaller<DynamicMessage> inputTypeMarshaller = ProtoUtils.marshaller(DynamicMessage.newBuilder(originMethodDescriptor.getInputType())
.buildPartial());
MethodDescriptor.Marshaller<DynamicMessage> outputTypeMarshaller = ProtoUtils.marshaller(DynamicMessage.newBuilder(originMethodDescriptor.getOutputType())
.buildPartial());
// 生成方法描述, originMethodDescriptor 的 fullMethodName 不正确
return MethodDescriptor.<DynamicMessage, DynamicMessage>newBuilder()
.setFullMethodName(fullMethodName)
.setRequestMarshaller(inputTypeMarshaller)
.setResponseMarshaller(outputTypeMarshaller)
// 使用 UNKNOWN,自动修改
.setType(MethodDescriptor.MethodType.UNKNOWN)
.build();
}
}
There isn't much to prevent this technically. The two big hurdles are:
having a runtime-callable parser for reading the .proto, and
having a general purpose gRPC client available that takes things like the service method name as literals
Both are possible, but neither is trivial.
For 1, the crude way would be to shell/invoke protoc using the descriptor-set option to generate a schema binary, then deserialize that as a FileDescriptorSet (from descriptor.proto); this model gives you access to how protoc sees the file. Some platforms also have native parsers (essentially reimplementing protoc as a library in that platform), for example protobuf-net.Reflection does this in .NET-land
For 2, here's an implementation of that in C#. The approach should be fairly portable to Java, even if the details vary. You can look at a generated implementation to see how it works in any particular language.
(Sorry that the specific examples are C#/.NET, but that's where I live; the approaches should be portable, even if the specific code: not directly)
technically both are possible.
The codegen is simply generating a handful of classes; mainly protobuf messages, grpc method descriptors and stubs. You can implement it or check in the generated code to bypass the codegen. i am not sure what is the benefit of doing this tbh. Also, it will be very annoying if the proto is changed.
It is also possible to do it dynamically using byte codegen as long as you check-in some interfaces/abstract classes to represent those generated stub/method descriptors and protobuf messages. you have to make sure those non dynamic code is in sync with the proto definition though (most likely runtime check/exception).
I want to attach multiple files to issue. I'm able to create issue successfully however i am facing problem in attaching documents after creating issue. I have referred to this link SOLVED: attach a file using REST from scriptrunner
I am getting 404 error even though issue exists and also user has all the permissions.
File fileToUpload = new File("D:\\dummy.txt");
InputStream in = null;
try {
in = new FileInputStream(fileToUpload);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
HttpResponse < String > response3 = Unirest
.post("https://.../rest/api/2/issue/test-85/attachments")
.basicAuth(username, password).field("file", in , "dummy.txt")
.asString();
System.out.println(response3.getStatus());
here test-85 is a issueKey value.
And i am using open-unirest-java-3.3.06.jar. Is the way i am attaching documents is correct?
I am not sure how open-unirest manages its fields, maybe it tries to put them as json field, rather than post content.
I've been using Rcarz's Jira client. It's a little bit outdated but it still works.
Maybe looking at its code will help you, or you can just use it directly.
The Issue class:
public JSON addAttachment(File file) throws JiraException {
try {
return restclient.post(getRestUri(key) + "/attachments", file);
} catch (Exception ex) {
throw new JiraException("Failed add attachment to issue " + key, ex);
}
}
And in RestClient class:
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
public JSON post(String path, File file) throws RestException, IOException, URISyntaxException {
return request(new HttpPost(buildURI(path)), file);
}
private JSON request(HttpEntityEnclosingRequestBase req, File file) throws RestException, IOException {
if (file != null) {
File fileUpload = file;
req.setHeader("X-Atlassian-Token", "nocheck");
MultipartEntity ent = new MultipartEntity();
ent.addPart("file", new FileBody(fileUpload));
req.setEntity(ent);
}
return request(req);
}
So I'm not sure why you're getting a 404, Jira is sometime fuzzy and not really clear about its error, try printing the full error, or checking Jira's log if you can. Maybe it's just the "X-Atlassian-Token", "nocheck", try adding it.
I'm trying to set up AWS SAM locally so I don't have to deploy every time I make a code change. But I'm having trouble getting the secrets out of Secrets Manager. I've created a new SAM project using sam init --runtime java
I then created a new secret in Secret Manager, and changed the code in the HelloWorldFunction to try to retrieve the secret.
package helloworld;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.*;
/**
* Handler for requests to Lambda function.
*/
public class App implements RequestHandler<Object, Object> {
public Object handleRequest(final Object input, final Context context) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("X-Custom-Header", "application/json");
try {
String secretName = "testsecret";
String region = "us-west-2";
// Create a Secrets Manager client
AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard()
.withRegion(region)
.build();
String secret, decodedBinarySecret;
GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest()
.withSecretId(secretName);
GetSecretValueResult getSecretValueResult = null;
try {
getSecretValueResult = client.getSecretValue(getSecretValueRequest);
} catch (DecryptionFailureException e) {
// Secrets Manager can't decrypt the protected secret text using the provided KMS key.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InternalServiceErrorException e) {
// An error occurred on the server side.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InvalidParameterException e) {
// You provided an invalid value for a parameter.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InvalidRequestException e) {
// You provided a parameter value that is not valid for the current state of the resource.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (ResourceNotFoundException e) {
System.out.println(e.getMessage());
StringWriter outError = new StringWriter();
e.printStackTrace(new PrintWriter(outError));
System.out.println(outError.toString());
// We can't find the resource that you asked for.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
}
// Decrypts secret using the associated KMS CMK.
// Depending on whether the secret is a string or binary, one of these fields will be populated.
if (getSecretValueResult.getSecretString() != null) {
secret = getSecretValueResult.getSecretString();
return new GatewayResponse(secret, headers, 200);
}
else {
decodedBinarySecret = new String(Base64.getDecoder().decode(getSecretValueResult.getSecretBinary()).array());
return new GatewayResponse(decodedBinarySecret, headers, 200);
}
} catch (Exception e) {
return new GatewayResponse("{}", headers, 500);
}
}
}
When I run sam local start-api and navigate to http://127.0.0.1:3000/hello, I get this error:
Secrets Manager can’t find the specified secret. (Service: AWSSecretsManager; Status Code: 400; Error Code: ResourceNotFoundException; Request ID: 6881467f-d968-4f4e-ae60-7e3128124cc5)
com.amazonaws.services.secretsmanager.model.ResourceNotFoundException: Secrets Manager can’t find the specified secret. (Service: AWSSecretsManager; Status Code: 400; Error Code: ResourceNotFoundException; Request ID: 6881467f-d968-4f4e-ae60-7e3128124cc5)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1632)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1304)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1058)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:743)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:717)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.doInvoke(AWSSecretsManagerClient.java:2024)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.invoke(AWSSecretsManagerClient.java:2000)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.executeGetSecretValue(AWSSecretsManagerClient.java:878)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.getSecretValue(AWSSecretsManagerClient.java:853)
at helloworld.App.handleRequest(App.java:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:259)
at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:178)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)
But, it's the same code to get the secret that was given in the secrets manager. Is it not possible to connect to real AWS services from sam local? I had a similar issue with DynamoDB, but was able to get it working with by using DynamoDB Local.
Any suggestions on how to either connect to the real secrets manager or to fake it locally somehow?
When you run DynamoDB Local, it is actually running a mock DDB server in a thread (or as a local process depending on how you start it) within you running test process. Unfortunately, Secrets Manager and other AWS services do not offer an equivalent testing solution.
However, if you are getting back ResourceNotFoundException it seems likely that you were able to successfully connect to Secrets Manager. It may be possible that the connection to secrets manager is using a different account than the one in which you stored the secret. One way you can check which credentials the code is using is to use the STS get caller identity call.
I need some help here.
I have been working on an android game where some information about your progress is sent to the server. Also you neeed to record your voice and the game will sent to our blobstore at my google server.
I managed to use Jsoup to upload a form to my datastore.
My problem is i ahve been trying to upload stuff in various ways to the file upload app that i did. No success.
This is my Google APP code (python). It works perfectly on my browser and it's meant to upload files to my blobstore. Basically it's an http file POST form
import os
import urllib
from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
class MainHandler(webapp.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload')
self.response.out.write('<html><body>')
self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit" name="submit" value="Submit"> </form></body></html>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
self.response.out.write('success!')
#self.redirect('/')
app= webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
], debug=True)
This is the code i have been trying to use to upload stuff to it. This code is run on my andorid phone.
public static void sendF(File file)
{
if (file.exists())
{
Log.e("msg", "exists");
}
else
{
Log.e("msg", "does not exists");
}
String url = "http://MYAPP.appspot.com/";
HttpClient httpclient = AndroidHttpClient.newInstance("MyGame");
HttpPost httpost = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
entity.addPart("file", new FileBody(file));
httpost.setEntity(entity);
HttpResponse response;
try {
response = httpclient.execute(httpost);
Log.e("internet", EntityUtils.toString(response.getEntity()));
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
problem is: I keep getting this
05-29 17:10:52.369: E/internet(1720): <h1>405 Method Not Allowed</h1>
05-29 17:10:52.369: E/internet(1720): The method POST is not allowed for this resource. <br /><br />
(Although I am able to use it from a web browser. Can someone help me? (sorry if I am not clear)
I am finding that JSoup has a bug that it does't handle redirects properly. Instead of transferring the request to a GET, it preserves it as a POST. That is not valid according to spec.
So I'm running out of ideas to try to actually get a client to connect to the SOAP service I'm running through axis2.
I tried two methods, one was to use wsdl2java to build the stub and associated client side classes, and then write a Client class that build the requests messages and sends them through the Stub. The other way was to use the ServiceClient to connect..
Both are failing in their own way..
Option #1, every time a message is sent through the stub I get this back:
org.apache.axis2.AxisFault: The input stream for an incoming message is null.
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:87)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:67)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:354)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:417)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
Option #2, everytime I run it I get this Exception:
org.apache.axis2.deployment.DeploymentException: org.apache.axis2.transport.local.LocalTransportSender
Option #2 source:
import javax.xml.stream.XMLStreamException;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.Constants;
import org.apache.axis2.client.ServiceClient;
public class loyaltyClient {
private static EndpointReference targetEPR =
new EndpointReference(
"http://localhost:8080/axis2/services/service");
public static OMElement verifyCustomer(String customer_id) {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
"http://localhost/", "service");
OMElement method = fac.createOMElement("VerifyCustomer", omNs);
OMElement value1 = fac.createOMElement("customer_id",omNs);
OMElement value2 = fac.createOMElement("source_id",omNs);
OMElement value3 = fac.createOMElement("source_password",omNs);
OMElement value4 = fac.createOMElement("source_txnid",omNs);
OMElement value5 = fac.createOMElement("timestamp",omNs);
value1.addChild(fac.createOMText(value1, customer_id));
value2.addChild(fac.createOMText(value2, "source"));
value3.addChild(fac.createOMText(value3, "1234"));
value4.addChild(fac.createOMText(value4, "123"));
value5.addChild(fac.createOMText(value5, "06-01-2010 12:01:01"));
method.addChild(value1);
method.addChild(value2);
method.addChild(value3);
method.addChild(value4);
method.addChild(value5);
return method;
}
public static void main(String[] args) {
try {
OMElement vctest = loyaltyClient.verifyCustomer("6177740603");
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
OMElement result = sender.sendReceive(vctest);
String response = result.getFirstElement().getText();
System.out.println(response);
} catch (Exception e) { //(XMLStreamException e) {
System.out.println(e.toString());
}
}
}
I've also encountered the error "The input stream for an incoming message is null" while using Axis to connect to a .Net service provider.
The problem is that .Net doesn't not support a feature called "chunked encoding", by default Axis will break its request header in chunks which is suppose to be a HTTP 1.1 compliant thing.
Anyway, you can turn this feature off in Axis by doing the following:
// Turn off the Axsis Chunked feature, some service providers (like .Net) don't support chunked headers.
Options options = serviceClient.getOptions();
options.setProperty(HTTPConstants.CHUNKED, Constants.VALUE_FALSE);
serviceClient.setOptions(options);
This worked for me. Another thing to make sure of when dealing with .Net services is to be able to specify the port name and make sure your message payload has the namespace prefix for each element.
Hope this info helps somebody.
Cheers,
DC
With the caveat that Axis2 is a buggy pile of crap, I recently had to write an Axis2 client, and found that using the default ServiceClient() constructor didn't work well -- I had to manually create a ConfigurationContext, etc. I found that using ServiceClient.getOptions() instead of creating new Options() preserved some default data. I'd also recommend dropping the options.setTransportInProtocol(...) unless you really need it -- everything should work fine via HTTP without this. Also, you may need to set options.setAction(...) to correspond with the "operation" in your WSDL.
I've included the bulk of my client (with sensitive information stripped out), in hopes that it will help. You can probably safely ignore the portions regarding addressing unless you plan to use WS-Addressing.
ConfigurationContext cfgCtx = null;
try {
/* Passing null to both params causes an AxisConfiguration to be created that uses
* the default axis2.xml file, which is included in the axis2 distribution jar.
* This is ideal for our case, since we cannot pass a full file path (relative
* paths are not allowed) because we do not know where the customer will deploy
* the application. This also allows engaging modules from the classpath. */
cfgCtx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null , null);
} catch (AxisFault e) {
// Bubble up the error
}
ServiceClient svcClient = null;
try {
svcClient = new ServiceClient(cfgCtx, null);
} catch (AxisFault e) {
// Bubble up the error
}
try {
/* This will work with the above ConfigurationContext as long as the module
* (addressing-1.5.1.mar) is on the classpath, e.g. in shared/lib. */
svcClient.engageModule("addressing");
} catch (AxisFault e) {
// Bubble up the error
}
Options opts = svcClient.getOptions();
opts.setTo(new EndpointReference("http://myservername:8080/axis2/services/MyService"));
opts.setAction("urn:doSomething"); // Corresponds to the "operation" in MyService's WSDL
opts.setSoapVersionURI(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI); // Set output to SOAP 1.2
SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
svcClient.addHeader(createSOAPSecurityHeader(factory, response)); // CreateSOAPHeader just creates an OMElement
try {
svcClient.sendReceive(createSOAPBody(factory, response)); // CreateSOAPBody just creates an OMElement
} catch (AxisFault e) {
throw new ResponseDeliveryException(1, "Error sending SOAP payload.", e);
}