Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publisher Points Table #1482

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Core/classes/i18n.properties
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ common.logic.not=Not

common.invalidRql=Invalid RQL

database.missingModelMapping=No model mapping for {0} to {1}

share.sharing=Sharing
share.userName=Username
share.accessType=Access type
Expand Down Expand Up @@ -1731,6 +1733,7 @@ event.audit.eventHandler=Event handler
event.audit.jsonData=Json data
event.audit.eventDetector=Event detector
event.audit.publisher=Publisher
event.audit.publishedPoint=Published point
event.audit.mailingList=Mailing list

event.audit.changedProperty=<br/>&nbsp;&nbsp;&nbsp;&nbsp;{0}: "{1}" to "{2}"
Expand Down Expand Up @@ -2104,6 +2107,7 @@ emport.error.pointType.invalid=Point type has an invalid ''{0}'' value of ''{1}'
emport.error.permission.missing=Missing ''{0}'' in point permission
emport.error.missingSource=Data source with XID ''{0}'' not found
emport.error.missingPoint=Data point with XID ''{0}'' not found
emport.error.missingPublisher=Publisher with XID ''{0}'' not found
emport.error.attractor.missingPoint=Data point with ''{0}'' XID ''{1}'' not found
emport.error.ped.missing=Point event detector must have a ''{0}''. Valid values are {1}
emport.error.ped.missingAttr=Point event detector must have a ''{0}''.
Expand Down Expand Up @@ -2159,6 +2163,7 @@ internal.monitor.pollingDataSource.SUCCESS={0} previous sequential successful po
internal.monitor.pollingDataSource.DURATION={0} last poll duration
internal.monitor.pollingDataSource.PERCENTAGE={0} poll success percentage
internal.monitor.JSON_DATA_COUNT=JSON data entries
internal.monitor.PUBLISHED_POINT_COUNT=Published points
internal.monitor.SERVER_THREADS=HTTP server threads
internal.monitor.SERVER_IDLE_THREADS=HTTP server idle threads
internal.monitor.SERVER_QUEUE_SIZE=HTTP server queue size
Expand Down
18 changes: 18 additions & 0 deletions Core/db/createTables-H2.sql
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,24 @@ CREATE TABLE publishers (
);
ALTER TABLE publishers ADD CONSTRAINT publishersUn1 UNIQUE (xid);

