OfficeDev / ews-java-api

A java client library to access Exchange web services. The API works against Office 365 Exchange Online as well as on premises Exchange.
MIT License
869 stars 560 forks source link

ServiceRequestException: The request failed. 40 #371

Open choonchernlim opened 9 years ago

choonchernlim commented 9 years ago

When invoking the following code in 2 running threads:-

@Override
public Set<ExchangeAppointmentBean> query(final String calendarEmail,
                                          final LocalDate startDate,
                                          final LocalDate endDate) {
    final ExchangeService service;
    final FindItemsResults<Appointment> findResults;
    final ExchangeCredentials credentials = new WebCredentials("user", "pwd");

    try {
        service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
        service.setCredentials(credentials);
        service.setUrl(new URI("https://hostname/ews/exchange.asmx"));

        final FolderId folderId = new FolderId(WellKnownFolderName.Calendar, new Mailbox(calendarEmail));
        final CalendarFolder calendarFolder = CalendarFolder.bind(service, folderId);
        final CalendarView calendarView = new CalendarView(startDate.toDate(), endDate.toDate());

        findResults = calendarFolder.findAppointments(calendarView);
    }
    catch (Exception e) {
        throw CommonUtils.createException(LOGGER, e, "Unexpected error occurred when querying Exchange Server");
    }

   ....

  service.close();
}    

... I get this error from the try-catch block:-

Caused by: microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRequestException: The request failed. 40
    at microsoft.exchange.webservices.data.core.request.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:74)
    at microsoft.exchange.webservices.data.core.request.MultiResponseServiceRequest.execute(MultiResponseServiceRequest.java:158)
    at microsoft.exchange.webservices.data.core.ExchangeService.bindToFolder(ExchangeService.java:500)
    at microsoft.exchange.webservices.data.core.ExchangeService.bindToFolder(ExchangeService.java:519)
    at microsoft.exchange.webservices.data.core.service.folder.CalendarFolder.bind(CalendarFolder.java:60)
    at microsoft.exchange.webservices.data.core.service.folder.CalendarFolder.bind(CalendarFolder.java:75)
    at myproject.module.pto.service.impl.MicrosoftExchangeServiceImpl.query(MicrosoftExchangeServiceImpl.java:78)
    ... 6 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 40
    at org.apache.http.impl.auth.NTLMEngineImpl$NTLMMessage.addByte(NTLMEngineImpl.java:911)
    at org.apache.http.impl.auth.NTLMEngineImpl$NTLMMessage.addULong(NTLMEngineImpl.java:940)
    at org.apache.http.impl.auth.NTLMEngineImpl$Type1Message.getResponse(NTLMEngineImpl.java:1043)
    at org.apache.http.impl.auth.NTLMEngineImpl.getType1Message(NTLMEngineImpl.java:148)
    at org.apache.http.impl.auth.NTLMEngineImpl.generateType1Msg(NTLMEngineImpl.java:1628)
    at org.apache.http.impl.auth.NTLMScheme.authenticate(NTLMScheme.java:139)
    at org.apache.http.impl.auth.AuthSchemeBase.authenticate(AuthSchemeBase.java:138)
    at org.apache.http.impl.auth.HttpAuthenticator.doAuth(HttpAuthenticator.java:239)
    at org.apache.http.impl.auth.HttpAuthenticator.generateAuthResponse(HttpAuthenticator.java:202)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:262)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at microsoft.exchange.webservices.data.core.request.HttpClientWebRequest.executeRequest(HttpClientWebRequest.java:292)
    at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.getEwsHttpWebResponse(ServiceRequestBase.java:720)
    at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.validateAndEmitRequest(ServiceRequestBase.java:639)
    at microsoft.exchange.webservices.data.core.request.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:62)
serious6 commented 9 years ago

a simple approach should be to add a synchronized to that method

public synchronized Set<ExchangeAppointmentBean> query(..)
   [...]
serious6 commented 9 years ago

seems to be a duplicate of #370 btw.

evpaassen commented 9 years ago

@serious6 Making the method synchronized is not the solution. The method creates a new ExchangeService every time it is invoked and doesn't share any variables, so I don't see a problem with this code.

It looks like some internal HttpComponents stuff is shared between instances, where it shouldn't be.

Also see: http://stackoverflow.com/questions/29681969/ntlm-authentication-failing-in-multithreaded-application

choonchernlim commented 9 years ago

I did stumble upon that SO post, but nothing I can do on my end to modify the connection manager.

I'm honestly not a big fan of using synchronized at all, but right now I made the synchronized block as small as possible to prevent the problem:-

private final Object lock = new Object();

