I have wcf library with service contracts and implementations.
[ServiceContract]
public interface IServiceProtoType
{
[OperationContract]
Response GetMessage(Request request);
[OperationContract]
String SayHello();
}
[DataContract]
public class Request
{
private string name;
[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}
[DataContract]
public class Response
{
private string message;
[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}
public class MyDemoService : IServiceProtoType
{
public Response GetMessage(Request request)
{
var response = new Response();
if (null == request)
{
response.Message = "Error!";
}
else
{
response.Message = "Hello, " + request.Name;
}
return response;
}
public string SayHello()
{
return "Hello, World!";
}
}
I have windows service project that references this library, where MyService is just an empty shell that inherits ServiceBase. This service is installed and running under local system.
static void Main()
{
ServiceBase.Run(CreateContainer().Resolve());
}
private static IWindsorContainer CreateContainer()
{
IWindsorContainer container = new WindsorContainer();
container.Install(FromAssembly.This());
return container;
}
public class ServiceInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
string myDir;
if (string.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath))
{
myDir = AppDomain.CurrentDomain.BaseDirectory;
}
else
{
myDir = AppDomain.CurrentDomain.RelativeSearchPath;
}
var wcfLibPath = Path.Combine(myDir , "WcfDemo.dll");
string baseUrl = "http://localhost:8731/DemoService/{0}";
AssemblyName myAssembly = AssemblyName.GetAssemblyName(wcfLibPath);
container
.Register(
AllTypes
.FromAssemblyNamed(myAssembly.Name)
.InSameNamespaceAs<WcfDemo.MyDemoService>()
.WithServiceDefaultInterfaces()
.Configure(c =>
c.Named(c.Implementation.Name)
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Implementation.Name)
)))), Component.For<ServiceBase>().ImplementedBy<MyService>());
}
#endregion
}
In Client Console app I have the following code and I am getting the following error:
{"Sequence contains no elements"}
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
string baseUrl = "http://localhost:8731/DemoService/{0}";
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
.Configure(
c => c.Named(c.Implementation.Name)
.AsWcfClient(new DefaultClientModel
{
Endpoint = WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Name.Substring(1)))
})));
var service1 = container.Resolve<IServiceProtoType>();
Console.WriteLine(service1.SayHello());
Console.ReadLine();
}
I have an idea what this may be but you can stop reading this now (and I apologize for wasting your time in advance) if the answer to the following is no:
Is one (or more) of Request, Response, or MyDemoService in the same namespace as IServiceProtoType?
I suspect that Windsor is getting confused about those, since you are doing...
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
... and then configuring everything which that returns as a WCF client proxy. This means that it will be trying to create proxies for things that should not be and hence a Sequence Contains no Elements exception (not the most useful message IMHO but crushing on).
The simple fix would be just to put your IServiceProtoType into its own namespace (I often have a namespace like XXXX.Services for my service contracts).
If that is not acceptable to you then you need to work out another way to identify just the service contracts - take a look at the If method for example or just a good ol' Component.For perhaps.
Related
I am new to webservices and also REST. I am trying to send a message as a post request to a rest service using rest java client.I am trying to get response of previous requests also(everything in json format). So, am storing the message objects into an arraylist and sending the list as a reponse. But I am not able to get the previous messages. Please tell me if am doing anything wrong.
This is my message model class.
public class Messages {
private String id;
private String message;
public Messages() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
the following is my webservice to receive a message object and return a json array.
#Path("/json/messages")
public class JSONMessages {
public List<Messages> list = new ArrayList<Messages>();
List<Messages> getAllMessages(Messages m){
list.add(m);
return list;
}
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response MessageListInJSON(Messages msg) {
System.out.println("message saved");
if(!(msg.getId().equals("1"))){
String output ="Invalid User";
return Response.ok(output).build();
}
else{
return Response.ok(getAllMessages(msg)).build();
}
}
}
Finally, the following is my client side code
public class ClientPost {
public static void main(String[] args) {
try {
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client
.resource("http://localhost:8050/lab.rest.webservices/rest/json/messages/post");
//for(int i=0;i<5;i++){
String input = "{\"id\":\"1\", \"message\":\"hey there!\"}";
ClientResponse response = webResource.accept("application/json").type("application/json")
.entity(input).post(ClientResponse.class);
if (response.getStatus() !=200 ) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output+"\n");
}
catch (Exception e) {
e.printStackTrace();
}
} }
Now, what I am expecting to see is the message I sent along with the previous responses stored in the array list(which were sent by running the client multiple times manually for now) but always am ending up with only the current message.
output:
Output from Server ....
[{"id":"1","message":"hey there!"}]
To be precise, what I want as output when i run my client several times(or put the try block in loop) is as follows which i am unable to get.
Output from Server ....
[{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"}] .
Resources in JAXRS aren't singletons. That means that for each request, the class JSONMessages is instantiated. So you lose the content of the attribute list. Changing it to static could fix your problem.
There is an annotation Singleton to change this behavior. In this case the resource will be managed as singleton and not in request scope. Here is a sample:
#Singleton
#Path("/json/messages")
public class JSONMessages {
(...)
}
Otherwise, be careful of concurrent accesses on your list. See this question for more details: java concurrent Array List access.
Hope it helps you,
Thierry
I'm trying to send a complex data type from one process to another using ASP.net MVC. For some reason the receiving end always receives blank (zero/default) data.
My sending side:
static void SendResult(ReportResultModel result)
{
//result contains valid data at this point
string portalRootPath = ConfigurationManager.AppSettings["webHost"];
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(portalRootPath);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage resp = client.PostAsJsonAsync("Reports/MetricEngineReport/MetricResultUpdate", result).Result;
if (!resp.IsSuccessStatusCode) {
//I've confirmed this isn't happening by putting a breakpoint in here.
}
}
My receiving side, in a different class, running in a different process on my local machine:
public class MetricEngineReportController : Controller
{
...
[HttpPost]
public void MetricResultUpdate(ReportResultModel result)
{
//this does get called, but
//all the guids in result are zero here :(
}
...
}
My model is a bit complicated:
[Serializable]
public class ReportResultModel
{
public ReportID reportID {get;set;}
public List<MetricResultModel> Results { get; set; }
}
[Serializable]
public class MetricResultModel
{
public Guid MetricGuid { get; set; }
public int Value { get; set; }
public MetricResultModel(MetricResultModel other)
{
MetricGuid = other.MetricGuid;
Value = other.Value;
}
public MetricResultModel(Guid MetricGuid, int Value)
{
this.MetricGuid = MetricGuid;
this.Value = Value;
}
}
[Serializable]
public struct ReportID
{
public Guid _topologyGuid;
public Guid _matchGuid;
}
Any idea why the data's not arriving?
Any help would be much appreciated...
P.S. For some reason I can't seem to catch the http POST message on fiddler, not sure why that is.
Try using "[FromBody]" parameter in Controller's Action. As you post data is passed to body not in url.
[HttpPost]
public void MetricResultUpdate([FromBody] ReportResultModel result)
{
//this does get called, but
//all the guids in result are zero here :(
}
The problem was twofold:
I needed to specify the type in my JSON post like this:
HttpResponseMessage resp = client.PostAsJsonAsync<MetricResultModel>("Reports/MetricEngineReport/MetricResultUpdate", result.Results[0]).Result;
The components of my model did not have default constructors, which is necessary for the JSON deserialization on the receiving end.
I just had the same problem. It seems that the content-length header is set to 0 when using the default PostAsJsonAsync extension method, which causes the server to ignore the request body.
My solution was to install the System.Net.Http.Json nuget package that uses the new System.Text.Json serializer.
When you add using System.Net.Http.Json;, you should be able to use the new extension method PostAsJsonAsync that works (sets the content-length header) properly.
namespace System.Net.Http.Json
{
public static class HttpClientJsonExtensions
{
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this HttpClient client, string? requestUri, TValue value, CancellationToken cancellationToken)
{
return client.PostAsJsonAsync(requestUri, value, null, cancellationToken);
}
}
}
How to force WCF Rest client to use Json deserializer regardless of content-type?
I am invoking a REST based web service through WCF.
The service returns JSON body, but has content-type "Application/xml". The WCF framework is now giving me the XmlException.
public class MessageFormatter : IClientMessageFormatter
{
private readonly IClientMessageFormatter _formatter;
public MessageFormatter(IClientMessageFormatter formatter)
{
_formatter = formatter;
}
public object DeserializeReply(System.ServiceModel.Channels.Message message, object[] parameters)
{
return _formatter.DeserializeReply(message, parameters);
}
}
that _formatter.DeserializeReply is throwing XmlException. I can't find any example anywhere to force json deserialization on reply.
Edit - The "message" object when moused over is throwing "{... Error reading body: System.Xml.XmlException: The data at the root level is invalid. Line 1, position 1. ...}"
That same object in another one of my project that communicate with a different REST service (Picasa web services) has a what seems like a xml serialised version of JSON object?? So the problem seems further up the stream. I need to find where this object is originating from. I'll go play around with MessageEncoder class.
Edit - (Adding more info)
public class MyBinding : WebHttpBinding
{
public MyBinding(WebHttpSecurityMode mode)
: base(mode)
{
}
public override BindingElementCollection CreateBindingElements()
{
var result = base.CreateBindingElements();
var replacements = result.OfType<MessageEncodingBindingElement>().ToList();
foreach (var messageEncodingBindingElement in replacements)
{
var index = result.IndexOf(messageEncodingBindingElement);
result.Remove(messageEncodingBindingElement);
result.Insert(index, new MyMessageEncodingBindingElement(messageEncodingBindingElement));
}
return result;
}
}
public class MyMessageEncodingBindingElement : MessageEncodingBindingElement
{
private readonly MessageEncodingBindingElement _element;
public MyMessageEncodingBindingElement(MessageEncodingBindingElement element)
{
_element = element;
}
public override BindingElement Clone()
{
var result = _element.Clone();
if (result is MessageEncodingBindingElement)
return new MyMessageEncodingBindingElement(result as MessageEncodingBindingElement);
return result;
}
public override MessageEncoderFactory CreateMessageEncoderFactory()
{
return new MyMessageEncoderFactory(_element.CreateMessageEncoderFactory());
}
}
The method CreateMessageEncoderFactory() is never called even when the constructor and Clone method are hit when breakpoints are set. Any help? I'm trying to set a custom MessageEncoder and MessageEncoderFactory class to modify the instantiation process of the Message object.
You can use a WebContentTypeMapper for that. That's a property of the WebHttpBinding, and you can customize how the deserialization will be done by the encoder from that binding, including forcing it to always use the JSON deserializer, regardless of the incoming message's Content-Type. The code below shows how this can be done.
public class StackOverflow_13225272
{
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
public override string ToString()
{
return string.Format("Person[Name={0},Age={1}]", Name, Age);
}
}
[ServiceContract]
public interface ITest
{
[WebGet(ResponseFormat = WebMessageFormat.Json)]
Person GetPerson(string responseContentType);
}
public class Service : ITest
{
public Person GetPerson(string responseContentType)
{
WebOperationContext.Current.OutgoingResponse.ContentType = responseContentType;
return new Person { Name = "John Doe", Age = 29 };
}
}
class AllJsonContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
return WebContentFormat.Json;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
#if USE_NETFX4
// This works on .NET 4.0 and beyond
WebHttpBinding binding = new WebHttpBinding();
binding.ContentTypeMapper = new AllJsonContentTypeMapper();
#else
// This works on .NET 3.5
CustomBinding binding = new CustomBinding(new WebHttpBinding());
binding.Elements.Find<WebMessageEncodingBindingElement>().ContentTypeMapper = new AllJsonContentTypeMapper();
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(binding, new EndpointAddress(baseAddress));
#endif
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(binding, new EndpointAddress(baseAddress));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
ITest proxy = factory.CreateChannel();
Console.WriteLine("With JSON: {0}", proxy.GetPerson("application/json"));
Console.WriteLine("With XML: {0}", proxy.GetPerson("application/xml"));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
This might work.
public class ForceJsonClientMessageFormatter : IClientMessageFormatter
{
private readonly DataContractJsonSerializer _jsonSerializer;
public ForceJsonClientMessageFormatter(Type responseType)
{
_jsonSerializer = new DataContractJsonSerializer(responseType);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
throw new NotImplementedException("This client message formatter is for replies only!");
}
public object DeserializeReply(Message message, object[] parameters)
{
string messageBody = message.GetBody<string>();
using (MemoryStream messageStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody)))
{
messageStream.Seek(0, SeekOrigin.Begin);
object deserializedObject = _jsonSerializer.ReadObject(messageStream);
return deserializedObject;
}
}
}
public class ForceJsonWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
return new ForceJsonClientMessageFormatter(operationDescription.Messages[1].Body.ReturnValue.Type);
}
}
I haven't tried it, but I think this will work. You can create a custom IClientMessageFormatter which overwrites the message format to Json, wrap that in a behavior, and then apply that behavior to your client endpoint configuration.
public class ForceJsonClientMessageFormatterDecorator : IClientMessageFormatter
{
private readonly IClientMessageFormatter _decoratedFormatter;
public ForceJsonClientMessageFormatterDecorator(IClientMessageFormatter decoratedFormatter)
{
_decoratedFormatter = decoratedFormatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
message.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(WebContentFormat.Json);
return _decoratedFormatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
return _decoratedFormatter.SerializeRequest(messageVersion, parameters);
}
}
public class ForceJsonWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
IClientMessageFormatter decoratedFormatter = base.GetReplyClientFormatter(operationDescription, endpoint);
return new ForceJsonClientMessageFormatterDecorator(decoratedFormatter);
}
}
I'm using Castle Windsor 2.5.3 in an ASP.NET 4.0 Web Application (not ASP.NET MVC)
I have an interceptor which is being used to intercept calls to a data access component. The interceptor depends on a cache manager. The cache manager is used by the interceptor to avoid calling the data access component if the cache manager has the required data.
Even though the cache manager is registered as a Singleton, it is being instantiated multiple times. I can prove this with a debug message or a hit-count breakpoint in its default constructor.
A new requirement is for the cache to be clearable on demand, so I thought it would be a simple matter of resolving the Cache Manager and calling EmptyCache. What is happening is that the container is creating a new instance of the Cache Manager on which the call to EmptyCache has no effect (since the new cache manager has no cached data). Here is the code in the web page for clearing the cache:
protected void flushButton_Click(object sender, EventArgs e)
{
ICacheManager cacheManager = null;
try
{
cacheManager = Global.Container.Resolve<ICacheManager>();
cacheManager.EmptyCache();
resultLabel.Text = "Cache has been flushed";
}
catch (Exception ex)
{
resultLabel.Text = "An error occurred. The reason given was: " + ex.Message;
}
finally
{
if (cacheManager != null)
Global.Container.Release(cacheManager);
}
}
When I hover over the Container in Visual Studio and drill into the Components, the CacheManager is marked as Singleton. How can this be happening?
My Cache Manager is registered like this:
public class WindsorComponentInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For(typeof(Data.Common.Cache.ICacheManager))
.ImplementedBy(typeof(Data.Common.Cache.CacheManager))
.LifeStyle.Singleton
);
container.Register(
Component.For<Data.Common.CachingInterceptor>()
);
}
}
The Cache Manager interface looks like this:
public interface ICacheManager
{
object CacheItem(string cacheKey, DateTime absoluteExpiration, CacheItemPriority priority, Func<object> itemProvider);
object CacheItem(string cacheKey, TimeSpan slidingExpiration, CacheItemPriority priority, Func<object> itemProvider);
void EmptyCache();
}
The interceptor looks like this:
public class CachingInterceptor : IInterceptor
{
private ILogger logger = NullLogger.Instance;
private ICacheManager cacheManager;
public CachingInterceptor(ICacheManager cacheManager)
{
this.cacheManager = cacheManager;
}
public ILogger Logger
{
set
{
if (value != null) logger = value;
}
}
public void Intercept(IInvocation invocation)
{
try
{
string cacheItemKey = MakeCacheItemKey(invocation);
//Debug.WriteLine("Cache Key: {0}", cacheItemKey);
TimeSpan lifespan = TimeSpan.Parse("00:20:00");
bool cacheHit = true;
object result = cacheManager.CacheItem(cacheItemKey, lifespan, CacheItemPriority.Low,
() =>
{
invocation.Proceed();
//Debug.WriteLine(String.Format("populate-the-cache callback was invoked and returned a {0}", invocation.ReturnValue ?? "null"));
cacheHit = false;
return invocation.ReturnValue;
}
);
logger.DebugFormat("Interceptor {0} Cache Hit: {1}", (invocation.Method.Name ?? "null"), cacheHit.ToString());
invocation.ReturnValue = result;
}
catch (Exception ex)
{
logger.Error("Intercept Error", ex);
}
}
private string MakeCacheItemKey(IInvocation invocation)
{
StringBuilder sb = new StringBuilder();
sb.Append(invocation.InvocationTarget);
sb.Append("|" + invocation.MethodInvocationTarget.Name);
sb.Append("|" + invocation.MethodInvocationTarget.ReturnType);
foreach (ParameterInfo pi in invocation.MethodInvocationTarget.GetParameters())
sb.Append("|" + pi.ParameterType.ToString());
foreach (var arg in invocation.Arguments)
{
sb.Append("|");
sb.Append(arg ?? "null");
}
return sb.ToString();
}
}
The data components are registered like this:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
string connStr = ConfigurationManager.ConnectionStrings["Database"].ConnectionString;
container.Register(
Component.For<IActualCostsVersusBudgetDataProvider>()
.ImplementedBy<ActualCostsVersusBudgetDataProvider>()
.DependsOn(Property.ForKey("connectionString").Eq(connStr))
.LifeStyle.Transient
.Interceptors(InterceptorReference.ForType<CachingInterceptor>())
.Anywhere
);
/* Many calls to .Register omitted */
}
The business objects that depend on data providers are registered like this:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
AllTypes.FromThisAssembly()
.Where(t => t.Name.EndsWith("Manager"))
.Configure(c => c.LifeStyle.Transient)
);
}
The container is initialized like this in global.asax:
public static IWindsorContainer Container { get; private set; }
public Global()
{
Container = BootstrapContainer();
}
private IWindsorContainer BootstrapContainer()
{
WindsorContainer container = new WindsorContainer();
container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.Log4net).WithAppConfig());
container.Install(
new Data.Common.Installers.WindsorComponentInstaller(),
new Data.Installers.WindsorComponentInstaller(),
new Business.Installers.WindsorComponentInstaller()
);
return container;
}
I am in the process of rewriting a bottle neck in the code of the project I am on, and in doing so I am creating a top level item that contains a self populating Ehcache. I am attempting to write a test to make sure that the basic call chain is established, but when the test executes it hands when retrieving the item from the cache.
Here are the Setup and the test, for reference mocking is being done with Mockito:
#Before
public void SetUp()
{
testCache = new Cache(getTestCacheConfiguration());
recordingFactory = new EntryCreationRecordingCache();
service = new Service<Request, Response>(testCache, recordingFactory);
}
#Test
public void retrievesResultsFromSuppliedCache()
{
ResultType resultType = mock(ResultType.class);
Response expectedResponse = mock(Response.class);
addToExpectedResults(resultType, expectedResponse);
Request request = mock(Request.class);
when(request.getResultType()).thenReturn(resultType);
assertThat(service.getResponse(request), sameInstance(expectedResponse));
assertTrue(recordingFactory.requestList.contains(request));
}
private void addToExpectedResults(ResultType resultType,
Response response) {
recordingFactory.responseMap.put(resultType, response);
}
private CacheConfiguration getTestCacheConfiguration() {
CacheConfiguration cacheConfiguration = new CacheConfiguration("TEST_CACHE", 10);
cacheConfiguration.setLoggingEnabled(false);
return cacheConfiguration;
}
private class EntryCreationRecordingCache extends ResponseFactory{
public final Map<ResultType, Response> responseMap = new ConcurrentHashMap<ResultType, Response>();
public final List<Request> requestList = new ArrayList<Request>();
#Override
protected Map<ResultType, Response> generateResponse(Request request) {
requestList.add(request);
return responseMap;
}
}
Here is the ServiceClass
public class Service<K extends Request, V extends Response> {
private Ehcache cache;
public Service(Ehcache cache, ResponseFactory factory) {
this.cache = new SelfPopulatingCache(cache, factory);
}
#SuppressWarnings("unchecked")
public V getResponse(K request)
{
ResultType resultType = request.getResultType();
Element cacheEntry = cache.get(request);
V response = null;
if(cacheEntry != null){
Map<ResultType, Response> resultTypeMap = (Map<ResultType, Response>) cacheEntry.getValue();
try{
response = (V) resultTypeMap.get(resultType);
}catch(NullPointerException e){
throw new RuntimeException("Result type not found for Result Type: " + resultType);
}catch(ClassCastException e){
throw new RuntimeException("Incorrect Response Type for Result Type: " + resultType);
}
}
return response;
}
}
And here is the ResponseFactory:
public abstract class ResponseFactory implements CacheEntryFactory{
#Override
public final Object createEntry(Object request) throws Exception {
return generateResponse((Request)request);
}
protected abstract Map<ResultType,Response> generateResponse(Request request);
}
After wrestling with it for a while, I discovered that the cache wasn't being initialized. Creating a CacheManager and adding the cache to it resolved the problem.
I also had a problem with EHCache hanging, although only in a hello-world example. Adding this to the end fixed it (the application ends normally).
CacheManager.getInstance().removeAllCaches();
https://stackoverflow.com/a/20731502/2736496