Multiple files upload to Box fails with HTTP client error "connection still allocated"

StackOverflow https://stackoverflow.com/questions/23529852

  •  17-07-2023
  •  | 
  •  

سؤال

I'm running Box java SDK v3.0.5 (latest). In my app I implement synchronization with a remote user Box and when an user creates several files locally I should create them on Box side.

My client created by following code:

this.client = new BoxClient(key, clientSecret, hub, parser, config);

With single file upload everything works well. But when several files submitted one by one in single thread and using this code:

BoxFileUploadRequestObject obj = BoxFileUploadRequestObject.uploadFileRequestObject(parentId,                                                              name,data);
  obj.setLocalFileCreatedAt(created.getTime());
  obj.put("created_at", formatDate(created));
  return client.getFilesManager().uploadFile(obj);

I face with following exception in my app:

java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
    at org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:216) ~[httpclient-4.1.2.jar:4.1.2]
    at org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(SingleClientConnManager.java:190) ~[httpclient-4.1.2.jar:4.1.2]
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:401) ~[httpclient-4.1.2.jar:4.1.2]
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820) ~[httpclient-4.1.2.jar:4.1.2]
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754) ~[httpclient-4.1.2.jar:4.1.2]
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732) ~[httpclient-4.1.2.jar:4.1.2]
    at com.box.boxjavalibv2.BoxRESTClient.getResponse(BoxRESTClient.java:148) ~[boxjavalibv2-3.0.5.jar:na]
    at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:98) ~[boxjavalibv2-3.0.5.jar:na]
    at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:72) ~[boxjavalibv2-3.0.5.jar:na]
    at com.box.boxjavalibv2.resourcemanagers.AbstractBoxResourceManager.getResponseAndParse(AbstractBoxResourceManager.java:118) ~[boxjavalibv2-3.0.5.jar:na]
    at com.box.boxjavalibv2.filetransfer.BoxFileUpload.execute(BoxFileUpload.java:58) ~[boxjavalibv2-3.0.5.jar:na]
    at com.box.boxjavalibv2.resourcemanagers.BoxFilesManagerImpl.uploadFile(BoxFilesManagerImpl.java:134) ~[boxjavalibv2-3.0.5.jar:na]
    at org.exoplatform.clouddrive.box.BoxAPI.createFile(BoxAPI.java:745) ~[exo-clouddrive-services-core-1.1.0-SNAPSHOT.jar:1.1.0-SNAPSHOT]
.........

Finally only first file uploaded successfully.

After googling about this error, I found that may be use of thread-safe connection would help. But as this code are in the Box SDK, the single thing that I was able to try it's use of BoxConnectionManager (which provides thread-safe) in the client creation:

BoxConnectionManagerBuilder connManager = new BoxConnectionManagerBuilder();
this.client = new BoxClient(key, clientSecret, hub, parser, config, connManager.build());

Indeed with the connection manager posted to the client another problem appears when I try access the Box API service:

Caused by: com.box.restclientv2.exceptions.BoxRestException: null
at com.box.boxjavalibv2.BoxRESTClient.handleException(BoxRESTClient.java:183) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:118) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:72) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.AbstractBoxResourceManager.getResponseAndParse(AbstractBoxResourceManager.java:118) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.AbstractBoxResourceManager.getResponseAndParseAndTryCast(AbstractBoxResourceManager.java:108) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.BoxEventsManagerImpl.getEventOptions(BoxEventsManagerImpl.java:60) ~[boxjavalibv2-3.0.5.jar:na]
at org.exoplatform.clouddrive.box.BoxAPI.updateChangesLink(BoxAPI.java:671) ~[exo-clouddrive-services-core-1.1.0-SNAPSHOT.jar:1.1.0-SNAPSHOT]
... 76 common frames omitted
Caused by: javax.net.ssl.SSLException: hostname in certificate didn't match: <api.box.com/74.112.185.97> != <*.box.com> OR <*.box.com> OR <box.com>
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:228) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:495) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.scheme.SchemeSocketFactoryAdaptor.connectSocket(SchemeSocketFactoryAdaptor.java:62) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732) ~[httpclient-4.1.2.jar:4.1.2]
at com.box.boxjavalibv2.BoxRESTClient.getResponse(BoxRESTClient.java:148) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:98) ~[boxjavalibv2-3.0.5.jar:na]
... 81 common frames omitted

FYI In my developer environment I'm running Tomcat on 8443 port. But with default REST client (w/o connection manager posted to the client constructor) all worked well.

What solution I can apply to perform multiple files uploading to Box?

هل كانت مفيدة؟

المحلول

I answer on my question myself.

Original problem "connection still allocated" was really actual as was assumed in the question above. Root cause was a need of

thread-safe connection (for HTTP client in Box SDK)... But as this code are in the Box SDK, the single thing that I was able to try it's use of BoxConnectionManager (which provides thread-safe).

But when I had used BoxConnectionManager I faced with the second error mentioned: hostname in certificate didn't match. This error is due to different versions of Apache HTTP client on the classpath. My server (eXo Platform 4.0) provides Apache HTTP client 4.1.2, but Box SDK requires 4.2.5. After installation of my app, the server libs has both these JARs and 4.1.2 appears as loaded for the Box. If remove JAR of 4.1.2, then everything works as expected and those who can do this way will not face with SSL cert error as I did. But I cannot do this way as other parts of the eXo certified with HTTP client 4.1.2 and I don't want get in risk for them.

My solution is use of custom BoxRESTClient in BoxClient. Thanks to the Box team it's possible to create an instance of their client with low-level details such as the REST client. The BoxConnectionManager hides this by providing an own BoxRESTClient, but it is also possible to create this REST client from external code, without using the manager. My custom REST client adopted to HTTP client 4.1.2 and has "allow-all" hostname verifier.

So far, my solution is acceptable and does work well. Below the code snippets that I used:

How I create Box client:

BoxResourceHub hub = new BoxResourceHub();
BoxJSONParser parser = new BoxJSONParser(hub);
this.client = new BoxClient(key,
                            clientSecret,
                            hub,
                            parser,
                            new RESTClient(),
                            new BoxConfigBuilder().build());

And custom RESTClient:

class RESTClient extends BoxRESTClient {

  final HttpClient httpClient;

  @SuppressWarnings("deprecation")
  RESTClient() {
    super();
    SchemeRegistry schemeReg = new SchemeRegistry();
    schemeReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    SSLSocketFactory socketFactory;
    try {
      socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS,
                                         null,
                                         null,
                                         null,
                                         null,
                                         null,
                                         SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    } catch (Exception ex) {
      throw new IllegalStateException("Failure initializing default SSL context for Box REST client", ex);
    }
    schemeReg.register(new Scheme("https", socketFactory, 443));
    ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(new BasicHttpParams(), schemeReg);
    this.httpClient = new DefaultHttpClient(connectionManager);
  }

  @Override
  public HttpClient getRawHttpClient() {
    return httpClient;
  }
}

This way the Box SDK works well and can upload multiple file to the user Box.

نصائح أخرى

From the stack trace, this looks like ssl cert not installed. Can you try run both codes(with and without ConnectionManager) on a same machine? Would one fail and one succeed?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top