I use Spring Rest Docs in version 1.1.2.RELEASE
The Test
MvcResult result = this.mockMvc.perform(get("/api").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andDo(document("index"))
.andReturn();
The API
#RequestMapping(value = "/api")
public ResponseEntity<String> apiWelcome() {
final HttpHeaders httpHeaders= new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<String>("{\"api\": \"test1\"}", httpHeaders, HttpStatus.OK);
}
When I run the application I can access "/api" in the browser and get the expected {"api": "test1"} response.
But if I run the test I get the following log entries:
c.i.crawler.testnet.measure.RestDocsTest INFO Started RestDocsTest in 2.96 seconds
o.s.web.servlet.PageNotFound WARN No mapping found for HTTP request with URI [/api] in DispatcherServlet with name '' [main]
and the test fails because of HTTP/1.1 404 Not Found.
What am I doing wrong?
Application start
#SpringBootApplication
#Configuration
#EnableConfigurationProperties
#EnableAutoConfiguration
#ComponentScan(basePackageClasses = { SomeController.class })
public class AppRUN {
public static void main(String[] args) {
SpringApplication.run(AppRUN.class, args);
}
}
My test class was annotated as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=RestDocsTest.class)
#WebAppConfiguration
Changing the annotations to the following removes the error:
#RunWith(SpringRunner.class)
#SpringBootTest
Related
I have developed asynchronous Spring Cloud Stream services, and I am trying to develop an edge service that uses #MessagingGateway to provide synchronous access to services that are async by nature.
I am currently getting the following stack trace:
Caused by: org.springframework.messaging.core.DestinationResolutionException: no output-channel or replyChannel header available
at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:355)
at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:271)
at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:188)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:115)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
... 47 common frames omitted
My #MessagingGateway:
#EnableBinding(AccountChannels.class)
#MessagingGateway
public interface AccountService {
#Gateway(requestChannel = AccountChannels.CREATE_ACCOUNT_REQUEST,replyChannel = AccountChannels.ACCOUNT_CREATED, replyTimeout = 60000, requestTimeout = 60000)
Account createAccount(#Payload Account account, #Header("Authorization") String authorization);
}
If I consume the message on the reply channel via a #StreamListener, it works just fine:
#HystrixCommand(commandKey = "acounts-edge:accountCreated", fallbackMethod = "accountCreatedFallback", commandProperties = {#HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE")}, ignoreExceptions = {ClientException.class})
#StreamListener(AccountChannels.ACCOUNT_CREATED)
public void accountCreated(Account account, #Header(name = "spanTraceId", required = false) String traceId) {
try {
if (log.isInfoEnabled()) {
log.info(new StringBuilder("Account created: ").append(objectMapper.writeValueAsString(account)).toString());
}
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
}
}
On the producer side, I am configuring requiredGroups to ensure that multiple consumers can process the message, and correspondingly, the consumers have matching group configurations.
Consumer:
spring:
cloud:
stream:
bindings:
create-account-request:
binder: rabbit1
contentType: application/json
destination: create-account-request
requiredGroups: accounts-service-create-account-request
account-created:
binder: rabbit1
contentType: application/json
destination: account-created
group: accounts-edge-account-created
Producer:
spring:
cloud:
stream:
bindings:
create-account-request:
binder: rabbit1
contentType: application/json
destination: create-account-request
group: accounts-service-create-account-request
account-created:
binder: rabbit1
contentType: application/json
destination: account-created
requiredGroups: accounts-edge-account-created
The bit of code on the producer side that processes the request and sends the response:
accountChannels.accountCreated().send(MessageBuilder.withPayload(accountService.createAccount(account)).build());
I can debug and see that the request is received and processed, but when the response is sent to the reply channel, that's when the error occurs.
To get the #MessagingGateway working, what configurations and/or code am I missing? I know I'm combining Spring Integration and Spring Cloud Gateway, so I'm not sure if using them together is causing the issues.
It's good question and really good idea. But it isn't going to work so easy.
First of all we have to determine for ourselves that gateway means request/reply, therefore correlation. And this available in #MessagingGateway via replyChannel header in face of TemporaryReplyChannel instance. Even if you have an explicit replyChannel = AccountChannels.ACCOUNT_CREATED, the correlation is done only via the mentioned header and its value. The fact that this TemporaryReplyChannel is not serializable and can't be transferred over the network to the consumer on another side.
Luckily Spring Integration provide some solution for us. It is a part of the HeaderEnricher and its headerChannelsToString option behind HeaderChannelRegistry:
Starting with Spring Integration 3.0, a new sub-element <int:header-channels-to-string/> is available; it has no attributes. This converts existing replyChannel and errorChannel headers (when they are a MessageChannel) to a String and stores the channel(s) in a registry for later resolution when it is time to send a reply, or handle an error. This is useful for cases where the headers might be lost; for example when serializing a message into a message store or when transporting the message over JMS. If the header does not already exist, or it is not a MessageChannel, no changes are made.
https://docs.spring.io/spring-integration/docs/5.0.0.RELEASE/reference/html/messaging-transformation-chapter.html#header-enricher
But in this case you have to introduce an internal channel from the gateway to the HeaderEnricher and only the last one will send the message to the AccountChannels.CREATE_ACCOUNT_REQUEST. So, the replyChannel header will be converted to a string representation and be able to travel over the network. On the consumer side when you send a reply you should ensure that you transfer that replyChannel header as well, as it is. So, when the message will arrive to the AccountChannels.ACCOUNT_CREATED on the producer side, where we have that #MessagingGateway, the correlation mechanism is able to convert a channel identificator to the proper TemporaryReplyChannel and correlate the reply to the waiting gateway call.
Only the problem here that your producer application must be as single consumer in the group for the AccountChannels.ACCOUNT_CREATED - we have to ensure that only one instance in the cloud is operating at a time. Just because only one instance has that TemporaryReplyChannel in its memory.
More info about gateway: https://docs.spring.io/spring-integration/docs/5.0.0.RELEASE/reference/html/messaging-endpoints-chapter.html#gateway
UPDATE
Some code for help:
#EnableBinding(AccountChannels.class)
#MessagingGateway
public interface AccountService {
#Gateway(requestChannel = AccountChannels.INTERNAL_CREATE_ACCOUNT_REQUEST, replyChannel = AccountChannels.ACCOUNT_CREATED, replyTimeout = 60000, requestTimeout = 60000)
Account createAccount(#Payload Account account, #Header("Authorization") String authorization);
}
#Bean
public IntegrationFlow headerEnricherFlow() {
return IntegrationFlows.from(AccountChannels.INTERNAL_CREATE_ACCOUNT_REQUEST)
.enrichHeaders(headerEnricher -> headerEnricher.headerChannelsToString())
.channel(AccountChannels.CREATE_ACCOUNT_REQUEST)
.get();
}
UPDATE
Some simple application to demonstrate the PoC:
#EnableBinding({ Processor.class, CloudStreamGatewayApplication.GatewayChannels.class })
#SpringBootApplication
public class CloudStreamGatewayApplication {
interface GatewayChannels {
String REQUEST = "request";
#Output(REQUEST)
MessageChannel request();
String REPLY = "reply";
#Input(REPLY)
SubscribableChannel reply();
}
private static final String ENRICH = "enrich";
#MessagingGateway
public interface StreamGateway {
#Gateway(requestChannel = ENRICH, replyChannel = GatewayChannels.REPLY)
String process(String payload);
}
#Bean
public IntegrationFlow headerEnricherFlow() {
return IntegrationFlows.from(ENRICH)
.enrichHeaders(HeaderEnricherSpec::headerChannelsToString)
.channel(GatewayChannels.REQUEST)
.get();
}
#StreamListener(Processor.INPUT)
#SendTo(Processor.OUTPUT)
public Message<?> process(Message<String> request) {
return MessageBuilder.withPayload(request.getPayload().toUpperCase())
.copyHeaders(request.getHeaders())
.build();
}
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext =
SpringApplication.run(CloudStreamGatewayApplication.class, args);
StreamGateway gateway = applicationContext.getBean(StreamGateway.class);
String result = gateway.process("foo");
System.out.println(result);
}
}
The application.yml:
spring:
cloud:
stream:
bindings:
input:
destination: requests
output:
destination: replies
request:
destination: requests
reply:
destination: replies
I use spring-cloud-starter-stream-rabbit.
The
MessageBuilder.withPayload(request.getPayload().toUpperCase())
.copyHeaders(request.getHeaders())
.build()
Does the trick copying request headers to the reply message. So, the gateway is able on the reply side to convert channel identifier in the headers to the appropriate TemporaryReplyChannel to convey the reply properly to the caller of gateway.
The SCSt issue on the matter: https://github.com/spring-cloud/spring-cloud-stream/issues/815
With Artem's help, I've found the solution I was looking for. I have taken the code Artem posted and split it into two services, a Gateway service and a CloudStream service. I also added a #RestController for testing purposes. This essentially mimics what I was wanting to do with durable queues. Thanks Artem for your assistance! I really appreciate your time! I hope this helps others who want to do the same thing.
Gateway Code
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.dsl.HeaderEnricherSpec;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
#EnableBinding({GatewayApplication.GatewayChannels.class})
#SpringBootApplication
public class GatewayApplication {
interface GatewayChannels {
String TO_UPPERCASE_REPLY = "to-uppercase-reply";
String TO_UPPERCASE_REQUEST = "to-uppercase-request";
#Input(TO_UPPERCASE_REPLY)
SubscribableChannel toUppercaseReply();
#Output(TO_UPPERCASE_REQUEST)
MessageChannel toUppercaseRequest();
}
#MessagingGateway
public interface StreamGateway {
#Gateway(requestChannel = ENRICH, replyChannel = GatewayChannels.TO_UPPERCASE_REPLY)
String process(String payload);
}
private static final String ENRICH = "enrich";
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
#Bean
public IntegrationFlow headerEnricherFlow() {
return IntegrationFlows.from(ENRICH).enrichHeaders(HeaderEnricherSpec::headerChannelsToString)
.channel(GatewayChannels.TO_UPPERCASE_REQUEST).get();
}
#RestController
public class UppercaseController {
#Autowired
StreamGateway gateway;
#GetMapping(value = "/string/{string}",
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<String> getUser(#PathVariable("string") String string) {
return new ResponseEntity<String>(gateway.process(string), HttpStatus.OK);
}
}
}
Gateway Config (application.yml)
spring:
cloud:
stream:
bindings:
to-uppercase-request:
destination: to-uppercase-request
producer:
required-groups: stream-to-uppercase-request
to-uppercase-reply:
destination: to-uppercase-reply
group: gateway-to-uppercase-reply
server:
port: 8080
CloudStream Code
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.support.MessageBuilder;
#EnableBinding({CloudStreamApplication.CloudStreamChannels.class})
#SpringBootApplication
public class CloudStreamApplication {
interface CloudStreamChannels {
String TO_UPPERCASE_REPLY = "to-uppercase-reply";
String TO_UPPERCASE_REQUEST = "to-uppercase-request";
#Output(TO_UPPERCASE_REPLY)
SubscribableChannel toUppercaseReply();
#Input(TO_UPPERCASE_REQUEST)
MessageChannel toUppercaseRequest();
}
public static void main(String[] args) {
SpringApplication.run(CloudStreamApplication.class, args);
}
#StreamListener(CloudStreamChannels.TO_UPPERCASE_REQUEST)
#SendTo(CloudStreamChannels.TO_UPPERCASE_REPLY)
public Message<?> process(Message<String> request) {
return MessageBuilder.withPayload(request.getPayload().toUpperCase())
.copyHeaders(request.getHeaders()).build();
}
}
CloudStream Config (application.yml)
spring:
cloud:
stream:
bindings:
to-uppercase-request:
destination: to-uppercase-request
group: stream-to-uppercase-request
to-uppercase-reply:
destination: to-uppercase-reply
producer:
required-groups: gateway-to-uppercase-reply
server:
port: 8081
Hmm, I am a bit confused as well as to what you are trying to accomplish, but let's se if we can figure this out.
Mixing SI and SCSt is definitely natural as one builds on another so all should work:
Here is an example code snippet I just dug up from an old sample that exposes REST endpoint yet delegates (via Gateway) to Source's output channel. See if that helps:
#EnableBinding(Source.class)
#SpringBootApplication
#RestController
public class FooApplication {
. . .
#Autowired
private Source channels;
#Autowired
private CompletionService completionService;
#RequestMapping("/complete")
public String completeRequest(#RequestParam int id) {
this.completionService.complete("foo");
return "OK";
}
#MessagingGateway
interface CompletionService {
#Gateway(requestChannel = Source.OUTPUT)
void complete(String message);
}
}
Hi I Have Created a Custom Service to Save Custom objects and using existing objects but after running the application the following error will be displaying in server console and stops the application to start
Here is my code for custom service :
#Service
public class FilterExtra {
// #Autowired
#Resource(name="org.broadleafcommerce.core.search.domain.FieldImpl")
FieldImpl f;
// #Autowired
#Resource(name="org.broadleafcommerce.core.catalog.domain.Product")
Product p;
public static String nme="";
#PersistenceContext(unitName = "blPU")
public EntityManager em;
ProductAttribute pa;
#SuppressWarnings("unchecked")
public String check1(String name) {
Query q=em.createQuery("SELECT * FROM PRODUCT_ATTRIBUTE WHERE NAME=:name");
q.setParameter("name", name);
List<ProductAttribute> inf0 = q.getResultList();
System.out.println(inf0);
if(inf0!=null)
{
f.setFriendlyName(name);
f.setAbbreviation(name);
f.setEntityType(p.getFieldEntityType());
f.setPropertyName("productAttributes("+name+").value");
em.merge(f);
}
if(name.equals(nme))
{
return name;
}
else {
return null;
}
}
}
here is my XML file:
screen shot of xml file:
http://i.prntscr.com/wkVH2q8MQBmAeJ26BfEvZw.png
here is server log for error:
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-11-23 09:59:43.881 ERROR 3827 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
APPLICATION FAILED TO START
Description:
A component required a bean named 'org.broadleafcommerce.core.search.domain.FieldImpl' that could not be found.
Action:
Consider defining a bean named 'org.broadleafcommerce.core.search.domain.FieldImpl' in your configuration.
Please Help me to Solve the issue
Thanks in Advance
I am a newbie to java servlet filters and I have a CXF web service A.
The address of A is: http://localhost:8080/AdditionWS/services/additioncls?wsdl
I want to implement a proxy web service B.
The address of B is:
http://localhost:8080/ForwardWS/services/ForwardClsPort?wsdl
To forward the requests to A through B, I added a servlet filter to B:
public class RequestFilter implements Filter {
public void doFilter(final ServletRequest request, final ServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
String redirect="http://localhost:8080/AdditionWS/services/additioncls";
Enumeration<String> enumeration=request.getParameterNames();
String parameter=null;
while(enumeration.hasMoreElements())
{
parameter=enumeration.nextElement();
if(parameter.toLowerCase()=="wsdl")
break;
}
// if the parameter 'wsdl' exists forward to http://localhost:8080/AdditionWS/services/additioncls?wsdl
if(parameter!=null)
redirect="http://localhost:8080/AdditionWS/services/additioncls?"+"wsdl";
redirect=resp.encodeRedirectURL(redirect);
resp.sendRedirect(redirect);
}
}
and I updated the web address at the client code like the following:
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.Service;
//before:
wsdlLocation=http://localhost:8080/AdditionWS/services/additioncls?wsdl
#WebServiceClient(name = "AdditionClsService",
wsdlLocation = "http://localhost:8080/ForwardWS/services/ForwardClsPort?wsdl",
targetNamespace = "http://logic/")
public class AdditionClsService extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://logic/", "AdditionClsService");
public final static QName AdditionClsPort = new QName("http://logic/", "AdditionClsPort");
static {
URL url = null;
try {
// before url=new URL("http://localhost:8080/AdditionWS/services/additioncls?wsdl");
url = new URL("http://localhost:8080/ForwardWS/services/ForwardClsPort?wsdl");
} catch (MalformedURLException e) {
java.util.logging.Logger.getLogger(AdditionClsService.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "http://localhost:8080/AdditionWS/services/additioncls?wsdl");
}
WSDL_LOCATION = url;
}
public AdditionClsService(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public AdditionClsService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public AdditionClsService() {
super(WSDL_LOCATION, SERVICE);
}
public AdditionClsService(WebServiceFeature ... features) {
super(WSDL_LOCATION, SERVICE, features);
}
public AdditionClsService(URL wsdlLocation, WebServiceFeature ... features) {
super(wsdlLocation, SERVICE, features);
}
public AdditionClsService(URL wsdlLocation, QName serviceName, WebServiceFeature ... features) {
super(wsdlLocation, serviceName, features);
}
/**
*
* #return
* returns AdditionWSSEI
*/
#WebEndpoint(name = "AdditionClsPort")
public AdditionWSSEI getAdditionClsPort() {
return super.getPort(AdditionClsPort, AdditionWSSEI.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns AdditionWSSEI
*/
#WebEndpoint(name = "AdditionClsPort")
public AdditionWSSEI getAdditionClsPort(WebServiceFeature... features) {
return super.getPort(AdditionClsPort, AdditionWSSEI.class, features);
}
}
For some reason, the client requests are not forwarded to A and I got the following errors:
Exception in thread "main" javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service.
at org.apache.cxf.jaxws.ServiceImpl.initialize(ServiceImpl.java:162)
at org.apache.cxf.jaxws.ServiceImpl.<init>(ServiceImpl.java:129)
at org.apache.cxf.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:82)
at javax.xml.ws.Service.<init>(Service.java:77)
at business.AdditionClsService.<init>(AdditionClsService.java:43)
at business.AdditionWSSEI_AdditionClsPort_Client.main(AdditionWSSEI_AdditionClsPort_Client.java:49)
Caused by: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service.
at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:87)
at org.apache.cxf.jaxws.ServiceImpl.initializePorts(ServiceImpl.java:217)
at org.apache.cxf.jaxws.ServiceImpl.initialize(ServiceImpl.java:160)
... 5 more
Caused by: javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR: com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog
at [row,col,system-id]: [1,0,"http://localhost:8080/ForwardWS/services/ForwardClsPort?wsdl"]
at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:228)
at org.apache.cxf.wsdl11.WSDLManagerImpl.getDefinition(WSDLManagerImpl.java:163)
at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:85)
... 7 more
Caused by: com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog
at [row,col,system-id]: [1,0,"http://localhost:8080/ForwardWS/services/ForwardClsPort?wsdl"]
at com.ctc.wstx.sr.StreamScanner.throwUnexpectedEOF(StreamScanner.java:685)
at com.ctc.wstx.sr.BasicStreamReader.handleEOF(BasicStreamReader.java:2141)
at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:2047)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1131)
at org.apache.cxf.staxutils.StaxUtils.readDocElements(StaxUtils.java:1369)
at org.apache.cxf.staxutils.StaxUtils.readDocElements(StaxUtils.java:1263)
at org.apache.cxf.staxutils.StaxUtils.read(StaxUtils.java:1191)
at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:219)
... 9 more
Did I miss something or is there a different way to implement a proxy cxf web service that will forward client requests to A or one of its duplicates?
Thank you!
I downloaded the android-async-http-1.4.8.jar and put it under the app->libs folder. Then add the following code in the MainActivity.
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onStart() {
// called before request is started
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// called when response HTTP status is "200 OK"
textViewDailyTip.setText(response.toString());
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
}
#Override
public void onRetry(int retryNo) {
// called when request is retried
}
});
but I got the error.
Error:(50, 9) error: cannot access AsyncHttpClient
bad class file: /Users/user/AndroidStudioProjects/yan.com/Yin/app/libs/android-async-http-1.4.8.jar(com/loopj/android/http/AsyncHttpClient.class)
unable to access file: null
Please remove or make sure it appears in the correct subdirectory of the classpath.
Add dependency in the build.gradle file under app:
dependencies {
compile 'com.loopj.android:android-async-http:1.4.9'
}
taken from: Installation & Basic Usage
If it didn't work, try executing the following command:
gradlew installarchives
It should also work without downloading the jar file.
Another note is that I am using version 1.4.5.
Good luck!
I am receiving an error when using NServiceBus 4.0.3 with NHibernate 3.3.1 when it's trying to process a message
INFO NServiceBus.Unicast.Transport.TransportReceiver [(null)] <(null)> - Failed to process message
Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'NServiceBus.Impersonation.ExtractIncomingPrincipal' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Unicast\Transport\TransportReceiver.cs:line 353
at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message) in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Unicast\Transport\TransportReceiver.cs:line 233
at NServiceBus.Transports.Msmq.MsmqDequeueStrategy.ProcessMessage(TransportMessage message) in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Transports\Msmq\MsmqDequeueStrategy.cs:line 262
at NServiceBus.Transports.Msmq.MsmqDequeueStrategy.Action() in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Transports\Msmq\MsmqDequeueStrategy.cs:line 197
2013-08-30 09:35:02,508 [9] WARN NServiceBus.Faults.Forwarder.FaultManager [(null)] <(null)> - Message has failed FLR and will be handed over to SLR for retry attempt: 1, MessageID=8aaed043-b744-49c2-965d-a22a009deb32.
I think it's fairly obvious what that I need to implement or register an "ExtractIncomingPrincipal", but I can't seem to find any documentation on how or whether there is a default one that I can use. I wouldn't have figured that I would have had to register any of the NServiceBus-related services as many of them are already being registered in my IoC implementation.
As requested, here is the EndpointConfig and supporting code I have currently:
[EndpointSLA("00:00:30")]
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization {
public void Init() {
Configure.With().ObjectBuilderAdapter().UseInMemoryTimeoutPersister().UseInMemoryGatewayPersister().InMemorySagaPersister().InMemorySubscriptionStorage();
}
}
//public class PrincipalExtractor : ExtractIncomingPrincipal {
// public IPrincipal GetPrincipal(TransportMessage message) {
// return Thread.CurrentPrincipal;
// }
//}
public class ObjectBuilderAdapter : IContainer {
readonly IDependencyInjector injector;
public ObjectBuilderAdapter(IDependencyInjectionBuilder dependencyInjectionBuilder) {
injector = dependencyInjectionBuilder.Create(); //This method does all the common service registrations that I am trying to re-use
//injector.RegisterType<ExtractIncomingPrincipal, PrincipalExtractor>();
}
public void Dispose() {
injector.Dispose();
}
public object Build(Type typeToBuild) {
return injector.Resolve(typeToBuild);
}
public IContainer BuildChildContainer() {
return new ObjectBuilderAdapter(new DependencyInjectorBuilder());
}
public IEnumerable<object> BuildAll(Type typeToBuild) {
return injector.ResolveAll(typeToBuild);
}
public void Configure(Type component, DependencyLifecycle dependencyLifecycle) {
injector.RegisterType(component);
}
public void Configure<T>(Func<T> component, DependencyLifecycle dependencyLifecycle) {
injector.RegisterType(component);
}
public void ConfigureProperty(Type component, string property, object value) {
if (injector is AutofacDependencyInjector) {
((AutofacDependencyInjector)injector).ConfigureProperty(component, property, value);
} else {
Debug.WriteLine("Configuring {0} for property {1} but we don't handle this scenario.", component.Name, property);
}
}
public void RegisterSingleton(Type lookupType, object instance) {
injector.RegisterInstance(lookupType, instance);
}
public bool HasComponent(Type componentType) {
return injector.IsRegistered(componentType);
}
public void Release(object instance) { }
}
public static class Extensions {
public static Configure ObjectBuilderAdapter(this Configure config) {
ConfigureCommon.With(config, new ObjectBuilderAdapter(new DependencyInjectorBuilder()));
return config;
}
}
I removed the IWantCustomInitialization (left over from something else I had tried earlier) interface implementation on the class and my service now processes the message. There are errors still (relating to trying to connect to Raven [even though I thought I am using everything in-memory), but it's processing the message.