{"action":"created","comment":{"url":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/comments/29395175","id":29395175,"diff_hunk":"@@ -0,0 +1,849 @@\n+/*\n+ * Copyright 2015 Red Hat, Inc. and/or its affiliates\n+ * and other contributors as indicated by the @author tags.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *    http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package org.hawkular.alerts.engine.impl;\n+\n+import com.datastax.driver.core.PreparedStatement;\n+import com.datastax.driver.core.ResultSet;\n+import com.datastax.driver.core.Row;\n+import java.util.ArrayList;\n+import java.util.Collection;\n+import java.util.EnumSet;\n+import java.util.HashMap;\n+import java.util.HashSet;\n+import java.util.Iterator;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.Timer;\n+import java.util.TimerTask;\n+import java.util.concurrent.CopyOnWriteArrayList;\n+import java.util.concurrent.CopyOnWriteArraySet;\n+import java.util.function.Predicate;\n+import javax.annotation.PostConstruct;\n+import javax.ejb.EJB;\n+import javax.ejb.Singleton;\n+import org.hawkular.alerts.api.model.condition.Alert;\n+import org.hawkular.alerts.api.model.condition.Condition;\n+import org.hawkular.alerts.api.model.condition.ConditionEval;\n+import org.hawkular.alerts.api.model.dampening.Dampening;\n+import org.hawkular.alerts.api.model.data.Data;\n+import org.hawkular.alerts.api.model.trigger.Tag;\n+import org.hawkular.alerts.api.model.trigger.Trigger;\n+import org.hawkular.alerts.api.services.ActionsService;\n+import org.hawkular.alerts.api.services.AlertsCriteria;\n+import org.hawkular.alerts.api.services.AlertsService;\n+import org.hawkular.alerts.api.services.DefinitionsService;\n+import org.hawkular.alerts.engine.log.MsgLogger;\n+import org.hawkular.alerts.engine.rules.RulesEngine;\n+import org.jboss.logging.Logger;\n+import com.datastax.driver.core.Session;\n+import com.google.gson.Gson;\n+import com.google.gson.GsonBuilder;\n+\n+/**\n+ * Cassandra implementation for {@link org.hawkular.alerts.api.services.AlertsService}.\n+ * This implementation processes data asynchronously using a buffer queue.\n+ *\n+ * @author Jay Shaughnessy\n+ * @author Lucas Ponce\n+ */\n+@Singleton\n+public class CassAlertsServiceImpl implements AlertsService {\n+    private final MsgLogger msgLog = MsgLogger.LOGGER;\n+    private final Logger log = Logger.getLogger(CassAlertsServiceImpl.class);\n+    private static final String ENGINE_DELAY = \"hawkular-alerts.engine-delay\";\n+    private static final String ENGINE_PERIOD = \"hawkular-alerts.engine-period\";\n+    private static final String CASSANDRA_KEYSPACE = \"hawkular-alerts.cassandra-keyspace\";\n+    private int delay;\n+    private int period;\n+\n+    private Session session;\n+    private String keyspace;\n+\n+    private Gson gson;\n+\n+    private PreparedStatement insertAlert;\n+    private PreparedStatement insertAlertTrigger;\n+    private PreparedStatement insertAlertCtime;\n+    private PreparedStatement insertAlertStatus;\n+    private PreparedStatement updateAlert;\n+    private PreparedStatement selectAlertStatus;\n+    private PreparedStatement deleteAlertStatus;\n+\n+    private final List<Data> pendingData;\n+    private final List<Alert> alerts;\n+    private final Set<Dampening> pendingTimeouts;\n+    private final Map<Trigger, List<Set<ConditionEval>>> autoResolvedTriggers;\n+    private final Set<Trigger> disabledTriggers;\n+\n+\n+    private final Timer wakeUpTimer;\n+    private TimerTask rulesTask;\n+\n+    @EJB\n+    RulesEngine rules;\n+\n+    @EJB\n+    DefinitionsService definitions;\n+\n+    @EJB\n+    ActionsService actions;\n+\n+    public CassAlertsServiceImpl() {\n+        pendingData = new CopyOnWriteArrayList<Data>();\n+        alerts = new CopyOnWriteArrayList<Alert>();\n+        pendingTimeouts = new CopyOnWriteArraySet<Dampening>();\n+        autoResolvedTriggers = new HashMap<Trigger, List<Set<ConditionEval>>>();\n+        disabledTriggers = new CopyOnWriteArraySet<Trigger>();\n+\n+        wakeUpTimer = new Timer(\"CassAlertsServiceImpl-Timer\");\n+\n+        delay = new Integer(AlertProperties.getProperty(ENGINE_DELAY, \"1000\"));\n+        period = new Integer(AlertProperties.getProperty(ENGINE_PERIOD, \"2000\"));\n+    }\n+\n+    @PostConstruct\n+    public void initServices() {\n+        try {\n+            if (this.keyspace == null) {\n+                this.keyspace = AlertProperties.getProperty(CASSANDRA_KEYSPACE, \"hawkular_alerts\");\n+            }\n+\n+            if (session == null) {\n+                session = CassCluster.getSession();\n+            }\n+\n+            initPreparedStatements();\n+\n+            GsonBuilder gsonBuilder = new GsonBuilder();\n+            gsonBuilder.registerTypeHierarchyAdapter(ConditionEval.class, new GsonAdapter<ConditionEval>());\n+            gson = gsonBuilder.create();\n+\n+            reload();\n+        } catch (Throwable t) {\n+            msgLog.errorCannotInitializeAlertsService(t.getMessage());\n+        }\n+    }\n+\n+    private void initPreparedStatements() throws Exception {\n+        if (insertAlert == null) {\n+            insertAlert = session.prepare(\"INSERT INTO \" + keyspace + \".alerts \" +\n+                    \"(alertId, payload) VALUES (?, ?) \");\n+        }\n+        if (insertAlertTrigger == null) {\n+            insertAlertTrigger = session.prepare(\"INSERT INTO \" + keyspace + \".alerts_triggers \" +\n+                    \"(alertId, triggerId) VALUES (?, ?) \");\n+        }\n+        if (insertAlertCtime == null) {\n+            insertAlertCtime = session.prepare(\"INSERT INTO \" + keyspace + \".alerts_ctimes \" +\n+                    \"(alertId, ctime) VALUES (?, ?) \");\n+\n+        }\n+        if (insertAlertStatus == null) {\n+            insertAlertStatus = session.prepare(\"INSERT INTO \" + keyspace + \".alerts_statuses \" +\n+                    \"(alertId, status) VALUES (?, ?) \");\n+        }\n+        if (updateAlert == null) {\n+            updateAlert = session.prepare(\"UPDATE \" + keyspace + \".alerts \" +\n+                    \"SET payload = ? WHERE alertId = ? \");\n+        }\n+        if (selectAlertStatus == null) {\n+            selectAlertStatus = session.prepare(\"SELECT alertId, status FROM \" + keyspace + \".alerts_statuses \" +\n+                    \"WHERE alertId = ? ALLOW FILTERING \");\n+        }\n+        if (deleteAlertStatus == null) {\n+            deleteAlertStatus = session.prepare(\"DELETE FROM \" + keyspace + \".alerts_statuses \" +\n+                    \"WHERE alertId = ? AND status = ?\");\n+        }\n+    }\n+\n+    public void addAlerts(Collection<Alert> alerts) throws Exception {\n+        if (alerts == null) {\n+            throw new IllegalArgumentException(\"Alerts must be not null\");\n+        }\n+        if (session == null) {\n+            throw new RuntimeException(\"Cassandra session is null\");\n+        }\n+        if (insertAlert == null) {\n+            throw new RuntimeException(\"insertAlert PreparedStatement is null\");\n+        }\n+        try {\n+            for (Alert a : alerts) {\n+                session.execute(insertAlert.bind(a.getAlertId(), toJson(a)));\n+                session.execute(insertAlertTrigger.bind(a.getAlertId(), a.getTriggerId()));\n+                session.execute(insertAlertCtime.bind(a.getAlertId(), a.getCtime()));\n+                session.execute(insertAlertStatus.bind(a.getAlertId(), a.getStatus().name()));\n+            }\n+        } catch (Exception e) {\n+            msgLog.errorDatabaseException(e.getMessage());\n+            throw e;\n+        }\n+    }\n+\n+    public List<Alert> getAlerts(AlertsCriteria criteria) throws Exception {\n+        if (session == null) {\n+            throw new RuntimeException(\"Cassandra session is null\");\n+        }\n+        boolean filter = (null != criteria && criteria.hasCriteria());\n+\n+        if (filter) {\n+            log.debugf(\"getAlerts criteria: %s\", criteria.toString());\n+        }\n+\n+        List<Alert> alerts = new ArrayList<>();\n+        Set<String> alertIds = new HashSet<>();\n+\n+        StringBuilder sAlerts = new StringBuilder(\"SELECT payload FROM \").append(keyspace).append(\".alerts \");\n+\n+        if (filter) {\n+            /*\n+                Triggers id can be passed explicitly in the criteria or indirectly via tags.\n+             */\n+            Set<String> triggerIds = new HashSet<>();\n+            if (isEmpty(criteria.getTriggerIds())) {\n+                if (!isEmpty(criteria.getTriggerId())) {\n+                    triggerIds.add(criteria.getTriggerId());\n+                }\n+            } else {\n+                for (String triggerId : criteria.getTriggerIds()) {\n+                    if (isEmpty(triggerId)) {\n+                        continue;\n+                    }\n+                    triggerIds.add(triggerId);\n+                }\n+            }\n+            if (!isEmpty(criteria.getTags()) || criteria.getTag() != null) {\n+                Set<Tag> tags = new HashSet<>();\n+                if (criteria.getTags() != null)  {\n+                    tags.addAll(criteria.getTags());\n+                }\n+                Tag tag = criteria.getTag();\n+                if (tag != null) {\n+                    tags.add(tag);\n+                }\n+                triggerIds.addAll(getTriggersIdByTags(tags));\n+            }\n+\n+            /*\n+                Get alertIds filtered by triggerIds\n+             */\n+            Set<String> alertIdsFilteredByTriggers = new HashSet<>();\n+            boolean filterByTriggers = false;\n+            if (triggerIds.size() > 0) {\n+                filterByTriggers = true;\n+                StringBuilder sAlertsTriggers = new StringBuilder(\"SELECT alertId FROM \").append(keyspace)\n+                        .append(\".alerts_triggers WHERE \");\n+                if (triggerIds.size() == 1) {\n+                    sAlertsTriggers.append(\"( triggerId = '\");\n+                    sAlertsTriggers.append(triggerIds.iterator().next());\n+                    sAlertsTriggers.append(\"' )\");\n+                } else {\n+                    sAlertsTriggers.append(\"( triggerId IN (\");\n+                    int entries = 0;\n+                    for (String triggerId : triggerIds) {\n+                        if (isEmpty(triggerId)) {\n+                            continue;\n+                        }\n+                        sAlertsTriggers.append(entries++ > 0 ? \",\" : \"\");\n+                        sAlertsTriggers.append(\"'\");\n+                        sAlertsTriggers.append(triggerId);\n+                        sAlertsTriggers.append(\"'\");\n+                    }\n+                    sAlertsTriggers.append(\") )\");\n+                }\n+                try {\n+                    ResultSet rsAlertIdsByTriggerIds = session.execute(sAlertsTriggers.toString());\n+                    if (rsAlertIdsByTriggerIds.isExhausted()) {\n+                        alertIdsFilteredByTriggers.add(\"empty-alert\");\n+                    } else {\n+                        Iterator<Row> itAlertIdsByTriggerIds = rsAlertIdsByTriggerIds.iterator();\n+                        while (itAlertIdsByTriggerIds.hasNext()) {\n+                            Row row = itAlertIdsByTriggerIds.next();\n+                            String alertId = row.getString(\"alertId\");\n+                            alertIdsFilteredByTriggers.add(alertId);\n+                        }\n+                    }\n+                } catch (Exception e) {\n+                    msgLog.errorDatabaseException(e.getMessage());\n+                    throw e;\n+                }\n+            }\n+\n+            /*\n+                Add ctime clause\n+             */\n+            Set<String> alertIdsFilteredByCtime = new HashSet<>();\n+            boolean filterByCtime = false;\n+            if (criteria.getStartTime() != null || criteria.getEndTime() != null) {\n+                filterByCtime = true;\n+                StringBuilder sAlertsCtimes = new StringBuilder(\"SELECT alertId FROM \").append(keyspace)\n+                        .append(\".alerts_ctimes WHERE \");\n+                boolean andNeeded = false;\n+                if (criteria.getStartTime() != null) {\n+                    sAlertsCtimes.append(\"( ctime >= \");\n+                    sAlertsCtimes.append(criteria.getStartTime());\n+                    sAlertsCtimes.append(\" )\");\n+                    andNeeded = true;\n+                }\n+                if (criteria.getEndTime() != null) {\n+                    if (andNeeded) {\n+                        sAlertsCtimes.append(\" AND \");\n+                    }\n+                    sAlertsCtimes.append(\"( ctime <= \");\n+                    sAlertsCtimes.append(criteria.getEndTime());\n+                    sAlertsCtimes.append(\" )\");\n+                }\n+                sAlertsCtimes.append(\" ALLOW FILTERING \");","path":"hawkular-alerts-engine/src/main/java/org/hawkular/alerts/engine/impl/CassAlertsServiceImpl.java","position":310,"original_position":310,"commit_id":"8766d4da5a9ed4b62a1c74f2fbb3e98fabf394be","original_commit_id":"8766d4da5a9ed4b62a1c74f2fbb3e98fabf394be","user":{"login":"jsanda","id":168121,"avatar_url":"https://avatars.githubusercontent.com/u/168121?v=3","gravatar_id":"","url":"https://api.github.com/users/jsanda","html_url":"https://github.com/jsanda","followers_url":"https://api.github.com/users/jsanda/followers","following_url":"https://api.github.com/users/jsanda/following{/other_user}","gists_url":"https://api.github.com/users/jsanda/gists{/gist_id}","starred_url":"https://api.github.com/users/jsanda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jsanda/subscriptions","organizations_url":"https://api.github.com/users/jsanda/orgs","repos_url":"https://api.github.com/users/jsanda/repos","events_url":"https://api.github.com/users/jsanda/events{/privacy}","received_events_url":"https://api.github.com/users/jsanda/received_events","type":"User","site_admin":false},"body":"I absolutely agree with merging changes sooner rather than later. The best way to learn is to have people beat on it, and that won't happen until the changes get merged. With that said, a lot of the things I have mentioned are not simply matters of scale. They are recommended/best practices and anti-patterns. Moving to Cassandra is a big paradigm shift, and Lucas is off to a really nice start; however, you want to cognizant of things you should and should not do regardless of scale.","created_at":"2015-04-30T00:26:30Z","updated_at":"2015-04-30T00:26:30Z","html_url":"https://github.com/hawkular/hawkular-alerts/pull/40#discussion_r29395175","pull_request_url":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40","_links":{"self":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/comments/29395175"},"html":{"href":"https://github.com/hawkular/hawkular-alerts/pull/40#discussion_r29395175"},"pull_request":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40"}}},"pull_request":{"url":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40","id":34357288,"html_url":"https://github.com/hawkular/hawkular-alerts/pull/40","diff_url":"https://github.com/hawkular/hawkular-alerts/pull/40.diff","patch_url":"https://github.com/hawkular/hawkular-alerts/pull/40.patch","issue_url":"https://api.github.com/repos/hawkular/hawkular-alerts/issues/40","number":40,"state":"open","locked":false,"title":"HWKALERTS-34 Add a Cassandra implementation","user":{"login":"lucasponce","id":1662329,"avatar_url":"https://avatars.githubusercontent.com/u/1662329?v=3","gravatar_id":"","url":"https://api.github.com/users/lucasponce","html_url":"https://github.com/lucasponce","followers_url":"https://api.github.com/users/lucasponce/followers","following_url":"https://api.github.com/users/lucasponce/following{/other_user}","gists_url":"https://api.github.com/users/lucasponce/gists{/gist_id}","starred_url":"https://api.github.com/users/lucasponce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucasponce/subscriptions","organizations_url":"https://api.github.com/users/lucasponce/orgs","repos_url":"https://api.github.com/users/lucasponce/repos","events_url":"https://api.github.com/users/lucasponce/events{/privacy}","received_events_url":"https://api.github.com/users/lucasponce/received_events","type":"User","site_admin":false},"body":"Initial branch with support for Cassandra persistence.\r\nThe \"rest\" profile has been extended also in hawkular-alerts-engine and hawkular-alerts-rest-tests projects to provide a server with Cassandra embedded as similar way it works in Kettle.\r\nThere is space for improvement, but we can have this start point here.\r\n\r\nPlease, help me to review & test it and check how it goes.\r\nThanks,\r\n","created_at":"2015-04-29T12:25:16Z","updated_at":"2015-04-30T00:26:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bf3445211f02b9f1f87d1aa1424818bce729e218","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40/commits","review_comments_url":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40/comments","review_comment_url":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/comments{/number}","comments_url":"https://api.github.com/repos/hawkular/hawkular-alerts/issues/40/comments","statuses_url":"https://api.github.com/repos/hawkular/hawkular-alerts/statuses/8766d4da5a9ed4b62a1c74f2fbb3e98fabf394be","head":{"label":"lucasponce:cassandra-lifecycle","ref":"cassandra-lifecycle","sha":"8766d4da5a9ed4b62a1c74f2fbb3e98fabf394be","user":{"login":"lucasponce","id":1662329,"avatar_url":"https://avatars.githubusercontent.com/u/1662329?v=3","gravatar_id":"","url":"https://api.github.com/users/lucasponce","html_url":"https://github.com/lucasponce","followers_url":"https://api.github.com/users/lucasponce/followers","following_url":"https://api.github.com/users/lucasponce/following{/other_user}","gists_url":"https://api.github.com/users/lucasponce/gists{/gist_id}","starred_url":"https://api.github.com/users/lucasponce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucasponce/subscriptions","organizations_url":"https://api.github.com/users/lucasponce/orgs","repos_url":"https://api.github.com/users/lucasponce/repos","events_url":"https://api.github.com/users/lucasponce/events{/privacy}","received_events_url":"https://api.github.com/users/lucasponce/received_events","type":"User","site_admin":false},"repo":{"id":29670224,"name":"hawkular-alerts","full_name":"lucasponce/hawkular-alerts","owner":{"login":"lucasponce","id":1662329,"avatar_url":"https://avatars.githubusercontent.com/u/1662329?v=3","gravatar_id":"","url":"https://api.github.com/users/lucasponce","html_url":"https://github.com/lucasponce","followers_url":"https://api.github.com/users/lucasponce/followers","following_url":"https://api.github.com/users/lucasponce/following{/other_user}","gists_url":"https://api.github.com/users/lucasponce/gists{/gist_id}","starred_url":"https://api.github.com/users/lucasponce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucasponce/subscriptions","organizations_url":"https://api.github.com/users/lucasponce/orgs","repos_url":"https://api.github.com/users/lucasponce/repos","events_url":"https://api.github.com/users/lucasponce/events{/privacy}","received_events_url":"https://api.github.com/users/lucasponce/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/lucasponce/hawkular-alerts","description":"Alerting subsystem for Hawkular","fork":true,"url":"https://api.github.com/repos/lucasponce/hawkular-alerts","forks_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/forks","keys_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/teams","hooks_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/hooks","issue_events_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/issues/events{/number}","events_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/events","assignees_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/assignees{/user}","branches_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/branches{/branch}","tags_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/tags","blobs_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/git/refs{/sha}","trees_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/statuses/{sha}","languages_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/languages","stargazers_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/stargazers","contributors_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/contributors","subscribers_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/subscribers","subscription_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/subscription","commits_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/commits{/sha}","git_commits_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/git/commits{/sha}","comments_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/comments{/number}","issue_comment_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/issues/comments{/number}","contents_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/contents/{+path}","compare_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/merges","archive_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/downloads","issues_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/issues{/number}","pulls_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/pulls{/number}","milestones_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/milestones{/number}","notifications_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/labels{/name}","releases_url":"https://api.github.com/repos/lucasponce/hawkular-alerts/releases{/id}","created_at":"2015-01-22T09:03:07Z","updated_at":"2015-04-01T09:07:51Z","pushed_at":"2015-04-29T14:19:09Z","git_url":"git://github.com/lucasponce/hawkular-alerts.git","ssh_url":"git@github.com:lucasponce/hawkular-alerts.git","clone_url":"https://github.com/lucasponce/hawkular-alerts.git","svn_url":"https://github.com/lucasponce/hawkular-alerts","homepage":null,"size":1017,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"hawkular:wintermute","ref":"wintermute","sha":"cd419bc1b385603a86d40f9ac9a08925ec90fa1d","user":{"login":"hawkular","id":10179627,"avatar_url":"https://avatars.githubusercontent.com/u/10179627?v=3","gravatar_id":"","url":"https://api.github.com/users/hawkular","html_url":"https://github.com/hawkular","followers_url":"https://api.github.com/users/hawkular/followers","following_url":"https://api.github.com/users/hawkular/following{/other_user}","gists_url":"https://api.github.com/users/hawkular/gists{/gist_id}","starred_url":"https://api.github.com/users/hawkular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hawkular/subscriptions","organizations_url":"https://api.github.com/users/hawkular/orgs","repos_url":"https://api.github.com/users/hawkular/repos","events_url":"https://api.github.com/users/hawkular/events{/privacy}","received_events_url":"https://api.github.com/users/hawkular/received_events","type":"Organization","site_admin":false},"repo":{"id":29608496,"name":"hawkular-alerts","full_name":"hawkular/hawkular-alerts","owner":{"login":"hawkular","id":10179627,"avatar_url":"https://avatars.githubusercontent.com/u/10179627?v=3","gravatar_id":"","url":"https://api.github.com/users/hawkular","html_url":"https://github.com/hawkular","followers_url":"https://api.github.com/users/hawkular/followers","following_url":"https://api.github.com/users/hawkular/following{/other_user}","gists_url":"https://api.github.com/users/hawkular/gists{/gist_id}","starred_url":"https://api.github.com/users/hawkular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hawkular/subscriptions","organizations_url":"https://api.github.com/users/hawkular/orgs","repos_url":"https://api.github.com/users/hawkular/repos","events_url":"https://api.github.com/users/hawkular/events{/privacy}","received_events_url":"https://api.github.com/users/hawkular/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hawkular/hawkular-alerts","description":"Alerting subsystem for Hawkular","fork":false,"url":"https://api.github.com/repos/hawkular/hawkular-alerts","forks_url":"https://api.github.com/repos/hawkular/hawkular-alerts/forks","keys_url":"https://api.github.com/repos/hawkular/hawkular-alerts/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hawkular/hawkular-alerts/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hawkular/hawkular-alerts/teams","hooks_url":"https://api.github.com/repos/hawkular/hawkular-alerts/hooks","issue_events_url":"https://api.github.com/repos/hawkular/hawkular-alerts/issues/events{/number}","events_url":"https://api.github.com/repos/hawkular/hawkular-alerts/events","assignees_url":"https://api.github.com/repos/hawkular/hawkular-alerts/assignees{/user}","branches_url":"https://api.github.com/repos/hawkular/hawkular-alerts/branches{/branch}","tags_url":"https://api.github.com/repos/hawkular/hawkular-alerts/tags","blobs_url":"https://api.github.com/repos/hawkular/hawkular-alerts/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hawkular/hawkular-alerts/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hawkular/hawkular-alerts/git/refs{/sha}","trees_url":"https://api.github.com/repos/hawkular/hawkular-alerts/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hawkular/hawkular-alerts/statuses/{sha}","languages_url":"https://api.github.com/repos/hawkular/hawkular-alerts/languages","stargazers_url":"https://api.github.com/repos/hawkular/hawkular-alerts/stargazers","contributors_url":"https://api.github.com/repos/hawkular/hawkular-alerts/contributors","subscribers_url":"https://api.github.com/repos/hawkular/hawkular-alerts/subscribers","subscription_url":"https://api.github.com/repos/hawkular/hawkular-alerts/subscription","commits_url":"https://api.github.com/repos/hawkular/hawkular-alerts/commits{/sha}","git_commits_url":"https://api.github.com/repos/hawkular/hawkular-alerts/git/commits{/sha}","comments_url":"https://api.github.com/repos/hawkular/hawkular-alerts/comments{/number}","issue_comment_url":"https://api.github.com/repos/hawkular/hawkular-alerts/issues/comments{/number}","contents_url":"https://api.github.com/repos/hawkular/hawkular-alerts/contents/{+path}","compare_url":"https://api.github.com/repos/hawkular/hawkular-alerts/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hawkular/hawkular-alerts/merges","archive_url":"https://api.github.com/repos/hawkular/hawkular-alerts/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hawkular/hawkular-alerts/downloads","issues_url":"https://api.github.com/repos/hawkular/hawkular-alerts/issues{/number}","pulls_url":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls{/number}","milestones_url":"https://api.github.com/repos/hawkular/hawkular-alerts/milestones{/number}","notifications_url":"https://api.github.com/repos/hawkular/hawkular-alerts/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hawkular/hawkular-alerts/labels{/name}","releases_url":"https://api.github.com/repos/hawkular/hawkular-alerts/releases{/id}","created_at":"2015-01-21T19:59:08Z","updated_at":"2015-04-29T00:05:57Z","pushed_at":"2015-04-29T14:19:09Z","git_url":"git://github.com/hawkular/hawkular-alerts.git","ssh_url":"git@github.com:hawkular/hawkular-alerts.git","clone_url":"https://github.com/hawkular/hawkular-alerts.git","svn_url":"https://github.com/hawkular/hawkular-alerts","homepage":null,"size":1583,"stargazers_count":2,"watchers_count":2,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":2,"forks":6,"open_issues":2,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40"},"html":{"href":"https://github.com/hawkular/hawkular-alerts/pull/40"},"issue":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/issues/40"},"comments":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/issues/40/comments"},"review_comments":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40/comments"},"review_comment":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/pulls/40/commits"},"statuses":{"href":"https://api.github.com/repos/hawkular/hawkular-alerts/statuses/8766d4da5a9ed4b62a1c74f2fbb3e98fabf394be"}}}}