I am using quickfix C++ implementation to connect to the FIX Server, everything is ok except when i tries to connect it says the field missing username. To correct this i added the following code to the toAdmin Method
void Application::toAdmin( FIX::Message& message, const FIX::SessionID& sessionID)
{
if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType))
{
FIX44::Logon & logon_message = dynamic_cast<FIX44::Logon&>(message);
logon_message.setField(FIX::Username("username"));
logon_message.setField(FIX::Password("password"));
}
std::cout<<message.toString();
}
}
but is causes an exception. To check whether it is working or not also tried to print the message using std::cout<<message.ToString();
but nothing worked.
I think you were almost there. Here is my solution for initiating a FIX session with FXCM in C# (should be easy for you to port a C++ implementation).
1- Use the QuickFix Examples.TradeClient project.
2- Ensure your fix.cfg file is present in TradeClient/bin/Debug directory.
3- Ensure your dictionary (FIXFXCM10.XML) is present in TradeClient/bin/Debug directory.
4- Your main Program.cs should look something like this;
var settings = new QuickFix.SessionSettings("fix.cfg");
var client = new QuickFixClient();
var storeFactory = new QuickFix.FileStoreFactory(settings);
var logFactory = new QuickFix.ScreenLogFactory(settings);
var initiator = new QuickFix.Transport.SocketInitiator(client, storeFactory, settings, logFactory);
initiator.Start();
client.Run();
initiator.Stop();
and replace
public void ToAdmin(Message message, SessionID sessionID) {}
with this
public void ToAdmin(Message message, SessionID sessionID)
{
if (message.GetType() == typeof(QuickFix.FIX44.Logon))
{
message.SetField(new Username("YOUR_USERNAME"));
message.SetField(new Password("YOUR_PASSWORD"));
}
message.SetField(new QuickFix.Fields.Account("YOUR_ACCOUNT_NUMBER"));
}
FXCM require the account number (tag 1=) to be sent with every message to be valid. That could also prevent a successful logon if its not present.
Hope this helps!
This is how I added password:
void toAdmin( FIX::Message& message, const FIX::SessionID& sessionID)
{
// put password in the logon message
if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType))
{
FIX::Password fixpasswd = ConfigSingleton::getInstance().CurrenexConfig.FIXPassword; //use your std::string password here.
message.getHeader().setField(FIX::Password(fixpasswd)); //also add username here.
}
}
If you can see your username and password, then it means ok already.
Regarding the exception, I also encountered before. For me, it comes from toApp function and I changed it as below and it works fine:
void toApp( FIX::Message& message, const FIX::SessionID& sessionID )
throw( FIX::DoNotSend )
{
try
{
FIX::PossDupFlag possDupFlag;
message.getHeader().getField( possDupFlag );
if ( possDupFlag ) throw FIX::DoNotSend();
}
catch ( FIX::FieldNotFound& e)
{
//std::cout << e.what() << " " << message.toString() << ENDLINE;
}
}
Actually, no exception.
BTW, if you didn't define your own function for some message types, the messages will be rejected.
Hope this will help.
Related
I have written an IoT Edge C++ module that is sending the event output using the following function call:
bool IoTEdgeClient::sendMessageAsync(std::string message)
{
bool retVal = false;
LOGGER_TRACE(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) START");
LOGGER_DEBUG(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) message : " << message);
Poco::Mutex::ScopedLock lock(_accessMutex);
MESSAGE_INSTANCE *messageInstance = CreateMessageInstance(message);
IOTHUB_CLIENT_RESULT clientResult = IoTHubModuleClient_LL_SendEventToOutputAsync(_iotHubModuleClientHandle, messageInstance->messageHandle, "output1", SendConfirmationCallback, messageInstance);
if (clientResult != IOTHUB_CLIENT_OK)
{
LOGGER_ERROR(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) ERROR : " << message << " Message id: " << messageInstance->messageTrackingId);
retVal = false;
}
else
{
retVal = true;
}
LOGGER_TRACE(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) END");
return retVal;
}
The result of the function call IoTHubModuleClient_LL_SendEventToOutputAsync is always coming as IOTHUB_CLIENT_OK. My module name is MicroServer and the route configured is:
FROM /messages/modules/MicroServer/outputs/output1 INTO $upstream
I do not see the SendConfirmationCallback function being called. Also, I do not see any device to cloud message appearing in the IoT hub. Any ideas why this is happening and how to fix it?
It turned out that I need to call this function atleast a couple of times per second
IoTHubModuleClient_LL_DoWork(_iotHubModuleClientHandle);
which I was not doing. As a result the code was not working properly. Once I started doing it. The code just worked.
I stuck in a issue, where I have to fill all slots from user.
Sharing required details -
I used Lex for writing Bot and intent Definition.
I exported Lex configuration to Alexa Skill kit.
Currently, I am facing issue, while fetching values of all slots of given intent from user.
Lambda code snippet -
#Override
public SpeechletResponse onIntent(SpeechletRequestEnvelope<IntentRequest> speechletRequestEnvelope) {
IntentRequest request = speechletRequestEnvelope.getRequest();
Session session = speechletRequestEnvelope.getSession();
log.info(String.format("onIntent. requestId : %s, sessionId : %s, Intent : %s", request.getRequestId(),
speechletRequestEnvelope.getSession().getSessionId(), speechletRequestEnvelope.getRequest().getIntent()));
Intent intent = request.getIntent();
String intentName = (intent != null) ? intent.getName() : null;
if ("HelloWorldIntent".equals(intentName)) {
return getHelloResponse();
} else if ("AMAZON.HelpIntent".equals(intentName)) {
return getHelpResponse();
} else if (LMDTFYIntent.MissingDrivesComplaint.name().equals(intentName)) {
return handleMissingDriveIntent(session, intent);
} else {
return getAskResponse("HelloWorld", "This is unsupported. Please try something else.");
}
}
private SpeechletResponse handleMissingDriveIntent(Session session, Intent intent) {
log.info(String.format("Executing intent : %s. Slots : %s", intent.getName(), intent.getSlots()));
Slot missingDriveSlot = intent.getSlot("missingDate");
Slot missingDrivesCountSlot = intent.getSlot("missingDrivesCount");
printSlots(intent.getSlots());
if(missingDriveSlot == null || missingDriveSlot.getValue() == null) {
printSlots(intent.getSlots());
log.info(String.format("Missing Drives slot is null"));
//return handleMissingDriveDialogRequest(intent, session);
ElicitSlotDirective elicitSlotDirective = new ElicitSlotDirective();
elicitSlotDirective.setSlotToElicit("missingDate");
SpeechletResponse speechletResponse = new SpeechletResponse();
speechletResponse.setDirectives(Arrays.asList(elicitSlotDirective));
SsmlOutputSpeech outputSpeech = new SsmlOutputSpeech();
outputSpeech.setSsml("On which date drives were missing");
speechletResponse.setOutputSpeech(outputSpeech);
return speechletResponse;
} else if(missingDrivesCountSlot == null || missingDrivesCountSlot.getValue() == null) {
printSlots(intent.getSlots());
log.info(String.format("Missing Drive Count is null"));
// return handleMissingDrivesCountDialogRequest(intent, session);
ElicitSlotDirective elicitSlotDirective = new ElicitSlotDirective();
elicitSlotDirective.setSlotToElicit("missingDrivesCount");
SpeechletResponse speechletResponse = new SpeechletResponse();
speechletResponse.setDirectives(Arrays.asList(elicitSlotDirective));
return speechletResponse;
} else if(missingDriveSlot.getValue() != null && missingDrivesCountSlot.getValue() != null) {
printSlots(intent.getSlots());
log.info(String.format("All slots filled."));
SpeechletResponse speechletResponse = new SpeechletResponse();
ConfirmIntentDirective confirmSlotDirective = new ConfirmIntentDirective();
speechletResponse.setDirectives(Arrays.asList(confirmSlotDirective));
return speechletResponse;
} else {
/*SpeechletResponse speechletResponse = new SpeechletResponse();
speechletResponse.setDirectives(Arrays.asList());*/
}
return null;
}
Check method -
handleMissingDriveIntent
Slots-
missingDate
missingDrivesCount
Question-
Amazon Echo Dot is saying - "There were a problem with a requested skill response". How can I figure out the reason ?
"There were a problem with a requested skill response"
Then Alexa responds to that error message back to you. That means there is a runtime error in your code.
You can check the CloudWatch logs from your lambda function (or using ask cli tool if you are using it). It can show you a line number where the error is happening. So you need to proceed from there.
I have a method I need to refactor, as F.Promise has been deprecated in Play 2.5. It's pretty readable actually. It sends a request and authenticates via a custom security token and returns true if the response is 200.
public boolean verify(final String xSassToken){
WSRequest request = WS.url(mdVerifyXSassTokenURL)
.setHeader("X-SASS", xSassToken)
.setMethod("GET");
final F.Promise<WSResponse> responsePromise = request.execute();
try {
final WSResponse response = responsePromise.get(10000);
int status = response.getStatus();
if(status == 200 ) { //ok
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
First thing I had to do was change this line:
final F.Promise<WSResponse> responsePromise = request.execute();
To this:
final CompletionStage<WSResponse> responsePromise = request.execute();
However, CompletionStage(T) doesn't have an equivalent get() method so I'm not sure the quickest and easiest way to get a WSResponse that I can verify the status of.
Yes, it does not. At least not directly.
What you are doing is "wrong" in the context of PlayFramework. get is a blocking call and you should avoid blocking as much as possible. That is why WS offers a non blocking API and a way to handle asynchronous results. So, first, you should probably rewrite your verify code to be async:
public CompletionStage<Boolean> verify(final String xSassToken) {
return WS.url(mdVerifyXSassTokenURL)
.setHeader("X-SASS", xSassToken)
.setMethod("GET")
.execute()
.thenApply(response -> response.getStatus() == Http.Status.OK);
}
Notice how I'm using thenApply to return a new a java.util.concurrent.CompletionStage instead of a plain boolean. That means that the code calling verify can also do the same. Per instance, an action at your controller can do something like this:
public class MyController extends Controller {
public CompletionStage<Result> action() {
return verify("whatever").thenApply(success -> {
if (success) return ok("successful request");
else return badRequest("xSassToken was not valid");
});
}
public CompletionStage<Boolean> verify(final String xSassToken) { ... }
}
This way your application will be able to handle a bigger workload without hanging.
Edit:
Since you have to maintain compatibility, this is what I would do to both evolve the design and also to keep code compatible while migrating:
/**
* #param xSassToken the token to be validated
* #return if the token is valid or not
*
* #deprecated Will be removed. Use {#link #verifyToken(String)} instead since it is non blocking.
*/
#Deprecated
public boolean verify(final String xSassToken) {
try {
return verifyToken(xSassToken).toCompletableFuture().get(10, TimeUnit.SECONDS);
} catch (Exception e) {
return false;
}
}
public CompletionStage<Boolean> verifyToken(final String xSassToken) {
return WS.url(mdVerifyXSassTokenURL)
.setHeader("X-SASS", xSassToken)
.setMethod("GET")
.execute()
.thenApply(response -> response.getStatus() == Http.Status.OK);
}
Basically, deprecate the old verify method and suggest users to migrate to new one.
I have referd to here :
QuickFix Login Failed due to password missing
and here :
How to make the login part in QuickFIX
to add username and password in toAdmin like following :
void Application::toAdmin( FIX::Message& message, const FIX::SessionID& sessionID)
{
if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType))
{
FIX44::Logon& logon_message = dynamic_cast<FIX44::Logon&>(message);
FIX::Username username = std::string("my_username") ;
logon_message.setField( username );
}
}
This cause compiler error in gcc 4.8.2 :
error: cannot dynamic_cast ??message?? (of type ??class FIX::Message??) to type ??class FIX44::Logon&?? (target is not pointer or reference to complete type)
then I change my code to
FIX44::Logon* logon_message = (FIX44::Logon*)(&message);
FIX::Username username = std::string("my_username") ;
logon_message->setField( username );
this time , compiler error again :
error: invalid use of incomplete type ??class FIX44::Logon??
logon_message->setField( username );
^
What should I modify so that I can correctly set username and password in
function toAdmin ? what is wrong with logon_message->setField( username ); ?
Edit :
according to this webpage :
https://sourceforge.net/p/quickfix/mailman/message/26233433/
The following works fine to me :
if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType))
{
message.getHeader().setField(553, "XXXXXXXXX");
message.getHeader().setField(554, "yyyyyyyyy");
}
Have you tried
FIX44::Logon* logon_message = dynamic_cast<FIX44::Logon*>(message);
or
FIX44::Logon* logon_message = dynamic_cast<FIX44::Logon*>( *(message) );
or
FIX44::Logon* logon_message = dynamic_cast<FIX44::Logon*>(&message);
I think this may be an issue of dereferencing message correctly.
The error message suggests that you did not #include "quickfix/fix44/Logon.h".
That is why it thinks that you are using an incomplete type. Your compiler now probably just sees a forward declared: class FIX44::Logon; and it does not know what methods this class contains.
The other answers correctly state that you don't even need to downcast
message.setField(FIX::Username(username));
message.setField(FIX::Password(password));
You don't need to cast your message. Ultimately you end up calling setField which is a function available to the base class FIX::Message.
void FIXSession::toAdmin(FIX::Message& msg, const FIX::SessionID& sid)
{
const std::string& field = msg.getHeader().getField(FIX::FIELD::MsgType);
if (FIX::MsgType_Logon == field)
{
FIX::Dictionary dd(m_sessionSettings.get(sid));
if (dd.has(FixSettingUsername))
{
FIX::Username username = dd.getString(FixSettingUsername);
msg.setField(username);
}
if (dd.has(FixSettingPassword))
{
FIX::Password password = dd.getString(FixSettingPassword);
msg.setField(password);
}
if (dd.has(FIX::SEND_RESETSEQNUMFLAG))
{
FIX::ResetSeqNumFlag rsn(dd.getBool(FIX::SEND_RESETSEQNUMFLAG));
msg.setField(rsn);
}
}
}
I am logging RequestXML for a webservice client using SoapHandler as follows
public boolean handleMessage(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
private void logToSystemOut(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean)
smc.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
out.println("\nOutbound message:");
} else {
out.println("\nInbound message:");
}
SOAPMessage message = smc.getMessage();
try {
message.writeTo(out);
out.println("");
} catch (Exception e) {
out.println("Exception in handler: " + e);
}
}
Got a new requirenment to add this xml to DB along with some extra values(which are not present in the xml). Is there any way I can pass few additional fields to above soap handler (in handleMessage method)?
Please note that changing the xml/WSDL or adding this to SOAP message header is not an option for me as it is owned by other interface. Any other solution?
Thanks!
You can cast your service class to a class of type "BindingProvider". In this form you can use it to assign it objects which you can access later from your SOAPHandler. Another useful usage is that you also can change the endPoint URL this way.
Before calling the service you do:
MySoapServicePortType service = new MySoapService().getMySoapServicePort();
BindingProvider bp = (BindingProvider)service;
MyTransferObject t = new MyTransferObject();
bp.getRequestContext().put("myTransferObject", t);
TypeResponse response = service.doRequest();
SOAPMessage message = t.getRequestMessage(message);
From your logging function you do:
private void logToSystemOut(SOAPMessageContext smc) {
...
MyTransferObject t = (MyTransferObject) messageContext.get("myTransferObject");
if (outboundProperty.booleanValue())
t.setRequestMessage(message);
else
t.setResponseMessage(message);
...
}