mirror of https://github.com/longtai-cn/hippo4j
commit
74351432a2
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 更新日志
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 更新日志
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 更新日志
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 更新日志
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* test for {@link PluginRuntime}
|
||||
*/
|
||||
public class PluginRuntimeTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
PluginRuntime runtime = new PluginRuntime("test");
|
||||
Assert.assertEquals("test", runtime.getPluginId());
|
||||
Assert.assertTrue(runtime.getInfoList().isEmpty());
|
||||
|
||||
runtime.addInfo("item", "item");
|
||||
PluginRuntime.Info info = runtime.getInfoList().get(0);
|
||||
Assert.assertEquals("item", info.getName());
|
||||
Assert.assertEquals("item", info.getValue());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ThreadUtil;
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
||||
import lombok.Getter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* test for default method of {@link ThreadPoolPlugin} and it's subclass
|
||||
*/
|
||||
public class ThreadPoolPluginTest {
|
||||
|
||||
@Test
|
||||
public void testDefaultMethod() {
|
||||
ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", new DefaultThreadPoolPluginManager(),
|
||||
1, 1, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
|
||||
|
||||
executor.register(new TestTaskAwarePlugin());
|
||||
executor.register(new TestExecuteAwarePlugin());
|
||||
executor.register(new TestRejectedAwarePlugin());
|
||||
executor.register(new TestShutdownAwarePlugin());
|
||||
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
executor.submit(() -> {
|
||||
ThreadUtil.sleep(100L);
|
||||
return count.incrementAndGet();
|
||||
});
|
||||
executor.submit(() -> {
|
||||
ThreadUtil.sleep(100L);
|
||||
count.incrementAndGet();
|
||||
});
|
||||
executor.submit(count::incrementAndGet, 2);
|
||||
|
||||
// waiting for shutdown
|
||||
executor.shutdown();
|
||||
while (!executor.isTerminated()) {
|
||||
}
|
||||
|
||||
Assert.assertEquals(2, count.get());
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestTaskAwarePlugin implements TaskAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestExecuteAwarePlugin implements ExecuteAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestRejectedAwarePlugin implements RejectedAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestShutdownAwarePlugin implements ShutdownAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.impl;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ThreadUtil;
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.PluginRuntime;
|
||||
import cn.hippo4j.core.plugin.ThreadPoolPlugin;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.TaskDecorator;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* test for {@link TaskDecoratorPlugin}
|
||||
*/
|
||||
public class TaskDecoratorPluginTest {
|
||||
|
||||
private final AtomicInteger taskExecuteCount = new AtomicInteger(0);
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
Assert.assertEquals(TaskDecoratorPlugin.PLUGIN_NAME, new TaskDecoratorPlugin().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuntime() {
|
||||
ThreadPoolPlugin plugin = new TaskDecoratorPlugin();
|
||||
PluginRuntime runtime = new TaskDecoratorPlugin().getPluginRuntime();
|
||||
Assert.assertNotNull(runtime);
|
||||
Assert.assertEquals(plugin.getId(), runtime.getPluginId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDecorator() {
|
||||
TaskDecoratorPlugin plugin = new TaskDecoratorPlugin();
|
||||
plugin.addDecorator(runnable -> runnable);
|
||||
plugin.addDecorator(runnable -> runnable);
|
||||
Assert.assertEquals(2, plugin.getDecorators().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveDecorator() {
|
||||
TaskDecoratorPlugin plugin = new TaskDecoratorPlugin();
|
||||
TaskDecorator decorator = runnable -> runnable;
|
||||
plugin.addDecorator(decorator);
|
||||
plugin.removeDecorator(decorator);
|
||||
Assert.assertTrue(plugin.getDecorators().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
TaskDecoratorPlugin plugin = new TaskDecoratorPlugin();
|
||||
TaskDecorator decorator = runnable -> runnable;
|
||||
plugin.addDecorator(decorator);
|
||||
plugin.addDecorator(decorator);
|
||||
plugin.clearDecorators();
|
||||
Assert.assertTrue(plugin.getDecorators().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeTaskExecute() {
|
||||
ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", new DefaultThreadPoolPluginManager(),
|
||||
5, 5, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
|
||||
TaskDecoratorPlugin plugin = new TaskDecoratorPlugin();
|
||||
plugin.addDecorator(runnable -> () -> {
|
||||
taskExecuteCount.incrementAndGet();
|
||||
runnable.run();
|
||||
});
|
||||
plugin.addDecorator(runnable -> () -> {
|
||||
taskExecuteCount.incrementAndGet();
|
||||
runnable.run();
|
||||
});
|
||||
executor.register(plugin);
|
||||
executor.execute(() -> {
|
||||
});
|
||||
ThreadUtil.sleep(500L);
|
||||
Assert.assertEquals(2, taskExecuteCount.get());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.impl;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ThreadUtil;
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* test for {@link TaskRejectCountRecordPlugin}
|
||||
*/
|
||||
public class TaskRejectCountRecordPluginTest {
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
Assert.assertEquals(TaskRejectCountRecordPlugin.PLUGIN_NAME, new TaskRejectCountRecordPlugin().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuntime() {
|
||||
Assert.assertNotNull(new TaskRejectCountRecordPlugin().getPluginRuntime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRejectCountNum() {
|
||||
TaskRejectCountRecordPlugin plugin = new TaskRejectCountRecordPlugin();
|
||||
Assert.assertEquals((Long) 0L, plugin.getRejectCountNum());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRejectCount() {
|
||||
TaskRejectCountRecordPlugin plugin = new TaskRejectCountRecordPlugin();
|
||||
Assert.assertEquals(0L, plugin.getRejectCount().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRejectCount() {
|
||||
TaskRejectCountRecordPlugin plugin = new TaskRejectCountRecordPlugin();
|
||||
AtomicLong atomicLong = new AtomicLong(0);
|
||||
plugin.setRejectCount(atomicLong);
|
||||
Assert.assertSame(atomicLong, plugin.getRejectCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeRejectedExecution() {
|
||||
ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", new DefaultThreadPoolPluginManager(),
|
||||
1, 1, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
|
||||
|
||||
TaskRejectCountRecordPlugin plugin = new TaskRejectCountRecordPlugin();
|
||||
executor.register(plugin);
|
||||
executor.submit(() -> ThreadUtil.sleep(500L));
|
||||
executor.submit(() -> ThreadUtil.sleep(500L));
|
||||
executor.submit(() -> ThreadUtil.sleep(500L));
|
||||
|
||||
ThreadUtil.sleep(500L);
|
||||
Assert.assertEquals((Long) 1L, plugin.getRejectCountNum());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.impl;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ThreadUtil;
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* test for {@link TaskRejectNotifyAlarmPlugin}
|
||||
*/
|
||||
public class TaskRejectNotifyAlarmPluginTest {
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
Assert.assertEquals(TaskRejectNotifyAlarmPlugin.PLUGIN_NAME, new TaskRejectNotifyAlarmPlugin().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuntime() {
|
||||
Assert.assertNotNull(new TaskRejectNotifyAlarmPlugin().getPluginRuntime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeRejectedExecution() {
|
||||
ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", new DefaultThreadPoolPluginManager(),
|
||||
1, 1, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
|
||||
|
||||
AtomicInteger rejectCount = new AtomicInteger(0);
|
||||
executor.register(new TestPlugin(rejectCount, executor));
|
||||
executor.submit(() -> ThreadUtil.sleep(200L));
|
||||
executor.submit(() -> ThreadUtil.sleep(200L));
|
||||
executor.submit(() -> ThreadUtil.sleep(200L));
|
||||
|
||||
// waiting for shutdown
|
||||
executor.shutdown();
|
||||
while (!executor.isTerminated()) {
|
||||
}
|
||||
Assert.assertEquals(1, rejectCount.get());
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class TestPlugin extends TaskRejectNotifyAlarmPlugin {
|
||||
|
||||
private final AtomicInteger count;
|
||||
private final ThreadPoolExecutor targetExecutor;
|
||||
|
||||
/**
|
||||
* Callback before task is rejected.
|
||||
*
|
||||
* @param runnable task
|
||||
* @param executor executor
|
||||
*/
|
||||
@Override
|
||||
public void beforeRejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
|
||||
count.incrementAndGet();
|
||||
Assert.assertEquals(targetExecutor, executor);
|
||||
super.beforeRejectedExecution(runnable, executor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.impl;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ThreadUtil;
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* test for {@link TaskTimeRecordPlugin}
|
||||
*/
|
||||
public class TaskTimeRecordPluginTest {
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
Assert.assertEquals(TaskTimeRecordPlugin.PLUGIN_NAME, new TaskTimeRecordPlugin().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuntime() {
|
||||
Assert.assertNotNull(new TaskTimeRecordPlugin().getPluginRuntime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSummarize() {
|
||||
ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", new DefaultThreadPoolPluginManager(),
|
||||
3, 3, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
|
||||
|
||||
TaskTimeRecordPlugin plugin = new TaskTimeRecordPlugin();
|
||||
executor.register(plugin);
|
||||
executor.submit(() -> ThreadUtil.sleep(1000L));
|
||||
executor.submit(() -> ThreadUtil.sleep(3000L));
|
||||
executor.submit(() -> ThreadUtil.sleep(2000L));
|
||||
|
||||
// waiting for shutdown
|
||||
executor.shutdown();
|
||||
while (!executor.isTerminated()) {
|
||||
}
|
||||
TaskTimeRecordPlugin.Summary summary = plugin.summarize();
|
||||
Assert.assertEquals(1, summary.getMinTaskTimeMillis() / 1000L);
|
||||
Assert.assertEquals(3, summary.getMaxTaskTimeMillis() / 1000L);
|
||||
Assert.assertEquals(2, summary.getAvgTaskTimeMillis() / 1000L);
|
||||
Assert.assertEquals(6, summary.getTotalTaskTimeMillis() / 1000L);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.impl;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ThreadUtil;
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* test for {@link TaskTimeoutNotifyAlarmPlugin}
|
||||
*/
|
||||
public class TaskTimeoutNotifyAlarmPluginTest {
|
||||
|
||||
private final ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", new DefaultThreadPoolPluginManager(),
|
||||
5, 5, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.AbortPolicy());
|
||||
|
||||
private final TaskTimeoutNotifyAlarmPlugin plugin = new TaskTimeoutNotifyAlarmPlugin(
|
||||
executor.getThreadPoolId(), 100L, executor);
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
Assert.assertEquals(TaskTimeoutNotifyAlarmPlugin.PLUGIN_NAME, plugin.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuntime() {
|
||||
Assert.assertNotNull(plugin.getPluginRuntime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExecuteTimeOut() {
|
||||
Assert.assertEquals(100L, plugin.getExecuteTimeOut().longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetExecuteTimeOut() {
|
||||
plugin.setExecuteTimeOut(200L);
|
||||
Assert.assertEquals(200L, plugin.getExecuteTimeOut().longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessTaskTime() {
|
||||
executor.register(plugin);
|
||||
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
executor.submit(() -> {
|
||||
count.incrementAndGet();
|
||||
ThreadUtil.sleep(100L);
|
||||
});
|
||||
executor.submit(() -> {
|
||||
count.incrementAndGet();
|
||||
ThreadUtil.sleep(300L);
|
||||
});
|
||||
|
||||
// waiting for shutdown
|
||||
executor.shutdown();
|
||||
while (!executor.isTerminated()) {
|
||||
}
|
||||
Assert.assertEquals(2, count.get());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.impl;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ThreadUtil;
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.ThreadPoolPlugin;
|
||||
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* test for {@link ThreadPoolExecutorShutdownPlugin}
|
||||
*/
|
||||
public class ThreadPoolExecutorShutdownPluginTest {
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
Assert.assertEquals(ThreadPoolExecutorShutdownPlugin.PLUGIN_NAME, new ThreadPoolExecutorShutdownPlugin(1000L).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuntime() {
|
||||
Assert.assertNotNull(new ThreadPoolExecutorShutdownPlugin(1000L).getPluginRuntime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAwaitTerminationMillis() {
|
||||
ThreadPoolExecutorShutdownPlugin plugin = new ThreadPoolExecutorShutdownPlugin(1000L);
|
||||
Assert.assertEquals(1000L, plugin.getAwaitTerminationMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAwaitTerminationMillis() {
|
||||
ThreadPoolExecutorShutdownPlugin plugin = new ThreadPoolExecutorShutdownPlugin(1000L);
|
||||
plugin.setAwaitTerminationMillis(5000L);
|
||||
Assert.assertEquals(5000L, plugin.getAwaitTerminationMillis());
|
||||
}
|
||||
|
||||
public ExtensibleThreadPoolExecutor getExecutor(ThreadPoolPlugin plugin) {
|
||||
ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", new DefaultThreadPoolPluginManager(),
|
||||
2, 2, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
|
||||
executor.register(plugin);
|
||||
return executor;
|
||||
}
|
||||
|
||||
private static Callable<Integer> getCallable(AtomicInteger completedCount) {
|
||||
return () -> {
|
||||
ThreadUtil.sleep(1000L);
|
||||
return completedCount.incrementAndGet();
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShutdown() {
|
||||
ExtensibleThreadPoolExecutor executor = getExecutor(
|
||||
new ThreadPoolExecutorShutdownPlugin(2000L));
|
||||
|
||||
AtomicInteger completedCount = new AtomicInteger(0);
|
||||
executor.submit(getCallable(completedCount));
|
||||
executor.submit(getCallable(completedCount));
|
||||
executor.submit(getCallable(completedCount));
|
||||
|
||||
executor.shutdownNow();
|
||||
Assert.assertEquals(2, completedCount.get());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.manager;
|
||||
|
||||
import cn.hippo4j.core.plugin.*;
|
||||
import lombok.Getter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* test for {@link DefaultThreadPoolPluginManager}
|
||||
*/
|
||||
public class DefaultThreadPoolPluginManagerTest {
|
||||
|
||||
private DefaultThreadPoolPluginManager manager;
|
||||
|
||||
@Before
|
||||
public void initRegistry() {
|
||||
manager = new DefaultThreadPoolPluginManager();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister() {
|
||||
manager.register(new TestShutdownAwarePlugin());
|
||||
Assert.assertEquals(1, manager.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPlugins() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
manager.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(2, manager.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
manager.clear();
|
||||
Assert.assertTrue(manager.getAllPlugins().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTryRegister() {
|
||||
Assert.assertTrue(manager.tryRegister(new TestExecuteAwarePlugin()));
|
||||
Assert.assertFalse(manager.tryRegister(new TestExecuteAwarePlugin()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRegistered() {
|
||||
Assert.assertFalse(manager.isRegistered(TestExecuteAwarePlugin.class.getSimpleName()));
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertTrue(manager.isRegistered(TestExecuteAwarePlugin.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregister() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
manager.unregister(TestExecuteAwarePlugin.class.getSimpleName());
|
||||
Assert.assertFalse(manager.isRegistered(TestExecuteAwarePlugin.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlugin() {
|
||||
ThreadPoolPlugin plugin = new TestExecuteAwarePlugin();
|
||||
manager.register(plugin);
|
||||
Assert.assertSame(plugin, manager.getPlugin(plugin.getId()).orElse(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRejectedAwarePluginList() {
|
||||
manager.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(1, manager.getRejectedAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetShutdownAwarePluginList() {
|
||||
manager.register(new TestShutdownAwarePlugin());
|
||||
Assert.assertEquals(1, manager.getShutdownAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTaskAwarePluginList() {
|
||||
manager.register(new TestTaskAwarePlugin());
|
||||
Assert.assertEquals(1, manager.getTaskAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExecuteAwarePluginList() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertEquals(1, manager.getExecuteAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPluginsOfType() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
manager.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(1, manager.getAllPluginsOfType(TestExecuteAwarePlugin.class).size());
|
||||
Assert.assertEquals(1, manager.getAllPluginsOfType(TestRejectedAwarePlugin.class).size());
|
||||
Assert.assertEquals(2, manager.getAllPluginsOfType(ThreadPoolPlugin.class).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPluginRuntimes() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
manager.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(2, manager.getAllPluginRuntimes().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPluginRuntime() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertTrue(manager.getRuntime(TestExecuteAwarePlugin.class.getSimpleName()).isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPluginOfType() {
|
||||
manager.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertTrue(manager.getPluginOfType(TestExecuteAwarePlugin.class.getSimpleName(), TestExecuteAwarePlugin.class).isPresent());
|
||||
Assert.assertTrue(manager.getPluginOfType(TestExecuteAwarePlugin.class.getSimpleName(), ThreadPoolPlugin.class).isPresent());
|
||||
Assert.assertFalse(manager.getPluginOfType(TestExecuteAwarePlugin.class.getSimpleName(), RejectedAwarePlugin.class).isPresent());
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestTaskAwarePlugin implements TaskAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestExecuteAwarePlugin implements ExecuteAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestRejectedAwarePlugin implements RejectedAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestShutdownAwarePlugin implements ShutdownAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.manager;
|
||||
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.impl.*;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* test for {@link DefaultThreadPoolPluginRegistrar}
|
||||
*/
|
||||
public class DefaultThreadPoolPluginRegistrarTest {
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
ThreadPoolPluginRegistrar registrar = new DefaultThreadPoolPluginRegistrar();
|
||||
Assert.assertEquals(registrar.getClass().getSimpleName(), registrar.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoRegister() {
|
||||
ThreadPoolPluginRegistrar registrar = new DefaultThreadPoolPluginRegistrar(100L, 100L);
|
||||
ThreadPoolPluginManager manager = new DefaultThreadPoolPluginManager();
|
||||
ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", manager,
|
||||
5, 5, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.AbortPolicy());
|
||||
registrar.doRegister(executor);
|
||||
|
||||
Assert.assertTrue(manager.getPlugin(TaskDecoratorPlugin.PLUGIN_NAME).isPresent());
|
||||
Assert.assertTrue(manager.getPlugin(TaskTimeoutNotifyAlarmPlugin.PLUGIN_NAME).isPresent());
|
||||
Assert.assertTrue(manager.getPlugin(TaskRejectCountRecordPlugin.PLUGIN_NAME).isPresent());
|
||||
Assert.assertTrue(manager.getPlugin(TaskRejectNotifyAlarmPlugin.PLUGIN_NAME).isPresent());
|
||||
Assert.assertTrue(manager.getPlugin(ThreadPoolExecutorShutdownPlugin.PLUGIN_NAME).isPresent());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.manager;
|
||||
|
||||
import cn.hippo4j.core.plugin.ThreadPoolPlugin;
|
||||
import lombok.Getter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* test for {@link cn.hippo4j.core.plugin.manager.EmptyThreadPoolPluginManager}
|
||||
*/
|
||||
public class EmptyThreadPoolPluginManagerTest {
|
||||
|
||||
private final ThreadPoolPluginManager manager = EmptyThreadPoolPluginManager.INSTANCE;
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
Assert.assertSame(manager, ThreadPoolPluginManager.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPlugins() {
|
||||
Assert.assertEquals(Collections.emptyList(), manager.getAllPluginRuntimes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
manager.clear();
|
||||
Assert.assertTrue(isEmpty(manager));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister() {
|
||||
manager.register(new TestPlugin());
|
||||
Assert.assertTrue(isEmpty(manager));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTryRegister() {
|
||||
Assert.assertFalse(manager.tryRegister(new TestPlugin()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRegistered() {
|
||||
manager.register(new TestPlugin());
|
||||
Assert.assertFalse(manager.isRegistered(TestPlugin.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregister() {
|
||||
manager.register(new TestPlugin());
|
||||
manager.unregister(TestPlugin.class.getSimpleName());
|
||||
Assert.assertTrue(isEmpty(manager));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlugin() {
|
||||
Assert.assertSame(Optional.empty(), manager.getPlugin(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRejectedAwarePluginList() {
|
||||
Assert.assertEquals(Collections.emptyList(), manager.getRejectedAwarePluginList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetShutdownAwarePluginList() {
|
||||
Assert.assertEquals(Collections.emptyList(), manager.getShutdownAwarePluginList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTaskAwarePluginList() {
|
||||
Assert.assertEquals(Collections.emptyList(), manager.getTaskAwarePluginList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExecuteAwarePluginList() {
|
||||
Assert.assertEquals(Collections.emptyList(), manager.getExecuteAwarePluginList());
|
||||
}
|
||||
|
||||
private static boolean isEmpty(ThreadPoolPluginManager manager) {
|
||||
return manager.getAllPlugins().isEmpty();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private static class TestPlugin implements ThreadPoolPlugin {
|
||||
|
||||
private final String id = TestPlugin.class.getSimpleName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.core.plugin.manager;
|
||||
|
||||
import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
|
||||
import cn.hippo4j.core.plugin.*;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* test for default method of {@link ThreadPoolPluginSupport}
|
||||
*/
|
||||
public class ThreadPoolPluginSupportTest {
|
||||
|
||||
private final ThreadPoolPluginManager manager = new DefaultThreadPoolPluginManager();
|
||||
private final ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
|
||||
"test", manager,
|
||||
5, 5, 1000L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.AbortPolicy());
|
||||
private final ThreadPoolPluginSupport support = new TestSupport(executor.getThreadPoolId(), executor, manager);
|
||||
|
||||
@Test
|
||||
public void testGetThreadPoolId() {
|
||||
Assert.assertEquals(executor.getThreadPoolId(), support.getThreadPoolId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetThreadPoolPluginManager() {
|
||||
Assert.assertEquals(manager, support.getThreadPoolPluginManager());
|
||||
}
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
private static class TestSupport implements ThreadPoolPluginSupport {
|
||||
|
||||
private final String threadPoolId;
|
||||
private final ExtensibleThreadPoolExecutor threadPoolExecutor;
|
||||
private final ThreadPoolPluginManager threadPoolPluginManager;
|
||||
}
|
||||
|
||||
// ================ default delegate method ================
|
||||
|
||||
@Test
|
||||
public void testRegister() {
|
||||
support.register(new TestShutdownAwarePlugin());
|
||||
Assert.assertEquals(1, support.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPlugins() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
support.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(2, support.getAllPlugins().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
support.clear();
|
||||
Assert.assertTrue(support.getAllPlugins().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTryRegister() {
|
||||
Assert.assertTrue(support.tryRegister(new TestExecuteAwarePlugin()));
|
||||
Assert.assertFalse(support.tryRegister(new TestExecuteAwarePlugin()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRegistered() {
|
||||
Assert.assertFalse(support.isRegistered(TestExecuteAwarePlugin.class.getSimpleName()));
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertTrue(support.isRegistered(TestExecuteAwarePlugin.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregister() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
support.unregister(TestExecuteAwarePlugin.class.getSimpleName());
|
||||
Assert.assertFalse(support.isRegistered(TestExecuteAwarePlugin.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlugin() {
|
||||
ThreadPoolPlugin plugin = new TestExecuteAwarePlugin();
|
||||
support.register(plugin);
|
||||
Assert.assertSame(plugin, support.getPlugin(plugin.getId()).orElse(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRejectedAwarePluginList() {
|
||||
support.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(1, support.getRejectedAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetShutdownAwarePluginList() {
|
||||
support.register(new TestShutdownAwarePlugin());
|
||||
Assert.assertEquals(1, support.getShutdownAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTaskAwarePluginList() {
|
||||
support.register(new TestTaskAwarePlugin());
|
||||
Assert.assertEquals(1, support.getTaskAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExecuteAwarePluginList() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertEquals(1, support.getExecuteAwarePluginList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPluginsOfType() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
support.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(1, support.getAllPluginsOfType(TestExecuteAwarePlugin.class).size());
|
||||
Assert.assertEquals(1, support.getAllPluginsOfType(TestRejectedAwarePlugin.class).size());
|
||||
Assert.assertEquals(2, support.getAllPluginsOfType(ThreadPoolPlugin.class).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPluginRuntimes() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
support.register(new TestRejectedAwarePlugin());
|
||||
Assert.assertEquals(2, support.getAllPluginRuntimes().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPluginRuntime() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertTrue(support.getRuntime(TestExecuteAwarePlugin.class.getSimpleName()).isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPluginOfType() {
|
||||
support.register(new TestExecuteAwarePlugin());
|
||||
Assert.assertTrue(support.getPluginOfType(TestExecuteAwarePlugin.class.getSimpleName(), TestExecuteAwarePlugin.class).isPresent());
|
||||
Assert.assertTrue(support.getPluginOfType(TestExecuteAwarePlugin.class.getSimpleName(), ThreadPoolPlugin.class).isPresent());
|
||||
Assert.assertFalse(support.getPluginOfType(TestExecuteAwarePlugin.class.getSimpleName(), RejectedAwarePlugin.class).isPresent());
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestTaskAwarePlugin implements TaskAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestExecuteAwarePlugin implements ExecuteAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestRejectedAwarePlugin implements RejectedAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final static class TestShutdownAwarePlugin implements ShutdownAwarePlugin {
|
||||
|
||||
private final String id = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.client;
|
||||
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* the client for RPC, Explain the role of the client in the request
|
||||
*/
|
||||
public interface Client extends Closeable {
|
||||
|
||||
/**
|
||||
* Start the client and try to send and receive data
|
||||
*/
|
||||
Response connection(Request request);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.client;
|
||||
|
||||
import cn.hippo4j.config.rpc.handler.Connection;
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
|
||||
/**
|
||||
* Applicable to client connections
|
||||
*/
|
||||
public interface ClientConnection extends Connection {
|
||||
|
||||
/**
|
||||
* Establish a connection and process
|
||||
*
|
||||
* @param request Request information
|
||||
*/
|
||||
Response connect(Request request);
|
||||
|
||||
/**
|
||||
* Get timeout, ms
|
||||
*/
|
||||
long timeout();
|
||||
|
||||
/**
|
||||
* SET timeout, ms
|
||||
*/
|
||||
void setTimeout(long timeout);
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.client;
|
||||
|
||||
import cn.hippo4j.config.rpc.exception.TimeOutException;
|
||||
import cn.hippo4j.config.rpc.process.ActivePostProcess;
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
import cn.hippo4j.config.rpc.support.NettyConnectPool;
|
||||
import cn.hippo4j.config.rpc.support.NettyConnectPoolHolder;
|
||||
import cn.hippo4j.config.rpc.support.ResultHolder;
|
||||
import cn.hippo4j.common.toolkit.Assert;
|
||||
import cn.hippo4j.common.web.exception.IllegalException;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
/**
|
||||
* Client implemented using netty
|
||||
*/
|
||||
@Slf4j
|
||||
public class NettyClientConnection implements ClientConnection {
|
||||
|
||||
String host;
|
||||
Integer port;
|
||||
// Obtain the connection timeout period. The default value is 30s
|
||||
long timeout = 30000L;
|
||||
Channel channel;
|
||||
EventLoopGroup worker = new NioEventLoopGroup();
|
||||
List<ActivePostProcess> activeProcesses;
|
||||
ChannelFuture future;
|
||||
NettyConnectPool connectionPool;
|
||||
|
||||
public NettyClientConnection(String host, int port,
|
||||
List<ActivePostProcess> activeProcesses) {
|
||||
Assert.notNull(worker);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.activeProcesses = activeProcesses;
|
||||
this.connectionPool = NettyConnectPoolHolder.getPool(host, port, timeout, worker);
|
||||
}
|
||||
|
||||
public NettyClientConnection(String host, int port) {
|
||||
this(host, port, new LinkedList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response connect(Request request) {
|
||||
preHandlers(request);
|
||||
this.channel = connectionPool.acquire(timeout);
|
||||
try {
|
||||
String key = request.getKey();
|
||||
this.future = channel.writeAndFlush(request);
|
||||
log.info("Call successful, target address is {}:{}, request key is {}", host, port, key);
|
||||
// Wait for execution to complete
|
||||
ResultHolder.put(key, Thread.currentThread());
|
||||
LockSupport.parkNanos(timeout() * 1000000);
|
||||
Response response = ResultHolder.get(key);
|
||||
if (response == null) {
|
||||
throw new TimeOutException("Timeout waiting for server-side response");
|
||||
}
|
||||
postHandlers(request, response);
|
||||
log.info("The response from {}:{} was received successfully with the response key {}.", host, port, key);
|
||||
return response;
|
||||
} catch (Exception ex) {
|
||||
afterCompletions(request, null, ex);
|
||||
throw new IllegalException(ex);
|
||||
} finally {
|
||||
connectionPool.release(this.channel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long timeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.channel == null) {
|
||||
return;
|
||||
}
|
||||
worker.shutdownGracefully();
|
||||
this.future.channel().close();
|
||||
this.channel.close();
|
||||
}
|
||||
|
||||
private void preHandlers(Request request) {
|
||||
for (ActivePostProcess process : activeProcesses) {
|
||||
process.preHandler(request);
|
||||
}
|
||||
}
|
||||
|
||||
private void postHandlers(Request request, Response response) {
|
||||
for (ActivePostProcess process : activeProcesses) {
|
||||
process.postHandler(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private void afterCompletions(Request request, Response response, Exception e) {
|
||||
for (ActivePostProcess process : activeProcesses) {
|
||||
process.afterCompletion(request, response, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.client;
|
||||
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The client, which provides a closing mechanism, maintains a persistent connection if not closed
|
||||
*/
|
||||
public class RPCClient implements Client {
|
||||
|
||||
ClientConnection clientConnection;
|
||||
|
||||
public RPCClient(ClientConnection clientConnection) {
|
||||
this.clientConnection = clientConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response connection(Request request) {
|
||||
return clientConnection.connect(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the client and release all connections.
|
||||
*
|
||||
* @throws IOException exception
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
clientConnection.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.coder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* object OutputStream
|
||||
*/
|
||||
public class CompactObjectOutputStream extends ObjectOutputStream {
|
||||
|
||||
static final int TYPE_FAT_DESCRIPTOR = 0;
|
||||
static final int TYPE_THIN_DESCRIPTOR = 1;
|
||||
|
||||
public CompactObjectOutputStream(OutputStream out) throws IOException {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeStreamHeader() throws IOException {
|
||||
writeByte(STREAM_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
|
||||
Class<?> clazz = desc.forClass();
|
||||
if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || desc.getSerialVersionUID() == 0) {
|
||||
write(TYPE_FAT_DESCRIPTOR);
|
||||
super.writeClassDescriptor(desc);
|
||||
} else {
|
||||
write(TYPE_THIN_DESCRIPTOR);
|
||||
writeUTF(desc.getName());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.coder;
|
||||
|
||||
import cn.hippo4j.config.rpc.exception.CoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.serialization.ClassResolver;
|
||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||
|
||||
/**
|
||||
* According to the decoder for java objects implemented by ObjectDecoder,
|
||||
* it is necessary to ensure that the transmitted objects can be serialized
|
||||
*/
|
||||
public class NettyDecoder extends ObjectDecoder {
|
||||
|
||||
public NettyDecoder(ClassResolver classResolver) {
|
||||
super(classResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) {
|
||||
ByteBuf byteBuf = in.retainedDuplicate();
|
||||
try {
|
||||
Object o = super.decode(ctx, in);
|
||||
if (o == null) {
|
||||
return byteBuf;
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CoderException("The encoding is abnormal, which may be caused by the failure of the transfer object to be deserialized");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.coder;
|
||||
|
||||
import cn.hippo4j.config.rpc.exception.CoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* this is a encoder, For custom gluing and unpacking<br>
|
||||
* {@link io.netty.handler.codec.serialization.ObjectEncoder}
|
||||
*/
|
||||
public class NettyEncoder extends MessageToByteEncoder<Serializable> {
|
||||
|
||||
private static final byte[] BYTE = new byte[4];
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf out) throws Exception {
|
||||
int startIndex = out.writerIndex();
|
||||
try (ByteBufOutputStream outPut = new ByteBufOutputStream(out)) {
|
||||
outPut.write(BYTE);
|
||||
try (ObjectOutputStream outputStream = new CompactObjectOutputStream(outPut)) {
|
||||
outputStream.writeObject(msg);
|
||||
outputStream.flush();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CoderException("The encoding is abnormal, which may be caused by the transfer object being unable to be serialized");
|
||||
}
|
||||
int endIndex = out.writerIndex();
|
||||
out.setInt(startIndex, endIndex - startIndex - 4);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.discovery;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* The adaptation layer of different service centers is used to know
|
||||
* the host of different services through the registration center
|
||||
*/
|
||||
public interface DiscoveryAdapter {
|
||||
|
||||
/**
|
||||
* get InetSocketAddress served in the registry
|
||||
*
|
||||
* @param name server name
|
||||
* @return InetSocketAddress
|
||||
*/
|
||||
InetSocketAddress getSocketAddress(String name);
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.exception;
|
||||
|
||||
/**
|
||||
* During decoding and encoding, if an exception occurs, an exception of type {@link CoderException} is thrown,
|
||||
* which is not different from a {@link RuntimeException}, but is more explicit about the type of exception
|
||||
*/
|
||||
public class CoderException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 8247610319171014183L;
|
||||
|
||||
public CoderException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CoderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CoderException(Throwable e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public CoderException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
|
||||
public CoderException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, throwable, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.exception;
|
||||
|
||||
/**
|
||||
* If an exception occurs during the connection between the server and the client, an exception of type
|
||||
* {@link ConnectionException} is thrown, which is not different from {@link RuntimeException}, but is more explicit
|
||||
* about the type of exception
|
||||
*/
|
||||
public class ConnectionException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 8247610319171014183L;
|
||||
|
||||
public ConnectionException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ConnectionException(Throwable e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public ConnectionException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
|
||||
public ConnectionException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, throwable, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.exception;
|
||||
|
||||
/**
|
||||
* If there is a timeout between the server and the client, you will get a {@link TimeOutException},
|
||||
* which is not different from {@link RuntimeException}, but it will be more explicit about the type of exception, right
|
||||
*/
|
||||
public class TimeOutException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 8247610319171014183L;
|
||||
|
||||
public TimeOutException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TimeOutException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TimeOutException(Throwable e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public TimeOutException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
|
||||
public TimeOutException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, throwable, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.handler;
|
||||
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
|
||||
/**
|
||||
* The handler in each connection, where the specific behavior of the connection
|
||||
* must be specified, such as serialization and parsing, requesting and receiving
|
||||
* requests, and so on
|
||||
*/
|
||||
public interface ConnectHandler {
|
||||
|
||||
/**
|
||||
* Processing after receiving the request
|
||||
*
|
||||
* @param request request
|
||||
*/
|
||||
default Response handler(Request request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing after receiving Response
|
||||
*
|
||||
* @param response response
|
||||
*/
|
||||
default void handler(Response response) {
|
||||
//
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.handler;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* Represents a network request connection and provides IO layer support
|
||||
*/
|
||||
public interface Connection extends Closeable {
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.handler;
|
||||
|
||||
import cn.hippo4j.config.rpc.coder.NettyDecoder;
|
||||
import cn.hippo4j.config.rpc.coder.NettyEncoder;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.pool.ChannelPoolHandler;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.serialization.ClassResolvers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Processing by the client connection pool handler to clean the buffer and define new connection properties
|
||||
*/
|
||||
@Slf4j
|
||||
public class NettyClientPoolHandler implements ChannelPoolHandler {
|
||||
|
||||
@Override
|
||||
public void channelReleased(Channel ch) {
|
||||
ch.writeAndFlush(Unpooled.EMPTY_BUFFER);
|
||||
log.info("The connection buffer has been emptied of data");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelAcquired(Channel ch) {
|
||||
// NO SOMETHING
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelCreated(Channel ch) {
|
||||
NioSocketChannel channel = (NioSocketChannel) ch;
|
||||
channel.config()
|
||||
.setTcpNoDelay(false);
|
||||
ch.pipeline().addLast(new NettyDecoder(ClassResolvers.cacheDisabled(null)));
|
||||
ch.pipeline().addLast(new NettyEncoder());
|
||||
ch.pipeline().addLast(new NettyClientTakeHandler());
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.handler;
|
||||
|
||||
import cn.hippo4j.config.rpc.exception.ConnectionException;
|
||||
import cn.hippo4j.config.rpc.support.ResultHolder;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
import cn.hippo4j.common.web.exception.IllegalException;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
/**
|
||||
* Interconnect with the netty mediation layer
|
||||
*/
|
||||
public class NettyClientTakeHandler extends ChannelInboundHandlerAdapter implements ConnectHandler {
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
try {
|
||||
Response response = (Response) msg;
|
||||
handler(response);
|
||||
ctx.flush();
|
||||
} catch (Exception e) {
|
||||
ctx.close();
|
||||
throw new IllegalException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
super.exceptionCaught(ctx, cause);
|
||||
Channel channel = ctx.channel();
|
||||
if (channel.isActive()) {
|
||||
ctx.close();
|
||||
} else {
|
||||
throw new ConnectionException(cause);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handler(Response response) {
|
||||
ResultHolder.put(response.getKey(), response);
|
||||
ResultHolder.wake(response.getKey());
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.handler;
|
||||
|
||||
import cn.hippo4j.config.rpc.exception.ConnectionException;
|
||||
import cn.hippo4j.config.rpc.process.ActivePostProcess;
|
||||
import cn.hippo4j.config.rpc.response.DefaultResponse;
|
||||
import cn.hippo4j.config.rpc.support.ClassRegistry;
|
||||
import cn.hippo4j.config.rpc.support.Instance;
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
import cn.hippo4j.common.toolkit.Assert;
|
||||
import cn.hippo4j.common.toolkit.ReflectUtil;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* netty adaptation layer
|
||||
*/
|
||||
public class NettyServerTakeHandler extends ChannelInboundHandlerAdapter implements ConnectHandler {
|
||||
|
||||
List<ActivePostProcess> processes;
|
||||
Instance instance;
|
||||
|
||||
public NettyServerTakeHandler(List<ActivePostProcess> processes, Instance instance) {
|
||||
this.processes = processes;
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public NettyServerTakeHandler(Instance instance) {
|
||||
this(new LinkedList<>(), instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
if (!(msg instanceof Request)) {
|
||||
return;
|
||||
}
|
||||
Request request = (Request) msg;
|
||||
Response response = handler(request);
|
||||
ctx.writeAndFlush(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
Channel channel = ctx.channel();
|
||||
if (channel.isActive()) {
|
||||
ctx.close();
|
||||
} else {
|
||||
throw new ConnectionException(cause);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response handler(Request request) {
|
||||
if (!preHandlers(request)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Class<?> cls = ClassRegistry.get(request.getClassName());
|
||||
Method method = ReflectUtil.getMethodByName(cls, request.getMethodName(), request.getParameterTypes());
|
||||
Assert.notNull(method);
|
||||
Object invoke = ReflectUtil.invoke(instance.getInstance(cls), method, request.getParameters());
|
||||
Response response = new DefaultResponse(request.getKey(), invoke.getClass(), invoke);
|
||||
postHandlers(request, response);
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
Response response = new DefaultResponse(request.getKey(), e, e.getMessage());
|
||||
afterCompletions(request, response, e);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean preHandlers(Request request) {
|
||||
for (ActivePostProcess process : processes) {
|
||||
if (!process.preHandler(request)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void postHandlers(Request request, Response response) {
|
||||
for (ActivePostProcess process : processes) {
|
||||
process.postHandler(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private void afterCompletions(Request request, Response response, Exception e) {
|
||||
for (ActivePostProcess process : processes) {
|
||||
process.afterCompletion(request, response, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.process;
|
||||
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
|
||||
/**
|
||||
* Callback while the connection is in progress
|
||||
*/
|
||||
public interface ActivePostProcess {
|
||||
|
||||
/**
|
||||
* Client: After establishing a connection and before passing parameters<br>
|
||||
* Server: Receives parameters and performs pre-call operations<br>
|
||||
*
|
||||
* @param request request
|
||||
* @return Whether to continue the execution. If it is a client, the returned value does not affect subsequent execution
|
||||
*/
|
||||
default boolean preHandler(Request request) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client: Action after receiving a response<br>
|
||||
* Server: performs the operation after the call<br>
|
||||
*
|
||||
* @param request request
|
||||
* @param response response
|
||||
*/
|
||||
default void postHandler(Request request, Response response) {
|
||||
// NO SOMETHING
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an exception or resource is cleaned
|
||||
*
|
||||
* @param request request
|
||||
* @param response response
|
||||
* @param e Exception
|
||||
*/
|
||||
default void afterCompletion(Request request, Response response, Exception e) {
|
||||
// NO SOMETHING
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.request;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* default request<br>
|
||||
* Use the fully qualified name key of the interface and override equals and hashCode
|
||||
*/
|
||||
public final class DefaultRequest implements Request {
|
||||
|
||||
String key;
|
||||
String className;
|
||||
String methodName;
|
||||
Class<?>[] parameterTypes;
|
||||
transient Object[] parameters;
|
||||
|
||||
public DefaultRequest(String key, String className, String methodName, Class<?>[] parameterTypes, Object[] parameters) {
|
||||
this.key = key;
|
||||
this.className = className;
|
||||
this.methodName = methodName;
|
||||
this.parameterTypes = parameterTypes;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
DefaultRequest that = (DefaultRequest) o;
|
||||
return Objects.equals(key, that.key)
|
||||
&& Objects.equals(className, that.className)
|
||||
&& Objects.equals(methodName, that.methodName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(key, className, methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redefine the behavior of serialization, that is, re-acquire the initially serialized
|
||||
* data from the stream and re-serialize it. Simple serialization will result in the
|
||||
* loss of the field identified by transient.
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream s) throws IOException {
|
||||
s.defaultWriteObject();
|
||||
if (parameters == null) {
|
||||
return;
|
||||
}
|
||||
// 序列化属性 parameters
|
||||
for (Object parameter : parameters) {
|
||||
s.writeObject(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redefine the deserialization behavior, and sequentially deserialize the data specified during
|
||||
* serialization, because there is data that is not deserialized during initial deserialization,
|
||||
* such as fields defined by transient
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
if (parameterTypes == null) {
|
||||
return;
|
||||
}
|
||||
// 反序列化属性 parameters
|
||||
int length = parameterTypes.length;
|
||||
Object[] a = new Object[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
a[i] = s.readObject();
|
||||
}
|
||||
this.parameters = a;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* request
|
||||
*/
|
||||
public interface Request extends Serializable {
|
||||
|
||||
/**
|
||||
* The unique identity of the current request
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* The Class name of the current request
|
||||
*/
|
||||
String getClassName();
|
||||
|
||||
/**
|
||||
* The Method name of the current request
|
||||
*/
|
||||
String getMethodName();
|
||||
|
||||
/**
|
||||
* The parameter type of the current request
|
||||
*/
|
||||
Class<?>[] getParameterTypes();
|
||||
|
||||
/**
|
||||
* The parameters of the current request
|
||||
*/
|
||||
Object[] getParameters();
|
||||
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* default request<br>
|
||||
* Use the fully qualified name key of the interface and override equals and hashCode
|
||||
*/
|
||||
public class DefaultResponse implements Response {
|
||||
|
||||
String key;
|
||||
Class<?> cls;
|
||||
transient Object obj;
|
||||
Throwable throwable;
|
||||
String errMsg;
|
||||
|
||||
public DefaultResponse(String key, Class<?> cls, Object obj, Throwable throwable, String errMsg) {
|
||||
this.key = key;
|
||||
this.cls = cls;
|
||||
this.obj = obj;
|
||||
this.throwable = throwable;
|
||||
this.errMsg = errMsg;
|
||||
}
|
||||
|
||||
public DefaultResponse(String key, Throwable throwable, String errMsg) {
|
||||
this(key, null, null, throwable, errMsg);
|
||||
}
|
||||
|
||||
public DefaultResponse(String key, Class<?> cls, Object obj) {
|
||||
this(key, cls, obj, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getCls() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObj() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrMsg() {
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErr() {
|
||||
return throwable != null || errMsg != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
DefaultResponse that = (DefaultResponse) o;
|
||||
return Objects.equals(key, that.key) && Objects.equals(cls, that.cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(key, cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redefine the behavior of serialization, that is, re-acquire the initially serialized
|
||||
* data from the stream and re-serialize it. Simple serialization will result in the
|
||||
* loss of the field identified by transient.
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream s) throws IOException {
|
||||
s.defaultWriteObject();
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
// 序列化属性 obj
|
||||
s.writeObject(this.obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redefine the deserialization behavior, and sequentially deserialize the data specified during
|
||||
* serialization, because there is data that is not deserialized during initial deserialization,
|
||||
* such as fields defined by transient
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
// 反序列化属性 obj
|
||||
this.obj = s.readObject();
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.response;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Response
|
||||
*/
|
||||
public interface Response extends Serializable {
|
||||
|
||||
/**
|
||||
* The unique identity of the current Response
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* The class of the current Response, The target of deserialization
|
||||
*/
|
||||
Class<?> getCls();
|
||||
|
||||
/**
|
||||
* The results of this request can be obtained, The source of deserialization
|
||||
*/
|
||||
Object getObj();
|
||||
|
||||
/**
|
||||
* The Throwable of the current Response
|
||||
*/
|
||||
Throwable getThrowable();
|
||||
|
||||
/**
|
||||
* the error message
|
||||
*/
|
||||
String getErrMsg();
|
||||
|
||||
/**
|
||||
* Whether the current request has an error
|
||||
*/
|
||||
boolean isErr();
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.server;
|
||||
|
||||
import cn.hippo4j.config.rpc.coder.NettyDecoder;
|
||||
import cn.hippo4j.config.rpc.coder.NettyEncoder;
|
||||
import cn.hippo4j.config.rpc.handler.NettyServerTakeHandler;
|
||||
import cn.hippo4j.config.rpc.process.ActivePostProcess;
|
||||
import cn.hippo4j.config.rpc.support.Instance;
|
||||
import cn.hippo4j.common.toolkit.Assert;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.serialization.ClassResolvers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* adapter to the netty server
|
||||
*/
|
||||
@Slf4j
|
||||
public class NettyServerConnection implements ServerConnection {
|
||||
|
||||
Integer port;
|
||||
EventLoopGroup leader;
|
||||
EventLoopGroup worker;
|
||||
Class<? extends ServerChannel> socketChannelCls = NioServerSocketChannel.class;
|
||||
List<ActivePostProcess> processes;
|
||||
Instance instance;
|
||||
ChannelFuture future;
|
||||
|
||||
public NettyServerConnection(EventLoopGroup leader, EventLoopGroup worker, List<ActivePostProcess> processes, Instance instance) {
|
||||
Assert.notNull(processes);
|
||||
Assert.notNull(instance);
|
||||
Assert.notNull(leader);
|
||||
Assert.notNull(worker);
|
||||
this.leader = leader;
|
||||
this.worker = worker;
|
||||
this.processes = processes;
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public NettyServerConnection(EventLoopGroup leader, EventLoopGroup worker, Instance instance) {
|
||||
this(leader, worker, new LinkedList<>(), instance);
|
||||
}
|
||||
|
||||
public NettyServerConnection(List<ActivePostProcess> processes, Instance instance) {
|
||||
this(new NioEventLoopGroup(), new NioEventLoopGroup(), processes, instance);
|
||||
}
|
||||
|
||||
public NettyServerConnection(Instance instance) {
|
||||
this(new NioEventLoopGroup(), new NioEventLoopGroup(), new LinkedList<>(), instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(int port) {
|
||||
ServerBootstrap server = new ServerBootstrap();
|
||||
server.group(leader, worker)
|
||||
.channel(socketChannelCls)
|
||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new NettyDecoder(ClassResolvers.cacheDisabled(null)));
|
||||
ch.pipeline().addLast(new NettyEncoder());
|
||||
ch.pipeline().addLast(new NettyServerTakeHandler(processes, instance));
|
||||
}
|
||||
});
|
||||
try {
|
||||
this.future = server.bind(port);
|
||||
log.info("The server is started and can receive requests. The listening port is {}", port);
|
||||
this.port = port;
|
||||
this.future.channel().closeFuture().sync();
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (port == null) {
|
||||
return;
|
||||
}
|
||||
leader.shutdownGracefully();
|
||||
worker.shutdownGracefully();
|
||||
this.future.channel().close();
|
||||
log.info("The server is shut down and no more requests are received. The release port is {}", port);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Server Implementation
|
||||
*/
|
||||
public class RPCServer implements Server {
|
||||
|
||||
int port;
|
||||
ServerConnection serverConnection;
|
||||
|
||||
public RPCServer(int port, ServerConnection serverConnection) {
|
||||
this.port = port;
|
||||
this.serverConnection = serverConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind() {
|
||||
serverConnection.bind(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down the server and release the port
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
serverConnection.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.server;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* the service for RPC, Explain the role of the service in the request
|
||||
*/
|
||||
public interface Server extends Closeable {
|
||||
|
||||
/**
|
||||
* Start the server. Attempt to listen on the port and receive the request.<br>
|
||||
* If the port being processed is already bound, an exception is thrown
|
||||
*/
|
||||
void bind();
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.server;
|
||||
|
||||
import cn.hippo4j.config.rpc.handler.Connection;
|
||||
|
||||
/**
|
||||
* This applies to server-side connections
|
||||
*/
|
||||
public interface ServerConnection extends Connection {
|
||||
|
||||
/**
|
||||
* Bind ports and process them
|
||||
*/
|
||||
void bind(int port);
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.support;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* the registration center for Client and Server
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ClassRegistry {
|
||||
|
||||
private static final Map<String, Class<?>> serverRegister = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* get a Obj in Registry center <br>
|
||||
*
|
||||
* @param s key
|
||||
* @return t element
|
||||
*/
|
||||
public static Class<?> get(String s) {
|
||||
return serverRegister.get(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* add the element to Registry Table <br>
|
||||
* if the key already exists, failure, and return before the value of the key. <br>
|
||||
* if success return the element
|
||||
*
|
||||
* @param s key
|
||||
* @param cls element
|
||||
* @return final mapped value
|
||||
*/
|
||||
public static Class<?> set(String s, Class<?> cls) {
|
||||
return serverRegister.putIfAbsent(s, cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* add the element to Registry Table <br>
|
||||
* if the key already exists, failure, replace it
|
||||
*
|
||||
* @param s key
|
||||
* @param cls element
|
||||
*/
|
||||
public static Class<?> put(String s, Class<?> cls) {
|
||||
return serverRegister.put(s, cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear
|
||||
*/
|
||||
public static void clear() {
|
||||
serverRegister.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.support;
|
||||
|
||||
import cn.hippo4j.common.toolkit.ReflectUtil;
|
||||
import cn.hippo4j.common.web.exception.IllegalException;
|
||||
|
||||
/**
|
||||
* Simply creating an instance of a class by its name and its specific type,
|
||||
* and then throwing an exception if it is an interface, is not elegant
|
||||
*/
|
||||
public class DefaultInstance implements Instance {
|
||||
|
||||
@Override
|
||||
public Object getInstance(Class<?> cls) {
|
||||
return ReflectUtil.createInstance(cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getInstance(String name) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(name);
|
||||
return getInstance(cls);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.support;
|
||||
|
||||
/**
|
||||
* Instance interface to get an instance
|
||||
*/
|
||||
public interface Instance {
|
||||
|
||||
/**
|
||||
* get a instance
|
||||
*
|
||||
* @param cls Class object
|
||||
* @return Information about instances created or found
|
||||
*/
|
||||
Object getInstance(Class<?> cls);
|
||||
|
||||
/**
|
||||
* Gets an instance of a class with a recognizable identity,
|
||||
* which can be the fully qualified name of class. It can also be a unique name in a container
|
||||
*
|
||||
* @param name Identifying name
|
||||
* @return Information about instances created or found
|
||||
*/
|
||||
Object getInstance(String name);
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.support;
|
||||
|
||||
import cn.hippo4j.config.rpc.exception.ConnectionException;
|
||||
import cn.hippo4j.config.rpc.handler.NettyClientPoolHandler;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.pool.ChannelHealthChecker;
|
||||
import io.netty.channel.pool.ChannelPool;
|
||||
import io.netty.channel.pool.ChannelPoolHandler;
|
||||
import io.netty.channel.pool.FixedChannelPool;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This parameter applies only to the connection pool of netty
|
||||
*/
|
||||
@Slf4j
|
||||
public class NettyConnectPool {
|
||||
|
||||
ChannelHealthChecker healthCheck = ChannelHealthChecker.ACTIVE;
|
||||
FixedChannelPool.AcquireTimeoutAction acquireTimeoutAction = FixedChannelPool.AcquireTimeoutAction.NEW;
|
||||
int maxPendingAcquires = Integer.MAX_VALUE;
|
||||
ChannelPoolHandler handler = new NettyClientPoolHandler();
|
||||
ChannelPool pool;
|
||||
String host;
|
||||
int port;
|
||||
|
||||
public NettyConnectPool(String host, int port, int maxConnect,
|
||||
long timeout, EventLoopGroup worker,
|
||||
Class<? extends Channel> socketChannelCls) {
|
||||
InetSocketAddress socketAddress = InetSocketAddress.createUnresolved(host, port);
|
||||
Bootstrap bootstrap = new Bootstrap()
|
||||
.group(worker)
|
||||
.channel(socketChannelCls)
|
||||
.remoteAddress(socketAddress);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.pool = new FixedChannelPool(bootstrap, handler, healthCheck, acquireTimeoutAction,
|
||||
timeout, maxConnect, maxPendingAcquires, true, true);
|
||||
log.info("The connection pool is established with the connection target {}:{}", host, port);
|
||||
NettyConnectPoolHolder.createPool(host, port, this);
|
||||
}
|
||||
|
||||
public Channel acquire(long timeoutMillis) {
|
||||
try {
|
||||
Future<Channel> fch = pool.acquire();
|
||||
return fch.get(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new ConnectionException("Failed to get the connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Future<Channel> acquire() {
|
||||
try {
|
||||
return pool.acquire();
|
||||
} catch (Exception e) {
|
||||
throw new ConnectionException("Failed to get the connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void release(Channel channel) {
|
||||
try {
|
||||
if (channel != null) {
|
||||
pool.release(channel);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ConnectionException("Failed to release the connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
pool.close();
|
||||
NettyConnectPoolHolder.remove(host, port);
|
||||
} catch (Exception e) {
|
||||
throw new ConnectionException("Failed to close the connection pool", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 cn.hippo4j.config.rpc.support;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.util.concurrent.EventExecutorGroup;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* To avoid creating multiple connection pools for the same host:port, save all connection pools of the client
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class NettyConnectPoolHolder {
|
||||
|
||||
static int maxConnect = 64;
|
||||
|
||||
static Map<String, NettyConnectPool> connectPoolMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static NettyConnectPool initPool(String host, int port,
|
||||
long timeout, EventLoopGroup worker) {
|
||||
return new NettyConnectPool(
|
||||
host, port, maxConnect,
|
||||
timeout, worker,
|
||||
NioSocketChannel.class);
|
||||
}
|
||||
|
||||
private static String getKey(String host, int port) {
|
||||
return host + ":" + port;
|
||||
}
|
||||
|
||||
/**
|
||||
* The connection pool connectPoolMapping may already exist before the connection pool
|
||||
* connectPoolMapping is established. In this case, the connection pool is directly overwritten
|
||||
*
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
* @param pool This parameter applies only to the connection pool of netty
|
||||
*/
|
||||
public static void createPool(String host, int port, NettyConnectPool pool) {
|
||||
connectPoolMap.put(getKey(host, port), pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a connection pool, or null if there is no corresponding connectPoolMapping
|
||||
*
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
* @return Map to the connection pool
|
||||
*/
|
||||
public static NettyConnectPool getPool(String host, int port) {
|
||||
return connectPoolMap.get(getKey(host, port));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a connection pool, and if there is no connectPoolMapping, creates one with the values provided and joins the connectPoolMapping
|
||||
*
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
* @param timeout timeout
|
||||
* @param worker Special {@link EventExecutorGroup} which allows registering {@link Channel}s
|
||||
* that get processed for later selection during the event loop.
|
||||
* @return Map to the connection pool
|
||||
*/
|
||||
public static synchronized NettyConnectPool getPool(String host, int port,
|
||||
long timeout, EventLoopGroup worker) {
|
||||
/*
|
||||
* this cannot use the computeIfAbsent method directly here because put is already used in init.
|
||||
* Details refer to https://bugs.openjdk.java.net/browse/JDK-8062841
|
||||
*/
|
||||
NettyConnectPool pool = getPool(host, port);
|
||||
return pool == null ? initPool(host, port, timeout, worker) : pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a connection connectPoolMapping. This must take effect at the same time as the connection pool is closed
|
||||
*
|
||||
* @param host host
|
||||
* @param port port
|
||||
*/
|
||||
public static void remove(String host, int port) {
|
||||
connectPoolMap.remove(getKey(host, port));
|
||||
}
|
||||
|
||||
/**
|
||||
* clear
|
||||
*/
|
||||
public static void clear() {
|
||||
connectPoolMap.clear();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue