It seems that the MapStore (write-behind mode) does not work properly when replacing some map items.
I expected that map items which have been replaced, are not processed anymore.
I am using Hazelcast 3.2.5
Did i miss something here?
Please see Server Test Class, Client Test Class and Output as well to demonstrate the problem.
Server Class:
public class HazelcastInstanceTest {
public static void main(String[] args) {
Config cfg = new Config();
MapConfig mapConfig = new MapConfig();
MapStoreConfig mapStoreConfig = new MapStoreConfig();
mapStoreConfig.setEnabled(true);
mapStoreConfig.setClassName("com.test.TestMapStore");
mapStoreConfig.setWriteDelaySeconds(15);
mapConfig.setMapStoreConfig(mapStoreConfig);
mapConfig.setName("customers");
cfg.addMapConfig(mapConfig);
HazelcastInstance instance = Hazelcast.newHazelcastInstance(cfg);
}
}
MapStore Impl Class
public class TestMapStore implements MapStore {
#Override
public Object load(Object arg0) {
System.out.println("--> LOAD");
return null;
}
#Override
public Map loadAll(Collection arg0) {
System.out.println("--> LOAD ALL");
return null;
}
#Override
public Set loadAllKeys() {
System.out.println("--> LOAD ALL KEYS");
return null;
}
#Override
public void delete(Object arg0) {
System.out.println("--> DELETE");
}
#Override
public void deleteAll(Collection arg0) {
System.out.println("--> DELETE ALL");
}
#Override
public void store(Object arg0, Object arg1) {
System.out.println("--> STORE " + arg1.toString());
}
#Override
public void storeAll(Map arg0) {
System.out.println("--> STORE ALL");
}
}
Client Class
public class HazelcastClientTest {
public static void main(String[] args) throws Exception {
ClientConfig clientConfig = new ClientConfig();
HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig);
IMap mapCustomers = client.getMap("customers");
System.out.println("Map Size:" + mapCustomers.size());
mapCustomers.put(1, "Item A");
mapCustomers.replace(1, "Item B");
mapCustomers.replace(1, "Item C");
System.out.println("Map Size:" + mapCustomers.size());
}
}
Client Output (which is ok):
Map Size:0
Map Size:1
Server Output (which is not ok, as i suppose. I expected only item C)
--> LOAD ALL KEYS
--> LOAD
--> STORE Item A
--> STORE ALL
--> STORE Item B
--> STORE Item C
Any help is appreciate.
Many thanks
Related
This is my source,how can i print message if some of the members is shut down for some reason?I think i can some event or some kind of action listener but how...
import com.hazelcast.core.*;
import com.hazelcast.config.*;
import java.util.Map;
/** * * #author alvel */ public class ShutDown {
public static void main(String[] args) {
Config cfg = new Config();
HazelcastInstance memberOne = Hazelcast.newHazelcastInstance(cfg);
HazelcastInstance memberTwo = Hazelcast.newHazelcastInstance(cfg);
Map<Integer, String> customerMap = memberOne.getMap("customers");
customerMap.put(1, "google");
customerMap.put(2, "apple");
customerMap.put(3, "yahoo");
customerMap.put(4, "microsoft");
System.out.println("Hazelcast Nodes in this cluster"+Hazelcast.getAllHazelcastInstances().size());
memberOne.shutdown();
System.out.println("Hazelcast Nodes in this cluster After shutdown"+Hazelcast.getAllHazelcastInstances().size());
Map<Integer, String> customerRestored = memberTwo.getMap("customers");
for(String val:customerRestored.values()){
System.out.println("-"+val);
}
} }
Try this, it adds a few lines into your code and a new class
public class ShutDown {
static {
// ONLY TEMPORARY
System.setProperty("hazelcast.logging.type", "none");
}
public static void main(String[] args) {
Config cfg = new Config();
HazelcastInstance memberOne = Hazelcast.newHazelcastInstance(cfg);
//ADDED TO MEMBER ONE
memberOne.getCluster().addMembershipListener(new ShutDownMembershipListener());
HazelcastInstance memberTwo = Hazelcast.newHazelcastInstance(cfg);
//ADDED TO MEMBER TWO
memberTwo.getCluster().addMembershipListener(new ShutDownMembershipListener());
Map<Integer, String> customerMap = memberOne.getMap("customers");
customerMap.put(1, "google");
customerMap.put(2, "apple");
customerMap.put(3, "yahoo");
customerMap.put(4, "microsoft");
System.out.println("Hazelcast Nodes in this cluster"+Hazelcast.getAllHazelcastInstances().size());
memberOne.shutdown();
System.out.println("Hazelcast Nodes in this cluster After shutdown"+Hazelcast.getAllHazelcastInstances().size());
Map<Integer, String> customerRestored = memberTwo.getMap("customers");
for(String val:customerRestored.values()){
System.out.println("-"+val);
}
}
static class ShutDownMembershipListener implements MembershipListener {
#Override
public void memberAdded(MembershipEvent membershipEvent) {
System.out.println(this + membershipEvent.toString());
}
#Override
public void memberAttributeChanged(MemberAttributeEvent arg0) {
}
#Override
public void memberRemoved(MembershipEvent membershipEvent) {
System.out.println(this + membershipEvent.toString());
}
}
}
The line System.setProperty("hazelcast.logging.type", "none") is just for testing to make it simpler to see what is happening.
Android Studio 2.3
I have the following method I want to test inside my model class:
public class RecipeListModelImp implements RecipeListModelContract {
private Subscription subscription;
private RecipesAPI recipesAPI;
private RecipeSchedulers recipeSchedulers;
#Inject
public RecipeListModelImp(#NonNull RecipesAPI recipesAPI, #NonNull RecipeSchedulers recipeSchedulers) {
this.recipesAPI = Preconditions.checkNotNull(recipesAPI);
this.recipeSchedulers = Preconditions.checkNotNull(recipeSchedulers);
}
#Override
public void getRecipesFromAPI(final RecipeGetAllListener recipeGetAllListener) {
subscription = recipesAPI.getAllRecipes()
.subscribeOn(recipeSchedulers.getBackgroundScheduler())
.observeOn(recipeSchedulers.getUIScheduler())
.subscribe(new Subscriber<List<Recipe>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
recipeGetAllListener.onRecipeGetAllFailure(e.getMessage());
}
#Override
public void onNext(List<Recipe> recipe) {
recipeGetAllListener.onRecipeGetAllSuccess(recipe);
}
});
}
#Override
public void shutdown() {
if(subscription != null && !subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
}
}
Inside my test class I am testing like this:
public class RecipeListModelImpTest {
#Mock Subscription subscription;
#Mock RecipesAPI recipesAPI;
#Mock RecipeListModelContract.RecipeGetAllListener recipeGetAllListener;
#Mock List<Recipe> recipes;
#Inject RecipeSchedulers recipeSchedulers;
private RecipeListModelContract recipeListModel;
#Before
public void setup() {
TestBusbyComponent testBusbyComponent = DaggerTestBusbyComponent.builder()
.mockRecipeSchedulersModule(new MockRecipeSchedulersModule())
.build();
testBusbyComponent.inject(RecipeListModelImpTest.this);
MockitoAnnotations.initMocks(RecipeListModelImpTest.this);
recipeListModel = new RecipeListModelImp(recipesAPI, recipeSchedulers);
}
#Test(expected = NullPointerException.class)
public void testShouldThrowExceptionOnNullParameter() {
recipeListModel = new RecipeListModelImp(null, null);
}
#Test
public void testRecipeListModelShouldNotBeNull() {
assertNotNull(recipeListModel);
}
#Test
public void testShouldGetRecipesFromAPI() {
when(recipesAPI.getAllRecipes()).thenReturn(Observable.just(recipes));
recipeListModel.getRecipesFromAPI(recipeGetAllListener);
verify(recipesAPI, times(1)).getAllRecipes();
verify(recipeGetAllListener, times(1)).onRecipeGetAllSuccess(recipes);
verify(recipeGetAllListener, never()).onRecipeGetAllFailure(anyString());
}
#Test
public void testShouldFailToGetRecipesFromAPI() {
when(recipesAPI.getAllRecipes())
.thenReturn(Observable.<List<Recipe>>error(
new Throwable(new RuntimeException("Failed to get recipes"))));
recipeListModel.getRecipesFromAPI(recipeGetAllListener);
verify(recipesAPI, times(1)).getAllRecipes();
verify(recipeGetAllListener, times(1)).onRecipeGetAllFailure(anyString());
verify(recipeGetAllListener, never()).onRecipeGetAllSuccess(recipes);
}
#Test
public void testShouldShutdown() {
when(subscription.isUnsubscribed()).thenReturn(false);
final Field subscriptionField;
try {
subscriptionField = recipeListModel.getClass().getDeclaredField("subscription");
subscriptionField.setAccessible(true);
subscriptionField.set(recipeListModel, subscription);
} catch(NoSuchFieldException e) {
e.printStackTrace();
}
catch(IllegalAccessException e) {
e.printStackTrace();
}
recipeListModel.shutdown();
verify(subscription, times(1)).unsubscribe();
}
}
However, the problem is the Subscription in my model class is always null so will never enter the if blook. Is there any way to test this with using Mockito or spys?
Many thanks for any suggestions,
You should for testing recipeListModel class, where you have shutdown() method , set mock into this class.
If you don't have set method for subscription in recipeListModel , or constructor param.... ),you can set mock object with reflection like :
#Test
public void testShouldShutdown() {
Subscription subscription = mock(Subscription.class);
when(subscription.isUnsubscribed()).thenReturn(false);
Field subscriptionField = recipeListModel.getClass().getDeclaredField("subscription");
subscriptionField.setAccessible(true);
subscriptionField.set(recipeListModel, subscriptionMock);
recipeListModel.shutdown();
verify(subscription, times(1)).unsubscribe();
}
after your update :
if you can't change way of creation , you should mock it like (full way of creation) , i don't know your api , so it's just idea:
Subscription subscription = mock(Subscription.class);
when(subscription.isUnsubscribed()).thenReturn(false);
// preparation mock for create Subscription
//for recipesAPI.getAllRecipes()
Object mockFor_getAllRecipes = mock(....);
when(recipesAPI.getAllRecipes()).thenReturn(mockFor_getAllRecipes );
//for subscribeOn(recipeSchedulers.getBackgroundScheduler())
Object mockFor_subscribeOn = mock();
when(mockFor_getAllRecipes.subscribeOn(any())).thenReturn(mockFor_subscribeOn);
//for .observeOn(recipeSchedulers.getUIScheduler())
Object mockFor_observeOn = mock();
when(mockFor_subscribeOn .observeOn(any())).thenReturn(observeOn);
// for .subscribe
when(observeOn.subscribe(any()).thenReturn(subscription);
hazelcast configuration for the map is
<map name="test">
<max-idle-seconds>120</max-idle-seconds>
<entry-listeners>
<entry-listener include-value="true" local="false">com.test.listener.SessionListener</entry-listener>
</entry-listeners>
</map>
I have a listener configured for the evict action.
Listener is not able to catch the evict action consistently .
Hazelcast Version : 3.6.5
Listener Class Implemetation:
public class SessionListener implements EntryListener<String, Object> {
#Override
public void entryEvicted(EntryEvent<String, Object> evictData) {
try {
Session sessionObjValue = (Session) evictData.getOldValue();
String sessionId = sessionObjValue.getSessionId();
String userName = sessionObjValue.getUsername();
JSONObject inputJSON = new JSONObject();
inputJSON.put(Constants.SESSIONID, sessionId);
inputJSON.put(Constants.USER_NAME, userName);
//Operations to be performed based on the JSON Value
} catch (Exception exception) {
LOGGER.logDebug(Constants.ERROR, methodName, exception.toString());
}
}
Below are the recommendations:
Include Eviction policy configurations in your map config. Right now eviction is happening only based on max-idle-seconds.
Implement all the methods from EntryListener interface which inturn extends other interfaces.
Implement EntryExpiredListener listener also, to catch the expiry events explicitly though evict event also will be called during expiry.
Sample code:
public class MapEntryListernerTest implements EntryListener, EntryExpiredListener {
#Override
public void entryAdded(EntryEvent event) {
}
#Override
public void entryEvicted(EntryEvent event) {
}
#Override
public void entryRemoved(EntryEvent event) {
}
#Override
public void entryUpdated(EntryEvent event) {
}
#Override
public void mapCleared(MapEvent event) {
}
#Override
public void mapEvicted(MapEvent event) {
}
#Override
public void entryExpired(EntryEvent event) {
}
}
How can i configure Atomikos for HazelCast instance.As per the mastering-hazel cast we can only do it in java.How can i configure like i do for databases.If configuring is java is the way,then how i can make use of TransactionalTask to remove the boilerplate code starting and committing the transactions.i have tried like
public void insertIntoGridJTA( final List<String> list)
throws NotSupportedException, SystemException,
IllegalStateException, RollbackException {
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
HazelcastXAResource xaResource = hazelcast.getXAResource();
TransactionContext context = xaResource.getTransactionContext();
hazelcast.executeTransaction(new TransactionalTask<Object>() {
public Object execute(TransactionalTaskContext context)
throws TransactionException {
// TODO Auto-generated method stub
TransactionalMap<Integer, String> map = context.getMap("demo");
System.out.println("map"+map.getName());
for (int i = 0; i < list.size(); i++) {
map.put(i, list.get(i));
}
return null;
}
});
}
But the transaction is not starting if i am using TransactionalTask
Did you had a look at the Atomikos example in our examples repo? https://github.com/hazelcast/hazelcast-code-samples/blob/master/transactions/xa-transactions/src/main/java/XATransaction.java
In addition to #noctarius, I have done it like this in the past
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private HazelcastXAResource hzXAResource;
#Autowired
private UserTransactionManager userTransactionManager;
#Transactional
public void insert() throws SystemException, RollbackException {
final Transaction transaction = userTransactionManager.getTransaction();
transaction.enlistResource(hzXAResource);
final TransactionContext hzTransactionContext = hzXAResource.getTransactionContext();
final TransactionalMap<Long, String> hzCustomerMap = hzTransactionContext.getMap("hzCustomerMap");
// Use a Java 8 stream to print out each tuple of the list
CUSTOMERS_TEST_DATA.forEach(customer -> {
log.info("Inserting customer record for {}", customer);
hzCustomerMap.put(customer.getId(), customer.toString());
});
jdbcTemplate.batchUpdate(Sql.SQL_INSERT.getSql(), new BatchPreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, CUSTOMERS_TEST_DATA.get(i).getFirstName());
ps.setString(2, CUSTOMERS_TEST_DATA.get(i).getLastName());
}
#Override
public int getBatchSize() {
return CUSTOMERS_TEST_DATA.size();
}
});
// Uncomment this to test the failure of the transaction
// hzCustomerMap.values((Predicate) entry -> {
// throw new RuntimeException();
// });
transaction.delistResource(hzXAResource, XAResource.TMSUCCESS);
}
Here is my code. I am using scene builder. The code is not working.For first time it loads the hello1.html but in thread the hello2.html does not load.
public class TwavlController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML public WebView webPane;
private Service<Void> back_thread;
private WebEngine engine;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
engine = webPane.getEngine();
final String html_file = "hello1.html"; //HTML file to view in web view
URL urlHello = getClass().getResource(html_file);
engine.load(urlHello.toExternalForm());
run();
}
private File last_update,current;
public void run(){
back_thread = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
updateMessage("hello2.html");
return null;
}
};
}
};
engine.userAgentProperty().bind(back_thread.messageProperty());
back_thread.restart();
}
}
I'm not really clear what you're trying to do here, but I think maybe you are looking for
public void run(){
back_thread = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
Platform.runLater(() ->
engine.load(getClass().getResource("hello2.html").toExternalForm()));
return null;
}
};
}
};
back_thread.restart();
}