在物联网系统开发中,如何优雅地描述和管理各种智能设备?如何让一个温湿度传感器、智能灯具、空调设备在数字世界中有统一的表达方式?本文将深入解析物模型的核心设计架构,并提供完整的实现代码,让你能够快速上手构建自己的物模型系统。
本文分为两大模块:
物模型是对物理设备在数字世界中的抽象表达。它解决的核心问题是:如何用统一的语言描述千差万别的IoT设备?
这种三要素设计体现了面向对象的核心思想:
public class ThingModel {
private String productKey; // 产品标识
private String productName; // 产品名称
private String version; // 版本号
private String description; // 描述信息
private List<Property> properties = new ArrayList<>(); // 属性列表
private List<Event> events = new ArrayList<>(); // 事件列表
private List<Service> services = new ArrayList<>(); // 服务列表
private Map<String, Object> extendInfo = new HashMap<>(); // 扩展信息
// 为提高查询效率,使用Map做缓存
privatetransient Map<String, Property> propertyMap;
privatetransient Map<String, Event> eventMap;
privatetransient Map<String, Service> serviceMap;
/**
* 初始化缓存
*/
private void initCache() {
if (propertyMap == null) {
propertyMap = new HashMap<>();
for (Property property : properties) {
propertyMap.put(property.getIdentifier(), property);
}
}
if (eventMap == null) {
eventMap = new HashMap<>();
for (Event event : events) {
eventMap.put(event.getIdentifier(), event);
}
}
if (serviceMap == null) {
serviceMap = new HashMap<>();
for (Service service : services) {
serviceMap.put(service.getIdentifier(), service);
}
}
}
/**
* 根据标识符获取属性
*/
public Property getProperty(String identifier) {
initCache();
return propertyMap.get(identifier);
}
/**
* 根据标识符获取事件
*/
public Event getEvent(String identifier) {
initCache();
return eventMap.get(identifier);
}
/**
* 根据标识符获取服务
*/
public Service getService(String identifier) {
initCache();
return serviceMap.get(identifier);
}
/**
* 添加属性
*/
public void addProperty(Property property) {
if (property != null) {
properties.add(property);
if (propertyMap != null) {
propertyMap.put(property.getIdentifier(), property);
}
}
}
/**
* 添加事件
*/
public void addEvent(Event event) {
if (event != null) {
events.add(event);
if (eventMap != null) {
eventMap.put(event.getIdentifier(), event);
}
}
}
/**
* 添加服务
*/
public void addService(Service service) {
if (service != null) {
services.add(service);
if (serviceMap != null) {
serviceMap.put(service.getIdentifier(), service);
}
}
}
// Getters and Setters
public String getProductKey() { return productKey; }
public void setProductKey(String productKey) { this.productKey = productKey; }
public String getProductName() { return productName; }
public void setProductName(String productName) { this.productName = productName; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public List<Property> getProperties() { return properties; }
public void setProperties(List<Property> properties) { this.properties = properties; }
public List<Event> getEvents() { return events; }
public void setEvents(List<Event> events) { this.events = events; }
public List<Service> getServices() { return services; }
public void setServices(List<Service> services) { this.services = services; }
public Map<String, Object> getExtendInfo() { return extendInfo; }
public void setExtendInfo(Map<String, Object> extendInfo) { this.extendInfo = extendInfo; }
}
public class Property {
private String identifier; // 属性标识符,如"temperature"
private String name; // 属性名称,如"环境温度"
private String description; // 属性描述
private AccessMode accessMode; // 访问模式:只读、只写、读写
private DataSpec dataSpec; // 数据规格
private Boolean required; // 是否必需
private Object extendInfo; // 扩展信息
/**
* 验证属性值是否有效
*/
public boolean validateValue(Object value) {
if (dataSpec == null) {
returntrue;
}
return dataSpec.validate(value);
}
/**
* 是否可读
*/
public boolean isReadable() {
return accessMode == AccessMode.R || accessMode == AccessMode.RW;
}
/**
* 是否可写
*/
public boolean isWritable() {
return accessMode == AccessMode.W || accessMode == AccessMode.RW;
}
// Getters and Setters
public String getIdentifier() { return identifier; }
public void setIdentifier(String identifier) { this.identifier = identifier; }
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 AccessMode getAccessMode() { return accessMode; }
public void setAccessMode(AccessMode accessMode) { this.accessMode = accessMode; }
public DataSpec getDataSpec() { return dataSpec; }
public void setDataSpec(DataSpec dataSpec) { this.dataSpec = dataSpec; }
public Boolean getRequired() { return required; }
public void setRequired(Boolean required) { this.required = required; }
public Object getExtendInfo() { return extendInfo; }
public void setExtendInfo(Object extendInfo) { this.extendInfo = extendInfo; }
}
public class DataSpec {
private DataType dataType; // 数据类型
private Number min; // 最小值(数值类型)
private Number max; // 最大值(数值类型)
private Number step; // 步长(数值类型)
private String unit; // 单位
private Integer maxLength; // 最大长度(字符串类型)
private Map<String, String> enumValues; // 枚举值(枚举类型)
private DataSpec itemType; // 数组元素类型
private Integer arrayMaxLength; // 数组最大长度
private Map<String, Property> structFields; // 结构体字段
private Object defaultValue; // 默认值
private Boolean required; // 是否必填
/**
* 验证数据是否符合规格
*/
public boolean validate(Object value) {
if (value == null) {
return !Boolean.TRUE.equals(required);
}
switch (dataType) {
case INT:
case LONG:
case FLOAT:
case DOUBLE:
return validateNumber(value);
case BOOL:
return value instanceof Boolean;
case TEXT:
return validateText(value);
case ENUM:
return validateEnum(value);
case ARRAY:
return validateArray(value);
case STRUCT:
return validateStruct(value);
case DATE:
case TIME:
case DATETIME:
case TIMESTAMP:
return validateDate(value);
case EMAIL:
return validateEmail(value);
case URL:
return validateURL(value);
case IP:
return validateIP(value);
case MAC:
return validateMAC(value);
default:
returntrue;
}
}
private boolean validateNumber(Object value) {
if (!(value instanceof Number)) {
returnfalse;
}
double doubleValue = ((Number) value).doubleValue();
if (min != null && doubleValue < min.doubleValue()) {
returnfalse;
}
if (max != null && doubleValue > max.doubleValue()) {
returnfalse;
}
// 步长验证
if (step != null && min != null) {
double stepValue = step.doubleValue();
double minValue = min.doubleValue();
double diff = doubleValue - minValue;
if (stepValue > && Math.abs(diff % stepValue) > 1e-10) {
returnfalse;
}
}
returntrue;
}
private boolean validateText(Object value) {
if (!(value instanceof String)) {
returnfalse;
}
String str = (String) value;
return maxLength == null || str.length() <= maxLength;
}
private boolean validateEnum(Object value) {
return enumValues != null && enumValues.containsKey(value.toString());
}
private boolean validateArray(Object value) {
if (!(value instanceof List)) {
returnfalse;
}
List<?> list = (List<?>) value;
if (arrayMaxLength != null && list.size() > arrayMaxLength) {
returnfalse;
}
if (itemType != null) {
for (Object item : list) {
if (!itemType.validate(item)) {
returnfalse;
}
}
}
returntrue;
}
private boolean validateStruct(Object value) {
if (!(value instanceof Map)) {
returnfalse;
}
Map<?, ?> map = (Map<?, ?>) value;
if (structFields != null) {
for (Map.Entry<String, Property> entry : structFields.entrySet()) {
Object fieldValue = map.get(entry.getKey());
Property property = entry.getValue();
if (property.getRequired() && fieldValue == null) {
returnfalse;
}
if (fieldValue != null && !property.validateValue(fieldValue)) {
returnfalse;
}
}
}
returntrue;
}
private boolean validateDate(Object value) {
return value instanceof String || value instanceof Long || value instanceof java.util.Date;
}
private boolean validateEmail(Object value) {
if (!(value instanceof String)) {
returnfalse;
}
String email = (String) value;
return email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
}
private boolean validateURL(Object value) {
if (!(value instanceof String)) {
returnfalse;
}
try {
new java.net.URL((String) value);
returntrue;
} catch (Exception e) {
returnfalse;
}
}
private boolean validateIP(Object value) {
if (!(value instanceof String)) {
returnfalse;
}
String ip = (String) value;
return ip.matches("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
}
private boolean validateMAC(Object value) {
if (!(value instanceof String)) {
returnfalse;
}
String mac = (String) value;
return mac.matches("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$");
}
// Getters and Setters
public DataType getDataType() { return dataType; }
public void setDataType(DataType dataType) { this.dataType = dataType; }
public Number getMin() { return min; }
public void setMin(Number min) { this.min = min; }
public Number getMax() { return max; }
public void setMax(Number max) { this.max = max; }
public Number getStep() { return step; }
public void setStep(Number step) { this.step = step; }
public String getUnit() { return unit; }
public void setUnit(String unit) { this.unit = unit; }
public Integer getMaxLength() { return maxLength; }
public void setMaxLength(Integer maxLength) { this.maxLength = maxLength; }
public Map<String, String> getEnumValues() { return enumValues; }
public void setEnumValues(Map<String, String> enumValues) { this.enumValues = enumValues; }
public DataSpec getItemType() { return itemType; }
public void setItemType(DataSpec itemType) { this.itemType = itemType; }
public Integer getArrayMaxLength() { return arrayMaxLength; }
public void setArrayMaxLength(Integer arrayMaxLength) { this.arrayMaxLength = arrayMaxLength; }
public Map<String, Property> getStructFields() { return structFields; }
public void setStructFields(Map<String, Property> structFields) { this.structFields = structFields; }
public Object getDefaultValue() { return defaultValue; }
public void setDefaultValue(Object defaultValue) { this.defaultValue = defaultValue; }
public Boolean getRequired() { return required; }
public void setRequired(Boolean required) { this.required = required; }
}
public class Event {
private String identifier; // 事件标识符
private String name; // 事件名称
private String description; // 事件描述
private EventType eventType; // 事件类型
private Boolean required; // 是否必需
private List<Property> outputData = new ArrayList<>(); // 输出参数
private Object extendInfo; // 扩展信息
/**
* 验证事件数据
*/
public boolean validateEventData(Object data) {
if (!(data instanceof Map)) {
returnfalse;
}
Map<?, ?> dataMap = (Map<?, ?>) data;
for (Property outputParam : outputData) {
Object value = dataMap.get(outputParam.getIdentifier());
if (outputParam.getRequired() && value == null) {
returnfalse;
}
if (value != null && !outputParam.validateValue(value)) {
returnfalse;
}
}
returntrue;
}
/**
* 添加输出参数
*/
public void addOutputParam(Property param) {
if (param != null) {
outputData.add(param);
}
}
// Getters and Setters
public String getIdentifier() { return identifier; }
public void setIdentifier(String identifier) { this.identifier = identifier; }
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 EventType getEventType() { return eventType; }
public void setEventType(EventType eventType) { this.eventType = eventType; }
public Boolean getRequired() { return required; }
public void setRequired(Boolean required) { this.required = required; }
public List<Property> getOutputData() { return outputData; }
public void setOutputData(List<Property> outputData) { this.outputData = outputData; }
public Object getExtendInfo() { return extendInfo; }
public void setExtendInfo(Object extendInfo) { this.extendInfo = extendInfo; }
}
public class Service {
private String identifier; // 服务标识符
private String name; // 服务名称
private String description; // 服务描述
private String callType; // 调用类型:sync/async
private Boolean required; // 是否必需
private List<Property> inputData = new ArrayList<>(); // 输入参数
private List<Property> outputData = new ArrayList<>(); // 输出参数
private Object extendInfo; // 扩展信息
/**
* 验证输入参数
*/
public boolean validateInput(Map<String, Object> input) {
if (input == null) {
input = new HashMap<>();
}
for (Property inputParam : inputData) {
Object value = input.get(inputParam.getIdentifier());
if (inputParam.getRequired() && value == null) {
returnfalse;
}
if (value != null && !inputParam.validateValue(value)) {
returnfalse;
}
}
returntrue;
}
/**
* 验证输出参数
*/
public boolean validateOutput(Map<String, Object> output) {
if (output == null) {
output = new HashMap<>();
}
for (Property outputParam : outputData) {
Object value = output.get(outputParam.getIdentifier());
if (outputParam.getRequired() && value == null) {
returnfalse;
}
if (value != null && !outputParam.validateValue(value)) {
returnfalse;
}
}
returntrue;
}
/**
* 添加输入参数
*/
public void addInputParam(Property param) {
if (param != null) {
inputData.add(param);
}
}
/**
* 添加输出参数
*/
public void addOutputParam(Property param) {
if (param != null) {
outputData.add(param);
}
}
// Getters and Setters
public String getIdentifier() { return identifier; }
public void setIdentifier(String identifier) { this.identifier = identifier; }
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 getCallType() { return callType; }
public void setCallType(String callType) { this.callType = callType; }
public Boolean getRequired() { return required; }
public void setRequired(Boolean required) { this.required = required; }
public List<Property> getInputData() { return inputData; }
public void setInputData(List<Property> inputData) { this.inputData = inputData; }
public List<Property> getOutputData() { return outputData; }
public void setOutputData(List<Property> outputData) { this.outputData = outputData; }
public Object getExtendInfo() { return extendInfo; }
public void setExtendInfo(Object extendInfo) { this.extendInfo = extendInfo; }
}
public enum DataType {
// 基础数值类型
INT("int", "整数型"),
LONG("long", "长整数型"),
FLOAT("float", "单精度浮点型"),
DOUBLE("double", "双精度浮点型"),
BOOL("bool", "布尔型"),
TEXT("text", "字符串型"),
// 时间类型
DATE("date", "日期型"),
TIME("time", "时间型"),
DATETIME("datetime", "日期时间型"),
TIMESTAMP("timestamp", "时间戳"),
// 复合类型
ENUM("enum", "枚举型"),
STRUCT("struct", "结构体"),
ARRAY("array", "数组型"),
MAP("map", "映射型"),
JSON("json", "JSON对象"),
JSON_ARRAY("jsonArray", "JSON数组"),
// 二进制类型
BINARY("binary", "二进制数据"),
IMAGE("image", "图片"),
FILE("file", "文件"),
// 地理位置类型
GEO_POINT("geoPoint", "地理坐标点"),
GEO_SHAPE("geoShape", "地理形状"),
// 特殊格式类型
PASSWORD("password", "密码"),
EMAIL("email", "邮箱"),
URL("url", "URL地址"),
IP("ip", "IP地址"),
MAC("mac", "MAC地址"),
COLOR("color", "颜色值"),
CRON("cron", "Cron表达式");
privatefinal String code;
privatefinal String description;
DataType(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
public static DataType fromCode(String code) {
for (DataType type : values()) {
if (type.getCode().equals(code)) {
return type;
}
}
thrownew IllegalArgumentException("Unknown data type: " + code);
}
/**
* 是否为基础类型
*/
public boolean isBasicType() {
returnthis == INT || this == LONG || this == FLOAT ||
this == DOUBLE || this == BOOL || this == TEXT;
}
/**
* 是否为时间相关类型
*/
public boolean isTimeType() {
returnthis == DATE || this == TIME || this == DATETIME || this == TIMESTAMP;
}
/**
* 是否为复合类型
*/
public boolean isCompositeType() {
returnthis == STRUCT || this == ARRAY || this == MAP ||
this == JSON || this == JSON_ARRAY;
}
/**
* 是否为二进制类型
*/
public boolean isBinaryType() {
returnthis == BINARY || this == IMAGE || this == FILE;
}
/**
* 是否为地理类型
*/
public boolean isGeoType() {
returnthis == GEO_POINT || this == GEO_SHAPE;
}
/**
* 是否为格式验证类型
*/
public boolean isFormatType() {
returnthis == EMAIL || this == URL || this == IP ||
this == MAC || this == COLOR || this == CRON;
}
}
public enum AccessMode {
R("r", "只读"),
W("w", "只写"),
RW("rw", "读写");
privatefinal String code;
privatefinal String description;
AccessMode(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
public static AccessMode fromCode(String code) {
for (AccessMode mode : values()) {
if (mode.getCode().equals(code)) {
return mode;
}
}
thrownew IllegalArgumentException("Unknown access mode: " + code);
}
public boolean isReadable() {
returnthis == R || this == RW;
}
public boolean isWritable() {
returnthis == W || this == RW;
}
}
public enum EventType {
INFO("info", "信息"),
WARN("warn", "警告"),
ERROR("error", "错误"),
ALERT("alert", "告警");
privatefinal String code;
privatefinal String description;
EventType(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
public static EventType fromCode(String code) {
for (EventType type : values()) {
if (type.getCode().equals(code)) {
return type;
}
}
thrownew IllegalArgumentException("Unknown event type: " + code);
}
/**
* 获取事件严重程度级别
*/
public int getSeverityLevel() {
switch (this) {
case INFO: return;
case WARN: return;
case ERROR: return;
case ALERT: return;
default: return;
}
}
/**
* 是否需要立即处理
*/
public boolean requiresImmediateAction() {
returnthis == ERROR || this == ALERT;
}
}
public class ThingModelRuntime {
privatefinal ThingModel model;
privatefinal Map<String, Object> runtimeData = new ConcurrentHashMap<>();
privatefinal Map<String, List<PropertyChangeListener>> propertyListeners = new ConcurrentHashMap<>();
privatefinal Map<String, List<EventListener>> eventListeners = new ConcurrentHashMap<>();
privatefinal Map<String, ServiceHandler> serviceHandlers = new ConcurrentHashMap<>();
privatefinal Map<String, Function<Object, Object>> valueTransformers = new ConcurrentHashMap<>();
privatefinal List<DataValidator> customValidators = new ArrayList<>();
public ThingModelRuntime(ThingModel model) {
this.model = model;
initializeRuntimeData();
}
/**
* 初始化运行时数据
*/
private void initializeRuntimeData() {
for (Property property : model.getProperties()) {
if (property.getDataSpec() != null &&
property.getDataSpec().getDefaultValue() != null) {
runtimeData.put(property.getIdentifier(),
property.getDataSpec().getDefaultValue());
}
}
}
/**
* 设置属性值的完整流程
*/
public void setPropertyValue(String identifier, Object value) {
Property property = model.getProperty(identifier);
if (property == null) {
thrownew IllegalArgumentException("Property not found: " + identifier);
}
if (!property.isWritable()) {
thrownew IllegalStateException("Property is read-only: " + identifier);
}
// 1. 应用值转换器
Object transformedValue = applyTransformer(identifier, value);
// 2. 多层验证
validatePropertyValue(property, transformedValue);
// 3. 获取旧值
Object oldValue = runtimeData.get(identifier);
// 4. 设置新值
runtimeData.put(identifier, transformedValue);
// 5. 触发变更事件
firePropertyChange(identifier, oldValue, transformedValue);
}
/**
* 获取属性值
*/
public Object getPropertyValue(String identifier) {
Property property = model.getProperty(identifier);
if (property == null) {
thrownew IllegalArgumentException("Property not found: " + identifier);
}
if (!property.isReadable()) {
thrownew IllegalStateException("Property is write-only: " + identifier);
}
return runtimeData.get(identifier);
}
/**
* 批量设置属性值
*/
public void setPropertyValues(Map<String, Object> values) {
for (Map.Entry<String, Object> entry : values.entrySet()) {
setPropertyValue(entry.getKey(), entry.getValue());
}
}
/**
* 获取所有属性值
*/
public Map<String, Object> getAllPropertyValues() {
Map<String, Object> result = new HashMap<>();
for (Property property : model.getProperties()) {
if (property.isReadable()) {
result.put(property.getIdentifier(), runtimeData.get(property.getIdentifier()));
}
}
return result;
}
/**
* 触发事件
*/
public void fireEvent(String identifier, Map<String, Object> data) {
Event event = model.getEvent(identifier);
if (event == null) {
thrownew IllegalArgumentException("Event not found: " + identifier);
}
// 验证事件数据
if (!event.validateEventData(data)) {
thrownew ValidationException("Invalid event data for: " + identifier);
}
// 触发事件监听器
List<EventListener> listeners = eventListeners.get(identifier);
if (listeners != null) {
for (EventListener listener : listeners) {
try {
listener.onEvent(identifier, data);
} catch (Exception e) {
System.err.println("Error in event listener: " + e.getMessage());
}
}
}
}
/**
* 调用服务
*/
public Map<String, Object> invokeService(String identifier, Map<String, Object> input) {
Service service = model.getService(identifier);
if (service == null) {
thrownew IllegalArgumentException("Service not found: " + identifier);
}
// 验证输入参数
if (!service.validateInput(input)) {
thrownew ValidationException("Invalid input for service: " + identifier);
}
// 获取服务处理器
ServiceHandler handler = serviceHandlers.get(identifier);
if (handler == null) {
thrownew IllegalStateException("No handler registered for service: " + identifier);
}
// 执行服务
Map<String, Object> output = handler.handle(input);
// 验证输出参数
if (!service.validateOutput(output)) {
thrownew ValidationException("Invalid output from service: " + identifier);
}
return output;
}
/**
* 注册属性变更监听器
*/
public void addPropertyChangeListener(String identifier, PropertyChangeListener listener) {
propertyListeners.computeIfAbsent(identifier, k -> new ArrayList<>()).add(listener);
}
/**
* 注册事件监听器
*/
public void addEventListener(String identifier, EventListener listener) {
eventListeners.computeIfAbsent(identifier, k -> new ArrayList<>()).add(listener);
}
/**
* 注册服务处理器
*/
public void registerServiceHandler(String identifier, ServiceHandler handler) {
serviceHandlers.put(identifier, handler);
}
/**
* 注册值转换器
*/
public void registerValueTransformer(String identifier, Function<Object, Object> transformer) {
valueTransformers.put(identifier, transformer);
}
/**
* 添加自定义验证器
*/
public void addCustomValidator(DataValidator validator) {
customValidators.add(validator);
}
/**
* 动态添加属性
*/
public void addDynamicProperty(Property property) {
model.addProperty(property);
if (property.getDataSpec() != null && property.getDataSpec().getDefaultValue() != null) {
runtimeData.put(property.getIdentifier(), property.getDataSpec().getDefaultValue());
}
}
// 私有辅助方法
private Object applyTransformer(String identifier, Object value) {
Function<Object, Object> transformer = valueTransformers.get(identifier);
if (transformer != null) {
return transformer.apply(value);
}
return value;
}
private void validatePropertyValue(Property property, Object value) {
// 内置验证
if (!property.validateValue(value)) {
thrownew ValidationException("Value validation failed for property: " +
property.getIdentifier());
}
// 自定义验证器
for (DataValidator validator : customValidators) {
if (!validator.validate(property, value)) {
thrownew ValidationException("Custom validation failed for property: " +
property.getIdentifier());
}
}
}
private void firePropertyChange(String identifier, Object oldValue, Object newValue) {
List<PropertyChangeListener> listeners = propertyListeners.get(identifier);
if (listeners != null) {
for (PropertyChangeListener listener : listeners) {
try {
listener.onPropertyChange(identifier, oldValue, newValue);
} catch (Exception e) {
System.err.println("Error in property change listener: " + e.getMessage());
}
}
}
}
// 内部接口定义
@FunctionalInterface
publicinterface PropertyChangeListener {
void onPropertyChange(String identifier, Object oldValue, Object newValue);
}
@FunctionalInterface
publicinterface EventListener {
void onEvent(String identifier, Map<String, Object> data);
}
@FunctionalInterface
publicinterface ServiceHandler {
Map<String, Object> handle(Map<String, Object> input);
}
@FunctionalInterface
publicinterface DataValidator {
boolean validate(Property property, Object value);
}
}
public class ThingModelBuilder {
private ThingModel model;
private PropertyBuilder currentPropertyBuilder;
private EventBuilder currentEventBuilder;
private ServiceBuilder currentServiceBuilder;
public ThingModelBuilder() {
this.model = new ThingModel();
}
public ThingModelBuilder productKey(String productKey) {
model.setProductKey(productKey);
returnthis;
}
public ThingModelBuilder productName(String productName) {
model.setProductName(productName);
returnthis;
}
public ThingModelBuilder version(String version) {
model.setVersion(version);
returnthis;
}
public ThingModelBuilder description(String description) {
model.setDescription(description);
returnthis;
}
public PropertyBuilder addProperty(String identifier) {
currentPropertyBuilder = new PropertyBuilder(this, identifier);
return currentPropertyBuilder;
}
public EventBuilder addEvent(String identifier) {
currentEventBuilder = new EventBuilder(this, identifier);
return currentEventBuilder;
}
public ServiceBuilder addService(String identifier) {
currentServiceBuilder = new ServiceBuilder(this, identifier);
return currentServiceBuilder;
}
public ThingModel build() {
return model;
}
// 属性建造者
publicstaticclass PropertyBuilder {
private ThingModelBuilder parent;
private Property property;
private DataSpec dataSpec;
public PropertyBuilder(ThingModelBuilder parent, String identifier) {
this.parent = parent;
this.property = new Property();
this.property.setIdentifier(identifier);
this.dataSpec = new DataSpec();
this.property.setDataSpec(dataSpec);
}
public PropertyBuilder name(String name) {
property.setName(name);
returnthis;
}
public PropertyBuilder description(String description) {
property.setDescription(description);
returnthis;
}
public PropertyBuilder dataType(DataType dataType) {
dataSpec.setDataType(dataType);
returnthis;
}
public PropertyBuilder accessMode(AccessMode accessMode) {
property.setAccessMode(accessMode);
returnthis;
}
public PropertyBuilder min(Number min) {
dataSpec.setMin(min);
returnthis;
}
public PropertyBuilder max(Number max) {
dataSpec.setMax(max);
returnthis;
}
public PropertyBuilder step(Number step) {
dataSpec.setStep(step);
returnthis;
}
public PropertyBuilder unit(String unit) {
dataSpec.setUnit(unit);
returnthis;
}
public PropertyBuilder maxLength(Integer maxLength) {
dataSpec.setMaxLength(maxLength);
returnthis;
}
public PropertyBuilder enumValue(String key, String value) {
if (dataSpec.getEnumValues() == null) {
dataSpec.setEnumValues(new HashMap<>());
}
dataSpec.getEnumValues().put(key, value);
returnthis;
}
public PropertyBuilder defaultValue(Object defaultValue) {
dataSpec.setDefaultValue(defaultValue);
returnthis;
}
public PropertyBuilder required(Boolean required) {
property.setRequired(required);
returnthis;
}
public ThingModelBuilder endProperty() {
parent.model.addProperty(property);
return parent;
}
}
// 事件建造者
publicstaticclass EventBuilder {
private ThingModelBuilder parent;
private Event event;
public EventBuilder(ThingModelBuilder parent, String identifier) {
this.parent = parent;
this.event = new Event();
this.event.setIdentifier(identifier);
}
public EventBuilder name(String name) {
event.setName(name);
returnthis;
}
public EventBuilder description(String description) {
event.setDescription(description);
returnthis;
}
public EventBuilder eventType(EventType eventType) {
event.setEventType(eventType);
returnthis;
}
public EventBuilder addOutputParam(String identifier, String name, DataType dataType) {
Property param = new Property();
param.setIdentifier(identifier);
param.setName(name);
param.setAccessMode(AccessMode.R);
DataSpec spec = new DataSpec();
spec.setDataType(dataType);
param.setDataSpec(spec);
event.addOutputParam(param);
returnthis;
}
public ThingModelBuilder endEvent() {
parent.model.addEvent(event);
return parent;
}
}
// 服务建造者
publicstaticclass ServiceBuilder {
private ThingModelBuilder parent;
private Service service;
public ServiceBuilder(ThingModelBuilder parent, String identifier) {
this.parent = parent;
this.service = new Service();
this.service.setIdentifier(identifier);
}
public ServiceBuilder name(String name) {
service.setName(name);
returnthis;
}
public ServiceBuilder description(String description) {
service.setDescription(description);
returnthis;
}
public ServiceBuilder callType(String callType) {
service.setCallType(callType);
returnthis;
}
public ServiceBuilder addInputParam(String identifier, String name, DataType dataType) {
Property param = new Property();
param.setIdentifier(identifier);
param.setName(name);
param.setAccessMode(AccessMode.W);
DataSpec spec = new DataSpec();
spec.setDataType(dataType);
param.setDataSpec(spec);
service.addInputParam(param);
returnthis;
}
public ServiceBuilder addOutputParam(String identifier, String name, DataType dataType) {
Property param = new Property();
param.setIdentifier(identifier);
param.setName(name);
param.setAccessMode(AccessMode.R);
DataSpec spec = new DataSpec();
spec.setDataType(dataType);
param.setDataSpec(spec);
service.addOutputParam(param);
returnthis;
}
public ThingModelBuilder endService() {
parent.model.addService(service);
return parent;
}
}
}
public class ThingModelTemplate {
private String templateId;
private String templateName;
private String description;
private String category;
private ThingModelTemplate parent;
private List<ThingModelTemplate> mixins = new ArrayList<>();
private ThingModel baseModel;
private Map<String, Object> metadata = new HashMap<>();
public ThingModelTemplate(String templateId, String templateName) {
this.templateId = templateId;
this.templateName = templateName;
this.baseModel = new ThingModel();
}
public ThingModelTemplate extend(ThingModelTemplate parent) {
this.parent = parent;
returnthis;
}
public ThingModelTemplate mixin(ThingModelTemplate... templates) {
Collections.addAll(this.mixins, templates);
returnthis;
}
public ThingModel instantiate(String productKey, String productName) {
ThingModel model = new ThingModel();
model.setProductKey(productKey);
model.setProductName(productName);
// 应用继承链
applyInheritance(model);
// 应用混入
for (ThingModelTemplate mixin : mixins) {
applyTemplate(model, mixin.baseModel);
}
// 应用自身定义
applyTemplate(model, baseModel);
// 设置模板信息
model.getExtendInfo().put("templateId", templateId);
model.getExtendInfo().put("templateName", templateName);
return model;
}
private void applyInheritance(ThingModel model) {
if (parent != null) {
parent.applyInheritance(model);
applyTemplate(model, parent.baseModel);
}
}
private void applyTemplate(ThingModel target, ThingModel source) {
// 复制属性(避免重复)
for (Property property : source.getProperties()) {
if (target.getProperty(property.getIdentifier()) == null) {
target.addProperty(cloneProperty(property));
}
}
// 复制事件(避免重复)
for (Event event : source.getEvents()) {
if (target.getEvent(event.getIdentifier()) == null) {
target.addEvent(cloneEvent(event));
}
}
// 复制服务(避免重复)
for (Service service : source.getServices()) {
if (target.getService(service.getIdentifier()) == null) {
target.addService(cloneService(service));
}
}
}
private Property cloneProperty(Property source) {
Property property = new Property();
property.setIdentifier(source.getIdentifier());
property.setName(source.getName());
property.setDescription(source.getDescription());
property.setAccessMode(source.getAccessMode());
property.setRequired(source.getRequired());
property.setDataSpec(cloneDataSpec(source.getDataSpec()));
property.setExtendInfo(source.getExtendInfo());
return property;
}
private DataSpec cloneDataSpec(DataSpec source) {
if (source == null) returnnull;
DataSpec spec = new DataSpec();
spec.setDataType(source.getDataType());
spec.setMin(source.getMin());
spec.setMax(source.getMax());
spec.setStep(source.getStep());
spec.setUnit(source.getUnit());
spec.setMaxLength(source.getMaxLength());
spec.setEnumValues(source.getEnumValues() != null ?
new HashMap<>(source.getEnumValues()) : null);
spec.setDefaultValue(source.getDefaultValue());
spec.setRequired(source.getRequired());
return spec;
}
private Event cloneEvent(Event source) {
Event event = new Event();
event.setIdentifier(source.getIdentifier());
event.setName(source.getName());
event.setDescription(source.getDescription());
event.setEventType(source.getEventType());
event.setRequired(source.getRequired());
event.setOutputData(new ArrayList<>(source.getOutputData()));
event.setExtendInfo(source.getExtendInfo());
return event;
}
private Service cloneService(Service source) {
Service service = new Service();
service.setIdentifier(source.getIdentifier());
service.setName(source.getName());
service.setDescription(source.getDescription());
service.setCallType(source.getCallType());
service.setRequired(source.getRequired());
service.setInputData(new ArrayList<>(source.getInputData()));
service.setOutputData(new ArrayList<>(source.getOutputData()));
service.setExtendInfo(source.getExtendInfo());
return service;
}
// Getters and Setters
public String getTemplateId() { return templateId; }
public void setTemplateId(String templateId) { this.templateId = templateId; }
public String getTemplateName() { return templateName; }
public void setTemplateName(String templateName) { this.templateName = templateName; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public ThingModel getBaseModel() { return baseModel; }
public void setBaseModel(ThingModel baseModel) { this.baseModel = baseModel; }
public Map<String, Object> getMetadata() { return metadata; }
public void setMetadata(Map<String, Object> metadata) { this.metadata = metadata; }
}
public class ThingModelRegistry {
privatefinal Map<String, Map<String, ThingModel>> registry = new ConcurrentHashMap<>();
privatefinal Map<String, String> aliasMap = new ConcurrentHashMap<>();
privatefinal Map<String, Set<String>> tagIndex = new ConcurrentHashMap<>();
privatestatic ThingModelRegistry instance;
private ThingModelRegistry() {}
public static ThingModelRegistry getInstance() {
if (instance == null) {
synchronized (ThingModelRegistry.class) {
if (instance == null) {
instance = new ThingModelRegistry();
}
}
}
return instance;
}
/**
* 注册物模型
*/
public void register(ThingModel model) {
if (model == null || model.getProductKey() == null) {
thrownew IllegalArgumentException("物模型或产品标识不能为空");
}
String productKey = model.getProductKey();
String version = model.getVersion() != null ? model.getVersion() : "1.0";
registry.computeIfAbsent(productKey, k -> new ConcurrentHashMap<>())
.put(version, model);
System.out.println("注册物模型: " + productKey + " v" + version);
}
/**
* 获取最新版本的物模型
*/
public ThingModel get(String productKey) {
Map<String, ThingModel> versions = registry.get(resolveAlias(productKey));
if (versions == null || versions.isEmpty()) {
returnnull;
}
// 获取最新版本
return versions.entrySet().stream()
.max(Map.Entry.comparingByKey(this::compareVersion))
.map(Map.Entry::getValue)
.orElse(null);
}
/**
* 获取指定版本的物模型
*/
public ThingModel get(String productKey, String version) {
Map<String, ThingModel> versions = registry.get(resolveAlias(productKey));
return versions != null ? versions.get(version) : null;
}
/**
* 获取所有版本
*/
public List<String> getVersions(String productKey) {
Map<String, ThingModel> versions = registry.get(resolveAlias(productKey));
if (versions == null) {
return Collections.emptyList();
}
returnnew ArrayList<>(versions.keySet());
}
/**
* 设置别名
*/
public void setAlias(String alias, String productKey) {
aliasMap.put(alias, productKey);
}
/**
* 添加标签
*/
public void addTag(String productKey, String tag) {
tagIndex.computeIfAbsent(tag, k -> ConcurrentHashMap.newKeySet())
.add(productKey);
}
/**
* 根据标签查找物模型
*/
public List<ThingModel> findByTag(String tag) {
Set<String> productKeys = tagIndex.get(tag);
if (productKeys == null) {
return Collections.emptyList();
}
return productKeys.stream()
.map(this::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
/**
* 搜索物模型
*/
public List<ThingModel> search(String keyword) {
return registry.values().stream()
.flatMap(versions -> versions.values().stream())
.filter(model -> matchKeyword(model, keyword))
.collect(Collectors.toList());
}
private String resolveAlias(String key) {
return aliasMap.getOrDefault(key, key);
}
private boolean matchKeyword(ThingModel model, String keyword) {
if (keyword == null || keyword.isEmpty()) {
returntrue;
}
String lowerKeyword = keyword.toLowerCase();
return (model.getProductKey() != null && model.getProductKey().toLowerCase().contains(lowerKeyword)) ||
(model.getProductName() != null && model.getProductName().toLowerCase().contains(lowerKeyword)) ||
(model.getDescription() != null && model.getDescription().toLowerCase().contains(lowerKeyword));
}
private int compareVersion(String v1, String v2) {
String[] parts1 = v1.split("\\.");
String[] parts2 = v2.split("\\.");
int length = Math.max(parts1.length, parts2.length);
for (int i = ; i < length; i++) {
int num1 = i < parts1.length ? Integer.parseInt(parts1[i]) : ;
int num2 = i < parts2.length ? Integer.parseInt(parts2[i]) : ;
if (num1 != num2) {
return Integer.compare(num1, num2);
}
}
return;
}
}
public class TempHumiditySensorExample {
public static void main(String[] args) {
// 1. 创建物模型
ThingModel sensorModel = createTempHumiditySensorModel();
// 2. 注册到注册中心
ThingModelRegistry registry = ThingModelRegistry.getInstance();
registry.register(sensorModel);
// 3. 创建运行时实例
ThingModelRuntime runtime = new ThingModelRuntime(sensorModel);
// 4. 注册监听器和服务处理器
setupRuntimeHandlers(runtime);
// 5. 模拟设备数据处理
simulateDeviceOperation(runtime);
}
private static ThingModel createTempHumiditySensorModel() {
returnnew ThingModelBuilder()
.productKey("TEMP_HUMIDITY_SENSOR_V2")
.productName("高精度温湿度传感器")
.version("2.0")
.description("支持多种环境参数监测的智能传感器")
// 温度属性
.addProperty("temperature")
.name("环境温度")
.description("当前环境的温度值")
.dataType(DataType.FLOAT)
.accessMode(AccessMode.R)
.min(-40.0)
.max(125.0)
.step(0.1)
.unit("℃")
.required(true)
.endProperty()
// 湿度属性
.addProperty("humidity")
.name("环境湿度")
.description("当前环境的相对湿度")
.dataType(DataType.FLOAT)
.accessMode(AccessMode.R)
.min(0.0)
.max(100.0)
.step(0.1)
.unit("%RH")
.required(true)
.endProperty()
// 工作模式属性
.addProperty("workMode")
.name("工作模式")
.description("传感器的工作模式")
.dataType(DataType.ENUM)
.accessMode(AccessMode.RW)
.enumValue("normal", "正常模式")
.enumValue("power_save", "节能模式")
.enumValue("high_precision", "高精度模式")
.defaultValue("normal")
.endProperty()
// 采集间隔属性
.addProperty("collectInterval")
.name("采集间隔")
.description("数据采集的时间间隔")
.dataType(DataType.INT)
.accessMode(AccessMode.RW)
.min()
.max()
.unit("秒")
.defaultValue()
.endProperty()
// 温度告警事件
.addEvent("tempAlert")
.name("温度告警")
.description("温度超出阈值时触发")
.eventType(EventType.ALERT)
.addOutputParam("temperature", "当前温度", DataType.FLOAT)
.addOutputParam("threshold", "告警阈值", DataType.FLOAT)
.addOutputParam("alertType", "告警类型", DataType.TEXT)
.endEvent()
// 湿度告警事件
.addEvent("humidityAlert")
.name("湿度告警")
.description("湿度超出阈值时触发")
.eventType(EventType.ALERT)
.addOutputParam("humidity", "当前湿度", DataType.FLOAT)
.addOutputParam("threshold", "告警阈值", DataType.FLOAT)
.endEvent()
// 校准服务
.addService("calibrate")
.name("传感器校准")
.description("对传感器进行校准")
.callType("async")
.addInputParam("tempOffset", "温度偏移", DataType.FLOAT)
.addInputParam("humidityOffset", "湿度偏移", DataType.FLOAT)
.addOutputParam("taskId", "任务ID", DataType.TEXT)
.addOutputParam("estimatedTime", "预计耗时", DataType.INT)
.endService()
// 重置服务
.addService("reset")
.name("重置传感器")
.description("将传感器恢复到出厂设置")
.callType("sync")
.addOutputParam("success", "是否成功", DataType.BOOL)
.addOutputParam("message", "结果消息", DataType.TEXT)
.endService()
.build();
}
private static void setupRuntimeHandlers(ThingModelRuntime runtime) {
// 注册温度变更监听器
runtime.addPropertyChangeListener("temperature", (identifier, oldValue, newValue) -> {
System.out.println("温度变化: " + oldValue + " -> " + newValue);
// 检查是否需要触发告警
if (newValue instanceof Number) {
double temp = ((Number) newValue).doubleValue();
if (temp > 40.0) {
Map<String, Object> alertData = new HashMap<>();
alertData.put("temperature", temp);
alertData.put("threshold", 40.0);
alertData.put("alertType", "HIGH_TEMPERATURE");
runtime.fireEvent("tempAlert", alertData);
}
}
});
// 注册湿度变更监听器
runtime.addPropertyChangeListener("humidity", (identifier, oldValue, newValue) -> {
System.out.println("湿度变化: " + oldValue + " -> " + newValue);
if (newValue instanceof Number) {
double humidity = ((Number) newValue).doubleValue();
if (humidity > 90.0) {
Map<String, Object> alertData = new HashMap<>();
alertData.put("humidity", humidity);
alertData.put("threshold", 90.0);
runtime.fireEvent("humidityAlert", alertData);
}
}
});
// 注册温度告警事件监听器
runtime.addEventListener("tempAlert", (eventId, data) -> {
System.out.println("收到温度告警: " + data);
// 这里可以执行告警处理逻辑,如发送通知等
});
// 注册校准服务处理器
runtime.registerServiceHandler("calibrate", input -> {
System.out.println("执行校准服务,输入参数: " + input);
// 模拟校准过程
String taskId = "CALIB_" + System.currentTimeMillis();
Map<String, Object> output = new HashMap<>();
output.put("taskId", taskId);
output.put("estimatedTime", ); // 5分钟
// 启动后台校准任务
startCalibrationTask(taskId, input);
return output;
});
// 注册重置服务处理器
runtime.registerServiceHandler("reset", input -> {
System.out.println("执行重置服务");
Map<String, Object> output = new HashMap<>();
try {
// 模拟重置过程
Thread.sleep();
// 重置工作模式为正常模式
runtime.setPropertyValue("workMode", "normal");
runtime.setPropertyValue("collectInterval", );
output.put("success", true);
output.put("message", "重置成功");
} catch (Exception e) {
output.put("success", false);
output.put("message", "重置失败: " + e.getMessage());
}
return output;
});
// 注册值转换器(温度值四舍五入到一位小数)
runtime.registerValueTransformer("temperature", value -> {
if (value instanceof Number) {
double temp = ((Number) value).doubleValue();
return Math.round(temp * 10.0) / 10.0;
}
return value;
});
// 注册自定义验证器
runtime.addCustomValidator((property, value) -> {
if ("temperature".equals(property.getIdentifier()) && value instanceof Number) {
double temp = ((Number) value).doubleValue();
// 自定义业务逻辑:冬季温度不应超过50度
if (isWinter() && temp > 50.0) {
System.out.println("警告:冬季温度异常 " + temp + "°C");
returnfalse;
}
}
returntrue;
});
}
private static void simulateDeviceOperation(ThingModelRuntime runtime) {
System.out.println("\n=== 开始模拟设备操作 ===");
// 1. 设置初始属性值
runtime.setPropertyValue("temperature", 25.3);
runtime.setPropertyValue("humidity", 65.8);
runtime.setPropertyValue("workMode", "normal");
runtime.setPropertyValue("collectInterval", );
// 2. 模拟温度变化并触发告警
runtime.setPropertyValue("temperature", 45.2); // 这会触发高温告警
// 3. 模拟湿度变化并触发告警
runtime.setPropertyValue("humidity", 95.5); // 这会触发高湿度告警
// 4. 调用校准服务
Map<String, Object> calibrateInput = new HashMap<>();
calibrateInput.put("tempOffset", 0.5);
calibrateInput.put("humidityOffset", -1.2);
Map<String, Object> calibrateResult = runtime.invokeService("calibrate", calibrateInput);
System.out.println("校准服务返回: " + calibrateResult);
// 5. 调用重置服务
Map<String, Object> resetResult = runtime.invokeService("reset", new HashMap<>());
System.out.println("重置服务返回: " + resetResult);
// 6. 查看当前所有属性值
System.out.println("\n当前设备状态:");
Map<String, Object> allValues = runtime.getAllPropertyValues();
allValues.forEach((key, value) -> {
System.out.println(key + ": " + value);
});
}
private static void startCalibrationTask(String taskId, Map<String, Object> input) {
// 模拟异步校准任务
new Thread(() -> {
try {
System.out.println("校准任务 " + taskId + " 开始执行...");
Thread.sleep(); // 模拟校准耗时
System.out.println("校准任务 " + taskId + " 执行完成");
} catch (InterruptedException e) {
System.out.println("校准任务 " + taskId + " 被中断");
}
}).start();
}
private static boolean isWinter() {
// 简单的季节判断逻辑
int month = java.time.LocalDate.now().getMonthValue();
return month == || month == || month == ;
}
}
public class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}
public ValidationException(String message, Throwable cause) {
super(message, cause);
}
}
通过这套物模型系统,我们实现了:
这套架构设计遵循了SOLID原则和常用设计模式,具有良好的可扩展性和可维护性。代码结构清晰,职责分明,可以作为IoT物模型系统的标准实现参考。