You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sirona.apache.org by rm...@apache.org on 2015/11/02 04:59:48 UTC
svn commit: r1711893 - in /incubator/sirona/trunk:
agent/pull/src/main/java/org/apache/sirona/agent/webapp/pull/repository/
api/src/main/java/org/apache/sirona/alert/
api/src/main/java/org/apache/sirona/configuration/ioc/
api/src/main/java/org/apache/s...
Author: rmannibucau
Date: Mon Nov 2 03:59:47 2015
New Revision: 1711893
URL: http://svn.apache.org/viewvc?rev=1711893&view=rev
Log:
SIRONA-47 adding AlertListener API
Added:
incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/
incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlertListener.java
incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlerterSupport.java
incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/CollectorBaseNodeStatusDataStore.java
incubator/sirona/trunk/core/src/test/java/org/apache/sirona/alert/
incubator/sirona/trunk/core/src/test/java/org/apache/sirona/alert/AlerterSupportTest.java
incubator/sirona/trunk/core/src/test/java/org/apache/sirona/repositories/
incubator/sirona/trunk/core/src/test/java/org/apache/sirona/repositories/DefaultRepositoryTest.java
Modified:
incubator/sirona/trunk/agent/pull/src/main/java/org/apache/sirona/agent/webapp/pull/repository/PullRepository.java
incubator/sirona/trunk/api/src/main/java/org/apache/sirona/configuration/ioc/IoCs.java
incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/EmptyStatuses.java
incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/NodeStatusDataStore.java
incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/PeriodicNodeStatusDataStore.java
incubator/sirona/trunk/core/src/main/java/org/apache/sirona/repositories/DefaultRepository.java
incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/InMemoryCollectorNodeStatusDataStore.java
incubator/sirona/trunk/core/src/test/resources/sirona.properties
incubator/sirona/trunk/plugins/hazelcast/agent/src/test/java/org/apache/sirona/plugin/hazelcast/BasicHazelcastTest.java
incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/agent/status/CassandraStatusDataStore.java
incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/collector/status/CassandraCollectorNodeStatusDataStore.java
incubator/sirona/trunk/server/websocket-server/src/test/java/org/apache/sirona/websocket/WebSocketTest.java
Modified: incubator/sirona/trunk/agent/pull/src/main/java/org/apache/sirona/agent/webapp/pull/repository/PullRepository.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/pull/src/main/java/org/apache/sirona/agent/webapp/pull/repository/PullRepository.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/agent/pull/src/main/java/org/apache/sirona/agent/webapp/pull/repository/PullRepository.java (original)
+++ incubator/sirona/trunk/agent/pull/src/main/java/org/apache/sirona/agent/webapp/pull/repository/PullRepository.java Mon Nov 2 03:59:47 2015
@@ -28,8 +28,8 @@ import org.apache.sirona.repositories.Re
import org.apache.sirona.status.NodeStatus;
import org.apache.sirona.status.NodeStatusReporter;
import org.apache.sirona.store.memory.counter.InMemoryCounterDataStore;
-import org.apache.sirona.store.status.EmptyStatuses;
import org.apache.sirona.store.memory.tracking.InMemoryPathTrackingDataStore;
+import org.apache.sirona.store.status.EmptyStatuses;
import java.util.Collection;
import java.util.Collections;
@@ -44,7 +44,7 @@ public class PullRepository extends Defa
private final boolean clearAfterCollect;
public PullRepository() {
- super(new InMemoryCounterDataStore(), new GaugeDataStoreAdapter(), new EmptyStatuses(), new InMemoryPathTrackingDataStore());
+ super(new InMemoryCounterDataStore(), new GaugeDataStoreAdapter(), new EmptyStatuses(), new InMemoryPathTrackingDataStore(), findAlerters());
cube = IoCs.findOrCreateInstance(CubeBuilder.class).build();
clearAfterCollect = Configuration.is(Configuration.CONFIG_PROPERTY_PREFIX + "pull.counter.clearOnCollect", false);
}
Added: incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlertListener.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlertListener.java?rev=1711893&view=auto
==============================================================================
--- incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlertListener.java (added)
+++ incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlertListener.java Mon Nov 2 03:59:47 2015
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.alert;
+
+import org.apache.sirona.status.NodeStatus;
+
+public interface AlertListener {
+ void onAlert(Alert alert);
+
+ class Alert {
+ private final String marker;
+ private final NodeStatus status;
+
+ protected Alert(final String node, final NodeStatus status) {
+ this.marker = node;
+ this.status = status;
+ }
+
+ public String getMarker() {
+ return marker;
+ }
+
+ public NodeStatus getStatus() {
+ return status;
+ }
+ }
+}
Added: incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlerterSupport.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlerterSupport.java?rev=1711893&view=auto
==============================================================================
--- incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlerterSupport.java (added)
+++ incubator/sirona/trunk/api/src/main/java/org/apache/sirona/alert/AlerterSupport.java Mon Nov 2 03:59:47 2015
@@ -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 org.apache.sirona.alert;
+
+import org.apache.sirona.status.NodeStatus;
+import org.apache.sirona.status.Status;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+public class AlerterSupport {
+ protected final Collection<AlertListener> listeners = new CopyOnWriteArraySet<AlertListener>();
+
+ public void notify(final Map<String, NodeStatus> nodeStatus) {
+ if (nodeStatus == null) {
+ return;
+ }
+ for (final Map.Entry<String, NodeStatus> entry : nodeStatus.entrySet()) {
+ final NodeStatus status = entry.getValue();
+ if (status.getStatus() != Status.OK) {
+ final AlertListener.Alert alert = new AlertListener.Alert(entry.getKey(), status);
+ for (final AlertListener listener : listeners) {
+ listener.onAlert(alert);
+ }
+ }
+ }
+ }
+
+ public void addAlerter(final AlertListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeAlerter(final AlertListener listener) {
+ listeners.remove(listener);
+ }
+
+ public boolean hasAlerter() {
+ return !listeners.isEmpty();
+ }
+}
Modified: incubator/sirona/trunk/api/src/main/java/org/apache/sirona/configuration/ioc/IoCs.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/api/src/main/java/org/apache/sirona/configuration/ioc/IoCs.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/api/src/main/java/org/apache/sirona/configuration/ioc/IoCs.java (original)
+++ incubator/sirona/trunk/api/src/main/java/org/apache/sirona/configuration/ioc/IoCs.java Mon Nov 2 03:59:47 2015
@@ -187,7 +187,14 @@ public final class IoCs {
continue;
}
- final String value = Configuration.getProperty(loadedClass.getName() + "." + field.getName(), null);
+ final String configKey;
+ if (key == null) {
+ configKey = loadedClass.getName() + "." + field.getName();
+ } else {
+ configKey = key + "." + field.getName();
+ }
+
+ final String value = Configuration.getProperty(configKey, null);
if (value != null) {
done.add(field.getName());
@@ -210,6 +217,10 @@ public final class IoCs {
}
public static void setSingletonInstance(final Class<?> clazz, final Object instance) {
+ if (instance == null) {
+ SINGLETONS.remove(clazz);
+ return;
+ }
SINGLETONS.put(clazz, instance);
}
Modified: incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/EmptyStatuses.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/EmptyStatuses.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/EmptyStatuses.java (original)
+++ incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/EmptyStatuses.java Mon Nov 2 03:59:47 2015
@@ -16,6 +16,7 @@
*/
package org.apache.sirona.store.status;
+import org.apache.sirona.alert.AlertListener;
import org.apache.sirona.status.NodeStatus;
import java.util.Map;
@@ -34,4 +35,16 @@ public class EmptyStatuses implements No
public void reset() {
// no-op
}
+
+ public void addAlerter(AlertListener listener) {
+ noAlert();
+ }
+
+ public void removeAlerter(final AlertListener listener) {
+ noAlert();
+ }
+
+ private void noAlert() {
+ throw new UnsupportedOperationException(getClass().getSimpleName() + " doesn't support alerts");
+ }
}
Modified: incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/NodeStatusDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/NodeStatusDataStore.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/NodeStatusDataStore.java (original)
+++ incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/NodeStatusDataStore.java Mon Nov 2 03:59:47 2015
@@ -16,6 +16,7 @@
*/
package org.apache.sirona.store.status;
+import org.apache.sirona.alert.AlertListener;
import org.apache.sirona.status.NodeStatus;
import java.util.Map;
@@ -23,4 +24,7 @@ import java.util.Map;
public interface NodeStatusDataStore {
Map<String, NodeStatus> statuses();
void reset();
+
+ void addAlerter(AlertListener listener);
+ void removeAlerter(AlertListener listener);
}
Modified: incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/PeriodicNodeStatusDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/PeriodicNodeStatusDataStore.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/PeriodicNodeStatusDataStore.java (original)
+++ incubator/sirona/trunk/api/src/main/java/org/apache/sirona/store/status/PeriodicNodeStatusDataStore.java Mon Nov 2 03:59:47 2015
@@ -16,6 +16,8 @@
*/
package org.apache.sirona.store.status;
+import org.apache.sirona.alert.AlertListener;
+import org.apache.sirona.alert.AlerterSupport;
import org.apache.sirona.configuration.Configuration;
import org.apache.sirona.configuration.ioc.Created;
import org.apache.sirona.configuration.ioc.Destroying;
@@ -35,6 +37,8 @@ import java.util.concurrent.atomic.Atomi
import java.util.logging.Level;
import java.util.logging.Logger;
+import static java.util.Collections.singletonMap;
+
public class PeriodicNodeStatusDataStore implements NodeStatusDataStore {
private static final Logger LOGGER = Logger.getLogger(PeriodicNodeStatusDataStore.class.getName());
@@ -42,6 +46,7 @@ public class PeriodicNodeStatusDataStore
protected final AtomicReference<NodeStatus> status = new AtomicReference<NodeStatus>();
protected final HashMap<String, NodeStatus> statusAsMap = new HashMap<String, NodeStatus>();
protected final NodeStatusReporter nodeStatusReporter;
+ protected final AlerterSupport listeners = new AlerterSupport();
public PeriodicNodeStatusDataStore() {
nodeStatusReporter = newNodeStatusReporter();
@@ -72,12 +77,23 @@ public class PeriodicNodeStatusDataStore
reload();
}
+ public void addAlerter(final AlertListener listener) {
+ listeners.addAlerter(listener);
+ }
+
+ public void removeAlerter(final AlertListener listener) {
+ listeners.removeAlerter(listener);
+ }
+
private void reload() {
final String name = getClass().getSimpleName().toLowerCase(Locale.ENGLISH).replace("nodestatusdatastore", "");
final long period = getPeriod(name);
+ if (period < 0) {
+ return;
+ }
final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory(name + "-status-schedule-"));
- final ScheduledFuture<?> future = ses.scheduleAtFixedRate(new ReportStatusTask(nodeStatusReporter), period, period, TimeUnit.MILLISECONDS);
+ final ScheduledFuture<?> future = ses.scheduleAtFixedRate(new ReportStatusTask(), period, period, TimeUnit.MILLISECONDS);
scheduledTask.set(new BatchFuture(ses, future));
}
@@ -100,22 +116,21 @@ public class PeriodicNodeStatusDataStore
return statusAsMap;
}
- private class ReportStatusTask implements Runnable {
- private final NodeStatusReporter reporter;
-
- public ReportStatusTask(final NodeStatusReporter nodeStatusReporter) {
- reporter = nodeStatusReporter;
+ protected void periodicTask() {
+ final NodeStatus nodeStatus = nodeStatusReporter.computeStatus();
+ try {
+ status.set(nodeStatus);
+ reportStatus(nodeStatus);
+ listeners.notify(singletonMap("local", nodeStatus));
+ } catch (final Exception e) {
+ LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
+ }
+ private class ReportStatusTask implements Runnable {
@Override
public void run() {
- final NodeStatus nodeStatus = reporter.computeStatus();
- try {
- status.set(nodeStatus);
- reportStatus(nodeStatus);
- } catch (final Exception e) {
- LOGGER.log(Level.SEVERE, e.getMessage(), e);
- }
+ PeriodicNodeStatusDataStore.this.periodicTask();
}
}
}
Modified: incubator/sirona/trunk/core/src/main/java/org/apache/sirona/repositories/DefaultRepository.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/main/java/org/apache/sirona/repositories/DefaultRepository.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/core/src/main/java/org/apache/sirona/repositories/DefaultRepository.java (original)
+++ incubator/sirona/trunk/core/src/main/java/org/apache/sirona/repositories/DefaultRepository.java Mon Nov 2 03:59:47 2015
@@ -18,6 +18,7 @@ package org.apache.sirona.repositories;
import org.apache.sirona.Role;
import org.apache.sirona.SironaException;
+import org.apache.sirona.alert.AlertListener;
import org.apache.sirona.configuration.Configuration;
import org.apache.sirona.configuration.ioc.IoCs;
import org.apache.sirona.counters.Counter;
@@ -40,7 +41,9 @@ import org.apache.sirona.store.gauge.Gau
import org.apache.sirona.store.status.CollectorNodeStatusDataStore;
import org.apache.sirona.store.status.NodeStatusDataStore;
import org.apache.sirona.store.tracking.PathTrackingDataStore;
+import org.apache.sirona.util.ClassLoaders;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.SortedMap;
@@ -53,11 +56,12 @@ public class DefaultRepository implement
protected final PathTrackingDataStore pathTrackingDataStore;
public DefaultRepository() {
- this(findCounterDataStore(), findGaugeDataStore(), findStatusDataStore(), findPathTrackingDataStore());
+ this(findCounterDataStore(), findGaugeDataStore(), findStatusDataStore(), findPathTrackingDataStore(), findAlerters());
}
protected DefaultRepository(final CounterDataStore counter, final CommonGaugeDataStore gauge, //
- final NodeStatusDataStore status, final PathTrackingDataStore pathTrackingDataStore) {
+ final NodeStatusDataStore status, final PathTrackingDataStore pathTrackingDataStore,
+ final Collection<AlertListener> alertListeners) {
this.counterDataStore = counter;
this.gaugeDataStore = gauge;
this.nodeStatusDataStore = status;
@@ -85,9 +89,36 @@ public class DefaultRepository implement
addGauge(new UsedNonHeapMemoryGauge());
addGauge(new ActiveThreadGauge());
}
+
+ for (final AlertListener listener : alertListeners) {
+ nodeStatusDataStore.addAlerter(listener);
+ }
+ }
+
+ protected static Collection<AlertListener> findAlerters() {
+ final Collection<AlertListener> listeners = new ArrayList<AlertListener>();
+ final String alerters = Configuration.getProperty(Configuration.CONFIG_PROPERTY_PREFIX + "alerters", null);
+ if (alerters != null && alerters.trim().length() > 0) {
+ for (final String alert : alerters.split(" *, *")) {
+ final String classKey = alert + ".class";
+ final String type = Configuration.getProperty(classKey, null);
+ if (type == null) {
+ throw new IllegalArgumentException("Missing configuration " + classKey);
+ }
+
+ try {
+ final Class<?> clazz = ClassLoaders.current().loadClass(type);
+ final AlertListener listener = IoCs.autoSet(alert, AlertListener.class.cast(clazz.newInstance()));
+ listeners.add(listener);
+ } catch (final Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ }
+ return listeners;
}
- private static NodeStatusDataStore findStatusDataStore() {
+ protected static NodeStatusDataStore findStatusDataStore() {
NodeStatusDataStore status = null;
try {
status = IoCs.findOrCreateInstance(NodeStatusDataStore.class);
@@ -100,7 +131,7 @@ public class DefaultRepository implement
return status;
}
- private static CommonGaugeDataStore findGaugeDataStore() {
+ protected static CommonGaugeDataStore findGaugeDataStore() {
CommonGaugeDataStore gauge = null;
try {
gauge = IoCs.findOrCreateInstance(GaugeDataStore.class);
@@ -120,7 +151,7 @@ public class DefaultRepository implement
return gauge;
}
- private static PathTrackingDataStore findPathTrackingDataStore() {
+ protected static PathTrackingDataStore findPathTrackingDataStore() {
PathTrackingDataStore pathTrackingDataStore = null;
try {
pathTrackingDataStore = IoCs.findOrCreateInstance(PathTrackingDataStore.class);
@@ -143,7 +174,7 @@ public class DefaultRepository implement
return pathTrackingDataStore;
}
- private static CounterDataStore findCounterDataStore() {
+ protected static CounterDataStore findCounterDataStore() {
CounterDataStore counter = null;
try {
counter = IoCs.findOrCreateInstance(CounterDataStore.class);
Added: incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/CollectorBaseNodeStatusDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/CollectorBaseNodeStatusDataStore.java?rev=1711893&view=auto
==============================================================================
--- incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/CollectorBaseNodeStatusDataStore.java (added)
+++ incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/CollectorBaseNodeStatusDataStore.java Mon Nov 2 03:59:47 2015
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.store.status;
+
+import org.apache.sirona.alert.AlertListener;
+import org.apache.sirona.alert.AlerterSupport;
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.configuration.ioc.Destroying;
+import org.apache.sirona.store.BatchFuture;
+import org.apache.sirona.util.DaemonThreadFactory;
+
+import java.util.Locale;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public abstract class CollectorBaseNodeStatusDataStore implements CollectorNodeStatusDataStore {
+ private final AlerterSupport listeners = new AlerterSupport();
+ private final AtomicReference<BatchFuture> scheduledTask = new AtomicReference<BatchFuture>();
+
+ @Destroying
+ public void shutdown() {
+ final BatchFuture task = scheduledTask.get();
+ if (task != null) {
+ task.done();
+ scheduledTask.compareAndSet(task, null);
+ }
+ }
+
+ @Override
+ public void reset() {
+ shutdown();
+ }
+
+ @Override
+ public void addAlerter(final AlertListener listener) {
+ listeners.addAlerter(listener);
+ if (scheduledTask.get() == null) {
+ final BatchFuture update = startTask();
+ if (!scheduledTask.compareAndSet(null, update)) {
+ update.done();
+ }
+ }
+ }
+
+ @Override
+ public void removeAlerter(final AlertListener listener) {
+ listeners.removeAlerter(listener);
+ if (!listeners.hasAlerter()) {
+ shutdown();
+ }
+ }
+
+ private BatchFuture startTask() {
+ final String name = getClass().getSimpleName().toLowerCase(Locale.ENGLISH).replace("nodestatusdatastore", "");
+ final long period = getPeriod(name);
+
+ final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory(name + "-status-alert-schedule-"));
+ final ScheduledFuture<?> future = ses.scheduleAtFixedRate(new CheckStatus(), period, period, TimeUnit.MILLISECONDS);
+ return new BatchFuture(ses, future);
+ }
+
+ protected int getPeriod(final String name) {
+ return Configuration.getInteger(Configuration.CONFIG_PROPERTY_PREFIX + name + ".status.period",
+ Configuration.getInteger(Configuration.CONFIG_PROPERTY_PREFIX + name + ".period", 60000));
+ }
+
+ private class CheckStatus implements Runnable {
+ private final Logger logger = Logger.getLogger(CheckStatus.class.getName());
+
+ public void run() {
+ try {
+ listeners.notify(CollectorBaseNodeStatusDataStore.this.statuses());
+ } catch (final Exception e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ }
+ }
+ }
+}
Modified: incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/InMemoryCollectorNodeStatusDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/InMemoryCollectorNodeStatusDataStore.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/InMemoryCollectorNodeStatusDataStore.java (original)
+++ incubator/sirona/trunk/core/src/main/java/org/apache/sirona/store/status/InMemoryCollectorNodeStatusDataStore.java Mon Nov 2 03:59:47 2015
@@ -17,14 +17,12 @@
package org.apache.sirona.store.status;
import org.apache.sirona.status.NodeStatus;
-import org.apache.sirona.store.status.CollectorNodeStatusDataStore;
-import org.apache.sirona.store.status.NodeStatusDataStore;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
-public class InMemoryCollectorNodeStatusDataStore implements CollectorNodeStatusDataStore {
+public class InMemoryCollectorNodeStatusDataStore extends CollectorBaseNodeStatusDataStore {
private final Map<String, NodeStatus> statuses = new ConcurrentHashMap<String, NodeStatus>();
@Override
@@ -34,6 +32,7 @@ public class InMemoryCollectorNodeStatus
@Override
public void reset() {
+ super.reset();
statuses.clear();
}
Added: incubator/sirona/trunk/core/src/test/java/org/apache/sirona/alert/AlerterSupportTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/test/java/org/apache/sirona/alert/AlerterSupportTest.java?rev=1711893&view=auto
==============================================================================
--- incubator/sirona/trunk/core/src/test/java/org/apache/sirona/alert/AlerterSupportTest.java (added)
+++ incubator/sirona/trunk/core/src/test/java/org/apache/sirona/alert/AlerterSupportTest.java Mon Nov 2 03:59:47 2015
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.alert;
+
+import org.apache.sirona.status.NodeStatus;
+import org.apache.sirona.status.Status;
+import org.apache.sirona.status.ValidationResult;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class AlerterSupportTest {
+ @Test
+ public void alert() {
+ final Map<String, NodeStatus> nodeStatus = new HashMap<String, NodeStatus>();
+
+ final AlerterSupport support = new AlerterSupport();
+ support.notify(nodeStatus); // all is empty but no exception
+
+ // add a listener
+ final Collection<AlertListener.Alert> alerts = new ArrayList<AlertListener.Alert>();
+ support.addAlerter(new AlertListener() {
+ public void onAlert(final Alert alert) {
+ alerts.add(alert);
+ }
+ });
+
+ support.notify(nodeStatus); // no status so no alert
+ assertEquals(0, alerts.size());
+
+ // now add a OK status
+ nodeStatus.put("host1", new NodeStatus(new ValidationResult[] { new ValidationResult("v1", Status.OK, "")}, new Date()));
+ support.notify(nodeStatus); // only 1 OK status so no alert
+ assertEquals(0, alerts.size());
+
+ // now add another OK status
+ nodeStatus.put("host2", new NodeStatus(new ValidationResult[] { new ValidationResult("v2", Status.OK, "")}, new Date()));
+ support.notify(nodeStatus); // only OK status so no alert
+ assertEquals(0, alerts.size());
+
+ // add a KO status so one alert
+ nodeStatus.put("host1", new NodeStatus(new ValidationResult[] { new ValidationResult("v2", Status.KO, "")}, new Date()));
+ support.notify(nodeStatus); // only OK status so no alert
+ assertEquals(1, alerts.size());
+ alerts.clear();
+
+ // add a DEGRADED status so one alert
+ nodeStatus.put("host1", new NodeStatus(new ValidationResult[] { new ValidationResult("v2", Status.DEGRADED, "")}, new Date()));
+ support.notify(nodeStatus); // only OK status so no alert
+ assertEquals(1, alerts.size());
+ alerts.clear();
+
+ // add a DEGRADED and a KO status so one alert
+ nodeStatus.put("host1", new NodeStatus(new ValidationResult[] { new ValidationResult("v2", Status.DEGRADED, "")}, new Date()));
+ nodeStatus.put("host2", new NodeStatus(new ValidationResult[] { new ValidationResult("v1", Status.KO, "")}, new Date()));
+ support.notify(nodeStatus); // only OK status so no alert
+ assertEquals(2, alerts.size());
+ alerts.clear();
+ }
+}
Added: incubator/sirona/trunk/core/src/test/java/org/apache/sirona/repositories/DefaultRepositoryTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/test/java/org/apache/sirona/repositories/DefaultRepositoryTest.java?rev=1711893&view=auto
==============================================================================
--- incubator/sirona/trunk/core/src/test/java/org/apache/sirona/repositories/DefaultRepositoryTest.java (added)
+++ incubator/sirona/trunk/core/src/test/java/org/apache/sirona/repositories/DefaultRepositoryTest.java Mon Nov 2 03:59:47 2015
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.repositories;
+
+import org.apache.sirona.SironaException;
+import org.apache.sirona.alert.AlertListener;
+import org.apache.sirona.configuration.ioc.IoCs;
+import org.apache.sirona.status.NodeStatus;
+import org.apache.sirona.status.NodeStatusReporter;
+import org.apache.sirona.status.Status;
+import org.apache.sirona.status.ValidationResult;
+import org.apache.sirona.store.status.NodeStatusDataStore;
+import org.apache.sirona.store.status.PeriodicNodeStatusDataStore;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+public class DefaultRepositoryTest {
+ @Test
+ public void alerts() {
+ if (Alerter1.instance != null && Alerter1.instance.alerts != null) {
+ Alerter1.instance.alerts.clear();
+ }
+ if (Alerter2.instance != null && Alerter2.instance.alerts != null) {
+ Alerter2.instance.alerts.clear();
+ }
+
+ NodeStatusDataStore original;
+ try {
+ original = IoCs.findOrCreateInstance(NodeStatusDataStore.class);
+ } catch (final SironaException se) {
+ original = null;
+ }
+
+ final ForTestPeriodicNodeStatusDataStore testNodeStatusStore = new ForTestPeriodicNodeStatusDataStore();
+ IoCs.setSingletonInstance(NodeStatusDataStore.class, testNodeStatusStore);
+ try {
+ new DefaultRepository(); // create alerters
+ assertEquals("a-config-value", Alerter1.instance.config);
+ assertNotNull(Alerter1.instance);
+ assertEquals(0, Alerter1.instance.alerts.size());
+ assertNotNull(Alerter2.instance);
+ assertEquals(0, Alerter2.instance.alerts.size());
+
+ testNodeStatusStore.periodicTask();
+ assertEquals(1, Alerter1.instance.alerts.size());
+ assertEquals(1, Alerter2.instance.alerts.size());
+ assertSame(Alerter1.instance.alerts.iterator().next(), Alerter2.instance.alerts.iterator().next());
+ } finally {
+ IoCs.setSingletonInstance(NodeStatusDataStore.class, original);
+ }
+ }
+
+ public static class Alerter1 implements AlertListener {
+ private static volatile Alerter1 instance;
+
+ private final Collection<Alert> alerts = new ArrayList<Alert>();
+
+ private String config;
+
+ public Alerter1() {
+ instance = this;
+ }
+
+ public void onAlert(final Alert alert) {
+ alerts.add(alert);
+ }
+ }
+ public static class Alerter2 implements AlertListener {
+ private static volatile Alerter2 instance;
+ private final Collection<Alert> alerts = new ArrayList<Alert>();
+
+ public Alerter2() {
+ instance = this;
+ }
+
+ public void onAlert(final Alert alert) {
+ alerts.add(alert);
+ }
+ }
+
+ public static class ForTestPeriodicNodeStatusDataStore extends PeriodicNodeStatusDataStore {
+ @Override
+ protected int getPeriod(final String name) {
+ return -1;
+ }
+
+ @Override
+ public void periodicTask() {
+ super.periodicTask();
+ }
+
+ @Override
+ protected NodeStatusReporter newNodeStatusReporter() {
+ return new NodeStatusReporter() {
+ @Override
+ public synchronized NodeStatus computeStatus() {
+ return new NodeStatus(new ValidationResult[] { new ValidationResult("ko", Status.KO, "")}, new Date());
+ }
+ };
+ }
+ }
+}
Modified: incubator/sirona/trunk/core/src/test/resources/sirona.properties
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/test/resources/sirona.properties?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/core/src/test/resources/sirona.properties (original)
+++ incubator/sirona/trunk/core/src/test/resources/sirona.properties Mon Nov 2 03:59:47 2015
@@ -23,3 +23,8 @@ org.apache.sirona.goodbeer=true
org.apache.sirona.configuration.IoCsTest$Field.field = field-value
org.apache.sirona.configuration.IoCsTest$Method.method = method-value
org.apache.sirona.configuration.IoCsTest$MethodNotField.methodNotField = method-value-again
+
+org.apache.sirona.alerters = test1,test2
+test1.class = org.apache.sirona.repositories.DefaultRepositoryTest$Alerter1
+test1.config = a-config-value
+test2.class = org.apache.sirona.repositories.DefaultRepositoryTest$Alerter2
Modified: incubator/sirona/trunk/plugins/hazelcast/agent/src/test/java/org/apache/sirona/plugin/hazelcast/BasicHazelcastTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/plugins/hazelcast/agent/src/test/java/org/apache/sirona/plugin/hazelcast/BasicHazelcastTest.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/plugins/hazelcast/agent/src/test/java/org/apache/sirona/plugin/hazelcast/BasicHazelcastTest.java (original)
+++ incubator/sirona/trunk/plugins/hazelcast/agent/src/test/java/org/apache/sirona/plugin/hazelcast/BasicHazelcastTest.java Mon Nov 2 03:59:47 2015
@@ -16,6 +16,10 @@
*/
package org.apache.sirona.plugin.hazelcast;
+import com.hazelcast.config.Config;
+import com.hazelcast.config.JoinConfig;
+import com.hazelcast.config.NetworkConfig;
+import com.hazelcast.config.TcpIpConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.LifecycleEvent;
@@ -33,6 +37,7 @@ import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.CountDownLatch;
+import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -45,8 +50,18 @@ public class BasicHazelcastTest {
@Test
public void gauges() throws Throwable {
- final HazelcastInstance instance1 = Hazelcast.newHazelcastInstance();
- final HazelcastInstance instance2 = Hazelcast.newHazelcastInstance();
+ final Config config = new Config();
+ final NetworkConfig networkConfig = new NetworkConfig();
+ final JoinConfig join = new JoinConfig();
+ final TcpIpConfig tcpIpConfig = new TcpIpConfig();
+ tcpIpConfig.setEnabled(true);
+ tcpIpConfig.setMembers(singletonList("localhost"));
+ join.setTcpIpConfig(tcpIpConfig);
+ networkConfig.setJoin(join);
+ config.setNetworkConfig(networkConfig);
+
+ final HazelcastInstance instance1 = Hazelcast.newHazelcastInstance(config);
+ final HazelcastInstance instance2 = Hazelcast.newHazelcastInstance(config);
HazelcastInstance instance3 = null;
Map<Long, Double> members1 = null, partitions;
@@ -54,7 +69,7 @@ public class BasicHazelcastTest {
final Gauge.LoaderHelper loader = new Gauge.LoaderHelper(false);
try {
Thread.sleep(250);
- instance3 = Hazelcast.newHazelcastInstance();
+ instance3 = Hazelcast.newHazelcastInstance(config);
Thread.sleep(250);
members1 = gaugeValues("hazelcast-members-cluster");
Modified: incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/agent/status/CassandraStatusDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/agent/status/CassandraStatusDataStore.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/agent/status/CassandraStatusDataStore.java (original)
+++ incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/agent/status/CassandraStatusDataStore.java Mon Nov 2 03:59:47 2015
@@ -56,6 +56,7 @@ public class CassandraStatusDataStore ex
return statuses;
}
statuses.put(marker, localStatus);
+ listeners.notify(statuses);
return statuses;
}
return super.statuses();
Modified: incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/collector/status/CassandraCollectorNodeStatusDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/collector/status/CassandraCollectorNodeStatusDataStore.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/collector/status/CassandraCollectorNodeStatusDataStore.java (original)
+++ incubator/sirona/trunk/server/store/cassandra/src/main/java/org/apache/sirona/cassandra/collector/status/CassandraCollectorNodeStatusDataStore.java Mon Nov 2 03:59:47 2015
@@ -31,7 +31,7 @@ import org.apache.sirona.configuration.i
import org.apache.sirona.status.NodeStatus;
import org.apache.sirona.status.Status;
import org.apache.sirona.status.ValidationResult;
-import org.apache.sirona.store.status.CollectorNodeStatusDataStore;
+import org.apache.sirona.store.status.CollectorBaseNodeStatusDataStore;
import java.util.Collection;
import java.util.Date;
@@ -41,7 +41,7 @@ import java.util.TreeMap;
import static org.apache.sirona.cassandra.collector.CassandraSirona.column;
-public class CassandraCollectorNodeStatusDataStore implements CollectorNodeStatusDataStore {
+public class CassandraCollectorNodeStatusDataStore extends CollectorBaseNodeStatusDataStore {
private final Keyspace keyspace;
private final String family;
private final String markerFamily;
@@ -101,9 +101,9 @@ public class CassandraCollectorNodeStatu
return statuses;
}
- @Override // TODO: like clearCounters() see if it should do something or not
- public void reset() {
- // no-op
+ @Override
+ public void reset() { // TODO: like clearCounters() see if it should do something or not
+ super.reset();
}
@Override
Modified: incubator/sirona/trunk/server/websocket-server/src/test/java/org/apache/sirona/websocket/WebSocketTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/server/websocket-server/src/test/java/org/apache/sirona/websocket/WebSocketTest.java?rev=1711893&r1=1711892&r2=1711893&view=diff
==============================================================================
--- incubator/sirona/trunk/server/websocket-server/src/test/java/org/apache/sirona/websocket/WebSocketTest.java (original)
+++ incubator/sirona/trunk/server/websocket-server/src/test/java/org/apache/sirona/websocket/WebSocketTest.java Mon Nov 2 03:59:47 2015
@@ -19,6 +19,7 @@ package org.apache.sirona.websocket;
import org.apache.catalina.startup.Constants;
import org.apache.johnzon.websocket.mapper.JohnzonTextDecoder;
import org.apache.sirona.Role;
+import org.apache.sirona.alert.AlertListener;
import org.apache.sirona.configuration.ioc.IoCs;
import org.apache.sirona.counters.Counter;
import org.apache.sirona.counters.Unit;
@@ -50,6 +51,7 @@ import org.junit.runner.RunWith;
import java.net.URL;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
@@ -122,7 +124,8 @@ public class WebSocketTest {
};
}
}),
- new InMemoryPathTrackingDataStore()
+ new InMemoryPathTrackingDataStore(),
+ Collections.<AlertListener>emptyList()
) {};
clientRepo.addGauge(new Gauge() {
@Override