CREATE TABLE publishedPoints (
id int NOT NULL auto_increment,
xid varchar(100) NOT NULL,
name varchar(255),
enabled char(1),
publisherId int NOT NULL,
dataPointId int NOT NULL,
data longtext NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE publishedPoints ADD CONSTRAINT publisherPointsUn1 UNIQUE (xid);
ALTER TABLE publishedPoints ADD CONSTRAINT publisherPointsFk1 FOREIGN KEY (publisherId) REFERENCES publishers(id);
ALTER TABLE publishedPoints ADD CONSTRAINT publisherPointsFk2 FOREIGN KEY (dataPointId) REFERENCES dataPoints(id);

CREATE INDEX publishedPointNameIndex on publishedPoints (name ASC);
CREATE INDEX publishedPointEnabledIndex on publishedPoints (enabled ASC);
CREATE INDEX publishedPointXidNameIndex on publishedPoints (xid ASC, name ASC);

--
--
-- JsonData
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (C) 2019 Infinite Automation Software. All rights reserved.
*/
package com.infiniteautomation.mango.spring.db;

import org.springframework.stereotype.Component;

import com.serotonin.m2m2.vo.publish.mock.MockPublishedPointDatabaseV1Model;
import com.serotonin.m2m2.vo.publish.mock.MockPublishedPointVO;

/**
* @author Terry Packer
*
*/
@Component
public class MockPublishedPointDatabaseModelV1Mapping implements DatabaseModelJacksonMapping<MockPublishedPointVO, MockPublishedPointDatabaseV1Model> {

@Override
public Class<? extends MockPublishedPointVO> fromClass() {
return MockPublishedPointVO.class;
}

@Override
public Class<? extends MockPublishedPointDatabaseV1Model> toClass() {
return MockPublishedPointDatabaseV1Model.class;
}

@Override
public MockPublishedPointDatabaseV1Model map(Object from, DatabaseModelMapper mapper) {
return new MockPublishedPointDatabaseV1Model((MockPublishedPointVO)from);
}

@Override
public String getVersion() {
return MockPublishedPointDatabaseV1Model.class.getName();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* Copyright (C) 2019 Infinite Automation Software. All rights reserved.
*/
package com.serotonin.m2m2.vo.publish;

import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import com.serotonin.m2m2.DataTypes;
import com.serotonin.m2m2.MangoTestBase;
import com.serotonin.m2m2.db.dao.DataPointDao;
import com.serotonin.m2m2.db.dao.DataSourceDao;
import com.serotonin.m2m2.db.dao.PublishedPointDao;
import com.serotonin.m2m2.db.dao.PublisherDao;
import com.serotonin.m2m2.module.ModuleElementDefinition;
import com.serotonin.m2m2.vo.DataPointVO;
import com.serotonin.m2m2.vo.dataPoint.MockPointLocatorVO;
import com.serotonin.m2m2.vo.dataSource.mock.MockDataSourceVO;
import com.serotonin.m2m2.vo.publish.mock.MockPublishedPointVO;
import com.serotonin.m2m2.vo.publish.mock.MockPublisherDefinition;
import com.serotonin.m2m2.vo.publish.mock.MockPublisherVO;

/**
* @author Terry Packer
*
*/
public class PublishedPointTest extends MangoTestBase {

@BeforeClass
public static void addDefinitions() {
List<ModuleElementDefinition> definitions = new ArrayList<>();
definitions.add(new MockPublisherDefinition());
addModule("mockPublisher", definitions);
}

@Test
public void testPublisherAuditTrail() {
MockPublisherVO pub = new MockPublisherVO();
pub.setDefinition(new MockPublisherDefinition());
pub.setXid("PUB_TEST1");
pub.setEnabled(false);
PublisherDao.getInstance().savePublisher(pub);

MockDataSourceVO ds = new MockDataSourceVO();
ds.setXid("DS_TEST1");
ds.setName("TEST");
DataSourceDao.getInstance().save(ds);

//Save a point
DataPointVO dp = new DataPointVO();
dp.setXid("DP_1");
dp.setName("Data point name");
dp.setPointLocator(new MockPointLocatorVO(DataTypes.NUMERIC, true));
dp.setDataSourceId(ds.getId());
DataPointDao.getInstance().save(dp);

//Save publisher point
MockPublishedPointVO pp = new MockPublishedPointVO();
pp.setXid(PublishedPointDao.getInstance().generateUniqueXid());
pp.setName("Test published point");
pp.setPublisherId(pub.getId());
pp.setDataPointId(dp.getId());
pp.setMockSetting("mock setting");
pp.ensureValid();
PublishedPointDao.getInstance().save(pp);

//Verify the point was created correctly
MockPublishedPointVO mpp = (MockPublishedPointVO)PublishedPointDao.getInstance().get(pp.getId());
Assert.assertEquals(pp.getId(), mpp.getId());
Assert.assertEquals(pp.getXid(), mpp.getXid());
Assert.assertEquals(pp.getName(), mpp.getName());
Assert.assertEquals(pp.isEnabled(), mpp.isEnabled());
Assert.assertEquals(pp.getPublisherId(), mpp.getPublisherId());
Assert.assertEquals(pp.getDataPointId(), mpp.getDataPointId());
Assert.assertEquals(pp.getMockSetting(), mpp.getMockSetting());

//TODO Verify Audit Events
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (C) 2019 Infinite Automation Software. All rights reserved.
*/
package com.serotonin.m2m2.vo.publish.mock;

import org.springframework.stereotype.Component;

import com.serotonin.m2m2.db.dao.PublishedPointDao.PublishedPointSettingsDatabaseModel;
import com.serotonin.m2m2.vo.publish.PublishedPointVO;

/**
* @author Terry Packer
*
*/
@Component
public class MockPublishedPointDatabaseV1Model extends PublishedPointSettingsDatabaseModel {

private String setting;

public MockPublishedPointDatabaseV1Model() {

}

public MockPublishedPointDatabaseV1Model(MockPublishedPointVO vo) {
this.setting = vo.getMockSetting();
}

public String getSetting() {
return setting;
}

public void setSetting(String setting) {
this.setting = setting;
}

@Override
public PublishedPointVO toVO() {
MockPublishedPointVO vo = new MockPublishedPointVO();
vo.setMockSetting(setting);
return vo;
}

@Override
public String getVersion() {
return this.getClass().getName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@
*
* @author Terry Packer
*/
public class MockPublishedPointVO extends PublishedPointVO{
public class MockPublishedPointVO extends PublishedPointVO {

private String mockSetting;

public String getMockSetting() {
return mockSetting;
}

public void setMockSetting(String mockSetting) {
this.mockSetting = mockSetting;
}

/* (non-Javadoc)
* @see com.serotonin.m2m2.vo.publish.PublishedPointVO#asModel()
*/
@Override
public AbstractPublishedPointModel<?> asModel() {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright (C) 2019 Infinite Automation Software. All rights reserved.
*/
package com.infiniteautomation.mango.spring.db;

import com.fasterxml.jackson.annotation.JsonTypeInfo;

/**
* @author Terry Packer
*
*/
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.EXISTING_PROPERTY, property=AbstractDatabaseModel.VERSION_FIELD)
public abstract class AbstractDatabaseModel {

public static final String VERSION_FIELD = "version";

/**
* Ensure the model has a version
* @return
*/
public abstract String getVersion();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (C) 2019 Infinite Automation Software. All rights reserved.
*/
package com.infiniteautomation.mango.spring.db;

/**
* Used to ensure Jackson is able to de-serialize the model (type T) in this mapping
*
* @author Terry Packer
*
*/
public interface DatabaseModelJacksonMapping <F, T> extends DatabaseModelMapping<F, T> {

/**
* Return the type name that maps the T class (Model) to a Type in Jackson
* in the DAO layer we call this the version
*/
public String getVersion();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (C) 2019 Infinite Automation Software. All rights reserved.
*/
package com.infiniteautomation.mango.spring.db;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.infiniteautomation.mango.spring.MangoRuntimeContextConfiguration;
import com.infiniteautomation.mango.util.exception.TranslatableRuntimeException;
import com.serotonin.m2m2.i18n.TranslatableMessage;

/**
* Gets a list of DatabaseModelMapping beans from the Spring context and uses them to convert an object to its model.
* The DatabaseModelMapping beans can be annotated with @Order to specify their priority.
*
* @author Terry Packer
*
*/
@Component
public class DatabaseModelMapper {
private final List<DatabaseModelMapping<?,?>> mappings;

@Autowired
public DatabaseModelMapper(Optional<List<DatabaseModelMapping<?,?>>> mappings,
@Qualifier(MangoRuntimeContextConfiguration.DAO_OBJECT_MAPPER_NAME)ObjectMapper objectMapper) {
this.mappings = mappings.orElseGet(Collections::emptyList);

//Load in the mappings for Jackson
for(DatabaseModelMapping<?,?> mapping : this.mappings) {
if(mapping instanceof DatabaseModelJacksonMapping)
objectMapper.registerSubtypes(new NamedType(mapping.toClass(), ((DatabaseModelJacksonMapping<?,?>)mapping).getVersion()));
}
}

public <T> T map(Object from, Class<T> model) {
Objects.requireNonNull(from);
Objects.requireNonNull(model);

for (DatabaseModelMapping<?,?> mapping : mappings) {
if (mapping.supports(from, model)) {
@SuppressWarnings("unchecked")
T result = (T) mapping.map(from, this);
if (result != null) {
return result;
}
}
}

throw new TranslatableRuntimeException(new TranslatableMessage("database.missingModelMapping", from.getClass(), model));
}

}
Loading