--- /dev/null
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ */\r
+package org.apache.catalina.tribes.group.interceptors;\r
+\r
+import static java.util.concurrent.TimeUnit.MILLISECONDS;\r
+\r
+import java.util.Arrays;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
+\r
+import org.apache.catalina.tribes.ChannelException;\r
+import org.apache.catalina.tribes.Member;\r
+import org.apache.catalina.tribes.group.AbsoluteOrder;\r
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;\r
+\r
+/**\r
+ * A dinky coordinator, just uses a sorted version of the member array.\r
+ * \r
+ * @author rnewson\r
+ * \r
+ */\r
+public class SimpleCoordinator extends ChannelInterceptorBase {\r
+\r
+ private Member[] view;\r
+\r
+ private AtomicBoolean membershipChanged = new AtomicBoolean();\r
+\r
+ private void membershipChanged() {\r
+ membershipChanged.set(true);\r
+ }\r
+\r
+ @Override\r
+ public void memberAdded(final Member member) {\r
+ super.memberAdded(member);\r
+ membershipChanged();\r
+ installViewWhenStable();\r
+ }\r
+\r
+ @Override\r
+ public void memberDisappeared(final Member member) {\r
+ super.memberDisappeared(member);\r
+ membershipChanged();\r
+ installViewWhenStable();\r
+ }\r
+\r
+ /**\r
+ * Override to receive view changes.\r
+ * \r
+ * @param view\r
+ */\r
+ protected void viewChange(final Member[] view) {\r
+ }\r
+\r
+ @Override\r
+ public void start(int svc) throws ChannelException {\r
+ super.start(svc);\r
+ installViewWhenStable();\r
+ }\r
+\r
+ private void installViewWhenStable() {\r
+ int stableCount = 0;\r
+\r
+ while (stableCount < 10) {\r
+ if (membershipChanged.compareAndSet(true, false)) {\r
+ stableCount = 0;\r
+ } else {\r
+ stableCount++;\r
+ }\r
+ try {\r
+ MILLISECONDS.sleep(250);\r
+ } catch (final InterruptedException e) {\r
+ Thread.currentThread().interrupt();\r
+ }\r
+ }\r
+\r
+ final Member[] members = getMembers();\r
+ final Member[] view = Arrays.copyOf(members, members.length + 1);\r
+ view[members.length] = getLocalMember(false);\r
+ Arrays.sort(view, AbsoluteOrder.comp);\r
+ if (Arrays.equals(view, this.view)) {\r
+ return;\r
+ }\r
+ this.view = view;\r
+ viewChange(view);\r
+ }\r
+\r
+ @Override\r
+ public void stop(int svc) throws ChannelException {\r
+ super.stop(svc);\r
+ }\r
+\r
+ public Member[] getView() {\r
+ return view;\r
+ }\r
+\r
+ public Member getCoordinator() {\r
+ return view == null ? null : view[0];\r
+ }\r
+\r
+ public boolean isCoordinator() {\r
+ return view == null ? false : getLocalMember(false).equals(\r
+ getCoordinator());\r
+ }\r
+\r
+}\r