http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/IndexDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/IndexDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/IndexDao.java index fe546bd..4187428 100644 --- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/IndexDao.java +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/IndexDao.java @@ -17,151 +17,18 @@ */ package org.apache.metron.indexing.dao; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import org.apache.metron.common.utils.JSONUtils; -import org.apache.metron.indexing.dao.search.FieldType; -import org.apache.metron.indexing.dao.search.GetRequest; -import org.apache.metron.indexing.dao.search.GroupRequest; -import org.apache.metron.indexing.dao.search.GroupResponse; -import org.apache.metron.indexing.dao.search.InvalidSearchException; -import org.apache.metron.indexing.dao.search.SearchRequest; -import org.apache.metron.indexing.dao.search.SearchResponse; -import org.apache.metron.indexing.dao.update.Document; -import org.apache.metron.indexing.dao.update.OriginalNotFoundException; -import org.apache.metron.indexing.dao.update.PatchRequest; -import org.apache.metron.indexing.dao.update.ReplaceRequest; +import org.apache.metron.indexing.dao.search.SearchDao; +import org.apache.metron.indexing.dao.update.UpdateDao; /** * The IndexDao provides a common interface for retrieving and storing data in a variety of persistent stores. * Document reads and writes require a GUID and sensor type with an index being optional. */ -public interface IndexDao { - - /** - * Return search response based on the search request - * - * @param searchRequest - * @return - * @throws InvalidSearchException - */ - SearchResponse search(SearchRequest searchRequest) throws InvalidSearchException; - - GroupResponse group(GroupRequest groupRequest) throws InvalidSearchException; +public interface IndexDao extends UpdateDao, SearchDao, RetrieveLatestDao, ColumnMetadataDao { /** * Initialize the DAO with the AccessConfig object. - * @param config + * @param config The config to use for initialization */ void init(AccessConfig config); - - /** - * Return the latest version of a document given the GUID and the sensor type. - * - * @param guid The GUID for the document - * @param sensorType The sensor type of the document - * @return The Document matching or null if not available. - * @throws IOException - */ - Document getLatest(String guid, String sensorType) throws IOException; - - /** - * Return a list of the latest versions of documents given a list of GUIDs and sensor types. - * - * @param getRequests A list of get requests for documents - * @return A list of documents matching or an empty list in not available. - * @throws IOException - */ - Iterable<Document> getAllLatest(List<GetRequest> getRequests) throws IOException; - - /** - * Return the latest version of a document given a GetRequest. - * @param request The GetRequest which indicates the GUID and sensor type. - * @return Optionally the document (dependent upon existence in the index). - * @throws IOException - */ - default Optional<Map<String, Object>> getLatestResult(GetRequest request) throws IOException { - Document ret = getLatest(request.getGuid(), request.getSensorType()); - if(ret == null) { - return Optional.empty(); - } - else { - return Optional.ofNullable(ret.getDocument()); - } - } - - /** - * Update a given Document and optionally the index where the document exists. This is a full update, - * meaning the current document will be replaced if it exists or a new document will be created if it does - * not exist. Partial updates are not supported in this method. - * - * @param update The document to replace from the index. - * @param index The index where the document lives. - * @throws IOException - */ - void update(Document update, Optional<String> index) throws IOException; - - /** - * Similar to the update method but accepts multiple documents and performs updates in batch. - * - * @param updates A map of the documents to update to the index where they live. - * @throws IOException - */ - void batchUpdate(Map<Document, Optional<String>> updates) throws IOException; - - /** - * Update a document in an index given a JSON Patch (see RFC 6902 at https://tools.ietf.org/html/rfc6902) - * @param request The patch request - * @param timestamp Optionally a timestamp to set. If not specified then current time is used. - * @throws OriginalNotFoundException If the original is not found, then it cannot be patched. - * @throws IOException - */ - default void patch( PatchRequest request - , Optional<Long> timestamp - ) throws OriginalNotFoundException, IOException { - Document d = getPatchedDocument(request, timestamp); - update(d, Optional.ofNullable(request.getIndex())); - } - - default Document getPatchedDocument(PatchRequest request - , Optional<Long> timestamp - ) throws OriginalNotFoundException, IOException { - Map<String, Object> latest = request.getSource(); - if(latest == null) { - Document latestDoc = getLatest(request.getGuid(), request.getSensorType()); - if(latestDoc != null && latestDoc.getDocument() != null) { - latest = latestDoc.getDocument(); - } - else { - throw new OriginalNotFoundException("Unable to patch an document that doesn't exist and isn't specified."); - } - } - Map<String, Object> updated = JSONUtils.INSTANCE.applyPatch(request.getPatch(), latest); - return new Document(updated - , request.getGuid() - , request.getSensorType() - , timestamp.orElse(System.currentTimeMillis())); - } - - /** - * Replace a document in an index. - * @param request The replacement request. - * @param timestamp The timestamp (optional) of the update. If not specified, then current time will be used. - * @throws IOException - */ - default void replace( ReplaceRequest request - , Optional<Long> timestamp - ) throws IOException { - Document d = new Document(request.getReplacement() - , request.getGuid() - , request.getSensorType() - , timestamp.orElse(System.currentTimeMillis()) - ); - update(d, Optional.ofNullable(request.getIndex())); - } - - Map<String, FieldType> getColumnMetadata(List<String> indices) throws IOException; }
http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/MetaAlertDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/MetaAlertDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/MetaAlertDao.java deleted file mode 100644 index 4530d2a..0000000 --- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/MetaAlertDao.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.metron.indexing.dao; - -import java.util.List; -import java.util.Optional; -import java.io.IOException; -import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateRequest; -import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateResponse; -import org.apache.metron.indexing.dao.metaalert.MetaAlertStatus; -import org.apache.metron.indexing.dao.search.GetRequest; -import org.apache.metron.indexing.dao.search.InvalidCreateException; -import org.apache.metron.indexing.dao.search.InvalidSearchException; -import org.apache.metron.indexing.dao.search.SearchResponse; - -/** - * The MetaAlertDao exposes methods for interacting with meta alerts. Meta alerts are objects that contain - * alerts and summary statistics based on the scores of these alerts. Meta alerts are returned in searches - * just as alerts are and match based on the field values of child alerts. If a child alert matches a search - * the meta alert will be returned while the original child alert will not. A meta alert also contains a - * status field that controls it's inclusion in search results and a groups field that can be used to track - * the groups a meta alert was created from. - * - * The structure of a meta alert is as follows: - * { - * "guid": "meta alert guid", - * "timestamp": timestamp, - * "source:type": "metaalert", - * "alerts": [ array of child alerts ], - * "status": "active or inactive", - * "groups": [ array of group names ], - * "average": 10, - * "max": 10, - * "threat:triage:score": 30, - * "count": 3, - * "sum": 30, - * "min": 10, - * "median": 10 - * } - * - * A child alert that has been added to a meta alert will store the meta alert GUID in a "metaalerts" field. - * This field is an array of meta alert GUIDs, meaning a child alert can be contained in multiple meta alerts. - * Any update to a child alert will trigger an update to the meta alert so that the alert inside a meta alert - * and the original alert will be kept in sync. - * - * Other fields can be added to a meta alert through the patch method on the IndexDao interface. However, attempts - * to directly change the "alerts" or "status" field will result in an exception. - */ -public interface MetaAlertDao extends IndexDao { - - String METAALERTS_INDEX = "metaalert_index"; - String METAALERT_TYPE = "metaalert"; - String METAALERT_FIELD = "metaalerts"; - String METAALERT_DOC = METAALERT_TYPE + "_doc"; - String THREAT_FIELD_DEFAULT = "threat:triage:score"; - String THREAT_SORT_DEFAULT = "sum"; - String ALERT_FIELD = "alert"; - String STATUS_FIELD = "status"; - String GROUPS_FIELD = "groups"; - - /** - * Given an alert GUID, retrieve all associated meta alerts. - * @param guid The alert GUID to be searched for - * @return All meta alerts with a child alert having the GUID - * @throws InvalidSearchException If a problem occurs with the search - */ - SearchResponse getAllMetaAlertsForAlert(String guid) throws InvalidSearchException; - - /** - * Creates a meta alert from a list of child alerts. The most recent version of each child alert is - * retrieved using the DAO abstractions. - * - * @param request A request object containing get requests for alerts to be added and a list of groups - * @return A response indicating success or failure along with the GUID of the new meta alert - * @throws InvalidCreateException If a malformed create request is provided - * @throws IOException If a problem occurs during communication - */ - MetaAlertCreateResponse createMetaAlert(MetaAlertCreateRequest request) - throws InvalidCreateException, IOException; - - - /** - * Adds a list of alerts to an existing meta alert. This will add each alert object to the "alerts" array in the meta alert - * and also add the meta alert GUID to each child alert's "metaalerts" array. After alerts have been added the - * meta alert scores are recalculated. Any alerts already in the meta alert are skipped and no updates are - * performed if all of the alerts are already in the meta alert. The most recent version of each child alert is - * retrieved using the DAO abstractions. Alerts cannot be added to an 'inactive' meta alert. - * - * @param metaAlertGuid The meta alert GUID - * @param getRequests Get requests for alerts to be added - * @return True or false depending on if any alerts were added - * @throws IOException - */ - boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> getRequests) throws IOException; - - /** - * Removes a list of alerts from an existing meta alert. This will remove each alert object from the "alerts" array in the meta alert - * and also remove the meta alert GUID from each child alert's "metaalerts" array. After alerts have been removed the - * meta alert scores are recalculated. Any alerts not contained in the meta alert are skipped and no updates are - * performed if no alerts can be found in the meta alert. Alerts cannot be removed from an 'inactive' meta alert. - * - * @param metaAlertGuid The meta alert GUID - * @param getRequests Get requests for alerts to be removed - * @return True or false depending on if any alerts were removed - * @throws IOException - */ - boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> getRequests) throws IOException; - - /** - * The meta alert status field can be set to either 'active' or 'inactive' and will control whether or not meta alerts - * (and child alerts) appear in search results. An 'active' status will cause meta alerts to appear in search - * results instead of it's child alerts and an 'inactive' status will suppress the meta alert from search results - * with child alerts appearing in search results as normal. A change to 'inactive' will cause the meta alert GUID to - * be removed from all it's child alert's "metaalerts" field. A change back to 'active' will have the opposite effect. - * - * @param metaAlertGuid The GUID of the meta alert - * @param status A status value of 'active' or 'inactive' - * @return True or false depending on if the status was changed - * @throws IOException - */ - boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status) throws IOException; - - /** - * Initializes a Meta Alert DAO with default "sum" meta alert threat sorting. - * @param indexDao The DAO to wrap for our queries. - */ - default void init(IndexDao indexDao) { - init(indexDao, Optional.empty()); - } - - /** - * Initializes a Meta Alert DAO. - * @param indexDao The DAO to wrap for our queries - * @param threatSort The aggregation to use as the threat field. E.g. "sum", "median", etc. - * null is "sum" - */ - void init(IndexDao indexDao, Optional<String> threatSort); -} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/RetrieveLatestDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/RetrieveLatestDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/RetrieveLatestDao.java new file mode 100644 index 0000000..caf754c --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/RetrieveLatestDao.java @@ -0,0 +1,67 @@ +/* + * 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.metron.indexing.dao; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.apache.metron.indexing.dao.search.GetRequest; +import org.apache.metron.indexing.dao.update.Document; + +/** + * An base interface for other DAOs to extend. All DAOs are expected to be able to retrieve + * Documents they've stored. + */ +public interface RetrieveLatestDao { + + /** + * Return the latest version of a document given the GUID and the sensor type. + * + * @param guid The GUID for the document + * @param sensorType The sensor type of the document + * @return The Document matching or null if not available. + * @throws IOException If an error occurs retrieving the latest document. + */ + Document getLatest(String guid, String sensorType) throws IOException; + + /** + * Return a list of the latest versions of documents given a list of GUIDs and sensor types. + * + * @param getRequests A list of get requests for documents + * @return A list of documents matching or an empty list in not available. + * @throws IOException If an error occurs retrieving the latest documents. + */ + Iterable<Document> getAllLatest(List<GetRequest> getRequests) throws IOException; + + /** + * Return the latest version of a document given a GetRequest. + * @param request The GetRequest which indicates the GUID and sensor type. + * @return Optionally the document (dependent upon existence in the index). + * @throws IOException If an error occurs while retrieving the document. + */ + default Optional<Map<String, Object>> getLatestResult(GetRequest request) throws IOException { + Document ret = getLatest(request.getGuid(), request.getSensorType()); + if (ret == null) { + return Optional.empty(); + } else { + return Optional.ofNullable(ret.getDocument()); + } + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/DeferredMetaAlertIndexDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/DeferredMetaAlertIndexDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/DeferredMetaAlertIndexDao.java new file mode 100644 index 0000000..1e5e723 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/DeferredMetaAlertIndexDao.java @@ -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.metron.indexing.dao.metaalert; + +import org.apache.metron.indexing.dao.IndexDao; + +/** + * Interface for a DAO that is allowed to defer to a child Index DAO in order to perform tasks. + * An example is metaalerts deferring to a base DAO. + */ +public interface DeferredMetaAlertIndexDao { + + IndexDao getIndexDao(); + + String getMetAlertSensorName(); + + String getMetaAlertIndex(); + + default String getThreatTriageField() { + return MetaAlertConstants.THREAT_FIELD_DEFAULT; + } + + default String getThreatSort() { + return MetaAlertConstants.THREAT_SORT_DEFAULT; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertAddRemoveRequest.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertAddRemoveRequest.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertAddRemoveRequest.java index 6183d37..a14749b 100644 --- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertAddRemoveRequest.java +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertAddRemoveRequest.java @@ -14,7 +14,6 @@ */ package org.apache.metron.indexing.dao.metaalert; -import java.util.Collection; import java.util.List; import org.apache.metron.indexing.dao.search.GetRequest; http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConfig.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConfig.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConfig.java new file mode 100644 index 0000000..9254425 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConfig.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.metron.indexing.dao.metaalert; + +public class MetaAlertConfig { + private String metaAlertIndex; + private String threatTriageField; + private String threatSort; + private String sourceTypeField; + + /** + * Simple object for storing and retrieving configs, primarily to make passing all the info to + * the sub DAOs easier. + * @param metaAlertIndex The metaalert index or collection we're using + * @param threatTriageField The threat triage field's name + * @param threatSort The sorting operation on the threat triage field + * @param sourceTypeField The source type field + */ + public MetaAlertConfig(String metaAlertIndex, String threatTriageField, + String threatSort, String sourceTypeField) { + this.metaAlertIndex = metaAlertIndex; + this.threatTriageField = threatTriageField; + this.threatSort = threatSort; + this.sourceTypeField = sourceTypeField; + } + + public String getMetaAlertIndex() { + return metaAlertIndex; + } + + public void setMetaAlertIndex(String metaAlertIndex) { + this.metaAlertIndex = metaAlertIndex; + } + + public String getThreatTriageField() { + return threatTriageField; + } + + public void setThreatTriageField(String threatTriageField) { + this.threatTriageField = threatTriageField; + } + + public String getThreatSort() { + return threatSort; + } + + public void setThreatSort(String threatSort) { + this.threatSort = threatSort; + } + + public String getSourceTypeField() { + return sourceTypeField; + } + + public void setSourceTypeField(String sourceTypeField) { + this.sourceTypeField = sourceTypeField; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConstants.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConstants.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConstants.java new file mode 100644 index 0000000..a055db5 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertConstants.java @@ -0,0 +1,30 @@ +/* + * 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.metron.indexing.dao.metaalert; + +public class MetaAlertConstants { + public static String METAALERT_TYPE = "metaalert"; + public static String METAALERT_FIELD = "metaalerts"; + public static String METAALERT_DOC = METAALERT_TYPE + "_doc"; + public static String THREAT_FIELD_DEFAULT = "threat:triage:score"; + public static String THREAT_SORT_DEFAULT = "sum"; + public static String ALERT_FIELD = "alert"; + public static String STATUS_FIELD = "status"; + public static String GROUPS_FIELD = "groups"; +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertDao.java new file mode 100644 index 0000000..c9e6711 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertDao.java @@ -0,0 +1,77 @@ +/* + * 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.metron.indexing.dao.metaalert; + +import java.util.Optional; +import org.apache.metron.indexing.dao.IndexDao; + +/** + * The MetaAlertDao exposes methods for interacting with meta alerts. Meta alerts are objects that contain + * alerts and summary statistics based on the scores of these alerts. Meta alerts are returned in searches + * just as alerts are and match based on the field values of child alerts. If a child alert matches a search + * the meta alert will be returned while the original child alert will not. A meta alert also contains a + * status field that controls it's inclusion in search results and a groups field that can be used to track + * the groups a meta alert was created from. + * + * </p> + * The structure of a meta alert is as follows: + * { + * "guid": "meta alert guid", + * "timestamp": timestamp, + * "source:type": "metaalert", + * "alerts": [ array of child alerts ], + * "status": "active or inactive", + * "groups": [ array of group names ], + * "average": 10, + * "max": 10, + * "threat:triage:score": 30, + * "count": 3, + * "sum": 30, + * "min": 10, + * "median": 10 + * } + * + * </p> + * A child alert that has been added to a meta alert will store the meta alert GUID in a "metaalerts" field. + * This field is an array of meta alert GUIDs, meaning a child alert can be contained in multiple meta alerts. + * Any update to a child alert will trigger an update to the meta alert so that the alert inside a meta alert + * and the original alert will be kept in sync. + * + * </p> + * Other fields can be added to a meta alert through the patch method on the IndexDao interface. However, attempts + * to directly change the "alerts" or "status" field will result in an exception. + */ +public interface MetaAlertDao extends MetaAlertSearchDao, MetaAlertUpdateDao, IndexDao { + + /** + * Initializes a Meta Alert DAO with default "sum" meta alert threat sorting. + * @param indexDao The DAO to wrap for our queries. + */ + default void init(IndexDao indexDao) { + init(indexDao, Optional.empty()); + } + + /** + * Initializes a Meta Alert DAO. + * @param indexDao The DAO to wrap for our queries + * @param threatSort The aggregation to use as the threat field. E.g. "sum", "median", etc. + * null is "sum" + */ + void init(IndexDao indexDao, Optional<String> threatSort); +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertRetrieveLatestDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertRetrieveLatestDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertRetrieveLatestDao.java new file mode 100644 index 0000000..1a0d2a0 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertRetrieveLatestDao.java @@ -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.metron.indexing.dao.metaalert; + +import org.apache.metron.indexing.dao.RetrieveLatestDao; + +public interface MetaAlertRetrieveLatestDao extends RetrieveLatestDao { + +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertSearchDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertSearchDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertSearchDao.java new file mode 100644 index 0000000..e8b9f26 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertSearchDao.java @@ -0,0 +1,35 @@ +/* + * 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.metron.indexing.dao.metaalert; + +import org.apache.metron.indexing.dao.search.InvalidSearchException; +import org.apache.metron.indexing.dao.search.SearchDao; +import org.apache.metron.indexing.dao.search.SearchResponse; + +public interface MetaAlertSearchDao extends SearchDao { + + /** + * Given an alert GUID, retrieve all associated meta alerts. + * @param guid The alert GUID to be searched for + * @return All meta alerts with a child alert having the GUID + * @throws InvalidSearchException If a problem occurs with the search + */ + SearchResponse getAllMetaAlertsForAlert(String guid) throws InvalidSearchException; + +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertUpdateDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertUpdateDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertUpdateDao.java new file mode 100644 index 0000000..f4374b4 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaAlertUpdateDao.java @@ -0,0 +1,146 @@ +/* + * 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.metron.indexing.dao.metaalert; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.metron.indexing.dao.search.GetRequest; +import org.apache.metron.indexing.dao.search.InvalidCreateException; +import org.apache.metron.indexing.dao.update.Document; +import org.apache.metron.indexing.dao.update.PatchRequest; +import org.apache.metron.indexing.dao.update.UpdateDao; + +public interface MetaAlertUpdateDao extends UpdateDao { + + String STATUS_PATH = "/" + MetaAlertConstants.STATUS_FIELD; + String ALERT_PATH = "/" + MetaAlertConstants.ALERT_FIELD; + + /** + * Determines if a given patch request is allowed or not. By default patching the 'alert' or + * 'status' fields are not allowed, because they should be updated via the specific methods. + * @param request The patch request to examine + * @return True if patch can be performed, false otherwise + */ + default boolean isPatchAllowed(PatchRequest request) { + if (request.getPatch() != null && !request.getPatch().isEmpty()) { + for (Map<String, Object> patch : request.getPatch()) { + Object pathObj = patch.get("path"); + if (pathObj != null && pathObj instanceof String) { + String path = (String) pathObj; + if (STATUS_PATH.equals(path) || ALERT_PATH.equals(path)) { + return false; + } + } + } + } + return true; + } + + /** + * Creates a meta alert from a list of child alerts. The most recent version of each child alert is + * retrieved using the DAO abstractions. + * + * @param request A request object containing get requests for alerts to be added and a list of groups + * @return A response indicating success or failure along with the GUID of the new meta alert + * @throws InvalidCreateException If a malformed create request is provided + * @throws IOException If a problem occurs during communication + */ + MetaAlertCreateResponse createMetaAlert(MetaAlertCreateRequest request) + throws InvalidCreateException, IOException; + + /** + * Adds alerts to a metaalert, based on a list of GetRequests provided for retrieval. + * @param metaAlertGuid The GUID of the metaalert to be given new children. + * @param alertRequests GetRequests for the appropriate alerts to add. + * @return True if metaalert is modified, false otherwise. + */ + boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) + throws IOException; + + /** + * Removes alerts from a metaalert + * @param metaAlertGuid The metaalert guid to be affected. + * @param alertRequests A list of GetReqests that will provide the alerts to remove + * @return True if there are updates, false otherwise + * @throws IOException If an error is thrown during retrieal. + */ + boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) + throws IOException; + + /** + * Removes a metaalert link from a given alert. An nonexistent link performs no change. + * @param metaAlertGuid The metaalert GUID to link. + * @param alert The alert to be linked to. + * @return True if the alert changed, false otherwise. + */ + default boolean removeMetaAlertFromAlert(String metaAlertGuid, Document alert) { + List<String> metaAlertField = new ArrayList<>(); + @SuppressWarnings("unchecked") + List<String> alertField = (List<String>) alert.getDocument() + .get(MetaAlertConstants.METAALERT_FIELD); + if (alertField != null) { + metaAlertField.addAll(alertField); + } + boolean metaAlertRemoved = metaAlertField.remove(metaAlertGuid); + if (metaAlertRemoved) { + alert.getDocument().put(MetaAlertConstants.METAALERT_FIELD, metaAlertField); + } + return metaAlertRemoved; + } + + /** + * The meta alert status field can be set to either 'active' or 'inactive' and will control whether or not meta alerts + * (and child alerts) appear in search results. An 'active' status will cause meta alerts to appear in search + * results instead of it's child alerts and an 'inactive' status will suppress the meta alert from search results + * with child alerts appearing in search results as normal. A change to 'inactive' will cause the meta alert GUID to + * be removed from all it's child alert's "metaalerts" field. A change back to 'active' will have the opposite effect. + * + * @param metaAlertGuid The GUID of the meta alert + * @param status A status value of 'active' or 'inactive' + * @return True or false depending on if the status was changed + * @throws IOException if an error occurs during the update. + */ + boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status) + throws IOException; + + /** + * Adds a metaalert link to a provided alert Document. Adding an existing link does no change. + * @param metaAlertGuid The GUID to be added. + * @param alert The alert we're adding the link to. + * @return True if the alert is modified, false if not. + */ + default boolean addMetaAlertToAlert(String metaAlertGuid, Document alert) { + List<String> metaAlertField = new ArrayList<>(); + @SuppressWarnings("unchecked") + List<String> alertField = (List<String>) alert.getDocument() + .get(MetaAlertConstants.METAALERT_FIELD); + if (alertField != null) { + metaAlertField.addAll(alertField); + } + + boolean metaAlertAdded = !metaAlertField.contains(metaAlertGuid); + if (metaAlertAdded) { + metaAlertField.add(metaAlertGuid); + alert.getDocument().put(MetaAlertConstants.METAALERT_FIELD, metaAlertField); + } + return metaAlertAdded; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaScores.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaScores.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaScores.java index 07285d6..55b1aa0 100644 --- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaScores.java +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/MetaScores.java @@ -18,12 +18,14 @@ package org.apache.metron.indexing.dao.metaalert; -import org.apache.commons.math3.stat.descriptive.rank.Median; - +import java.util.ArrayList; import java.util.DoubleSummaryStatistics; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.math3.stat.descriptive.rank.Median; +import org.apache.metron.indexing.dao.update.Document; +import org.apache.metron.stellar.common.utils.ConversionUtils; public class MetaScores { @@ -52,4 +54,50 @@ public class MetaScores { public Map<String, Object> getMetaScores() { return metaScores; } + + /** + * Calculate the meta alert scores for a Document. The scores are placed directly in the provided + * document. + * @param metaAlert The Document containing scores + */ + @SuppressWarnings("unchecked") + public static void calculateMetaScores(Document metaAlert, String threatTriageField, + String threatSort) { + MetaScores metaScores = new MetaScores(new ArrayList<>()); + List<Object> alertsRaw = ((List<Object>) metaAlert.getDocument() + .get(MetaAlertConstants.ALERT_FIELD)); + if (alertsRaw != null && !alertsRaw.isEmpty()) { + ArrayList<Double> scores = new ArrayList<>(); + for (Object alertRaw : alertsRaw) { + Map<String, Object> alert = (Map<String, Object>) alertRaw; + Double scoreNum = parseThreatField(alert.get(threatTriageField)); + if (scoreNum != null) { + scores.add(scoreNum); + } + } + metaScores = new MetaScores(scores); + } + + // add a summary (max, min, avg, ...) of all the threat scores from the child alerts + metaAlert.getDocument().putAll(metaScores.getMetaScores()); + + // add the overall threat score for the metaalert; one of the summary aggregations as defined + // by `threatSort` + Object threatScore = metaScores.getMetaScores().get(threatSort); + + // add the threat score as a float; type needs to match the threat score field from each of + // the sensor indices + metaAlert.getDocument() + .put(threatTriageField, ConversionUtils.convert(threatScore, Float.class)); + } + + protected static Double parseThreatField(Object threatRaw) { + Double threat = null; + if (threatRaw instanceof Number) { + threat = ((Number) threatRaw).doubleValue(); + } else if (threatRaw instanceof String) { + threat = Double.parseDouble((String) threatRaw); + } + return threat; + } } http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java new file mode 100644 index 0000000..b47d648 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java @@ -0,0 +1,334 @@ +/* + * 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.metron.indexing.dao.metaalert.lucene; + +import static org.apache.metron.common.Constants.GUID; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import org.apache.metron.common.Constants; +import org.apache.metron.indexing.dao.RetrieveLatestDao; +import org.apache.metron.indexing.dao.metaalert.MetaAlertConfig; +import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants; +import org.apache.metron.indexing.dao.metaalert.MetaAlertRetrieveLatestDao; +import org.apache.metron.indexing.dao.metaalert.MetaAlertStatus; +import org.apache.metron.indexing.dao.metaalert.MetaAlertUpdateDao; +import org.apache.metron.indexing.dao.metaalert.MetaScores; +import org.apache.metron.indexing.dao.search.GetRequest; +import org.apache.metron.indexing.dao.update.Document; +import org.apache.metron.indexing.dao.update.OriginalNotFoundException; +import org.apache.metron.indexing.dao.update.PatchRequest; +import org.apache.metron.indexing.dao.update.UpdateDao; + +public abstract class AbstractLuceneMetaAlertUpdateDao implements MetaAlertUpdateDao { + + private UpdateDao updateDao; + private MetaAlertRetrieveLatestDao retrieveLatestDao; + private MetaAlertConfig config; + + protected AbstractLuceneMetaAlertUpdateDao( + UpdateDao updateDao, + MetaAlertRetrieveLatestDao retrieveLatestDao, + MetaAlertConfig config) { + this.updateDao = updateDao; + this.retrieveLatestDao = retrieveLatestDao; + this.config = config; + } + + public UpdateDao getUpdateDao() { + return updateDao; + } + + public MetaAlertRetrieveLatestDao getRetrieveLatestDao() { + return retrieveLatestDao; + } + + public MetaAlertConfig getConfig() { + return config; + } + + /** + * Performs a patch operation on a document based on the result of @{link #isPatchAllowed(PatchRequest)} + * + * @param retrieveLatestDao DAO to retrieve the item to be patched + * @param request The patch request. + * @param timestamp Optionally a timestamp to set. If not specified then current time is used. + * @throws OriginalNotFoundException If no original document is found to patch. + * @throws IOException If an error occurs performing the patch. + */ + @Override + public void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request, + Optional<Long> timestamp) + throws OriginalNotFoundException, IOException { + if (isPatchAllowed(request)) { + updateDao.patch(retrieveLatestDao, request, timestamp); + } else { + throw new IllegalArgumentException( + "Meta alert patches are not allowed for /alert or /status paths. " + + "Please use the add/remove alert or update status functions instead."); + } + } + + @Override + public void batchUpdate(Map<Document, Optional<String>> updates) { + throw new UnsupportedOperationException("Meta alerts do not allow for bulk updates"); + } + + /** + * Build the Document representing a meta alert to be created. + * @param alerts The Elasticsearch results for the meta alerts child documents + * @param groups The groups used to create this meta alert + * @return A Document representing the new meta alert + */ + protected Document buildCreateDocument(Iterable<Document> alerts, List<String> groups, + String alertField) { + // Need to create a Document from the multiget. Scores will be calculated later + Map<String, Object> metaSource = new HashMap<>(); + List<Map<String, Object>> alertList = new ArrayList<>(); + for (Document alert : alerts) { + alertList.add(alert.getDocument()); + } + metaSource.put(alertField, alertList); + + // Add any meta fields + String guid = UUID.randomUUID().toString(); + metaSource.put(GUID, guid); + metaSource.put(Constants.Fields.TIMESTAMP.getName(), System.currentTimeMillis()); + metaSource.put(MetaAlertConstants.GROUPS_FIELD, groups); + metaSource.put(MetaAlertConstants.STATUS_FIELD, MetaAlertStatus.ACTIVE.getStatusString()); + + return new Document(metaSource, guid, MetaAlertConstants.METAALERT_TYPE, + System.currentTimeMillis()); + } + + /** + * Builds the set of updates when alerts are removed from a meta alert + * @param metaAlert The meta alert to remove alerts from + * @param alerts The alert Documents to be removed + * @return The updates to be run + * @throws IOException If an error is thrown. + */ + @SuppressWarnings("unchecked") + protected Map<Document, Optional<String>> buildRemoveAlertsFromMetaAlert(Document metaAlert, + Iterable<Document> alerts) + throws IOException { + Map<Document, Optional<String>> updates = new HashMap<>(); + + List<String> alertGuids = new ArrayList<>(); + for (Document alert : alerts) { + alertGuids.add(alert.getGuid()); + } + List<Map<String, Object>> alertsBefore = new ArrayList<>(); + Map<String, Object> documentBefore = metaAlert.getDocument(); + if (documentBefore.containsKey(MetaAlertConstants.ALERT_FIELD)) { + alertsBefore + .addAll((List<Map<String, Object>>) documentBefore.get(MetaAlertConstants.ALERT_FIELD)); + } + boolean metaAlertUpdated = removeAlertsFromMetaAlert(metaAlert, alertGuids); + if (metaAlertUpdated) { + List<Map<String, Object>> alertsAfter = (List<Map<String, Object>>) metaAlert.getDocument() + .get(MetaAlertConstants.ALERT_FIELD); + if (alertsAfter.size() < alertsBefore.size() && alertsAfter.size() == 0) { + throw new IllegalStateException("Removing these alerts will result in an empty meta alert. Empty meta alerts are not allowed."); + } + MetaScores + .calculateMetaScores(metaAlert, config.getThreatTriageField(), config.getThreatSort()); + updates.put(metaAlert, Optional.of(config.getMetaAlertIndex())); + for (Document alert : alerts) { + if (removeMetaAlertFromAlert(metaAlert.getGuid(), alert)) { + updates.put(alert, Optional.empty()); + } + } + } + return updates; + } + + @Override + @SuppressWarnings("unchecked") + public boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) + throws IOException { + Document metaAlert = retrieveLatestDao + .getLatest(metaAlertGuid, MetaAlertConstants.METAALERT_TYPE); + if (metaAlert == null) { + return false; + } + if (MetaAlertStatus.ACTIVE.getStatusString() + .equals(metaAlert.getDocument().get(MetaAlertConstants.STATUS_FIELD))) { + Iterable<Document> alerts = retrieveLatestDao.getAllLatest(alertRequests); + Map<Document, Optional<String>> updates = buildRemoveAlertsFromMetaAlert(metaAlert, alerts); + update(updates); + return updates.size() != 0; + } else { + throw new IllegalStateException("Removing alerts from an INACTIVE meta alert is not allowed"); + } + } + + /** + * Removes a given set of alerts from a given alert. AlertGuids that are not found are ignored. + * @param metaAlert The metaalert to be mutated. + * @param alertGuids The alerts to remove from the metaaelrt. + * @return True if the metaAlert changed, false otherwise. + */ + protected boolean removeAlertsFromMetaAlert(Document metaAlert, Collection<String> alertGuids) { + // If we don't have child alerts or nothing is being removed, immediately return false. + if (!metaAlert.getDocument().containsKey(MetaAlertConstants.ALERT_FIELD) + || alertGuids.size() == 0) { + return false; + } + + @SuppressWarnings("unchecked") + List<Map<String, Object>> currentAlerts = (List<Map<String, Object>>) metaAlert.getDocument() + .get(MetaAlertConstants.ALERT_FIELD); + int previousSize = currentAlerts.size(); + // Only remove an alert if it is in the meta alert + currentAlerts.removeIf(currentAlert -> alertGuids.contains(currentAlert.get(GUID))); + return currentAlerts.size() != previousSize; + } + + @Override + public boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status) + throws IOException { + Document metaAlert = retrieveLatestDao + .getLatest(metaAlertGuid, MetaAlertConstants.METAALERT_TYPE); + String currentStatus = (String) metaAlert.getDocument().get(MetaAlertConstants.STATUS_FIELD); + boolean metaAlertUpdated = !status.getStatusString().equals(currentStatus); + if (metaAlertUpdated) { + List<GetRequest> getRequests = new ArrayList<>(); + @SuppressWarnings("unchecked") + List<Map<String, Object>> currentAlerts = (List<Map<String, Object>>) metaAlert.getDocument() + .get(MetaAlertConstants.ALERT_FIELD); + currentAlerts.stream() + .forEach(currentAlert -> getRequests.add(new GetRequest((String) currentAlert.get(GUID), + (String) currentAlert.get(config.getSourceTypeField())))); + Iterable<Document> alerts = retrieveLatestDao.getAllLatest(getRequests); + Map<Document, Optional<String>> updates = buildStatusChangeUpdates(metaAlert, alerts, status); + update(updates); + } + return metaAlertUpdated; + } + + /** + * Given a Metaalert and a status change, builds the set of updates to be run. + * @param metaAlert The metaalert to have status changed + * @param alerts The alerts to change status for + * @param status The status to change to + * @return The updates to be run + */ + protected Map<Document, Optional<String>> buildStatusChangeUpdates(Document metaAlert, + Iterable<Document> alerts, + MetaAlertStatus status) { + metaAlert.getDocument().put(MetaAlertConstants.STATUS_FIELD, status.getStatusString()); + + Map<Document, Optional<String>> updates = new HashMap<>(); + updates.put(metaAlert, Optional.of(config.getMetaAlertIndex())); + + for (Document alert : alerts) { + boolean metaAlertAdded = false; + boolean metaAlertRemoved = false; + // If we're making it active add add the meta alert guid for every alert. + if (MetaAlertStatus.ACTIVE.equals(status)) { + metaAlertAdded = addMetaAlertToAlert(metaAlert.getGuid(), alert); + } + // If we're making it inactive, remove the meta alert guid from every alert. + if (MetaAlertStatus.INACTIVE.equals(status)) { + metaAlertRemoved = removeMetaAlertFromAlert(metaAlert.getGuid(), alert); + } + if (metaAlertAdded || metaAlertRemoved) { + updates.put(alert, Optional.empty()); + } + } + return updates; + } + + /** + * Builds the updates to be run based on a given metaalert and a set of new alerts for the it. + * @param metaAlert The base metaalert we're building updates for + * @param alerts The alerts being added + * @return The set of resulting updates. + */ + protected Map<Document, Optional<String>> buildAddAlertToMetaAlertUpdates(Document metaAlert, + Iterable<Document> alerts) { + Map<Document, Optional<String>> updates = new HashMap<>(); + boolean metaAlertUpdated = addAlertsToMetaAlert(metaAlert, alerts); + if (metaAlertUpdated) { + MetaScores + .calculateMetaScores(metaAlert, config.getThreatTriageField(), config.getThreatSort()); + updates.put(metaAlert, Optional.of(config.getMetaAlertIndex())); + for (Document alert : alerts) { + if (addMetaAlertToAlert(metaAlert.getGuid(), alert)) { + updates.put(alert, Optional.empty()); + } + } + } + return updates; + } + + /** + * Adds the provided alerts to a given metaalert. + * @param metaAlert The metaalert to be given new children. + * @param alerts The alerts to be added as children + * @return True if metaalert is modified, false otherwise. + */ + protected boolean addAlertsToMetaAlert(Document metaAlert, Iterable<Document> alerts) { + boolean alertAdded = false; + @SuppressWarnings("unchecked") + List<Map<String, Object>> currentAlerts = (List<Map<String, Object>>) metaAlert.getDocument() + .get(MetaAlertConstants.ALERT_FIELD); + if (currentAlerts == null) { + currentAlerts = new ArrayList<>(); + metaAlert.getDocument().put(MetaAlertConstants.ALERT_FIELD, currentAlerts); + } + Set<String> currentAlertGuids = currentAlerts.stream().map(currentAlert -> + (String) currentAlert.get(GUID)).collect(Collectors.toSet()); + for (Document alert : alerts) { + String alertGuid = alert.getGuid(); + // Only add an alert if it isn't already in the meta alert + if (!currentAlertGuids.contains(alertGuid)) { + currentAlerts.add(alert.getDocument()); + alertAdded = true; + } + } + return alertAdded; + } + + /** + * Calls the single update variant if there's only one update, otherwise calls batch. + * MetaAlerts may defer to an implementation specific IndexDao. + * @param updates The list of updates to run + * @throws IOException If there's an update error + */ + protected void update(Map<Document, Optional<String>> updates) + throws IOException { + if (updates.size() == 1) { + Entry<Document, Optional<String>> singleUpdate = updates.entrySet().iterator().next(); + updateDao.update(singleUpdate.getKey(), singleUpdate.getValue()); + } else if (updates.size() > 1) { + updateDao.batchUpdate(updates); + } // else we have no updates, so don't do anything + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchDao.java index eee91ae..582f1ef 100644 --- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchDao.java +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchDao.java @@ -17,18 +17,22 @@ */ package org.apache.metron.indexing.dao.search; -import java.io.IOException; -import java.util.List; -import org.apache.metron.indexing.dao.update.Document; - public interface SearchDao { + /** + * Return search response based on the search request + * + * @param searchRequest The request defining the search parameters. + * @return A response containing the results of the search. + * @throws InvalidSearchException If the search request is malformed. + */ SearchResponse search(SearchRequest searchRequest) throws InvalidSearchException; + /** + * Return group response based on the group request + * @param groupRequest The request defining the grouping parameters. + * @return A response containing the results of the grouping operation. + * @throws InvalidSearchException If the grouping request is malformed. + */ GroupResponse group(GroupRequest groupRequest) throws InvalidSearchException; - - Document getLatest(String guid, String sensorType) throws IOException; - - Iterable<Document> getAllLatest(List<GetRequest> getRequests) throws IOException; - } http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchResponse.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchResponse.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchResponse.java index 5b0b006..b4dfab7 100644 --- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchResponse.java +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/search/SearchResponse.java @@ -18,7 +18,6 @@ package org.apache.metron.indexing.dao.search; import com.fasterxml.jackson.annotation.JsonInclude; - import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -84,4 +83,13 @@ public class SearchResponse { result = 31 * result + (getFacetCounts() != null ? getFacetCounts().hashCode() : 0); return result; } + + @Override + public String toString() { + return "SearchResponse{" + + "total=" + total + + ", results=" + results + + ", facetCounts=" + facetCounts + + '}'; + } } http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/PatchUtil.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/PatchUtil.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/PatchUtil.java new file mode 100644 index 0000000..5a4ef27 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/PatchUtil.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.metron.indexing.dao.update; + +import java.io.IOException; +import java.util.Map; +import java.util.Optional; +import org.apache.metron.common.utils.JSONUtils; +import org.apache.metron.indexing.dao.RetrieveLatestDao; + +public class PatchUtil { + + public static Document getPatchedDocument( + RetrieveLatestDao retrieveLatestDao, + PatchRequest request + , Optional<Long> timestamp + ) throws OriginalNotFoundException, IOException { + Map<String, Object> latest = request.getSource(); + if (latest == null) { + Document latestDoc = retrieveLatestDao.getLatest(request.getGuid(), request.getSensorType()); + if (latestDoc != null && latestDoc.getDocument() != null) { + latest = latestDoc.getDocument(); + } else { + throw new OriginalNotFoundException( + "Unable to patch an document that doesn't exist and isn't specified."); + } + } + Map<String, Object> updated = JSONUtils.INSTANCE.applyPatch(request.getPatch(), latest); + return new Document(updated + , request.getGuid() + , request.getSensorType() + , timestamp.orElse(System.currentTimeMillis())); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java index ca21b62..6f136ea 100644 --- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java @@ -20,11 +20,58 @@ package org.apache.metron.indexing.dao.update; import java.io.IOException; import java.util.Map; import java.util.Optional; +import org.apache.metron.indexing.dao.RetrieveLatestDao; public interface UpdateDao { + /** + * Update a given Document and optionally the index where the document exists. This is a full + * update, meaning the current document will be replaced if it exists or a new document will be + * created if it does not exist. Partial updates are not supported in this method. + * + * @param update The document to replace from the index. + * @param index The index where the document lives. + * @throws IOException If an error occurs during the update. + */ void update(Document update, Optional<String> index) throws IOException; + /** + * Similar to the update method but accepts multiple documents and performs updates in batch. + * + * @param updates A map of the documents to update to the index where they live. + * @throws IOException If an error occurs during the updates. + */ void batchUpdate(Map<Document, Optional<String>> updates) throws IOException; + /** + * Update a document in an index given a JSON Patch (see RFC 6902 at + * https://tools.ietf.org/html/rfc6902) + * @param request The patch request + * @param timestamp Optionally a timestamp to set. If not specified then current time is used. + * @throws OriginalNotFoundException If the original is not found, then it cannot be patched. + * @throws IOException If an error occurs while patching. + */ + default void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request + , Optional<Long> timestamp + ) throws OriginalNotFoundException, IOException { + Document d = PatchUtil.getPatchedDocument(retrieveLatestDao, request, timestamp); + update(d, Optional.ofNullable(request.getIndex())); + } + + + /** + * Replace a document in an index. + * @param request The replacement request. + * @param timestamp The timestamp (optional) of the update. If not specified, then current time will be used. + * @throws IOException If an error occurs during replacement. + */ + default void replace(ReplaceRequest request, Optional<Long> timestamp) + throws IOException { + Document d = new Document(request.getReplacement(), + request.getGuid(), + request.getSensorType(), + timestamp.orElse(System.currentTimeMillis()) + ); + update(d, Optional.ofNullable(request.getIndex())); + } } http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/util/IndexingCacheUtil.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/util/IndexingCacheUtil.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/util/IndexingCacheUtil.java new file mode 100644 index 0000000..3ff3a20 --- /dev/null +++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/util/IndexingCacheUtil.java @@ -0,0 +1,35 @@ +/* + * 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.metron.indexing.util; + +import java.util.Map; +import java.util.function.Function; +import org.apache.metron.common.configuration.IndexingConfigurations; +import org.apache.metron.common.zookeeper.ConfigurationsCache; + +public class IndexingCacheUtil { + public static Function<String, String> getIndexLookupFunction(ConfigurationsCache cache) { + return sensorType -> { + IndexingConfigurations indexingConfigs = cache.get( IndexingConfigurations.class); + Map<String, Object> indexingSensorConfigs = indexingConfigs.getSensorIndexingConfig(sensorType); + String indexingTopic = (String) indexingSensorConfigs.get(IndexingConfigurations.INDEX_CONF); + return indexingTopic != null ? indexingTopic : sensorType; + }; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/49f851e0/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java ---------------------------------------------------------------------- diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java index baa5416..803d320 100644 --- a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java +++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java @@ -32,8 +32,10 @@ import java.util.Optional; import java.util.stream.Collectors; import org.adrianwalker.multilinestring.Multiline; import org.apache.metron.common.utils.JSONUtils; +import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants; import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateRequest; import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateResponse; +import org.apache.metron.indexing.dao.metaalert.MetaAlertDao; import org.apache.metron.indexing.dao.metaalert.MetaAlertStatus; import org.apache.metron.indexing.dao.metaalert.MetaScores; import org.apache.metron.indexing.dao.search.FieldType; @@ -57,6 +59,7 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { public static Map<String, Collection<String>> METAALERT_STORE = new HashMap<>(); private IndexDao indexDao; + private int pageSize = 10; /** * { @@ -96,6 +99,7 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { // Ignore threatSort for test. } + @Override public Document getLatest(String guid, String sensorType) throws IOException { return indexDao.getLatest(guid, sensorType); @@ -112,7 +116,7 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { } @Override - public void batchUpdate(Map<Document, Optional<String>> updates) throws IOException { + public void batchUpdate(Map<Document, Optional<String>> updates) { throw new UnsupportedOperationException("InMemoryMetaAlertDao can't do bulk updates"); } @@ -128,9 +132,10 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { } @Override - public void patch(PatchRequest request, Optional<Long> timestamp) + public void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request, + Optional<Long> timestamp) throws OriginalNotFoundException, IOException { - indexDao.patch(request, timestamp); + indexDao.patch(retrieveLatestDao, request, timestamp); } @Override @@ -153,7 +158,7 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { @SuppressWarnings("unchecked") @Override public MetaAlertCreateResponse createMetaAlert(MetaAlertCreateRequest request) - throws InvalidCreateException, IOException { + throws InvalidCreateException { List<GetRequest> alertRequests = request.getAlerts(); if (alertRequests.isEmpty()) { MetaAlertCreateResponse response = new MetaAlertCreateResponse(); @@ -162,12 +167,13 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { } // Build meta alert json. Give it a reasonable GUID JSONObject metaAlert = new JSONObject(); - String metaAlertGuid = "meta_" + (InMemoryDao.BACKING_STORE.get(MetaAlertDao.METAALERTS_INDEX).size() + 1); + String metaAlertGuid = + "meta_" + (InMemoryDao.BACKING_STORE.get(getMetaAlertIndex()).size() + 1); metaAlert.put(GUID, metaAlertGuid); JSONArray groupsArray = new JSONArray(); groupsArray.addAll(request.getGroups()); - metaAlert.put(MetaAlertDao.GROUPS_FIELD, groupsArray); + metaAlert.put(MetaAlertConstants.GROUPS_FIELD, groupsArray); // Retrieve the alert for each guid // For the purpose of testing, we're just using guids for the alerts field and grabbing the scores. @@ -183,7 +189,8 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { List<SearchResult> searchResults = searchResponse.getResults(); if (searchResults.size() > 1) { throw new InvalidCreateException( - "Found more than one result for: " + alertRequest.getGuid() + ". Values: " + searchResults + "Found more than one result for: " + alertRequest.getGuid() + ". Values: " + + searchResults ); } @@ -191,7 +198,9 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { SearchResult result = searchResults.get(0); alertArray.add(result.getSource()); Double threatScore = Double - .parseDouble(result.getSource().getOrDefault(THREAT_FIELD_DEFAULT, "0").toString()); + .parseDouble( + result.getSource().getOrDefault(MetaAlertConstants.THREAT_FIELD_DEFAULT, "0") + .toString()); threatScores.add(threatScore); } @@ -201,12 +210,12 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { alertGuids.add(alertRequest.getGuid()); } - metaAlert.put(MetaAlertDao.ALERT_FIELD, alertArray); + metaAlert.put(MetaAlertConstants.ALERT_FIELD, alertArray); metaAlert.putAll(new MetaScores(threatScores).getMetaScores()); - metaAlert.put(STATUS_FIELD, MetaAlertStatus.ACTIVE.getStatusString()); + metaAlert.put(MetaAlertConstants.STATUS_FIELD, MetaAlertStatus.ACTIVE.getStatusString()); // Add the alert to the store, but make sure not to overwrite existing results - InMemoryDao.BACKING_STORE.get(MetaAlertDao.METAALERTS_INDEX).add(metaAlert.toJSONString()); + InMemoryDao.BACKING_STORE.get(getMetaAlertIndex()).add(metaAlert.toJSONString()); METAALERT_STORE.put(metaAlertGuid, new HashSet<>(alertGuids)); @@ -217,12 +226,13 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { } @Override - public boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) throws IOException { + public boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) { Collection<String> currentAlertGuids = METAALERT_STORE.get(metaAlertGuid); if (currentAlertGuids == null) { return false; } - Collection<String> alertGuids = alertRequests.stream().map(GetRequest::getGuid).collect(Collectors.toSet()); + Collection<String> alertGuids = alertRequests.stream().map(GetRequest::getGuid) + .collect(Collectors.toSet()); boolean added = currentAlertGuids.addAll(alertGuids); if (added) { METAALERT_STORE.put(metaAlertGuid, currentAlertGuids); @@ -231,12 +241,13 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { } @Override - public boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) throws IOException { + public boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) { Collection<String> currentAlertGuids = METAALERT_STORE.get(metaAlertGuid); if (currentAlertGuids == null) { return false; } - Collection<String> alertGuids = alertRequests.stream().map(GetRequest::getGuid).collect(Collectors.toSet()); + Collection<String> alertGuids = alertRequests.stream().map(GetRequest::getGuid) + .collect(Collectors.toSet()); boolean removed = currentAlertGuids.removeAll(alertGuids); if (removed) { METAALERT_STORE.put(metaAlertGuid, currentAlertGuids); @@ -249,16 +260,17 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { public boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status) throws IOException { boolean statusChanged = false; - List<String> metaAlerts = InMemoryDao.BACKING_STORE.get(MetaAlertDao.METAALERTS_INDEX); - for (String metaAlert: metaAlerts) { + List<String> metaAlerts = InMemoryDao.BACKING_STORE.get(getMetaAlertIndex()); + for (String metaAlert : metaAlerts) { JSONObject metaAlertJSON = JSONUtils.INSTANCE.load(metaAlert, JSONObject.class); if (metaAlertGuid.equals(metaAlertJSON.get(GUID))) { - statusChanged = !status.getStatusString().equals(metaAlertJSON.get(STATUS_FIELD)); + statusChanged = !status.getStatusString() + .equals(metaAlertJSON.get(MetaAlertConstants.STATUS_FIELD)); if (statusChanged) { - metaAlertJSON.put(STATUS_FIELD, status.getStatusString()); + metaAlertJSON.put(MetaAlertConstants.STATUS_FIELD, status.getStatusString()); metaAlerts.remove(metaAlert); metaAlerts.add(metaAlertJSON.toJSONString()); - InMemoryDao.BACKING_STORE.put(MetaAlertDao.METAALERTS_INDEX, metaAlerts); + InMemoryDao.BACKING_STORE.put(getMetaAlertIndex(), metaAlerts); } break; } @@ -266,9 +278,24 @@ public class InMemoryMetaAlertDao implements MetaAlertDao { return statusChanged; } + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public String getMetAlertSensorName() { + return MetaAlertConstants.METAALERT_TYPE; + } + + public String getMetaAlertIndex() { + return "metaalert_index"; + } + public static void clear() { InMemoryDao.clear(); METAALERT_STORE.clear(); } - }
