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 2013/11/05 18:25:24 UTC

svn commit: r1539076 [4/17] - in /incubator/sirona/trunk: ./ agent/ agent/performance/ agent/performance/aop/ agent/performance/aop/src/ agent/performance/aop/src/main/ agent/performance/aop/src/main/java/ agent/performance/aop/src/main/java/org/ agent...

Added: incubator/sirona/trunk/agent/performance/web/src/test/java/org/apache/sirona/test/web/RequestPerformanceTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/web/src/test/java/org/apache/sirona/test/web/RequestPerformanceTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/web/src/test/java/org/apache/sirona/test/web/RequestPerformanceTest.java (added)
+++ incubator/sirona/trunk/agent/performance/web/src/test/java/org/apache/sirona/test/web/RequestPerformanceTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,117 @@
+/*
+ * 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.test.web;
+
+import com.gargoylesoftware.htmlunit.TextPage;
+import com.gargoylesoftware.htmlunit.WebClient;
+import org.apache.catalina.startup.Constants;
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.counters.Unit;
+import org.apache.sirona.repositories.Repository;
+import org.apache.sirona.web.registration.WebMonitoringInitializer;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.servlet.ServletContainerInitializer;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Arquillian.class)
+public class RequestPerformanceTest {
+    static { // to start faster
+        System.setProperty(Constants.DEFAULT_JARS_TO_SKIP, "a*,c*,d*,e*,g*,h*,i*,j*,l*,m*,n*,p*,r*,sa*,se*,sh*,su*,t*,v*,w*,x*,z*");
+    }
+
+    @Deployment(testable = false)
+    public static Archive<?> war() { // note: we depend on tomcat embedded adapter since we don't add dependencies + we use the fact Repository.INSTANCE is in the same JVM
+        return ShrinkWrap.create(WebArchive.class, "sirona-test.war")
+            .addPackages(true, "org.apache.sirona.web")
+            .addClasses(HittableServlet.class)
+            .addAsLibraries(
+                ShrinkWrap.create(JavaArchive.class, "sci.jar")
+                    .addAsServiceProvider(ServletContainerInitializer.class, WebMonitoringInitializer.class));
+    }
+
+    @ArquillianResource
+    private URL base;
+
+    @Before
+    public void resetCounters() {
+        Repository.INSTANCE.clear();
+    }
+
+    @Test
+    public void monitorRequest() throws IOException {
+        final TextPage page = newClient().getPage(base.toExternalForm() + "hit");
+        assertEquals(HttpURLConnection.HTTP_OK, page.getWebResponse().getStatusCode());
+
+        final Counter hitCounter = Repository.INSTANCE.getCounter(new Counter.Key(Role.WEB, "/sirona-test/hit"));
+        assertEquals(1, hitCounter.getHits());
+    }
+
+    @Test
+    public void knownStatusIsMonitored() throws IOException, InterruptedException {
+        final Role role = new Role("/sirona-test-HTTP-200", Unit.UNARY);
+        final int before = statusGaugeSum(role);
+        final TextPage page = newClient().getPage(base.toExternalForm() + "hit");
+        assertEquals(HttpURLConnection.HTTP_OK, page.getWebResponse().getStatusCode());
+        Thread.sleep(1000);
+        assertEquals("" + Repository.INSTANCE.getGaugeValues(0, System.currentTimeMillis() + 1000, role), 1, statusGaugeSum(role) - before);
+    }
+
+    @Test
+    public void unknownStatusIsIgnored() throws IOException, InterruptedException {
+        final TextPage page = newClient().getPage(base.toExternalForm() + "hit?status=4567");
+        assertEquals(4567, page.getWebResponse().getStatusCode());
+        Thread.sleep(1000);
+        assertEquals(0, statusGaugeSum(new Role("/sirona-test-HTTP-4567", Unit.UNARY)));
+    }
+
+    private static WebClient newClient() {
+        final WebClient webClient = new WebClient();
+        webClient.getOptions().setJavaScriptEnabled(false);
+        webClient.getOptions().setCssEnabled(false);
+        webClient.getOptions().setAppletEnabled(false);
+        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
+        return webClient;
+    }
+
+    private static int statusGaugeSum(final Role role) {
+        return sum(Repository.INSTANCE.getGaugeValues(0, System.currentTimeMillis() + 1000, role));
+    }
+
+    private static int sum(final Map<Long, Double> gaugeValues) {
+        int sum = 0;
+        for (final Double d : gaugeValues.values()) {
+            sum += d.intValue();
+        }
+        return sum;
+    }
+}

Added: incubator/sirona/trunk/agent/performance/web/src/test/resources/arquillian.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/web/src/test/resources/arquillian.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/web/src/test/resources/arquillian.xml (added)
+++ incubator/sirona/trunk/agent/performance/web/src/test/resources/arquillian.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+
+    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.
+-->
+<arquillian xmlns="http://jboss.org/schema/arquillian"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://jboss.org/schema/arquillian
+                                http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+  <container qualifier="tomcat7" default="true">
+    <configuration>
+      <property name="tomcatHome">target/tomcat7</property>
+      <property name="workDir">target/arquillian-work</property>
+      <property name="unpackArchive">true</property>
+      <property name="bindHttpPort">1234</property>
+    </configuration>
+  </container>
+</arquillian>

Added: incubator/sirona/trunk/agent/performance/web/src/test/resources/sirona.properties
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/web/src/test/resources/sirona.properties?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/web/src/test/resources/sirona.properties (added)
+++ incubator/sirona/trunk/agent/performance/web/src/test/resources/sirona.properties Tue Nov  5 17:25:15 2013
@@ -0,0 +1,15 @@
+# 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.
+org.apache.sirona.web.gauge.status.period = 150

Added: incubator/sirona/trunk/agent/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/pom.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/pom.xml (added)
+++ incubator/sirona/trunk/agent/pom.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>sirona</artifactId>
+    <groupId>org.apache.sirona</groupId>
+    <version>0.1-incubating-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>sirona-agent</artifactId>
+  <name>Apache Sirona Incubator :: Agent</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>performance</module>
+    <module>store</module>
+  </modules>
+</project>

Added: incubator/sirona/trunk/agent/store/cube/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/pom.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/pom.xml (added)
+++ incubator/sirona/trunk/agent/store/cube/pom.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>sirona-store</artifactId>
+    <groupId>org.apache.sirona</groupId>
+    <version>0.1-incubating-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>sirona-cube</artifactId>
+  <name>Apache Sirona Incubator:: Agent :: Store :: Cube</name>
+  <description>A DataStore for https://github.com/square/cube</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+    </dependency>
+  </dependencies>
+</project>

Added: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/Cube.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/Cube.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/Cube.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/Cube.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,168 @@
+/*
+ * 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.cube;
+
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class Cube {
+    private static final Logger LOGGER = Logger.getLogger(Cube.class.getName());
+
+    private static final String JSON_BASE = "{" +
+        "\"type\": \"%s\"," +
+        "\"time\": \"%s\"," +
+        "\"data\": %s" +
+        "}";
+
+    private static final String POST = "POST";
+    private static final String CONTENT_TYPE = "Content-Type";
+    private static final String CONTENT_LENGTH = "Content-Length";
+    private static final String APPLICATION_JSON = "application/json";
+
+    private static final String JS_ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+    private static final String UTC = "UTC";
+
+    private final CubeBuilder config;
+    private final Proxy proxy;
+
+    private final BlockingQueue<DateFormat> isoDateFormatters;
+
+    public Cube(final CubeBuilder cubeBuilder) {
+        config = cubeBuilder;
+        if (config.getProxyHost() != null) {
+            proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.getProxyHost(), config.getProxyPort()));
+        } else {
+            proxy = Proxy.NO_PROXY;
+        }
+
+        final int maxConcurrency = 2 * Runtime.getRuntime().availableProcessors();
+        isoDateFormatters = new ArrayBlockingQueue<DateFormat>(maxConcurrency);
+        for (int i = 0; i < maxConcurrency; i++) {
+            isoDateFormatters.add(newIsoDateFormatter());
+        }
+    }
+
+    public StringBuilder newEventStream() {
+        return new StringBuilder();
+    }
+
+    public void post(final StringBuilder payload) {
+        if (payload.length() > 0) {
+            doPost(finalPayload(payload.substring(0, payload.length() - 1)));
+        }
+    }
+
+    private void doPost(final String payload) {
+        try {
+            final URL url = new URL(config.getCollector());
+
+            final HttpURLConnection connection = HttpURLConnection.class.cast(url.openConnection(proxy));
+            connection.setRequestMethod(POST);
+            connection.setRequestProperty(CONTENT_TYPE, APPLICATION_JSON);
+            connection.setRequestProperty(CONTENT_LENGTH, Long.toString(payload.length()));
+            connection.setUseCaches(false);
+            connection.setDoInput(true);
+            connection.setDoOutput(true);
+
+            try {
+                final OutputStream output = connection.getOutputStream();
+                try {
+                    output.write(payload.getBytes());
+                    output.flush();
+
+                    final int status = connection.getResponseCode();
+                    if (status / 100 != 2) {
+                        LOGGER.warning("Pushed data but response code is: " + status);
+                    }
+                } finally {
+                    if (output != null) {
+                        output.close();
+                    }
+                }
+            } finally {
+                if (connection != null) {
+                    connection.disconnect();
+                }
+            }
+        } catch (final Exception e) {
+            LOGGER.log(Level.WARNING, "Can't post data to collector", e);
+        }
+    }
+
+    public static String finalPayload(final String events) {
+        return '[' + events + ']';
+    }
+
+    public StringBuilder buildEvent(final StringBuilder builder, final String type, final long time, final Map<String, Object> data) {
+        data.put("marker", config.getMarker());
+        return builder.append(String.format(JSON_BASE, type, isoDate(time), buildData(data))).append(',');
+    }
+
+    private String isoDate(final long time) {
+        final Date date = new Date(time);
+
+        DateFormat formatter = null;
+        try {
+            formatter = isoDateFormatters.take();
+            return formatter.format(date);
+        } catch (final InterruptedException e) {
+            return newIsoDateFormatter().format(date);
+        } finally {
+            if (formatter != null) {
+                isoDateFormatters.add(formatter);
+            }
+        }
+    }
+
+    private static String buildData(final Map<String, Object> data) {
+        final StringBuilder builder = new StringBuilder().append("{");
+        for (final Map.Entry<String, Object> entry : data.entrySet()) {
+            builder.append('\"').append(entry.getKey()).append('\"').append(':');
+
+            final Object value = entry.getValue();
+            if (String.class.isInstance(value)) {
+                builder.append('\"').append(value).append('\"');
+            } else {
+                builder.append(value);
+            }
+
+            builder.append(',');
+        }
+        builder.setLength(builder.length() - 1);
+        return builder.append("}").toString();
+    }
+
+    private static DateFormat newIsoDateFormatter() {
+        final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(JS_ISO_FORMAT, Locale.ENGLISH);
+        simpleDateFormat.setTimeZone(TimeZone.getTimeZone(UTC));
+        return simpleDateFormat;
+    }
+
+}

Added: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeBuilder.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeBuilder.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeBuilder.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeBuilder.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,65 @@
+/*
+ * 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.cube;
+
+import org.apache.sirona.configuration.Configuration;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@Configuration.AutoSet
+public class CubeBuilder {
+    private static final String DEFAULT_MARKER = "sirona";
+
+    private String proxyHost;
+    private int proxyPort;
+    private String collector;
+    private String marker;
+
+    public synchronized Cube build() {
+        if (marker == null) {
+            try {
+                marker = InetAddress.getLocalHost().getHostName();
+            } catch (final UnknownHostException e) {
+                marker = DEFAULT_MARKER;
+            }
+        }
+
+        return new Cube(this);
+    }
+
+    public String getProxyHost() {
+        return proxyHost;
+    }
+
+    public int getProxyPort() {
+        return proxyPort;
+    }
+
+    public String getCollector() {
+        return collector;
+    }
+
+    public String getMarker() {
+        return marker;
+    }
+
+    @Override
+    public String toString() {
+        return "CubeBuilder{" + collector + '}';
+    }
+}

Added: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeCounterDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeCounterDataStore.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeCounterDataStore.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeCounterDataStore.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,64 @@
+/*
+ * 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.cube;
+
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.store.counter.BatchCounterDataStore;
+
+import java.util.Collection;
+
+public class CubeCounterDataStore extends BatchCounterDataStore {
+    private static final String COUNTER_TYPE = "counter";
+
+    private static final String NAME = "name";
+    private static final String ROLE = "role";
+    private static final String UNIT = "unit";
+    private static final String CONCURRENCY = "concurrency";
+    private static final String MEAN = "mean";
+    private static final String VARIANCE = "variance";
+    private static final String HITS = "hits";
+    private static final String MAX = "max";
+    private static final String MIN = "min";
+    private static final String SUM = "sum";
+    private static final String M_2 = "m2";
+
+    private final Cube cube = Configuration.findOrCreateInstance(CubeBuilder.class).build();
+
+    @Override
+    protected synchronized void pushCountersByBatch(final Collection<Counter> instances) {
+        final long ts = System.currentTimeMillis();
+        final StringBuilder events = cube.newEventStream();
+        for (final Counter counter : instances) {
+            cube.buildEvent(events, COUNTER_TYPE, ts, new MapBuilder()
+                    .add(NAME, counter.getKey().getName())
+                    .add(ROLE, counter.getKey().getRole().getName())
+                    .add(UNIT, counter.getKey().getRole().getUnit().getName())
+                    // minimum metrics to be able to aggregate counters later
+                    .add(CONCURRENCY, counter.currentConcurrency().intValue())
+                    .add(MEAN, counter.getMean())
+                    .add(VARIANCE, counter.getVariance())
+                    .add(HITS, counter.getHits())
+                    .add(MAX, counter.getMax())
+                    .add(MIN, counter.getMin())
+                    .add(SUM, counter.getSum())
+                    .add(M_2, counter.getSecondMoment())
+                    .map());
+        }
+        cube.post(events);
+    }
+}

Propchange: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeCounterDataStore.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeDataStoreFactory.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeDataStoreFactory.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeDataStoreFactory.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeDataStoreFactory.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,25 @@
+/*
+ * 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.cube;
+
+import org.apache.sirona.store.DelegateDataStoreFactory;
+
+public class CubeDataStoreFactory extends DelegateDataStoreFactory {
+    public CubeDataStoreFactory() {
+        super(new CubeCounterDataStore(), new CubeGaugeDataStore(), new CubeNodeStatusDataStore());
+    }
+}

Propchange: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeDataStoreFactory.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeGaugeDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeGaugeDataStore.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeGaugeDataStore.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeGaugeDataStore.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.cube;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.gauges.RemoteGaugeDataStore;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class CubeGaugeDataStore extends RemoteGaugeDataStore {
+    private static final Logger LOGGER = Logger.getLogger(CubeGaugeDataStore.class.getName());
+
+    private static final String GAUGE_TYPE = "gauge";
+
+    private final Cube cube = Configuration.findOrCreateInstance(CubeBuilder.class).build();
+
+    @Override
+    public void addToGauge(final Role role, final long time, final double value) {
+        try {
+            cube.post(
+                cube.buildEvent(new StringBuilder(), GAUGE_TYPE, time,
+                        new MapBuilder()
+                                .add("value", value)
+                                .add("role", role.getName())
+                                .add("unit", role.getUnit().getName())
+                                .map()));
+        } catch (final Exception e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        }
+    }
+}

Propchange: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeGaugeDataStore.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeNodeStatusDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeNodeStatusDataStore.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeNodeStatusDataStore.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/CubeNodeStatusDataStore.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.cube;
+
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.status.NodeStatus;
+import org.apache.sirona.status.ValidationResult;
+import org.apache.sirona.store.status.PeriodicNodeStatusDataStore;
+
+public class CubeNodeStatusDataStore extends PeriodicNodeStatusDataStore {
+    private static final String VALIDATION_TYPE = "validation";
+
+    private final Cube cube = Configuration.findOrCreateInstance(CubeBuilder.class).build();
+
+    @Override
+    protected void reportStatus(final NodeStatus nodeStatus) {
+        final long ts = System.currentTimeMillis();
+        final StringBuilder events = cube.newEventStream();
+        for (final ValidationResult result : nodeStatus.getResults()) {
+            cube.buildEvent(events, VALIDATION_TYPE, ts, new MapBuilder()
+                .add("message", result.getMessage())
+                .add("status", result.getStatus().name())
+                .add("name", result.getName())
+                .map());
+        }
+        cube.post(events);
+    }
+}

Added: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/MapBuilder.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/MapBuilder.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/MapBuilder.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/MapBuilder.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.cube;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapBuilder {
+    private final Map<String, Object> map = new HashMap<String, Object>();
+
+    public MapBuilder add(final String key, final Object value) {
+        map.put(key, value);
+        return this;
+    }
+
+    public Map<String, Object> map() {
+        return map;
+    }
+}
\ No newline at end of file

Propchange: incubator/sirona/trunk/agent/store/cube/src/main/java/org/apache/sirona/cube/MapBuilder.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeDataStoreTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeDataStoreTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeDataStoreTest.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeDataStoreTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,96 @@
+/*
+ * 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.cube;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.gauges.Gauge;
+import org.apache.sirona.repositories.Repository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class CubeDataStoreTest {
+    private CubeServer server;
+    private Gauge.LoaderHelper gauges;
+
+    @Before
+    public void startCube() throws IOException {
+        server = new CubeServer("localhost", 1234).start();
+        Repository.INSTANCE.clear();
+        gauges = new Gauge.LoaderHelper(false);
+    }
+
+    @After
+    public void stopCube() {
+        gauges.destroy();
+        Repository.INSTANCE.clear();
+        server.stop();
+    }
+
+
+    @Test
+    public void store() throws InterruptedException, UnknownHostException {
+        { // force some counter data
+            final Counter counter = Repository.INSTANCE.getCounter(new Counter.Key(Role.PERFORMANCES, "test"));
+            counter.add(1.4);
+            counter.add(1.6);
+            Thread.sleep(150);
+            counter.add(2.3);
+            counter.add(2.9);
+            Thread.sleep(1500);
+        }
+
+        final Collection<String> messages = server.getMessages();
+        final Collection<String> gauges = new ArrayList<String>(4);
+        int counters = 0;
+        String aCounterMessage = null;
+        for (final String m : messages) {
+            if (m.contains("\"type\": \"gauge\"")) {
+                gauges.add(m.replaceAll("\"time\": \"[^\"]*\"", "\"time\": \"-\"")); // remove date to be able to test it easily
+            } else {
+                counters++;
+                aCounterMessage = m;
+            }
+        }
+
+        final String host = InetAddress.getLocalHost().getHostName();
+        assertTrue(gauges.contains("[{\"type\": \"gauge\",\"time\": \"-\",\"data\": {\"unit\":\"u\",\"marker\":\"" + host + "\",\"value\":0.0,\"role\":\"mock\"}}]"));
+        assertTrue(gauges.contains("[{\"type\": \"gauge\",\"time\": \"-\",\"data\": {\"unit\":\"u\",\"marker\":\"" + host + "\",\"value\":1.0,\"role\":\"mock\"}}]"));
+        assertTrue(gauges.contains("[{\"type\": \"gauge\",\"time\": \"-\",\"data\": {\"unit\":\"u\",\"marker\":\"" + host + "\",\"value\":2.0,\"role\":\"mock\"}}]"));
+
+        assertTrue(counters >= 3);
+        assertNotNull(aCounterMessage);
+        assertThat(aCounterMessage, containsString("name"));
+        assertThat(aCounterMessage, containsString("role"));
+        assertThat(aCounterMessage, containsString("hits"));
+        assertThat(aCounterMessage, containsString("sum"));
+        assertThat(aCounterMessage, containsString("concurrency"));
+        assertThat(aCounterMessage, containsString("marker"));
+    }
+}

Added: incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeServer.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeServer.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeServer.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/CubeServer.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,176 @@
+/*
+ * 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.cube;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.stream.ChunkedWriteHandler;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class CubeServer {
+    private static final Logger LOGGER = Logger.getLogger(CubeServer.class.getName());
+
+    private final String host;
+    private final int port;
+
+    private NioEventLoopGroup workerGroup;
+    private final Collection<String> messages = new LinkedList<String>();
+
+    public CubeServer(final String host, final int port) {
+        this.host = host;
+        if (port <= 0) { // generate a port
+            this.port = findNextAvailablePort();
+        } else {
+            this.port = port;
+        }
+    }
+
+    public Collection<String> getMessages() {
+        synchronized (messages) {
+            return new ArrayList<String>(messages);
+        }
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    private static int findNextAvailablePort() {
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(0);
+            return serverSocket.getLocalPort();
+        } catch (final IOException e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        } finally {
+            if (serverSocket != null) {
+                try {
+                    serverSocket.close();
+                } catch (final IOException e) {
+                    // no-op
+                }
+            }
+        }
+        return 0;
+    }
+
+    public CubeServer start() {
+        workerGroup = new NioEventLoopGroup(8);
+
+        try {
+            final ServerBootstrap bootstrap = new ServerBootstrap();
+            bootstrap
+                .option(ChannelOption.SO_REUSEADDR, true)
+                .option(ChannelOption.SO_SNDBUF, 1024)
+                .option(ChannelOption.TCP_NODELAY, true)
+                .group(workerGroup)
+                .channel(NioServerSocketChannel.class)
+                .childHandler(new Initializer(messages))
+                .bind(host, port).addListener(new ChannelFutureListener() {
+                @Override
+                public void operationComplete(final ChannelFuture future) throws Exception {
+                    if (!future.isSuccess()) {
+                        LOGGER.severe("Can't start HTTP server");
+                    } else {
+                        LOGGER.info(String.format("Server started on http://%s:%s", host, port));
+                    }
+                }
+            }).sync();
+        } catch (final InterruptedException e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        }
+
+        return this;
+    }
+
+    public void stop() {
+        if (workerGroup != null) {
+            workerGroup.shutdownGracefully();
+            LOGGER.info(String.format("Server http://%s:%s stopped", host, port));
+        }
+    }
+
+    private static class Initializer extends ChannelInitializer<SocketChannel> {
+        private final Collection<String> messages;
+
+        private Initializer(final Collection<String> messages) {
+            this.messages = messages;
+        }
+
+        @Override
+        protected void initChannel(final SocketChannel ch) throws Exception {
+            final ChannelPipeline pipeline = ch.pipeline();
+
+            pipeline
+                .addLast("decoder", new HttpRequestDecoder())
+                .addLast("aggregator", new HttpObjectAggregator(Integer.MAX_VALUE))
+                .addLast("encoder", new HttpResponseEncoder())
+                .addLast("chunked-writer", new ChunkedWriteHandler())
+                .addLast("featured-mock-server", new RequestHandler(messages));
+        }
+    }
+
+    private static class RequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
+        private final Collection<String> messages;
+
+        private RequestHandler(final Collection<String> messages) {
+            this.messages = messages;
+        }
+
+        @Override
+        protected void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest fullHttpRequest) throws Exception {
+            final ChannelFuture future;
+            if (HttpMethod.POST.equals(fullHttpRequest.getMethod())) {
+                synchronized (messages) {
+                    messages.add(fullHttpRequest.content().toString(Charset.defaultCharset()));
+                }
+                final HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
+                future = ctx.writeAndFlush(response);
+            } else {
+                LOGGER.warning("Received " + fullHttpRequest.getMethod());
+                future = ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR));
+            }
+            future.addListener(ChannelFutureListener.CLOSE);
+        }
+    }
+}
\ No newline at end of file

Added: incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/gauge/MockGauge.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/gauge/MockGauge.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/gauge/MockGauge.java (added)
+++ incubator/sirona/trunk/agent/store/cube/src/test/java/org/apache/sirona/cube/gauge/MockGauge.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.cube.gauge;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Unit;
+import org.apache.sirona.gauges.Gauge;
+
+public class MockGauge implements Gauge {
+    public static final Role MOCK = new Role("mock", Unit.UNARY);
+
+    private int count = 0;
+
+    @Override
+    public Role role() {
+        return MOCK;
+    }
+
+    @Override
+    public double value() {
+        return count++;
+    }
+
+    @Override
+    public long period() {
+        return 100;
+    }
+}

Added: incubator/sirona/trunk/agent/store/cube/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge (added)
+++ incubator/sirona/trunk/agent/store/cube/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge Tue Nov  5 17:25:15 2013
@@ -0,0 +1 @@
+org.apache.sirona.cube.gauge.MockGauge

Added: incubator/sirona/trunk/agent/store/cube/src/test/resources/sirona.properties
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/cube/src/test/resources/sirona.properties?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/cube/src/test/resources/sirona.properties (added)
+++ incubator/sirona/trunk/agent/store/cube/src/test/resources/sirona.properties Tue Nov  5 17:25:15 2013
@@ -0,0 +1,21 @@
+# 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.
+org.apache.sirona.store.DataStoreFactory = org.apache.sirona.cube.CubeDataStoreFactory
+org.apache.sirona.cube.period = 100
+org.apache.sirona.cube.CubeBuilder.collector = http://localhost:1234/1.0/event/put
+
+org.apache.sirona.core.gauge.activated = false

Added: incubator/sirona/trunk/agent/store/graphite/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/pom.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/pom.xml (added)
+++ incubator/sirona/trunk/agent/store/graphite/pom.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>sirona-store</artifactId>
+    <groupId>org.apache.sirona</groupId>
+    <version>0.1-incubating-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>sirona-graphite</artifactId>
+  <name>Apache Sirona Incubator:: Agent :: Store :: Graphite</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-servlet_3.0_spec</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+  </dependencies>
+</project>

Added: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/Graphite.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/Graphite.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/Graphite.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/Graphite.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,114 @@
+/*
+ * 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.graphite;
+
+import javax.net.SocketFactory;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.nio.charset.Charset;
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+public class Graphite implements Closeable {
+    private static final char LN = '\n';
+    private static final String SPACE = " ";
+    private static final Charset UTF_8 = Charset.forName("UTF-8");
+    private static final Pattern WHITESPACE = Pattern.compile("[\\s]+");
+    private static final String SPACE_REPLACEMENT = "_";
+    private static final String VALUE_FORMAT = "%2.2f";
+
+    private final Charset charset;
+    private final SocketFactory factory;
+    private final InetAddress address;
+    private final int port;
+
+    private BufferedWriter writer = null;
+    private Socket socket = null;
+
+    public Graphite(final SocketFactory factory, final InetAddress address, final int port, final Charset charset) throws IOException {
+        if (charset != null) {
+            this.charset = charset;
+        } else {
+            this.charset = UTF_8;
+        }
+        if (factory != null) {
+            this.factory = factory;
+        } else {
+            this.factory = SocketFactory.getDefault();
+        }
+        this.address = address;
+        this.port = port;
+    }
+
+    public Graphite(final SocketFactory factory, final String address, final int port, final Charset charset) throws IOException {
+        this(factory, InetAddress.getByName(address), port, charset);
+    }
+
+    public InetAddress getAddress() {
+        return address;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void open() throws IOException {
+        socket = factory.createSocket(address, port);
+        writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), charset));
+    }
+
+    /**
+     * this method is to use with open() and close() once for batch pushes.
+     */
+    public void push(final String metricPath, final double metricValue, final long metricTimeStamp) throws IOException {
+        writer.write(
+                WHITESPACE.matcher(noSpace(metricPath)).replaceAll(SPACE_REPLACEMENT) + SPACE
+                        + String.format(Locale.US, VALUE_FORMAT, metricValue) + SPACE
+                        + metricTimeStamp
+                        + LN);
+    }
+
+    @Override
+    public void close() {
+        try {
+            if (writer != null) {
+                writer.flush();
+                writer.close();
+            }
+        } catch (final IOException ioe) {
+            // no-op
+        }
+        try {
+            if (socket != null) {
+                socket.close();
+            }
+        } catch (final IOException ioe) {
+            // no-op
+        }
+        writer = null;
+        socket = null;
+    }
+
+    private static String noSpace(final String s) {
+        return s.replace(SPACE, SPACE_REPLACEMENT);
+    }
+
+}

