1 // Copyright 2011 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.api
.conversion
;
5 import com
.google
.appengine
.api
.conversion
.ConversionServicePb
.ConversionOutput
;
6 import com
.google
.appengine
.api
.conversion
.ConversionServicePb
.ConversionRequest
;
7 import com
.google
.appengine
.api
.conversion
.ConversionServicePb
.ConversionResponse
;
8 import com
.google
.appengine
.api
.utils
.FutureWrapper
;
9 import com
.google
.apphosting
.api
.ApiProxy
;
10 import com
.google
.common
.base
.Throwables
;
11 import com
.google
.common
.collect
.Lists
;
13 import java
.io
.IOException
;
14 import java
.util
.Arrays
;
15 import java
.util
.List
;
16 import java
.util
.concurrent
.ExecutionException
;
17 import java
.util
.concurrent
.Future
;
18 import java
.util
.logging
.Logger
;
21 * A {@code ConversionService} which performs conversions by making RPCs to
22 * the backend service.
25 class ConversionServiceImpl
implements ConversionService
{
26 static final String CONVERSION_SERVICE
= "conversion";
28 static final String CONVERT_METHOD
= "Convert";
30 Logger logger
= Logger
.getLogger(getClass().getName());
32 private final ConversionRequestProtoConverter conversionRequestProtoConverter
=
33 new ConversionRequestProtoConverter();
34 private final ConversionResultProtoConverter conversionResultProtoConverter
=
35 new ConversionResultProtoConverter();
38 * The number of seconds allowing conversion request to run,
39 * or null for the default deadline.
40 */ private final Double deadline
;
43 * Constructs a {@link ConversionServiceImpl} with default deadline.
45 ConversionServiceImpl() {
50 * Constructs a {@link ConversionServiceImpl} with specified deadline.
52 ConversionServiceImpl(double deadline
) {
53 this.deadline
= deadline
;
57 public ConversionResult
convert(Conversion conversion
) {
58 List
<ConversionResult
> results
= convert(Arrays
.asList(conversion
));
59 return results
.get(0);
63 public List
<ConversionResult
> convert(List
<Conversion
> conversions
) {
65 return convertAsync(conversions
).get();
66 } catch (ExecutionException e
) {
67 Throwables
.propagateIfInstanceOf(e
.getCause(), ConversionServiceException
.class);
68 throw new ConversionServiceException(ConversionErrorCode
.INTERNAL_ERROR
, e
);
69 } catch (InterruptedException e
) {
70 throw new ConversionServiceException(ConversionErrorCode
.INTERNAL_ERROR
, e
);
75 public Future
<ConversionResult
> convertAsync(Conversion conversion
) {
76 logger
.warning("The Conversion API will be decommissioned in November 2012 "
77 + "and all calls to it will return an error.");
78 final ConversionRequest request
=
79 conversionRequestProtoConverter
.convert(Arrays
.asList(conversion
));
81 Future
<byte[]> responseBytes
= ApiProxy
.makeAsyncCall(
82 CONVERSION_SERVICE
, CONVERT_METHOD
, request
.toByteArray(), createApiConfig(deadline
));
83 return new ConversionFutureWrapper
<byte[], ConversionResult
>(responseBytes
) {
85 protected ConversionResult
wrap(byte[] responseBytes
) throws IOException
{
86 ConversionResponse
.Builder response
= ConversionResponse
.newBuilder()
87 .mergeFrom(responseBytes
);
88 return conversionResultProtoConverter
.reverse(response
.getResultList().get(0));
94 public Future
<List
<ConversionResult
>> convertAsync(List
<Conversion
> conversions
) {
95 logger
.warning("The Conversion API will be decommissioned in November 2012 "
96 + "and all calls to it will return an error.");
97 final ConversionRequest request
=
98 conversionRequestProtoConverter
.convert(conversions
);
100 Future
<byte[]> responseBytes
= ApiProxy
.makeAsyncCall(
101 CONVERSION_SERVICE
, CONVERT_METHOD
, request
.toByteArray(), createApiConfig(deadline
));
102 return new ConversionFutureWrapper
<byte[], List
<ConversionResult
>>(responseBytes
) {
104 protected List
<ConversionResult
> wrap(byte[] responseBytes
) throws IOException
{
105 ConversionResponse
.Builder response
= ConversionResponse
.newBuilder()
106 .mergeFrom(responseBytes
);
107 List
<ConversionResult
> results
= Lists
.newArrayList();
108 for (ConversionOutput result
: response
.getResultList()) {
109 results
.add(conversionResultProtoConverter
.reverse(result
));
117 * Inner FutureWrapper subclass providing our own convertException
120 private abstract static class ConversionFutureWrapper
<K
, V
> extends FutureWrapper
<K
, V
> {
121 ConversionFutureWrapper(Future
<K
> parent
) {
126 protected Throwable
convertException(Throwable cause
) {
127 if (cause
instanceof ApiProxy
.ApplicationException
) {
128 ApiProxy
.ApplicationException e
= (ApiProxy
.ApplicationException
) cause
;
129 return new ConversionServiceException(
130 ConversionErrorCode
.intToEnum(e
.getApplicationError()), e
.getErrorDetail());
131 } else if (cause
instanceof ApiProxy
.ApiDeadlineExceededException
) {
132 return new ConversionServiceException(ConversionErrorCode
.TIMEOUT
, cause
.getMessage());
139 * Creates and returns an ApiConfig instance with deadline setting.
141 private ApiProxy
.ApiConfig
createApiConfig( Double deadline
) {
142 ApiProxy
.ApiConfig apiConfig
= new ApiProxy
.ApiConfig();
143 apiConfig
.setDeadlineInSeconds(deadline
);