@Override
public Set<ExchangeAppointmentBean> query(final String calendarEmail,
                                          final LocalDate startDate,
                                          final LocalDate endDate) {
    final ExchangeService service;
    final FindItemsResults<Appointment> findResults;
    final ExchangeCredentials credentials = new WebCredentials("user", "pwd");
    final FolderId folderId = new FolderId(WellKnownFolderName.Calendar, new Mailbox(calendarEmail));
    final CalendarView calendarView = new CalendarView(startDate.toDate(), endDate.toDate());
    final CalendarFolder calendarFolder;

    try {
        service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
        service.setCredentials(credentials);
        service.setUrl(new URI("https://hostname/ews/exchange.asmx"));

        // problematic part using HttpClient
        synchronized (lock) {
            calendarFolder = CalendarFolder.bind(service, folderId);
        }

        findResults = calendarFolder.findAppointments(calendarView);
    }
    catch (Exception e) {
        throw CommonUtils.createException(LOGGER, e, "Unexpected error occurred when querying Exchange Server");
    }

   ....

  service.close();
}   

This works for me, but I'm not certain if I like this solution. Thank you.

evpaassen commented 9 years ago

It works only because making the method synchronized will eliminate all concurrency. I think this is a bug which should be fixed, however.

bah7303 commented 9 years ago

This is affecting me as well. It is making this version of the API unusable for me. I have been able to mitigate the issue caused by this error by writing code to retry following this error but I am worried this solution will not scale very well.

codewheeney commented 9 years ago

I, too, am affected by this issue. The API should support multiple instantiations of the ExchangeSevice that may be used concurrently, IMHO.

pathikrit commented 9 years ago

:+1:

schakko commented 9 years ago

@codewheeney I implemented a dirty fix for our issue. Would you please give my branch a try?

Monte-Hansen commented 8 years ago

I am experience this issue as well, bottom of stack below for additional insight (which support other branch suggestions). I agree that the synchronized block is not a solution as I am attempting to mitigate performance issues by parallelizing the work on separate connections.

Caused by: java.lang.ArrayIndexOutOfBoundsException: 40 at org.apache.http.impl.auth.NTLMEngineImpl$NTLMMessage.addByte(NTLMEngineImpl.java:911) at org.apache.http.impl.auth.NTLMEngineImpl$NTLMMessage.addULong(NTLMEngineImpl.java:939) at org.apache.http.impl.auth.NTLMEngineImpl$Type1Message.getResponse(NTLMEngineImpl.java:1007) at org.apache.http.impl.auth.NTLMEngineImpl.getType1Message(NTLMEngineImpl.java:148) at org.apache.http.impl.auth.NTLMEngineImpl.generateType1Msg(NTLMEngineImpl.java:1628) at org.apache.http.impl.auth.NTLMScheme.authenticate(NTLMScheme.java:139) at org.apache.http.impl.auth.AuthSchemeBase.authenticate(AuthSchemeBase.java:138) at org.apache.http.impl.auth.HttpAuthenticator.doAuth(HttpAuthenticator.java:239) at org.apache.http.impl.auth.HttpAuthenticator.generateAuthResponse(HttpAuthenticator.java:202) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:262) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at microsoft.exchange.webservices.data.core.request.HttpClientWebRequest.executeRequest(HttpClientWebRequest.java:292) at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.getEwsHttpWebResponse(ServiceRequestBase.java:720) at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.validateAndEmitRequest(ServiceRequestBase.java:639) at microsoft.exchange.webservices.data.core.request.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:62) ... 14 more

danxfisher commented 8 years ago

I've come across this same issue and adding a synchronized to the method or adding a synchronized block does not correct this issue. Have there been any fixes for this?

prophe05 commented 8 years ago

+1

ralphavalon commented 8 years ago

+1

maroswal commented 8 years ago

+1

indriesergiu commented 8 years ago

Has anyone tried upgrading httpclient to 4.5.2 to fix the problem?

http://www.apache.org/dist/httpcomponents/httpclient/RELEASE_NOTES-4.5.x.txt [HTTPCLIENT-1715] NTLMEngineImpl#Type1Message not thread safe but declared as a constant. The issue was resolved in February 2016.

derylspielman commented 8 years ago

@indriesergiu I will hopefully be attempting to upgrade the httpclient dependency very soon and will report any results here.

scorchio commented 8 years ago

@derylspielman Deryl, any luck on your end with the httpclient upgrade?

scorchio commented 8 years ago

Just an idea: could implementing #423 help in this?

indriesergiu commented 8 years ago

Hi guys, I've tested using the httpclient version 4.5.2 and it fixes the "The request failed. 40" issue, however, you will still run into "Connection is still allocated" issues (see https://github.com/OfficeDev/ews-java-api/issues/276). So at this point, if you use a new ExchangeService instance for each EWS request you can execute multiple EWS requests in parallel :)

ghost commented 7 years ago

+1. although hI have not had problems since switching to 4.5.2 seems to fix it.

derylspielman commented 7 years ago

This worked for me as well although I am using httpclient-4.5.3 and creating a new ExchangeService per e-mail.