Added: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteBuilder.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteBuilder.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteBuilder.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteBuilder.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.graphite;
+
+import org.apache.sirona.MonitoringException;
+import org.apache.sirona.configuration.Configuration;
+
+import javax.net.SocketFactory;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+@Configuration.AutoSet
+public class GraphiteBuilder {
+    private String address;
+    private int port;
+    private String charset;
+
+    public synchronized Graphite build() {
+        if (charset == null) {
+            charset = "UTF-8";
+        }
+        try {
+            return new Graphite(SocketFactory.getDefault(), address, port, Charset.forName(charset));
+        } catch (final IOException e) {
+            throw new MonitoringException(e);
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteCounterDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteCounterDataStore.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteCounterDataStore.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteCounterDataStore.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,62 @@
+/*
+ * 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.graphite;
+
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.counters.MetricData;
+import org.apache.sirona.store.counter.BatchCounterDataStore;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class GraphiteCounterDataStore extends BatchCounterDataStore {
+    private static final Logger LOGGER = Logger.getLogger(GraphiteCounterDataStore.class.getName());
+
+    private static final String COUNTER_PREFIX = "counter-";
+    private static final char SEP = '-';
+
+    private final Graphite graphite = Configuration.findOrCreateInstance(GraphiteBuilder.class).build();
+
+    @Override
+    protected synchronized void pushCountersByBatch(final Collection<Counter> instances) {
+        try {
+            graphite.open();
+
+            final long ts = System.currentTimeMillis();
+
+            for (final Counter counter : instances) {
+                final Counter.Key key = counter.getKey();
+                final String prefix = COUNTER_PREFIX + key.getRole().getName() + SEP + key.getName() + SEP;
+
+                for (final MetricData data : MetricData.values()) {
+                    graphite.push(
+                            prefix + data.name(),
+                            data.value(counter),
+                            ts);
+                }
+            }
+        } catch (final IOException e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        } finally {
+            graphite.close();
+        }
+    }
+
+}

Propchange: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteCounterDataStore.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteDataStoreFactory.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteDataStoreFactory.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteDataStoreFactory.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteDataStoreFactory.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,26 @@
+/*
+ * 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.graphite;
+
+import org.apache.sirona.store.DelegateDataStoreFactory;
+import org.apache.sirona.store.status.EmptyStatuses;
+
+public class GraphiteDataStoreFactory extends DelegateDataStoreFactory {
+    public GraphiteDataStoreFactory() {
+        super(new GraphiteCounterDataStore(), new GraphiteGaugeDataStore(), new EmptyStatuses());
+    }
+}

Propchange: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteDataStoreFactory.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteGaugeDataStore.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteGaugeDataStore.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteGaugeDataStore.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteGaugeDataStore.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.graphite;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.store.gauge.AggregatedGaugeDataStore;
+import org.apache.sirona.store.gauge.Value;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class GraphiteGaugeDataStore extends AggregatedGaugeDataStore {
+    private static final Logger LOGGER = Logger.getLogger(GraphiteGaugeDataStore.class.getName());
+
+    private static final String GAUGE_PREFIX = "gauge-";
+
+    private final Graphite graphite = Configuration.findOrCreateInstance(GraphiteBuilder.class).build();
+
+    @Override
+    protected void pushGauges(final Map<Role, Value> gauges) {
+        try {
+            graphite.open();
+
+            final long ts = System.currentTimeMillis();
+
+            for (final Map.Entry<Role, Value> gauge : gauges.entrySet()) {
+                graphite.push(GAUGE_PREFIX + gauge.getKey().getName(), gauge.getValue().getMean(), ts);
+            }
+        } catch (final IOException e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        } finally {
+            graphite.close();
+        }
+    }
+}

Propchange: incubator/sirona/trunk/agent/store/graphite/src/main/java/org/apache/sirona/graphite/GraphiteGaugeDataStore.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTest.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,76 @@
+/*
+ * 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.graphite;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class GraphiteTest extends GraphiteTestBase {
+    @Test
+    public void checkCountersAndGauges() throws InterruptedException {
+        { // force some counter data
+            final Counter counter = Repository.INSTANCE.getCounter(new Counter.Key(Role.PERFORMANCES, "test"));
+            Thread.sleep(175);
+            counter.add(1.4);
+            counter.add(1.6);
+            Thread.sleep(140);
+            counter.add(2.3);
+            counter.add(2.9);
+            Thread.sleep(30);
+        }
+
+        final Collection<String> messages = messages();
+        final Collection<String> counters = new ArrayList<String>(messages.size());
+        final Collection<String> gauges = new ArrayList<String>(messages.size());
+        for (final String msg : messages) {
+            final String substring = msg.substring(0, msg.lastIndexOf(" "));
+            if (msg.startsWith("counter")) {
+                counters.add(substring);
+            } else {
+                gauges.add(substring);
+            }
+        }
+
+        { // counters
+            assertEquals(30, counters.size());
+            assertTrue(counters.contains("counter-performances-test-Hits 2.00"));
+            assertTrue(counters.contains("counter-performances-test-Max 1.60"));
+            assertTrue(counters.contains("counter-performances-test-Mean 1.50"));
+            assertTrue(counters.contains("counter-performances-test-Min 1.40"));
+            assertTrue(counters.contains("counter-performances-test-StandardDeviation 0.14"));
+            assertTrue(counters.contains("counter-performances-test-Sum 3.00"));
+            assertTrue(counters.contains("counter-performances-test-Value 3.00"));
+        }
+        { // gauges
+            assertEquals(3, gauges.size());
+
+            final String message = gauges.toString();
+            // graphite store uses an aggregated gauge store
+            assertTrue("0.5 " + message, gauges.contains("gauge-mock 0.50"));
+            assertTrue("2.0 " + message, gauges.contains("gauge-mock 2.00"));
+            assertTrue("3.0 " + message, gauges.contains("gauge-mock 3.00"));
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTestBase.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTestBase.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTestBase.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/GraphiteTestBase.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,51 @@
+/*
+ * 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.graphite;
+
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.gauges.Gauge;
+import org.apache.sirona.graphite.server.GraphiteMockServer;
+import org.apache.sirona.repositories.Repository;
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.IOException;
+import java.util.Collection;
+
+public abstract class GraphiteTestBase {
+    private GraphiteMockServer server;
+    private Gauge.LoaderHelper gauges;
+
+    @Before
+    public void startGraphite() throws IOException {
+        Repository.INSTANCE.clear();
+        server = new GraphiteMockServer(1234).start();
+        gauges = new Gauge.LoaderHelper(false);
+    }
+
+    @After
+    public void shutdownGraphite() throws IOException {
+        Configuration.shutdown();
+        gauges.destroy();
+        server.stop();
+        Repository.INSTANCE.clear();
+    }
+
+    protected Collection<String> messages() {
+        return server.getMessages();
+    }
+}

Added: incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/gauge/MockGauge.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/gauge/MockGauge.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/gauge/MockGauge.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/gauge/MockGauge.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.graphite.gauge;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Unit;
+import org.apache.sirona.gauges.Gauge;
+
+public class MockGauge implements Gauge {
+    public static final Role MOCK = new Role("mock", Unit.UNARY);
+
+    private int count = 0;
+
+    @Override
+    public Role role() {
+        return MOCK;
+    }
+
+    @Override
+    public double value() {
+        return count++;
+    }
+
+    @Override
+    public long period() {
+        return 100;
+    }
+}

Added: incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/server/GraphiteMockServer.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/server/GraphiteMockServer.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/server/GraphiteMockServer.java (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/test/java/org/apache/sirona/graphite/server/GraphiteMockServer.java Tue Nov  5 17:25:15 2013
@@ -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 org.apache.sirona.graphite.server;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+// little mok to replace Graphite as a server
+public class GraphiteMockServer {
+    private final int port;
+
+    private ServerSocket server;
+    private GraphiteThread thread;
+
+    private Collection<String> messages = new ArrayList<String>();
+
+    public GraphiteMockServer(final int port) {
+        this.port = port;
+    }
+
+    public GraphiteMockServer start() throws IOException {
+        server = new ServerSocket(port);
+        thread = new GraphiteThread(server, messages);
+        thread.start();
+        return this;
+    }
+
+    public void stop() throws IOException {
+        thread.shutdown();
+        server.close();
+    }
+
+    public Collection<String> getMessages() {
+        return messages;
+    }
+
+    private static class GraphiteThread extends Thread {
+        private final Collection<String> messages;
+
+        private final AtomicBoolean done = new AtomicBoolean(false);
+        private final ServerSocket server;
+
+        public GraphiteThread(final ServerSocket server, final Collection<String> messages) {
+            this.messages = messages;
+            this.server = server;
+            setName("graphite-server");
+        }
+
+        @Override
+        public void run() {
+            while (!done.get()) {
+                try {
+                    final Socket s = server.accept();
+                    synchronized (this) {
+                        final InputStream is = s.getInputStream();
+                        final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+                        String line;
+
+                        try {
+                            while ((line = reader.readLine()) != null) {
+                                messages.add(line);
+                            }
+                        } finally {
+                            s.close();
+                        }
+                    }
+                } catch (final IOException e) {
+                    if (!done.get()) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }
+
+        public void shutdown() {
+            done.set(true);
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/store/graphite/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/test/resources/META-INF/services/org.apache.sirona.gauges.Gauge Tue Nov  5 17:25:15 2013
@@ -0,0 +1 @@
+org.apache.sirona.graphite.gauge.MockGauge

Added: incubator/sirona/trunk/agent/store/graphite/src/test/resources/sirona.properties
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/graphite/src/test/resources/sirona.properties?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/graphite/src/test/resources/sirona.properties (added)
+++ incubator/sirona/trunk/agent/store/graphite/src/test/resources/sirona.properties Tue Nov  5 17:25:15 2013
@@ -0,0 +1,24 @@
+# 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.
+org.apache.sirona.store.DataStoreFactory = org.apache.sirona.graphite.GraphiteDataStoreFactory
+
+org.apache.sirona.graphite.period = 125
+
+org.apache.sirona.graphite.GraphiteBuilder.address = localhost
+org.apache.sirona.graphite.GraphiteBuilder.port = 1234
+
+org.apache.sirona.core.gauge.activated = false

Added: incubator/sirona/trunk/agent/store/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/store/pom.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/store/pom.xml (added)
+++ incubator/sirona/trunk/agent/store/pom.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>sirona-agent</artifactId>
+    <groupId>org.apache.sirona</groupId>
+    <version>0.1-incubating-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>sirona-store</artifactId>
+  <name>Apache Sirona Incubator:: Agent :: Store</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>graphite</module>
+    <module>cube</module>
+  </modules>
+</project>

Modified: incubator/sirona/trunk/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/pom.xml?rev=1539076&r1=1539075&r2=1539076&view=diff
==============================================================================
--- incubator/sirona/trunk/pom.xml (original)
+++ incubator/sirona/trunk/pom.xml Tue Nov  5 17:25:15 2013
@@ -57,18 +57,8 @@
 
   <modules>
     <module>core</module>
-    <module>aop</module>
-    <module>jdbc</module>
-    <module>jpa</module>
-    <module>aspectj</module>
-    <module>cdi</module>
-    <module>spring</module>
-    <module>jta</module>
-    <module>web</module>
-    <module>reporting</module>
-    <module>graphite</module>
-    <module>cube</module>
-    <module>collector</module>
+    <module>agent</module>
+    <module>server</module>
   </modules>
 
   <developers>

Added: incubator/sirona/trunk/server/collector/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/server/collector/pom.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/server/collector/pom.xml (added)
+++ incubator/sirona/trunk/server/collector/pom.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>sirona-server</artifactId>
+    <groupId>org.apache.sirona</groupId>
+    <version>0.1-incubating-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>sirona-collector</artifactId>
+  <name>Apache Sirona Incubator :: Server :: Collector</name>
+  <packaging>war</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-servlet_3.0_spec</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-reporting</artifactId>
+      <version>${project.version}</version>
+      <classifier>classes</classifier>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.jaxrs</groupId>
+      <artifactId>jackson-jaxrs-json-provider</artifactId>
+      <version>2.2.2</version>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-cube</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+    </dependency>
+  </dependencies>
+</project>