I recently started exploring redisson for one of the use-case, where the map should hold string & queue of pojo objects. I tried to add the objects to queue for a particular key but when I'm retrieving it's values, it is giving empty results.
#Autowired
private RedissonClient redissonClient;
private RMapCache<String, Queue<AbstractXXXEvent>> mapCache;
#PostConstruct()
public void init() {
this.mapCache = redissonClient.getMapCache("test8", JsonJacksonCodec.INSTANCE);
}
#PreDestroy
public void cleanup() {
if (Objects.nonNull(redissonClient)) {
redissonClient.shutdown();
}
}
#RestController
class TestController {
#GetMapping("/get")
public Set<Map.Entry<String, Queue<AbstractXXXEvent>>> get() {
return mapCache.entrySet();
}
#PostMapping("/post")
public void post() {
mapCache.put("test", new ConcurrentLinkedQueue<>());
Queue<AbstractXXXEvent> queue = mapCache.get("test");
queue.add(new aXXXEvent().setDescription("compile done"));
queue.add(new bXXXEvent());
queue.add(new cXXXEvent().setDescription("completed"));
}
}
When I do a get request, it is giving the empty result with given key ex: [{"test":[]}]. Kindly provide your suggestions on how to fix this.
You need to put Redisson's RQueue instead of ConcurrentLinkedQueue
Related
I have a conceptual doubt about how to organize and test code like the following, where a call to an auxiliary method is the first instruction of all the public methods of the class. My idea is make the code clean and testable.
The code is an example to try to illustrate this by a class "cache". This class has an optional prefix will be applied to all keys in the cache if it is set.
import java.util.HashMap;
public class Cache {
private HashMap<String, Integer> inMemoryCache;
private String prefix;
public Cache() {
this.inMemoryCache = new HashMap<String, Integer>();
prefix = null;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public int getValue(String key) throws NullPointerException {
String prefixedKey = applyPrefixOrDefault(key);
return inMemoryCache.get(prefixedKey);
}
public void setValue(String key, int value) {
String prefixedKey = applyPrefixOrDefault(key);
inMemoryCache.put(prefixedKey, value);
}
public boolean isCached(String key) {
String prefixedKey = applyPrefixOrDefault(key);
return inMemoryCache.containsKey(prefixedKey);
}
private String applyPrefixOrDefault(String key) {
if (prefix == null) {
return key;
} else {
return prefix + key;
}
}
public static void main (String[] arg) {
Cache cache = new Cache();
cache.setPrefix("global:");
cache.setValue("id", 4);
int value = cache.getValue("id");
System.out.println(value);
}
}
This code poses two questions to me:
If I had many methods accessing the inner hash table, would it be right separate the behavior of the cache in one class and the behavior of the prefix in other?
What would be the cleanest way to test this? Test the getValue, setValue and isCached is simple if we do not consider the prefix. With the prefix we need to test two things, the correct internal behavior of the cache and we need test also that all methods call applyPrefixOrDefault before accessing the data.
This is a common use case and I'm sure there must be some design pattern to organize this. Any idea?
To my opinion, what we miss here is a constructor that let us set the state of the cache. So I would add one as follows:
public Cache() {
this(null, new HashMap<String, Integer>());
}
public Cache(String prefix, Map<String, Integer> cache) {
this.prefix = prefix;
this.inMemoryCache = cache;
}
With this new constructor, you should be able to write test-cases for every possible cache state. I would also change the visibility of the applyPrefixOrDefault method to protected or package so that test code can access it. For instance, to test the GetValue method, I would write:
public class EmptyCacheTests {
private final Map<String, Integer> memory;
private final String prefix;
private final Cache cache;
public EmptyCacheTests() {
this.memory = new HasMap<String, Integer>();
this.prefix = "foo";
this.cache = new Cache(prefix, memory);
}
public void testGetValue() {
String key = this.cache.applyPrefixOrDefault("bar")
this.memory.put(key, 50);
result = this.cache.getValue("bar");
assertEquals(50, result, "The value retrieved is wrong!");
}
}
The point here, it to allow the test to set up the internal state of the cache, so that we can then test against many different ones.
This is my client side code to get the string "get-image-data" through RPC calls and getting byte[] from the server.
CommandMessage msg = new CommandMessage(itemId, "get-image-data");
cmain.ivClient.execute(msg, new AsyncCallback<ResponseMessage>() {
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(ResponseMessage result) {
if (result.result) {
result.data is byte[].
}
}
});
From the server side I got the length of the data is 241336.
But I could not get the value in onSuccess method. It is always goes to onFailure method.
And I got log on Apache:
com.google.gwt.user.client.rpc.SerializationException: Type '[B' was
not included in the set of types which can be serialized by this
SerializationPolicy or its Class object could not be loaded.
How can I do serialisation in GWT?
1) Create a pojo which implements Serializable interface
Let this pojo has all the data you want in the response of RPC service, in this case image-data
2) Pass this pojo in the response for your RPC service.
The below tutorial has enough information for creating RPC service
http://www.gwtproject.org/doc/latest/tutorial/RPC.html
The objects you transfer to and from the server has to implement IsSerializable.
All your custom Objects within the Object you are transferring also needs to implement IsSerializable.
Your objects cannot have final fields and needs an no argument constructor.
You need getters and setters.
A common serialize object in GWT:
public class MyClass implements IsSerializable {
private String txt;
private MyOtherClass myOtherClass; // Also implements IsSerializable
public MyClass() {
}
public String getTxt() {
return this.txt;
}
public void setTxt(String txt) {
return this.txt = txt;
}
public String getMyOtherClass() {
return this.myOtherClass;
}
public void setMyOtherClass(MyOtherClass myOtherClass) {
return this.myOtherClass = myOtherClass;
}
}
I want create a RabbitListener when a property is present, but #ConditionOnProperty cannot combine with #RabbitListener. Now I have a workaround below. Does it exist any better method?
#Bean
#ConditionalOnProperty(name = "pmc.multiple.hypervisor.reply.routerkey.kvm")
public SimpleMessageListenerContainer kvmReplyQueueConsumer() {
return getSimpleMessageListenerContainer(environment
.getProperty("pmc.multiple.hypervisor.reply.routerkey.kvm"));
}
Did you actually try it? This works fine for me...
public static class ConditionalListener {
#RabbitListener(queues="test.queue")
public void listen(String foo) {
System.out.println(foo);
}
}
#ConditionalOnProperty("foo.enabled")
#Bean
public ConditionalListener foo() {
return new ConditionalListener();
}
When run with -Dfoo.enabled=true I get messages; otherwise the bean is not declared.
you can using #Component and #Conditional for a single class
I am learning spring aop now,and I have no idea to pass context arguments to the advice.
Note I mean the context arguments,not the normal arguments.
It is simple to pass the normal arguments,for example:
a join point:
public void read(String something){
}
#Aspect
public class SessionAspect {
#Pointcut("execution(* *.*(String)) &&args(something)")
public void sess() {
}
#Before("sess()")
public void checkSessionExist(String something) {
//Here
}
}
Then the something argument will be passed to the the advice checkSessionExist.
But how about I want to get the context arguments like HttpSession or something else?
a join point:
public void listUser(){
dao.list(User.class,.....);
}
#Aspect
public class SessionAspect {
#Pointcut("execution(* *.*(String))")
public void sess() {
}
#Before("sess()")
public void checkSessionExist(String something) {
//Here
}
}
In this example,the listUser join point is only allowed for logined user.
So I want to check if there is a identify in the current HttpSession,so I need to get an instance of HttpSession at the advice checkSessionExist.
But how to get it?
The simplest way is to add the HttpSession argumets to all the joit points like this:
public void listUser(HttpSession session){
dao.list(User.class,.....);
}
However this have gone against the AOP it self. In my opinion,the join point even does not need to know the exist of the Aspect,isn't it?
How to fix it ?
Instead of passing HttpSession via #Pointcuts, you could fetch HttpSession reference in the #Aspect itself
RequestContextHolder.currentRequestAttributes()
.getAttribute("user", RequestAttributes.SCOPE_SESSION)
#Aspect
public class SessionAspect {
// fetch the current HttpSession attributes and use as required
private ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
#Pointcut("execution(* *.*(String))")
public void sess() {
}
#Before("sess()")
public void checkSessionExist(String something) {
//Here
}
}
I have a service proxy class that makes asyn call to service operation. I use a callback method to pass results back to my view model.
Doing functional testing of view model, I can mock service proxy to ensure methods are called on the proxy, but how can I ensure that callback method is called as well?
With RhinoMocks I can test that events are handled and event raise events on the mocked object, but how can I test callbacks?
ViewModel:
public class MyViewModel
{
public void GetDataAsync()
{
// Use DI framework to get the object
IMyServiceClient myServiceClient = IoC.Resolve<IMyServiceClient>();
myServiceClient.GetData(GetDataAsyncCallback);
}
private void GetDataAsyncCallback(Entity entity, ServiceError error)
{
// do something here...
}
}
ServiceProxy:
public class MyService : ClientBase<IMyService>, IMyServiceClient
{
// Constructor
public NertiAdminServiceClient(string endpointConfigurationName, string remoteAddress)
:
base(endpointConfigurationName, remoteAddress)
{
}
// IMyServiceClient member.
public void GetData(Action<Entity, ServiceError> callback)
{
Channel.BeginGetData(EndGetData, callback);
}
private void EndGetData(IAsyncResult result)
{
Action<Entity, ServiceError> callback =
result.AsyncState as Action<Entity, ServiceError>;
ServiceError error;
Entity results = Channel.EndGetData(out error, result);
if (callback != null)
callback(results, error);
}
}
Thanks
Played around with this a bit and I think I may have what you're looking for. First, I'll display the MSTest code I did to verify this:
[TestClass]
public class UnitTest3
{
private delegate void MakeCallbackDelegate(Action<Entity, ServiceError> callback);
[TestMethod]
public void CallbackIntoViewModel()
{
var service = MockRepository.GenerateStub<IMyServiceClient>();
var model = new MyViewModel(service);
service.Stub(s => s.GetData(null)).Do(
new MakeCallbackDelegate(c => model.GetDataCallback(new Entity(), new ServiceError())));
model.GetDataAsync(null);
}
}
public class MyViewModel
{
private readonly IMyServiceClient client;
public MyViewModel(IMyServiceClient client)
{
this.client = client;
}
public virtual void GetDataAsync(Action<Entity, ServiceError> callback)
{
this.client.GetData(callback);
}
internal void GetDataCallback(Entity entity, ServiceError serviceError)
{
}
}
public interface IMyServiceClient
{
void GetData(Action<Entity, ServiceError> callback);
}
public class Entity
{
}
public class ServiceError
{
}
You'll notice a few things:
I made your callback internal. You'll need to use the InternalsVisisbleTo() attribute so your ViewModel assembly exposes internals to your unit tests (I'm not crazy about this, but it happens in rare cases like this).
I use Rhino.Mocks "Do" to execute the callback whenever the GetData is called. It's not using the callback supplied, but this is really more of an integration test. I assume you've got a ViewModel unit test to make sure that the real callback passed in to GetData is executed at the appropriate time.
Obviously, you'll want to create mock/stub Entity and ServiceError objects instead of just new'ing up like I did.