/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.spi.communication; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.UUID; import java.util.concurrent.CountDownLatch; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.GridDirectCollection; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.managers.communication.GridIoManager; import org.apache.ignite.internal.managers.communication.GridIoMessageFactory; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.communication.GridMessageListener; import org.apache.ignite.internal.processors.cache.GridCacheMessage; import org.apache.ignite.internal.util.typedef.CO; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageWriter; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import static java.util.concurrent.TimeUnit.SECONDS; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; /** * Messaging test. */ public class GridCacheMessageSelfTest extends GridCommonAbstractTest { /** IP finder. */ private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true); /** Sample count. */ private static final int SAMPLE_CNT = 1; /** */ public static final String TEST_BODY = "Test body"; /** * */ static { GridIoMessageFactory.registerCustom(TestMessage.DIRECT_TYPE, new CO<Message>() { @Override public Message apply() { return new TestMessage(); } }); GridIoMessageFactory.registerCustom(GridTestMessage.DIRECT_TYPE, new CO<Message>() { @Override public Message apply() { return new GridTestMessage(); } }); GridIoMessageFactory.registerCustom(TestMessage1.DIRECT_TYPE, new CO<Message>() { @Override public Message apply() { return new TestMessage1(); } }); GridIoMessageFactory.registerCustom(TestMessage2.DIRECT_TYPE, new CO<Message>() { @Override public Message apply() { return new TestMessage2(); } }); } /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); discoSpi.setIpFinder(ipFinder); cfg.setDiscoverySpi(discoSpi); cfg.setIncludeEventTypes((int[])null); CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); ccfg.setCacheMode(CacheMode.PARTITIONED); ccfg.setAtomicityMode(CacheAtomicityMode.ATOMIC); ccfg.setWriteSynchronizationMode(FULL_SYNC); ccfg.setBackups(0); cfg.setCacheConfiguration(ccfg); return cfg; } /** * @throws Exception If failed. */ public void testSendMessage() throws Exception { try { startGridsMultiThreaded(2); doSend(); } finally { stopAllGrids(); } } /** * @throws Exception If failed. */ private void doSend() throws Exception { GridIoManager mgr0 = ((IgniteKernal)grid(0)).context().io(); GridIoManager mgr1 = ((IgniteKernal)grid(1)).context().io(); String topic = "test-topic"; final CountDownLatch latch = new CountDownLatch(SAMPLE_CNT); mgr1.addMessageListener(topic, new GridMessageListener() { @Override public void onMessage(UUID nodeId, Object msg) { try { latch.countDown(); Collection<TestMessage1> messages = ((TestMessage) msg).entries(); assertEquals(10, messages.size()); int count = 0; for (TestMessage1 msg1 : messages) { assertTrue(msg1.body().contains(TEST_BODY)); int i = Integer.parseInt(msg1.body().substring(TEST_BODY.length() + 1)); assertEquals(count, i); TestMessage2 msg2 = (TestMessage2) msg1.message(); assertEquals(TEST_BODY + "_" + i + "_2", msg2.body()); assertEquals(grid(0).localNode().id(), msg2.nodeId()); assertEquals(i, msg2.id()); GridTestMessage msg3 = (GridTestMessage) msg2.message(); assertEquals(count, msg3.getMsgId()); assertEquals(grid(1).localNode().id(), msg3.getSourceNodeId()); count++; } } catch (Exception e) { fail("Exception " + e.getMessage()); } } }); TestMessage msg = new TestMessage(); for (int i = 0; i < 10; i++) { TestMessage2 mes1 = new TestMessage2(); mes1.init(new GridTestMessage(grid(1).localNode().id(), i, 0), grid(0).localNode().id(), i, TEST_BODY + "_" + i + "_2"); TestMessage1 mes2 = new TestMessage1(); mes2.init(mes1, TEST_BODY + "_" + i); msg.add(mes2); } mgr0.sendToCustomTopic(grid(1).localNode(), topic, msg, GridIoPolicy.PUBLIC_POOL); assert latch.await(3, SECONDS); } /** */ private static class TestMessage extends GridCacheMessage { /** */ public static final short DIRECT_TYPE = 202; /** */ @GridDirectCollection(TestMessage1.class) private Collection<TestMessage1> entries = new ArrayList<>(); /** * @param entry Entry. */ public void add(TestMessage1 entry) { entries.add(entry); } /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return false; } /** * @return COllection of test messages. */ public Collection<TestMessage1> entries() { return entries; } /** {@inheritDoc} */ @Override public short directType() { return DIRECT_TYPE; } /** {@inheritDoc} */ @Override public byte fieldsCount() { return 4; } /** {@inheritDoc} */ @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) { writer.setBuffer(buf); if (!super.writeTo(buf, writer)) return false; if (!writer.isHeaderWritten()) { if (!writer.writeHeader(directType(), fieldsCount())) return false; writer.onHeaderWritten(); } switch (writer.state()) { case 3: if (!writer.writeCollection("entries", entries, MessageCollectionItemType.MSG)) return false; writer.incrementState(); } return true; } /** {@inheritDoc} */ @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) { reader.setBuffer(buf); if (!reader.beforeMessageRead()) return false; if (!super.readFrom(buf, reader)) return false; switch (reader.state()) { case 3: entries = reader.readCollection("entries", MessageCollectionItemType.MSG); if (!reader.isLastRead()) return false; reader.incrementState(); } return true; } } /** * Test message class. */ static class TestMessage1 extends GridCacheMessage { /** */ public static final short DIRECT_TYPE = 203; /** Body. */ private String body; /** */ private Message msg; /** * @param msg Message. * @param body Message body. */ public void init(Message msg, String body) { this.msg = msg; this.body = body; } /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return false; } /** * @return Body. */ public String body() { return body; } /** * @return Message. */ public Message message() { return msg; } /** {@inheritDoc} */ @Override public short directType() { return DIRECT_TYPE; } /** {@inheritDoc} */ @Override public byte fieldsCount() { return 5; } /** {@inheritDoc} */ @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) { writer.setBuffer(buf); if (!super.writeTo(buf, writer)) return false; if (!writer.isHeaderWritten()) { if (!writer.writeHeader(directType(), fieldsCount())) return false; writer.onHeaderWritten(); } switch (writer.state()) { case 3: if (!writer.writeString("body", body)) return false; writer.incrementState(); case 4: if (!writer.writeMessage("msg", msg)) return false; writer.incrementState(); } return true; } /** {@inheritDoc} */ @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) { reader.setBuffer(buf); if (!reader.beforeMessageRead()) return false; if (!super.readFrom(buf, reader)) return false; switch (reader.state()) { case 3: body = reader.readString("body"); if (!reader.isLastRead()) return false; reader.incrementState(); case 4: msg = reader.readMessage("msg"); if (!reader.isLastRead()) return false; reader.incrementState(); } return true; } } /** * Test message class. */ static class TestMessage2 extends GridCacheMessage { /** */ public static final short DIRECT_TYPE = 201; /** Node id. */ private UUID nodeId; /** Integer field. */ private int id; /** Body. */ private String body; /** */ private Message msg; /** * @param mes Message. */ public void init(Message mes, UUID nodeId, int id, String body) { this.nodeId = nodeId; this.id = id; this.msg = mes; this.body = body; } /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return false; } /** * @return Body. */ public String body() { return body; } /** * @return Message. */ public Message message() { return msg; } /** * @return Node id. */ public UUID nodeId() { return nodeId; } /** * @return Id. */ public int id() { return id; } /** {@inheritDoc} */ @Override public short directType() { return DIRECT_TYPE; } /** {@inheritDoc} */ @Override public byte fieldsCount() { return 7; } /** {@inheritDoc} */ @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) { writer.setBuffer(buf); if (!super.writeTo(buf, writer)) return false; if (!writer.isHeaderWritten()) { if (!writer.writeHeader(directType(), fieldsCount())) return false; writer.onHeaderWritten(); } switch (writer.state()) { case 3: if (!writer.writeUuid("nodeId", nodeId)) return false; writer.incrementState(); case 4: if (!writer.writeInt("id", id)) return false; writer.incrementState(); case 5: if (!writer.writeString("body", body)) return false; writer.incrementState(); case 6: if (!writer.writeMessage("msg", msg)) return false; writer.incrementState(); } return true; } /** {@inheritDoc} */ @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) { reader.setBuffer(buf); if (!reader.beforeMessageRead()) return false; if (!super.readFrom(buf, reader)) return false; switch (reader.state()) { case 3: nodeId = reader.readUuid("nodeId"); if (!reader.isLastRead()) return false; reader.incrementState(); case 4: id = reader.readInt("id"); if (!reader.isLastRead()) return false; reader.incrementState(); case 5: body = reader.readString("body"); if (!reader.isLastRead()) return false; reader.incrementState(); case 6: msg = reader.readMessage("msg"); if (!reader.isLastRead()) return false; reader.incrementState(); } return true; } } }