Repository: eagle
Updated Branches:
refs/heads/master 3fe637eb5 -> ab5bf1076
[EAGLE-957] Add dashboard metadata entities and services
# Add dashboard metadata entities and services
* org.apache.eagle.metadata.model.DashboardEntity
* org.apache.eagle.metadata.service.DashboardEntityService (Memory/JDBC)
* org.apache.eagle.metadata.resource.DashboardResource
# API
DELETE /rest/dashboards/{uuid}
(org.apache.eagle.metadata.resource.DashboardResource)
GET /rest/dashboards
(org.apache.eagle.metadata.resource.DashboardResource)
GET /rest/dashboards/{uuidOrName}
(org.apache.eagle.metadata.resource.DashboardResource)
POST /rest/dashboards
(org.apache.eagle.metadata.resource.DashboardResource)
# Example
* Create dashboard
POST /rest/dashboards
{
"name": "Sample Dashboard",
"description": "This is a sample dashboard",
"settings": {
},
"charts": [
"{chartType: LINE}",
"{chartType: PIE}"
]
}
* Update dashboard
POST /rest/dashboards
{
"uuid": "e24fd133-adc2-4dd2-b7aa-ebf4890b145a"
"name": "Sample Dashboard 2",
"description": "This is another sample dashboard"
}
Author: Hao Chen <[email protected]>
Closes #873 from haoch/EAGLE-957.
Project: http://git-wip-us.apache.org/repos/asf/eagle/repo
Commit: http://git-wip-us.apache.org/repos/asf/eagle/commit/ab5bf107
Tree: http://git-wip-us.apache.org/repos/asf/eagle/tree/ab5bf107
Diff: http://git-wip-us.apache.org/repos/asf/eagle/diff/ab5bf107
Branch: refs/heads/master
Commit: ab5bf1076e3d199edfe58659fb9b14904d63ac8f
Parents: 3fe637e
Author: Hao Chen <[email protected]>
Authored: Wed Mar 15 17:07:41 2017 +0800
Committer: Hao Chen <[email protected]>
Committed: Wed Mar 15 17:07:41 2017 +0800
----------------------------------------------------------------------
.../eagle/metadata/model/DashboardEntity.java | 135 +++++++++++
.../metadata/resource/DashboardResource.java | 68 ++++++
.../service/DashboardEntityService.java | 42 ++++
.../DashboardEntityServiceMemoryImpl.java | 119 ++++++++++
.../service/memory/MemoryMetadataStore.java | 2 +
.../TestDashboardEntityServiceMemoryImpl.java | 109 +++++++++
.../TestSiteEntityServiceMemoryImpl.java | 3 +-
.../JDBCMetadataMetadataStoreServiceImpl.java | 75 +++++++
.../store/jdbc/JDBCMetadataQueryService.java | 11 +-
.../metadata/store/jdbc/JDBCMetadataStore.java | 3 +
.../jdbc/provider/JDBCDataSourceProvider.java | 2 +-
.../service/DashboardEntityServiceJDBCImpl.java | 224 +++++++++++++++++++
.../DashboardEntityServiceJDBCImplTest.java | 112 ++++++++++
.../jdbc/SiteEntityServiceJDBCImplTest.java | 3 +-
.../src/test/resources/init.sql | 35 ++-
.../src/main/bin/metadata-ddl.sql | 36 ++-
16 files changed, 954 insertions(+), 25 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/model/DashboardEntity.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/model/DashboardEntity.java
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/model/DashboardEntity.java
new file mode 100644
index 0000000..d8939ab
--- /dev/null
+++
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/model/DashboardEntity.java
@@ -0,0 +1,135 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.metadata.model;
+
+import com.google.common.base.Preconditions;
+import org.apache.eagle.metadata.persistence.PersistenceEntity;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Dashboard Config Entity.
+ */
+public class DashboardEntity extends PersistenceEntity {
+
+ private String name;
+ private String description;
+ private String author;
+ /**
+ * Dashboard Level Settings.
+ */
+ private Map<String,Object> settings;
+
+ /**
+ * Charts configurations.
+ */
+ private List<String> charts;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public Map<String, Object> getSettings() {
+ return settings;
+ }
+
+ public void setSettings(Map<String, Object> settings) {
+ this.settings = settings;
+ }
+
+ public List<String> getCharts() {
+ return charts;
+ }
+
+ public void setCharts(List<String> charts) {
+ this.charts = charts;
+ }
+
+ @Override
+ public void ensureDefault() {
+ Preconditions.checkNotNull(this.name, "name should not be null");
+ Preconditions.checkNotNull(this.description, "description should not
be null");
+ Preconditions.checkNotNull(this.author, "author should not be null");
+ if (this.settings == null) {
+ this.settings = new HashMap<>();
+ }
+ if (this.charts == null) {
+ this.charts = new ArrayList<>(0);
+ }
+ super.ensureDefault();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ DashboardEntity entity = (DashboardEntity) o;
+
+ if (name != null ? !name.equals(entity.name) : entity.name != null) {
+ return false;
+ }
+ if (description != null ? !description.equals(entity.description) :
entity.description != null) {
+ return false;
+ }
+ if (author != null ? !author.equals(entity.author) : entity.author !=
null) {
+ return false;
+ }
+ if (settings != null ? !settings.equals(entity.settings) :
entity.settings != null) {
+ return false;
+ }
+ return charts != null ? charts.equals(entity.charts) : entity.charts
== null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name != null ? name.hashCode() : 0;
+ result = 31 * result + (description != null ? description.hashCode() :
0);
+ result = 31 * result + (author != null ? author.hashCode() : 0);
+ result = 31 * result + (settings != null ? settings.hashCode() : 0);
+ result = 31 * result + (charts != null ? charts.hashCode() : 0);
+ return result;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/resource/DashboardResource.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/resource/DashboardResource.java
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/resource/DashboardResource.java
new file mode 100644
index 0000000..c22e840
--- /dev/null
+++
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/resource/DashboardResource.java
@@ -0,0 +1,68 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.metadata.resource;
+
+
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import org.apache.eagle.common.rest.RESTResponse;
+import org.apache.eagle.common.security.RolesAllowed;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.metadata.model.DashboardEntity;
+import org.apache.eagle.metadata.service.DashboardEntityService;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+@Path("/dashboards")
+public class DashboardResource {
+ @Inject
+ private DashboardEntityService dashboardEntityService;
+
+ @GET
+ @Path("/")
+ @Produces(MediaType.APPLICATION_JSON)
+ public RESTResponse<Collection<DashboardEntity>> listAllDashboards() {
+ return RESTResponse.async(() ->
dashboardEntityService.findAll()).get();
+ }
+
+ @GET
+ @Path("/{uuidOrName}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public RESTResponse<DashboardEntity>
getDashboardByUUIDOrName(@PathParam("uuidOrName") String uuidOrName) {
+ return RESTResponse.async(() ->
dashboardEntityService.getByUUIDOrName(uuidOrName, uuidOrName)).get();
+ }
+
+ @POST
+ @Path("/")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @RolesAllowed({User.Role.USER, User.Role.ADMINISTRATOR})
+ public RESTResponse<DashboardEntity>
createOrUpdateDashboard(DashboardEntity dashboardEntity, @Auth User user) {
+ return RESTResponse.async(() ->
dashboardEntityService.createOrUpdate(dashboardEntity, user)).get();
+ }
+
+ @DELETE
+ @Path("/{uuid}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @RolesAllowed({User.Role.USER, User.Role.ADMINISTRATOR})
+ public RESTResponse<DashboardEntity> deleteDashboard(String uuid, @Auth
User user) {
+ return RESTResponse.async(() ->
dashboardEntityService.deleteByUUID(uuid, user)).get();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/DashboardEntityService.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/DashboardEntityService.java
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/DashboardEntityService.java
new file mode 100644
index 0000000..d0b575a
--- /dev/null
+++
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/DashboardEntityService.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.metadata.service;
+
+import com.google.common.base.Preconditions;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.metadata.exceptions.EntityNotFoundException;
+import org.apache.eagle.metadata.model.DashboardEntity;
+import org.apache.eagle.metadata.persistence.PersistenceService;
+
+public interface DashboardEntityService extends
PersistenceService<DashboardEntity> {
+ DashboardEntity update(DashboardEntity dashboardEntity, User user) throws
EntityNotFoundException;
+
+ DashboardEntity getByUUIDOrName(String uuid, String name) throws
EntityNotFoundException;
+
+ DashboardEntity deleteByUUID(String uuid, User user) throws
EntityNotFoundException;
+
+ default DashboardEntity createOrUpdate(DashboardEntity dashboardEntity,
User user) throws EntityNotFoundException {
+ Preconditions.checkNotNull(dashboardEntity, "DashboardEntity should
not be null");
+ if (dashboardEntity.getUuid() == null) {
+ Preconditions.checkArgument(dashboardEntity.getAuthor() == null,
"author is immutable");
+ dashboardEntity.setAuthor(user.getName());
+ return create(dashboardEntity);
+ } else {
+ return update(dashboardEntity, user);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/DashboardEntityServiceMemoryImpl.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/DashboardEntityServiceMemoryImpl.java
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/DashboardEntityServiceMemoryImpl.java
new file mode 100644
index 0000000..79608b9
--- /dev/null
+++
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/DashboardEntityServiceMemoryImpl.java
@@ -0,0 +1,119 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.metadata.service.memory;
+
+import com.google.common.base.Preconditions;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.metadata.exceptions.EntityNotFoundException;
+import org.apache.eagle.metadata.model.DashboardEntity;
+import org.apache.eagle.metadata.service.DashboardEntityService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class DashboardEntityServiceMemoryImpl implements
DashboardEntityService {
+ private final Map<String, DashboardEntity> dashboardEntityMap = new
HashMap<>();
+ private static final Logger LOGGER =
LoggerFactory.getLogger(DashboardEntityServiceMemoryImpl.class);
+
+ @Override
+ public synchronized Collection<DashboardEntity> findAll() {
+ return dashboardEntityMap.values();
+ }
+
+ @Override
+ public synchronized DashboardEntity getByUUID(String uuid) throws
EntityNotFoundException {
+ Preconditions.checkNotNull(uuid, "uuid should not be null");
+ if (!dashboardEntityMap.containsKey(uuid)) {
+ throw new EntityNotFoundException("uuid " + uuid + "not exist");
+ }
+ return dashboardEntityMap.get(uuid);
+ }
+
+ @Override
+ public synchronized DashboardEntity create(DashboardEntity entity) {
+ Preconditions.checkNotNull(entity, "DashboardEntity is null");
+ Preconditions.checkArgument(entity.getUuid() == null, "Dashboard
Entity uuid should be null");
+ entity.ensureDefault();
+ try {
+ Preconditions.checkArgument(getByUUIDOrName(entity.getUuid(),
entity.getName()) == null, "Duplicated dashboard name");
+ } catch (EntityNotFoundException e) {
+ // ignore
+ }
+ dashboardEntityMap.put(entity.getUuid(), entity);
+ return entity;
+ }
+
+ @Override
+ public synchronized DashboardEntity update(DashboardEntity entity, User
user) throws EntityNotFoundException {
+ Preconditions.checkNotNull(entity, "Entity should not be null");
+ Preconditions.checkNotNull(entity.getUuid(), "uuid should not be
null");
+ DashboardEntity current = getByUUID(entity.getUuid());
+
+ Preconditions.checkArgument(user.isInRole(User.Role.ADMINISTRATOR)
+ || current.getAuthor().equals(user.getName()), "UPDATE operation
is not allowed");
+
+ if (entity.getName() != null) {
+ current.setName(entity.getName());
+ }
+ if (entity.getDescription() != null) {
+ current.setDescription(entity.getDescription());
+ }
+ if (entity.getAuthor() != null) {
+ current.setAuthor(entity.getAuthor());
+ }
+ if (entity.getCharts() != null) {
+ current.setCharts(entity.getCharts());
+ }
+ if (entity.getSettings() != null) {
+ current.setSettings(entity.getSettings());
+ }
+ if (entity.getCreatedTime() > 0) {
+ LOGGER.warn("createdTime is not updatable but provided: {},
ignore", current.getCreatedTime());
+ }
+ if (entity.getModifiedTime() > 0) {
+ LOGGER.warn("modifiedTime is not updatable but provided: {},
ignore", current.getModifiedTime());
+ }
+ current.ensureDefault();
+ dashboardEntityMap.put(current.getUuid(), current);
+ return current;
+ }
+
+ @Override
+ public synchronized DashboardEntity getByUUIDOrName(String uuid, String
name) throws EntityNotFoundException {
+ if (uuid != null) {
+ return getByUUID(uuid);
+ } else if (name != null) {
+ return dashboardEntityMap.values().stream()
+ .filter((dashboardEntity ->
dashboardEntity.getName().equals(name))).findAny()
+ .orElseThrow(() -> new EntityNotFoundException("Dashboard
named: " + name + " not found"));
+ }
+ throw new IllegalArgumentException("Both uuid and name are null");
+ }
+
+ @Override
+ public synchronized DashboardEntity deleteByUUID(String uuid, User user)
throws EntityNotFoundException {
+ Preconditions.checkNotNull(uuid, "UUID should not be null");
+ DashboardEntity current = this.getByUUID(uuid);
+ Preconditions.checkArgument(user.isInRole(User.Role.ADMINISTRATOR)
+ || current.getAuthor().equals(user.getName()), "DELETE operation
is not allowed for user " + user.getName());
+ dashboardEntityMap.remove(uuid);
+ return current;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/MemoryMetadataStore.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/MemoryMetadataStore.java
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/MemoryMetadataStore.java
index 747c3be..7cc076a 100644
---
a/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/MemoryMetadataStore.java
+++
b/eagle-core/eagle-metadata/eagle-metadata-base/src/main/java/org/apache/eagle/metadata/service/memory/MemoryMetadataStore.java
@@ -21,6 +21,7 @@ import org.apache.eagle.alert.metadata.IMetadataDao;
import org.apache.eagle.alert.metadata.impl.InMemMetadataDaoImpl;
import org.apache.eagle.metadata.persistence.MetadataStore;
import org.apache.eagle.metadata.service.ApplicationEntityService;
+import org.apache.eagle.metadata.service.DashboardEntityService;
import org.apache.eagle.metadata.service.SiteEntityService;
public class MemoryMetadataStore extends MetadataStore {
@@ -29,5 +30,6 @@ public class MemoryMetadataStore extends MetadataStore {
bind(SiteEntityService.class).to(SiteEntityEntityServiceMemoryImpl.class).in(Singleton.class);
bind(ApplicationEntityService.class).to(ApplicationEntityServiceMemoryImpl.class).in(Singleton.class);
bind(IMetadataDao.class).to(InMemMetadataDaoImpl.class).in(Singleton.class);
+
bind(DashboardEntityService.class).to(DashboardEntityServiceMemoryImpl.class).in(Singleton.class);
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestDashboardEntityServiceMemoryImpl.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestDashboardEntityServiceMemoryImpl.java
b/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestDashboardEntityServiceMemoryImpl.java
new file mode 100644
index 0000000..a731e92
--- /dev/null
+++
b/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestDashboardEntityServiceMemoryImpl.java
@@ -0,0 +1,109 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.metadata.service;
+
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.metadata.exceptions.EntityNotFoundException;
+import org.apache.eagle.metadata.model.DashboardEntity;
+import
org.apache.eagle.metadata.service.memory.DashboardEntityServiceMemoryImpl;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+
+public class TestDashboardEntityServiceMemoryImpl {
+ private DashboardEntityService dashboardEntityService = new
DashboardEntityServiceMemoryImpl();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void testDashboardCRUD() throws EntityNotFoundException {
+ User user1 = new User();
+ user1.setName("user1");
+ user1.setRoles(Collections.singleton(User.Role.USER));
+
+ User user2 = new User();
+ user2.setName("user2");
+ user2.setRoles(Collections.singleton(User.Role.USER));
+
+ User admin = new User();
+ admin.setName("admin");
+ admin.setRoles(Collections.singleton(User.Role.ADMINISTRATOR));
+
+ DashboardEntity entity = new DashboardEntity();
+ {
+ entity.setName("Sample Dashboard");
+ entity.setDescription("A sample dashboard for unit test");
+ entity.setAuthor(user1.getName());
+ entity.setSettings(new HashMap<String, Object>() {
+ {
+ put("Stringkey", "SettingValue");
+ }
+ });
+ entity.setCharts(Arrays.asList(
+ "{chartType: 'LINE'}",
+ "{chartType}: 'PIE'"
+ ));
+ }
+
+ {
+ Assert.assertEquals(0, dashboardEntityService.findAll().size());
+ }
+
+ DashboardEntity createdEntity;
+ {
+ createdEntity = dashboardEntityService.create(entity);
+ Assert.assertNotNull(createdEntity.getUuid());
+ Assert.assertTrue(createdEntity.getCreatedTime() > 0);
+ Assert.assertTrue(createdEntity.getModifiedTime() > 0);
+ Assert.assertEquals(1, dashboardEntityService.findAll().size());
+ }
+
+ DashboardEntity updatedEntity;
+ {
+ DashboardEntity entityToUpdate = new DashboardEntity();
+ entityToUpdate.setUuid(createdEntity.getUuid());
+ entityToUpdate.setName("Sample Dashboard (Updated)");
+ updatedEntity = dashboardEntityService.update(entityToUpdate,
user1);
+ Assert.assertEquals(createdEntity.getUuid(),
updatedEntity.getUuid());
+ Assert.assertEquals("Sample Dashboard (Updated)",
updatedEntity.getName());
+ Assert.assertEquals(createdEntity.getCreatedTime(),
updatedEntity.getCreatedTime());
+
Assert.assertEquals(createdEntity.getAuthor(),updatedEntity.getAuthor());
+ Assert.assertEquals(createdEntity.getCharts(),
updatedEntity.getCharts());
+ Assert.assertEquals(createdEntity.getSettings(),
updatedEntity.getSettings());
+ Assert.assertEquals(1, dashboardEntityService.findAll().size());
+ }
+
+ DashboardEntity deletedEntity;
+
+ {
+ expectedException.expect(IllegalArgumentException.class);
+ dashboardEntityService.deleteByUUID(updatedEntity.getUuid(),
user2);
+ Assert.assertEquals(1, dashboardEntityService.findAll().size());
+ }
+
+ {
+ deletedEntity =
dashboardEntityService.deleteByUUID(updatedEntity.getUuid(), admin);
+ Assert.assertEquals(updatedEntity, deletedEntity);
+ Assert.assertEquals(0, dashboardEntityService.findAll().size());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestSiteEntityServiceMemoryImpl.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestSiteEntityServiceMemoryImpl.java
b/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestSiteEntityServiceMemoryImpl.java
index 645d18a..c0225e2 100644
---
a/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestSiteEntityServiceMemoryImpl.java
+++
b/eagle-core/eagle-metadata/eagle-metadata-base/src/test/java/org/apache/eagle/metadata/service/TestSiteEntityServiceMemoryImpl.java
@@ -16,10 +16,11 @@
*/
package org.apache.eagle.metadata.service;
-import junit.framework.Assert;
+
import org.apache.eagle.metadata.exceptions.EntityNotFoundException;
import org.apache.eagle.metadata.model.SiteEntity;
import
org.apache.eagle.metadata.service.memory.SiteEntityEntityServiceMemoryImpl;
+import org.junit.Assert;
import org.junit.Test;
/**
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataMetadataStoreServiceImpl.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataMetadataStoreServiceImpl.java
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataMetadataStoreServiceImpl.java
index e62ebe4..e7a50cd 100644
---
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataMetadataStoreServiceImpl.java
+++
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataMetadataStoreServiceImpl.java
@@ -18,6 +18,7 @@ package org.apache.eagle.metadata.store.jdbc;
import com.google.inject.Inject;
+import org.apache.eagle.common.function.ThrowableConsumer;
import org.apache.eagle.common.function.ThrowableConsumer2;
import org.apache.eagle.common.function.ThrowableFunction;
import org.slf4j.Logger;
@@ -65,6 +66,35 @@ public class JDBCMetadataMetadataStoreServiceImpl implements
JDBCMetadataQuerySe
}
@Override
+ public <T, E extends Throwable> boolean execute(String sql, T entity,
ThrowableConsumer2<PreparedStatement, T, E> mapper) throws SQLException, E {
+ Connection connection = null;
+ PreparedStatement statement = null;
+ try {
+ connection = dataSource.getConnection();
+ statement = connection.prepareStatement(sql);
+ mapper.accept(statement,entity);
+ return statement.executeUpdate() > 0;
+ } catch (SQLException e) {
+ throw e;
+ } finally {
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ @Override
public boolean dropTable(String tableName) throws SQLException {
LOGGER.debug("Dropping table {}", tableName);
return execute(String.format("DROP TABLE %s", tableName));
@@ -207,6 +237,51 @@ public class JDBCMetadataMetadataStoreServiceImpl
implements JDBCMetadataQuerySe
}
@Override
+ public <T, E extends Throwable> List<T> queryWithCond(String querySql,
+
ThrowableConsumer<PreparedStatement, SQLException> preparer,
+
ThrowableFunction<ResultSet, T, E> mapper) throws SQLException, E {
+ Connection connection = null;
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ try {
+ connection = dataSource.getConnection();
+ statement = connection.prepareStatement(querySql);
+ preparer.accept(statement);
+ resultSet = statement.executeQuery();
+ List<T> result = new LinkedList<>();
+ while (resultSet.next()) {
+ result.add(mapper.apply(resultSet));
+ }
+ return result;
+ } catch (SQLException e) {
+ LOGGER.error("Error to query cond: {}", querySql, e);
+ throw e;
+ } finally {
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (SQLException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ @Override
public <T, E extends Throwable> int update(String updateSql, T entity,
ThrowableConsumer2<PreparedStatement, T, E> mapper) throws SQLException, E {
Connection connection = null;
PreparedStatement statement = null;
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataQueryService.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataQueryService.java
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataQueryService.java
index d869305..843e609 100644
---
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataQueryService.java
+++
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataQueryService.java
@@ -16,6 +16,7 @@
*/
package org.apache.eagle.metadata.store.jdbc;
+import org.apache.eagle.common.function.ThrowableConsumer;
import org.apache.eagle.common.function.ThrowableConsumer2;
import org.apache.eagle.common.function.ThrowableFunction;
@@ -24,10 +25,13 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
+import java.util.function.Consumer;
public interface JDBCMetadataQueryService {
boolean execute(String sql) throws SQLException;
+ <T, E extends Throwable> boolean execute(String sql, T entity,
ThrowableConsumer2<PreparedStatement, T, E> mapper) throws SQLException, E;
+
boolean dropTable(String tableName) throws SQLException;
<T, E extends Throwable> int insert(String insertSql, Collection<T>
entities, ThrowableConsumer2<PreparedStatement, T, E> mapper) throws E,
SQLException;
@@ -36,8 +40,13 @@ public interface JDBCMetadataQueryService {
<T, E extends Throwable> List<T> query(String querySql,
ThrowableFunction<ResultSet, T, E> mapper) throws SQLException, E;
+
+ /**
+ * @see #queryWithCond(String, ThrowableConsumer, ThrowableFunction)
+ */
<T, E extends Throwable> List<T> queryWithCond(String querySql, T entity,
ThrowableConsumer2<PreparedStatement, T, E> mapper1,
ThrowableFunction<ResultSet, T, E> mapper) throws SQLException, E;
- <T, E extends Throwable> int update(String updateSql, T entity,
ThrowableConsumer2<PreparedStatement, T, E> mapper) throws SQLException, E;
+ <T, E extends Throwable> List<T> queryWithCond(String querySql,
ThrowableConsumer<PreparedStatement, SQLException> preparer,
ThrowableFunction<ResultSet, T, E> mapper) throws SQLException, E;
+ <T, E extends Throwable> int update(String updateSql, T entity,
ThrowableConsumer2<PreparedStatement, T, E> mapper) throws SQLException, E;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataStore.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataStore.java
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataStore.java
index 2e12e23..1af8e78 100644
---
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataStore.java
+++
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/JDBCMetadataStore.java
@@ -23,10 +23,12 @@ import org.apache.eagle.alert.metadata.MetadataUtils;
import org.apache.eagle.alert.metadata.impl.JdbcMetadataDaoImpl;
import org.apache.eagle.metadata.persistence.MetadataStore;
import org.apache.eagle.metadata.service.ApplicationEntityService;
+import org.apache.eagle.metadata.service.DashboardEntityService;
import org.apache.eagle.metadata.service.SiteEntityService;
import org.apache.eagle.metadata.store.jdbc.provider.JDBCDataSourceProvider;
import
org.apache.eagle.metadata.store.jdbc.provider.JDBCMetadataStoreConfigProvider;
import
org.apache.eagle.metadata.store.jdbc.service.ApplicationEntityServiceJDBCImpl;
+import
org.apache.eagle.metadata.store.jdbc.service.DashboardEntityServiceJDBCImpl;
import org.apache.eagle.metadata.store.jdbc.service.SiteEntityServiceJDBCImpl;
import javax.sql.DataSource;
@@ -40,5 +42,6 @@ public class JDBCMetadataStore extends MetadataStore {
bind(JDBCMetadataQueryService.class).to(JDBCMetadataMetadataStoreServiceImpl.class).in(Singleton.class);
bind(ApplicationEntityService.class).to(ApplicationEntityServiceJDBCImpl.class).in(Singleton.class);
bind(SiteEntityService.class).to(SiteEntityServiceJDBCImpl.class).in(Singleton.class);
+
bind(DashboardEntityService.class).to(DashboardEntityServiceJDBCImpl.class).in(Singleton.class);
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/provider/JDBCDataSourceProvider.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/provider/JDBCDataSourceProvider.java
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/provider/JDBCDataSourceProvider.java
index 40f08c1..7495ef5 100644
---
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/provider/JDBCDataSourceProvider.java
+++
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/provider/JDBCDataSourceProvider.java
@@ -45,7 +45,7 @@ public class JDBCDataSourceProvider implements
Provider<DataSource> {
@Override
public void run() {
try {
- LOGGER.info("Shutting down data fromStream");
+ LOGGER.info("Shutting down data source");
datasource.close();
} catch (SQLException e) {
LOGGER.error("SQLException: {}", e.getMessage(), e);
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/service/DashboardEntityServiceJDBCImpl.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/service/DashboardEntityServiceJDBCImpl.java
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/service/DashboardEntityServiceJDBCImpl.java
new file mode 100644
index 0000000..0566687
--- /dev/null
+++
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/main/java/org/apache/eagle/metadata/store/jdbc/service/DashboardEntityServiceJDBCImpl.java
@@ -0,0 +1,224 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.metadata.store.jdbc.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.CollectionType;
+import com.fasterxml.jackson.databind.type.MapType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.google.common.base.Preconditions;
+import com.mongodb.util.JSON;
+import org.apache.eagle.common.function.ThrowableConsumer2;
+import org.apache.eagle.common.function.ThrowableFunction;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.metadata.exceptions.EntityNotFoundException;
+import org.apache.eagle.metadata.model.DashboardEntity;
+import org.apache.eagle.metadata.service.DashboardEntityService;
+import org.apache.eagle.metadata.store.jdbc.JDBCMetadataQueryService;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+public class DashboardEntityServiceJDBCImpl implements DashboardEntityService {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(DashboardEntityServiceJDBCImpl.class);
+
+ private static final String TABLE_NAME = "dashboards";
+ private static final String SELECT_ALL_SQL = "SELECT * FROM " + TABLE_NAME;
+ private static final String FILTER_BY_UUID_SQL = "SELECT * FROM " +
TABLE_NAME + " WHERE uuid = ?";
+ private static final String DELETE_BY_UUID_SQL_FORMAT = "DELETE FROM " +
TABLE_NAME + " WHERE uuid = '%s'";
+ private static final String FILTER_BY_UUID_OR_NAME_SQL = "SELECT * FROM "
+ TABLE_NAME + " WHERE uuid = ? or name = ?";
+ private static final String CREATE_SQL = "INSERT INTO " + TABLE_NAME
+ + "(name, description, author, charts, settings, modifiedtime,
createdtime, uuid) VALUES (?,?,?,?,?,?,?,?)";
+ private static final String UPDATE_SQL = "UPDATE " + TABLE_NAME
+ + " SET name = ?, description = ?, author = ?, charts = ?, settings =
?, modifiedtime = ?, createdtime = ? WHERE uuid = ?";
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ private static final MapType SETTINGS_TYPE =
TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class,
Object.class);
+ private static final CollectionType CHARTS_TYPE =
TypeFactory.defaultInstance().constructCollectionType(LinkedList.class,
String.class);
+
+ private static ThrowableFunction<ResultSet, DashboardEntity, SQLException>
DASHBOARD_DESERIALIZER = resultSet -> {
+ DashboardEntity entity = new DashboardEntity();
+ entity.setUuid(resultSet.getString("uuid"));
+ entity.setName(resultSet.getString("name"));
+ entity.setDescription(resultSet.getString("description"));
+ String settings = resultSet.getString("settings");
+ String charts = resultSet.getString("charts");
+ if (charts != null) {
+ try {
+ entity.setCharts(OBJECT_MAPPER.readValue(charts, CHARTS_TYPE));
+ } catch (IOException e) {
+ throw new SQLException("Error to deserialize JSON as
List<String>: " + charts, e);
+ }
+ }
+ if (settings != null) {
+ try {
+ entity.setSettings(OBJECT_MAPPER.readValue(settings,
SETTINGS_TYPE));
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error to deserialize JSON
as Map<String, Object>: " + settings, e);
+ }
+ }
+ entity.setAuthor(resultSet.getString("author"));
+ entity.setCreatedTime(resultSet.getLong("createdtime"));
+ entity.setModifiedTime(resultSet.getLong("modifiedtime"));
+ return entity;
+ };
+
+ private static ThrowableConsumer2<PreparedStatement, DashboardEntity,
SQLException> DASHBOARD_SERIALIZER = (statement, dashboard) -> {
+ statement.setString(1, dashboard.getName());
+ statement.setString(2, dashboard.getDescription());
+ statement.setString(3, dashboard.getAuthor());
+ if (dashboard.getCharts() != null) {
+ try {
+ statement.setString(4,
OBJECT_MAPPER.writeValueAsString(dashboard.getCharts()));
+ } catch (JsonProcessingException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ }
+ }
+ if (dashboard.getSettings() != null) {
+ try {
+ statement.setString(5,
OBJECT_MAPPER.writeValueAsString(dashboard.getSettings()));
+ } catch (JsonProcessingException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ }
+ }
+ statement.setLong(6, dashboard.getModifiedTime());
+ statement.setLong(7, dashboard.getCreatedTime());
+ statement.setString(8, dashboard.getUuid());
+ };
+
+ @Inject
+ JDBCMetadataQueryService queryService;
+
+ @Override
+ public Collection<DashboardEntity> findAll() {
+ try {
+ return queryService.query(SELECT_ALL_SQL, DASHBOARD_DESERIALIZER);
+ } catch (SQLException e) {
+ LOGGER.error("Error to execute {}: {}", SELECT_ALL_SQL,
e.getMessage(), e);
+ throw new IllegalArgumentException("SQL execution error" +
e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public DashboardEntity getByUUID(String uuid) throws
EntityNotFoundException {
+ try {
+ return queryService.queryWithCond(FILTER_BY_UUID_SQL,
+ o -> o.setString(1, uuid),
DASHBOARD_DESERIALIZER).stream().findAny().orElseThrow(() -> new
EntityNotFoundException("Dashboard (uuid: " + uuid + ") not found"));
+ } catch (SQLException e) {
+ LOGGER.error("Error to execute {} (uuid: {}): {}",
FILTER_BY_UUID_SQL, uuid, e.getMessage(), e);
+ throw new IllegalArgumentException("SQL execution error:" +
e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public DashboardEntity create(DashboardEntity entity) {
+ Preconditions.checkNotNull(entity, "Entity should not be null");
+ entity.ensureDefault();
+ try {
+ int retCode = queryService.insert(CREATE_SQL,
Collections.singletonList(entity), DASHBOARD_SERIALIZER);
+ if (retCode > 0) {
+ return entity;
+ } else {
+ throw new SQLException("Insertion returned: " + retCode);
+ }
+ } catch (SQLException e) {
+ LOGGER.error("Error to insert entity {} (entity: {}): {}",
CREATE_SQL, entity.toString(), e.getMessage(), e);
+ throw new IllegalArgumentException("SQL execution error:" +
e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public DashboardEntity update(DashboardEntity entity, User user) throws
EntityNotFoundException {
+ Preconditions.checkNotNull(entity, "Entity should not be null");
+ Preconditions.checkNotNull(entity.getUuid(), "uuid should not be
null");
+ DashboardEntity current = getByUUID(entity.getUuid());
+
+ Preconditions.checkArgument(user.isInRole(User.Role.ADMINISTRATOR)
+ || current.getAuthor().equals(user.getName()), "UPDATE operation
is not allowed");
+
+ if (entity.getName() != null) {
+ current.setName(entity.getName());
+ }
+ if (entity.getDescription() != null) {
+ current.setDescription(entity.getDescription());
+ }
+ if (entity.getAuthor() != null) {
+ current.setAuthor(entity.getAuthor());
+ }
+ if (entity.getCharts() != null) {
+ current.setCharts(entity.getCharts());
+ }
+ if (entity.getSettings() != null) {
+ current.setSettings(entity.getSettings());
+ }
+ if (entity.getCreatedTime() > 0) {
+ LOGGER.warn("createdTime is not updatable but provided: {},
ignore", current.getCreatedTime());
+ }
+ if (entity.getModifiedTime() > 0) {
+ LOGGER.warn("modifiedTime is not updatable but provided: {},
ignore", current.getModifiedTime());
+ }
+ current.ensureDefault();
+ try {
+ if (!queryService.execute(UPDATE_SQL, current,
DASHBOARD_SERIALIZER)) {
+ throw new IllegalArgumentException("Failed to update
dashboard");
+ }
+ } catch (SQLException e) {
+ LOGGER.error("Error to execute {}: {}", UPDATE_SQL, current, e);
+ throw new IllegalArgumentException("SQL execution error: " +
e.getMessage(), e);
+ }
+ return current;
+ }
+
+ @Override
+ public DashboardEntity getByUUIDOrName(String uuid, String name) throws
EntityNotFoundException {
+ Preconditions.checkArgument(uuid != null && name != null, "Both uuid
and name are null");
+ try {
+ return queryService.queryWithCond(FILTER_BY_UUID_OR_NAME_SQL, o ->
{
+ o.setString(0, uuid);
+ o.setString(1, name);
+ }, DASHBOARD_DESERIALIZER).stream().findAny().orElseThrow(() ->
new EntityNotFoundException("Dashboard (uuid: " + uuid + " or name: " + name +
") not found"));
+ } catch (SQLException e) {
+ LOGGER.error("Error to execute {} (uuid: {}, name: {}): {}",
FILTER_BY_UUID_OR_NAME_SQL, uuid, e.getMessage(), e);
+ throw new IllegalArgumentException("SQL execution error: " +
e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public DashboardEntity deleteByUUID(String uuid, User user) throws
EntityNotFoundException {
+ Preconditions.checkNotNull(uuid, "uuid should not be null");
+ DashboardEntity entity = this.getByUUID(uuid);
+
+ Preconditions.checkArgument(user.isInRole(User.Role.ADMINISTRATOR)
+ || entity.getAuthor().equals(user.getName()), "DELETE operation is
not allowed");
+
+ try {
+ queryService.execute(String.format(DELETE_BY_UUID_SQL_FORMAT,
uuid));
+ } catch (SQLException e) {
+ LOGGER.error("Error to execute {}: {}",
String.format(DELETE_BY_UUID_SQL_FORMAT, uuid), uuid, e.getMessage(), e);
+ throw new IllegalArgumentException("SQL execution error: " +
e.getMessage(), e);
+ }
+ return entity;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/DashboardEntityServiceJDBCImplTest.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/DashboardEntityServiceJDBCImplTest.java
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/DashboardEntityServiceJDBCImplTest.java
new file mode 100644
index 0000000..55fc54f
--- /dev/null
+++
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/DashboardEntityServiceJDBCImplTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.metadata.store.jdbc;
+
+
+import com.google.inject.Inject;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.metadata.exceptions.EntityNotFoundException;
+import org.apache.eagle.metadata.model.DashboardEntity;
+import org.apache.eagle.metadata.service.DashboardEntityService;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+
+public class DashboardEntityServiceJDBCImplTest extends JDBCMetadataTestBase {
+ @Inject
+ private DashboardEntityService dashboardEntityService;
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void testDashboardCRUD() throws EntityNotFoundException {
+ User user1 = new User();
+ user1.setName("user1");
+ user1.setRoles(Collections.singleton(User.Role.USER));
+
+ User user2 = new User();
+ user2.setName("user2");
+ user2.setRoles(Collections.singleton(User.Role.USER));
+
+ User admin = new User();
+ admin.setName("admin");
+ admin.setRoles(Collections.singleton(User.Role.ADMINISTRATOR));
+
+ DashboardEntity entity = new DashboardEntity();
+ {
+ entity.setName("Sample Dashboard");
+ entity.setDescription("A sample dashboard for unit test");
+ entity.setAuthor(user1.getName());
+ entity.setSettings(new HashMap<String, Object>() {
+ {
+ put("Stringkey", "SettingValue");
+ }
+ });
+ entity.setCharts(Arrays.asList(
+ "{chartType: 'LINE'}",
+ "{chartType}: 'PIE'"
+ ));
+ }
+
+ {
+ Assert.assertEquals(0, dashboardEntityService.findAll().size());
+ }
+
+ DashboardEntity createdEntity;
+ {
+ createdEntity = dashboardEntityService.create(entity);
+ Assert.assertNotNull(createdEntity.getUuid());
+ Assert.assertTrue(createdEntity.getCreatedTime() > 0);
+ Assert.assertTrue(createdEntity.getModifiedTime() > 0);
+ Assert.assertEquals(1, dashboardEntityService.findAll().size());
+ }
+
+ DashboardEntity updatedEntity;
+ {
+ DashboardEntity entityToUpdate = new DashboardEntity();
+ entityToUpdate.setUuid(createdEntity.getUuid());
+ entityToUpdate.setName("Sample Dashboard (Updated)");
+ updatedEntity = dashboardEntityService.update(entityToUpdate,
user1);
+ Assert.assertEquals(createdEntity.getUuid(),
updatedEntity.getUuid());
+ Assert.assertEquals("Sample Dashboard (Updated)",
updatedEntity.getName());
+ Assert.assertEquals(createdEntity.getCreatedTime(),
updatedEntity.getCreatedTime());
+
Assert.assertEquals(createdEntity.getAuthor(),updatedEntity.getAuthor());
+ Assert.assertEquals(createdEntity.getCharts(),
updatedEntity.getCharts());
+ Assert.assertEquals(createdEntity.getSettings(),
updatedEntity.getSettings());
+ Assert.assertEquals(1, dashboardEntityService.findAll().size());
+ }
+
+ DashboardEntity deletedEntity;
+
+ {
+ expectedException.expect(IllegalArgumentException.class);
+ dashboardEntityService.deleteByUUID(updatedEntity.getUuid(),
user2);
+ Assert.assertEquals(1, dashboardEntityService.findAll().size());
+ }
+
+ {
+ deletedEntity =
dashboardEntityService.deleteByUUID(updatedEntity.getUuid(), admin);
+ Assert.assertEquals(updatedEntity, deletedEntity);
+ Assert.assertEquals(0, dashboardEntityService.findAll().size());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/SiteEntityServiceJDBCImplTest.java
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/SiteEntityServiceJDBCImplTest.java
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/SiteEntityServiceJDBCImplTest.java
index 88ed729..c22cc2b 100644
---
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/SiteEntityServiceJDBCImplTest.java
+++
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/java/org/apache/eagle/metadata/store/jdbc/SiteEntityServiceJDBCImplTest.java
@@ -58,6 +58,7 @@ public class SiteEntityServiceJDBCImplTest extends
JDBCMetadataTestBase {
public void testInsertSiteEntityWithNullValues() throws SQLException {
SiteEntity siteEntity = new SiteEntity();
siteEntity.setSiteId("test-null-site");
+ siteEntity.setSiteName("Test Site Name");
siteEntityService.create(siteEntity);
String uuid = siteEntity.getUuid();
@@ -69,7 +70,7 @@ public class SiteEntityServiceJDBCImplTest extends
JDBCMetadataTestBase {
SiteEntity siteEntityFromDB = results.iterator().next();
Assert.assertEquals(uuid, siteEntityFromDB.getUuid());
Assert.assertEquals("test-null-site", siteEntityFromDB.getSiteId());
- Assert.assertNull(siteEntityFromDB.getSiteName());
+ Assert.assertEquals("Test Site Name",siteEntityFromDB.getSiteName());
Assert.assertNull(siteEntityFromDB.getDescription());
Assert.assertEquals(createdTime, siteEntityFromDB.getCreatedTime());
Assert.assertEquals(modifiedTime, siteEntityFromDB.getModifiedTime());
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/resources/init.sql
----------------------------------------------------------------------
diff --git
a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/resources/init.sql
b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/resources/init.sql
index 749032b..1168473 100644
--- a/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/resources/init.sql
+++ b/eagle-core/eagle-metadata/eagle-metadata-jdbc/src/test/resources/init.sql
@@ -18,7 +18,7 @@
CREATE TABLE IF NOT EXISTS applications (
uuid varchar(50) PRIMARY KEY,
- appid varchar(100) DEFAULT NULL,
+ appid varchar(100) NOT NULL,
siteid varchar(100) DEFAULT NULL,
apptype varchar(30) DEFAULT NULL,
appmode varchar(10) DEFAULT NULL,
@@ -26,16 +26,31 @@ CREATE TABLE IF NOT EXISTS applications (
appstatus varchar(20) DEFAULT NULL,
configuration mediumtext DEFAULT NULL,
context mediumtext DEFAULT NULL,
- createdtime bigint(20) DEFAULT NULL,
- modifiedtime bigint(20) DEFAULT NULL
-);
+ createdtime bigint(20) NOT NULL,
+ modifiedtime bigint(20) NOT NULL,
+ UNIQUE INDEX `appid_UNIQUE` (`appid` ASC))
+COMMENT = 'eagle application metadata';
CREATE TABLE IF NOT EXISTS sites (
uuid varchar(50) PRIMARY KEY,
- siteid varchar(100) DEFAULT NULL,
- sitename varchar(100) DEFAULT NULL,
+ siteid varchar(100) NOT NULL,
+ sitename varchar(100) NOT NULL,
description varchar(255) DEFAULT NULL,
- createdtime bigint(20) DEFAULT NULL,
- modifiedtime bigint(20) DEFAULT NULL,
- UNIQUE (siteid)
-);
\ No newline at end of file
+ createdtime bigint(20) NOT NULL,
+ modifiedtime bigint(20) NOT NULL,
+ UNIQUE INDEX `siteid_UNIQUE` (`siteid` ASC))
+COMMENT = 'eagle site metadata';
+
+CREATE TABLE IF NOT EXISTS `dashboards` (
+ `uuid` VARCHAR(50) NOT NULL,
+ `name` VARCHAR(200) NOT NULL,
+ `description` VARCHAR(500) NOT NULL,
+ `settings` mediumtext NULL,
+ `charts` longtext NULL,
+ `modifiedtime` BIGINT(20) NOT NULL,
+ `createdtime` BIGINT(20) NOT NULL,
+ `author` VARCHAR(50) NOT NULL,
+ PRIMARY KEY (`uuid`),
+ UNIQUE INDEX `uuid_UNIQUE` (`uuid` ASC),
+ UNIQUE INDEX `name_UNIQUE` (`name` ASC))
+COMMENT = 'eagle dashboard metadata';
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ab5bf107/eagle-server-assembly/src/main/bin/metadata-ddl.sql
----------------------------------------------------------------------
diff --git a/eagle-server-assembly/src/main/bin/metadata-ddl.sql
b/eagle-server-assembly/src/main/bin/metadata-ddl.sql
index c24e592..44101a3 100644
--- a/eagle-server-assembly/src/main/bin/metadata-ddl.sql
+++ b/eagle-server-assembly/src/main/bin/metadata-ddl.sql
@@ -16,12 +16,11 @@
-- *
-- */
-
-- application framework metadata
CREATE TABLE IF NOT EXISTS applications (
uuid varchar(50) PRIMARY KEY,
- appid varchar(100) DEFAULT NULL,
+ appid varchar(100) NOT NULL,
siteid varchar(100) DEFAULT NULL,
apptype varchar(30) DEFAULT NULL,
appmode varchar(10) DEFAULT NULL,
@@ -29,19 +28,34 @@ CREATE TABLE IF NOT EXISTS applications (
appstatus varchar(20) DEFAULT NULL,
configuration mediumtext DEFAULT NULL,
context mediumtext DEFAULT NULL,
- createdtime bigint(20) DEFAULT NULL,
- modifiedtime bigint(20) DEFAULT NULL
-);
+ createdtime bigint(20) NOT NULL,
+ modifiedtime bigint(20) NOT NULL,
+ UNIQUE INDEX `appid_UNIQUE` (`appid` ASC))
+COMMENT = 'eagle application metadata';
CREATE TABLE IF NOT EXISTS sites (
uuid varchar(50) PRIMARY KEY,
- siteid varchar(100) DEFAULT NULL,
- sitename varchar(100) DEFAULT NULL,
+ siteid varchar(100) NOT NULL,
+ sitename varchar(100) NOT NULL,
description varchar(255) DEFAULT NULL,
- createdtime bigint(20) DEFAULT NULL,
- modifiedtime bigint(20) DEFAULT NULL,
- UNIQUE (siteid)
-);
+ createdtime bigint(20) NOT NULL,
+ modifiedtime bigint(20) NOT NULL,
+ UNIQUE INDEX `siteid_UNIQUE` (`siteid` ASC))
+COMMENT = 'eagle site metadata';
+
+CREATE TABLE IF NOT EXISTS `dashboards` (
+ `uuid` VARCHAR(50) NOT NULL,
+ `name` VARCHAR(200) NOT NULL,
+ `description` VARCHAR(500) NOT NULL,
+ `settings` mediumtext NULL,
+ `charts` longtext NULL,
+ `modifiedtime` BIGINT(20) NOT NULL,
+ `createdtime` BIGINT(20) NOT NULL,
+ `author` VARCHAR(50) NOT NULL,
+ PRIMARY KEY (`uuid`),
+ UNIQUE INDEX `uuid_UNIQUE` (`uuid` ASC),
+ UNIQUE INDEX `name_UNIQUE` (`name` ASC))
+COMMENT = 'eagle dashboard metadata';
-- eagle security module metadata