CActive or thread?
Login to reply to this topic.
Wed, 2004-11-10 16:36
Joined: 2004-09-06
Forum posts: 348
I believe that my application requires a second thread (please correct me if I'm wrong):
The application is supposed to do multiple http-connections using the HTTP support classes of Series 60 SDK 2.1 and wait for the result of each HTTP request before issuing the next request. As far as I have understood CActive, CActive cannot be used here. The problem I'm thinking about is the loop of connections that will be made - as I understood CActive will not preempt the requesting phone, it will only say "hi there, I'm waiting for something" and just go on. If I'm wrong, please tell me how this can be solved with CActive - otherwise, can someone tell me how to use threads in Symbian?

Regards,
Joachim

Thu, 2004-11-11 10:17
Joined: 2003-10-01
Forum posts: 723
Hi,

I don't really understand your problem:
Quote
The problem I'm thinking about is the loop of connections that will be made

What do you mean?

Anyway, you don't have to use another thread just for this purpose. If you're concerned about multiple connections and/or multiple HTTP sessions, then a new thread will not solve your problem. The only thing you need to issue multiple HTTP requests is to use multiple RHTTPSession objects and that's all. Note that I can't see when active objects come into play here, because you can use these HTTP session without active objects: it uses callbacks, that is, you don't have to maintain request statuses, because you functions will simply called back.

tOtE

Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/

Thu, 2004-11-11 11:51
Joined: 2004-09-06
Forum posts: 348
Quote
and wait for the result of each HTTP request before issuing the next request.

I have a series of requests (I meant requests, not connections - sorry for that) that has to be done one after another, and the next cannot start until the previous has completed.

Thanks for your reply,

Joachim
Thu, 2004-11-11 13:15
Joined: 2004-07-28
Forum posts: 1379
Use a state machine.

class CBlah : public CActive
{
enum TState
{
EState1,
EState2
}

TState iState;
};

void CBLah::RunL()
{
switch(iState)
{
case EState1:
{
iState = EState2;
// do what ever to request state 2
break;
}
case EState2:
{
break;
}
}
}

It's a very common pattern in Symbian OS programming, you should be able to find some better/more complete examples knocking about on NewLC I would think.

didster

Tue, 2004-11-30 13:49
Joined: 2003-12-12
Forum posts: 36
Hi... I have a related question: somebody said here that we should not use CActive with  HTTP CLiente API because of it uses CallBack.... so should I use the HTTP Client API as a synchronous request and that´s all?Huh
Tue, 2004-11-30 13:53
Joined: 2004-07-28
Forum posts: 1379
So what if it uses callbacks?  You can still use CActive.

As a general rule avoid synchronous communications programming... What happens if your using the HTTP client in a synchronous way and the user presses Exit etc??  You app locks up until the current request has finished - its very ugly - and CActive solves it quite well without having to mess around with threads (in most cases anyway).

didster

Tue, 2004-11-30 14:10
Joined: 2003-12-12
Forum posts: 36
I agree with you... .....  I am newbie in using AO....

Could you justa ask one more question??

I have a CActive class that makes a bluetooth connection to read an information and then sends it to a servlet via HTTP.
When I finish tha reading from BT, I make SetActive and then in RunL  I make the  HTTP connection... is it OK??? The programm gets locked after reading from BT and never makes tha HTTP connection.....  I´m sure its a problem whith ActiveScheduler... do you have any idea of where can be the error? Maybe tha BT reading always pending???
Wed, 2004-12-01 08:54
Joined: 2004-07-28
Forum posts: 1379
Quote from: amattiuz
I make SetActive and then in RunL  I make the  HTTP connection... is it OK???

Yes - providing you keep some kind of state so you know when your RunL gets called wheather its because of your bluetooth connection, or your HTTP connection.

Put up your code if it's not working.

didster

Tue, 2004-12-07 17:13
Joined: 2003-12-12
Forum posts: 36
hello....

i´ve been trying, but.... I really don´t  know how to sove the problem...
i´m gonna post my code... if someone has patience to read it., please do, I´ll be  forever thankful......
i´m desperate, i think  Sad

Code:

// http.cpp
//declarations + includes + constructors....
void CTest::RunL()
{
switch (iState){

case EParse:{
ParseRequestL();
SetActive();
}
break;
case ESent: {
if(iStatus.Int() == KErrNone){
iSocket.Close();
iSent = ETrue;
}
}
break;
case ESendHTTP:{
if(iStatus.Int() == KErrNone){
iSocket.Close();
iSent = ETrue;
}
//it runs OK until here... the data is never sent to the servlet...
SendHTTPMesg();
}
break;

default:
break;
}

}

        .
        .
    some auxiliar functions ...
        .
        .

void CTest::ParseRequestL() {
 //parses the string .... thn compares:
if (code.Compare(KGetLocalPosition) == 0)
{
ReturnLocalDataL();
iState = ESent;
}
else if (code.Compare(KGetSMS) == 0)
{

}
else if (code.Compare(KSendSMS) == 0)
{

}
else if (code.Compare(KSetInterval) == 0)
{

}
else if (code.Compare(KSetSending) == 0)
{

}
else if (code.Compare(KSendPosition) == 0)
{
DispatchDataL();
iState = ESendHTTP;

}
else if (code.Compare(KGetIMEINumber) == 0)
{

}
else{
ReturnInvalidCode();
iState = ESent;
}
return;

}

void CHTTPProtocol::ReturnInvalidCode()
{
 //not done yet
}

//reads from Bluetooth device (the class CModel does the reading itself via BT Sockets)
void CTest::ReturnLocalDataL()
{
CModel* cm;
cm = CModel::NewL();
cm->StartTestL();
if ((cm->iDataBuffer).Length() <= 0){
posBuffer.Copy(_L("Error. Nothind was read"));
}
else{
posBuffer.Copy(cm->iDataBuffer);
}
        //this socket has nothing to do with BT Sockets...
        // the BT socket  was closed in CModel, after reading
iSocket.Write(posBuffer, iStatus);
User::WaitForRequest(iStatus);
TRequestStatus* status=&iStatus;
User::RequestComplete(status, KErrNone);

}

//now, send the data to a server
void CHTTPProtocol::DispatchDataL()
{
  ReturnLocalDataL();
  iSess.OpenL();
iTransObs = CHttpEventHandler::NewL();
RStringPool strP = iSess.StringPool();
method = strP.StringF(HTTP::EPOST,RHTTPSession::GetTable());
}


void CTest::SendHTTPMesg()
{
GetRequestBodyL();
TBuf8<256> url8;
url8.Copy(_L("http://some.servlet"));
InvokeHttpMethodL(url8, method);
}

void CTest::GetRequestBodyL()
{

TBuf8<12> deviceID = TBuf8<12>::TBuf8();
TBuf8<12> userID = TBuf8<12>::TBuf8();
TBuf8<14> date = TBuf8<14>::TBuf8();
TBuf<14>  dateAux;

TTime time;
TDateTime dateTime;
time.HomeTime();
       dateTime=time.DateTime();    

TBuf8<1024> first = TBuf8<1024>::TBuf8();
TBuf8<1024> second = TBuf8<1024>::TBuf8();
first.Copy(_L("123"));
second.Copy(_L("456"));
deviceID.Copy(_L("12345678910"));
userID.Copy(_L("Name"));

GetStringDateTime(dateAux, dateTime);
date.Copy(dateAux);

if (iFormEncoder)
{
delete iFormEncoder;
iFormEncoder = NULL;
}

iFormEncoder = CHTTPFormEncoder::NewL();
iFormEncoder->AddFieldL(KIdMobile, mobileID);
iFormEncoder->AddFieldL(KLoginUser, userID);
iFormEncoder->AddFieldL(KDate, date);
iFormEncoder->AddFieldL(K1, first);
iFormEncoder->AddFieldL(K2, second);

return;

void CTest::GetStringDateTime(TDes& aBuffer,TDateTime aDateTime){

 //do some data manipulation
}
void CTest::InvokeHttpMethodL(const TDesC8& aUri, RStringF aMethod)
{

TUriParser8 uri;
uri.Parse(aUri);
iTrans = iSess.OpenTransactionL(uri, *iTransObs, aMethod);
RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();

SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
SetHeaderL(hdr, HTTP::EAccept, KAccept);

TBuf8<KMaxContentTypeSize> contTypeBuf;
contTypeBuf.Copy(_L("application/x-www-form-urlencoded"));
RStringF contTypeStr = iSess.StringPool().OpenFStringL(contTypeBuf);
THTTPHdrVal contType(contTypeStr);
hdr.SetFieldL(iSess.StringPool().StringF(HTTP::EContentType,RHTTPSession::GetTable()), contType);
contTypeStr.Close();

MHTTPDataSupplier*dataSupplier = iFormEncoder;
iTrans.Request().SetBody(*dataSupplier);

iTrans.SubmitL();

}
void CTest::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue)
{
RStringF valStr = iSess.StringPool().OpenFStringL(aHdrValue);
THTTPHdrVal val(valStr);
aHeaders.SetFieldL(iSess.StringPool().StringF(aHdrField,RHTTPSession::GetTable()), val);
valStr.Close();
}

//event handler
void CHttpEventHandler::ConstructL(){}

CHttpEventHandler::CHttpEventHandler() {}

CHttpEventHandler::~CHttpEventHandler(){}

CHttpEventHandler* CHttpEventHandler::NewLC()
{
CHttpEventHandler* me = new(ELeave)CHttpEventHandler();
CleanupStack::PushL(me);
me->ConstructL();
return me;
}

CHttpEventHandler* CHttpEventHandler::NewL()
{
CHttpEventHandler* me = NewLC();
CleanupStack::Pop(me);
return me;
}

void CHttpEventHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
{
switch (aEvent.iStatus)
{
case THTTPEvent::EGotResponseHeaders:
{

RHTTPResponse resp = aTransaction.Response();
TInt status = resp.StatusCode();

if (status != 200){
aTransaction.Close();

}
else{
RStringF statusStr = resp.StatusText();
TBuf<32> statusStr16;
statusStr16.Copy(statusStr.DesC());
             }
} break;
case THTTPEvent::EGotResponseBodyData:
{
         
           } break;
case THTTPEvent::EResponseComplete:
{

} break;
case THTTPEvent::ESucceeded:
{

aTransaction.Close();

} break;
case THTTPEvent::EFailed:
{

aTransaction.Close();

} break;
case THTTPEvent::ERedirectedPermanently:
{

} break;
case THTTPEvent::ERedirectedTemporarily:
{

} break;
default:
{

if (aEvent.iStatus < 0)
{
aTransaction.Close();

}
} break;
}
}

TInt CHttpEventHandler::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/)
{
return KErrNone;
}


thanks!!!!  Smiley  Huh:

copyright 2003-2009 NewLC SARL