Search in sources :

Example 16 with Attribute

use of org.openremote.model.attribute.Attribute in project openremote by openremote.

the class AbstractIOClientProtocol method getGenericStringEncodersAndDecoders.

/**
 * Supplies a set of encoders/decoders that convert from/to {@link String} to/from {@link ByteBuf} based on the generic protocol {@link Attribute}s
 */
public static Supplier<ChannelHandler[]> getGenericStringEncodersAndDecoders(AbstractNettyIOClient<String, ?> client, IOAgent<?, ?, ?> agent) {
    boolean hexMode = agent.getMessageConvertHex().orElse(false);
    boolean binaryMode = agent.getMessageConvertBinary().orElse(false);
    Charset charset = agent.getMessageCharset().map(Charset::forName).orElse(CharsetUtil.UTF_8);
    int maxLength = agent.getMessageMaxLength().orElse(Integer.MAX_VALUE);
    String[] delimiters = agent.getMessageDelimiters().orElse(new String[0]);
    boolean stripDelimiter = agent.getMessageStripDelimiter().orElse(false);
    return () -> {
        List<ChannelHandler> encodersDecoders = new ArrayList<>();
        if (hexMode || binaryMode) {
            encodersDecoders.add(new AbstractNettyIOClient.MessageToByteEncoder<>(String.class, client, (msg, out) -> {
                byte[] bytes = hexMode ? ProtocolUtil.bytesFromHexString(msg) : ProtocolUtil.bytesFromBinaryString(msg);
                out.writeBytes(bytes);
            }));
            if (delimiters.length > 0) {
                ByteBuf[] byteDelimiters = Arrays.stream(delimiters).map(delim -> Unpooled.wrappedBuffer(hexMode ? ProtocolUtil.bytesFromHexString(delim) : ProtocolUtil.bytesFromBinaryString(delim))).toArray(ByteBuf[]::new);
                encodersDecoders.add(new DelimiterBasedFrameDecoder(maxLength, stripDelimiter, byteDelimiters));
            } else {
                encodersDecoders.add(new FixedLengthFrameDecoder(maxLength));
            }
            // Incoming messages will be bytes
            encodersDecoders.add(new AbstractNettyIOClient.ByteToMessageDecoder<>(client, (byteBuf, messages) -> {
                byte[] bytes = new byte[byteBuf.readableBytes()];
                byteBuf.readBytes(bytes);
                String msg = hexMode ? ProtocolUtil.bytesToHexString(bytes) : ProtocolUtil.bytesToBinaryString(bytes);
                messages.add(msg);
            }));
        } else {
            encodersDecoders.add(new StringEncoder(charset));
            if (agent.getMessageMaxLength().isPresent()) {
                encodersDecoders.add(new FixedLengthFrameDecoder(maxLength));
            } else {
                ByteBuf[] byteDelimiters;
                if (delimiters.length > 0) {
                    byteDelimiters = Arrays.stream(delimiters).map(delim -> Unpooled.wrappedBuffer(delim.getBytes(charset))).toArray(ByteBuf[]::new);
                } else {
                    byteDelimiters = Delimiters.lineDelimiter();
                }
                encodersDecoders.add(new DelimiterBasedFrameDecoder(maxLength, stripDelimiter, byteDelimiters));
            }
            encodersDecoders.add(new StringDecoder(charset));
            encodersDecoders.add(new AbstractNettyIOClient.MessageToMessageDecoder<>(String.class, client));
        }
        return encodersDecoders.toArray(new ChannelHandler[0]);
    };
}
Also used : Arrays(java.util.Arrays) Protocol(org.openremote.model.asset.agent.Protocol) ConnectionStatus(org.openremote.model.asset.agent.ConnectionStatus) Supplier(java.util.function.Supplier) Unpooled(io.netty.buffer.Unpooled) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) AgentLink(org.openremote.model.asset.agent.AgentLink) ByteBuf(io.netty.buffer.ByteBuf) Charset(java.nio.charset.Charset) Attribute(org.openremote.model.attribute.Attribute) AttributeEvent(org.openremote.model.attribute.AttributeEvent) CharsetUtil(io.netty.util.CharsetUtil) SyslogCategory(org.openremote.model.syslog.SyslogCategory) StringEncoder(io.netty.handler.codec.string.StringEncoder) Logger(java.util.logging.Logger) DelimiterBasedFrameDecoder(io.netty.handler.codec.DelimiterBasedFrameDecoder) FixedLengthFrameDecoder(io.netty.handler.codec.FixedLengthFrameDecoder) AbstractProtocol(org.openremote.agent.protocol.AbstractProtocol) Container(org.openremote.model.Container) PROTOCOL(org.openremote.model.syslog.SyslogCategory.PROTOCOL) List(java.util.List) StringDecoder(io.netty.handler.codec.string.StringDecoder) ChannelHandler(io.netty.channel.ChannelHandler) Agent(org.openremote.model.asset.agent.Agent) ProtocolUtil(org.openremote.model.protocol.ProtocolUtil) Delimiters(io.netty.handler.codec.Delimiters) DelimiterBasedFrameDecoder(io.netty.handler.codec.DelimiterBasedFrameDecoder) Charset(java.nio.charset.Charset) StringDecoder(io.netty.handler.codec.string.StringDecoder) ChannelHandler(io.netty.channel.ChannelHandler) ByteBuf(io.netty.buffer.ByteBuf) StringEncoder(io.netty.handler.codec.string.StringEncoder) FixedLengthFrameDecoder(io.netty.handler.codec.FixedLengthFrameDecoder) ArrayList(java.util.ArrayList) List(java.util.List)

Example 17 with Attribute

use of org.openremote.model.attribute.Attribute in project openremote by openremote.

the class AssetStorageService method merge.

/**
 * Merge the requested {@link Asset} checking that it meets all constraint requirements before doing so; the
 * timestamp of each {@link Attribute} will also be updated to the current system time if it has changed to assist
 * with {@link Attribute} equality (see {@link Attribute#equals}).
 * @param overrideVersion If <code>true</code>, the merge will override the data in the database, independent of
 *                        version.
 * @param skipGatewayCheck Don't check if asset is a gateway asset and merge asset into local persistence service.
 * @param userName        the user which this asset needs to be assigned to.
 * @return The current stored asset state.
 * @throws IllegalArgumentException if the realm or parent is illegal, or other asset constraint is violated.
 */
@SuppressWarnings("unchecked")
public <T extends Asset<?>> T merge(T asset, boolean overrideVersion, boolean skipGatewayCheck, String userName) throws IllegalStateException, ConstraintViolationException {
    return persistenceService.doReturningTransaction(em -> {
        String gatewayId = gatewayService.getLocallyRegisteredGatewayId(asset.getId(), asset.getParentId());
        if (!skipGatewayCheck && gatewayId != null) {
            LOG.fine("Sending asset merge request to gateway: Gateway ID=" + gatewayId);
            return gatewayService.mergeGatewayAsset(gatewayId, asset);
        }
        // Do standard JSR-380 validation on the asset (includes custom validation)
        Set<ConstraintViolation<Asset<?>>> validationFailures = ValueUtil.validate(asset, Asset.AssetSave.class);
        if (validationFailures.size() > 0) {
            String msg = "Asset merge failed as asset has failed constraint validation: asset=" + asset;
            ConstraintViolationException ex = new ConstraintViolationException(validationFailures);
            LOG.log(Level.WARNING, msg + ", exception=" + ex.getMessage(), ex);
            throw ex;
        }
        T existingAsset = TextUtil.isNullOrEmpty(asset.getId()) ? null : (T) em.find(Asset.class, asset.getId());
        if (existingAsset != null) {
            // Verify type has not been changed
            if (!existingAsset.getType().equals(asset.getType())) {
                String msg = "Asset type cannot be changed: asset=" + asset;
                LOG.info(msg);
                throw new IllegalStateException(msg);
            }
            if (!existingAsset.getRealm().equals(asset.getRealm())) {
                String msg = "Asset realm cannot be changed: asset=" + asset;
                LOG.info(msg);
                throw new IllegalStateException(msg);
            }
            // Update timestamp on modified attributes this allows fast equality checking
            asset.getAttributes().stream().forEach(attr -> {
                existingAsset.getAttribute(attr.getName()).ifPresent(existingAttr -> {
                    // If attribute is modified make sure the timestamp is also updated to allow simple equality
                    if (!attr.deepEquals(existingAttr) && attr.getTimestamp().orElse(0L) <= existingAttr.getTimestamp().orElse(0L)) {
                        // In the unlikely situation that we are in the same millisecond as last update
                        // we will always ensure a delta of >= 1ms
                        attr.setTimestamp(Math.max(existingAttr.getTimestamp().orElse(0L) + 1, timerService.getCurrentTimeMillis()));
                    }
                });
            });
            // concurrent updates
            if (overrideVersion) {
                asset.setVersion(existingAsset.getVersion());
            }
        }
        // Validate realm
        if (asset.getRealm() == null) {
            String msg = "Asset realm must be set : asset=" + asset;
            LOG.info(msg);
            throw new IllegalStateException(msg);
        }
        if (!identityService.getIdentityProvider().tenantExists(asset.getRealm())) {
            String msg = "Asset realm not found or is inactive: asset=" + asset;
            LOG.info(msg);
            throw new IllegalStateException(msg);
        }
        if (asset.getParentId() != null && asset.getParentId().equals(asset.getId())) {
            String msg = "Asset parent cannot be the asset: asset=" + asset;
            LOG.info(msg);
            throw new IllegalStateException(msg);
        }
        // Validate parent only if asset is new or parent has changed
        if ((existingAsset == null && asset.getParentId() != null) || (existingAsset != null && asset.getParentId() != null && !asset.getParentId().equals(existingAsset.getParentId()))) {
            Asset<?> parent = find(em, asset.getParentId(), true);
            // The parent must exist
            if (parent == null) {
                String msg = "Asset parent not found: asset=" + asset;
                LOG.info(msg);
                throw new IllegalStateException(msg);
            }
            // The parent can not be a child of the asset
            if (parent.pathContains(asset.getId())) {
                String msg = "Asset parent cannot be a descendant of the asset: asset=" + asset;
                LOG.info(msg);
                throw new IllegalStateException(msg);
            }
            // The parent should be in the same realm
            if (!parent.getRealm().equals(asset.getRealm())) {
                String msg = "Asset parent must be in the same realm: asset=" + asset;
                LOG.info(msg);
                throw new IllegalStateException(msg);
            }
            // if parent is of type group then this child asset must have the correct type
            if (parent instanceof GroupAsset) {
                String childAssetType = parent.getAttributes().getValue(GroupAsset.CHILD_ASSET_TYPE).orElseThrow(() -> {
                    String msg = "Asset parent is of type GROUP but the childAssetType attribute is invalid: asset=" + asset;
                    LOG.info(msg);
                    return new IllegalStateException(msg);
                });
                // Look through type hierarchy for a match - this allows sub types
                Class<?> clazz = asset.getClass();
                boolean typeMatch = childAssetType.equals(clazz.getSimpleName());
                while (!typeMatch && clazz != Asset.class) {
                    clazz = clazz.getSuperclass();
                    typeMatch = childAssetType.equals(clazz.getSimpleName());
                }
                if (!typeMatch) {
                    String msg = "Asset type does not match parent GROUP asset's childAssetType attribute: asset=" + asset;
                    LOG.info(msg);
                    throw new IllegalStateException(msg);
                }
            }
        }
        // Validate group child asset type attribute
        if (asset instanceof GroupAsset) {
            String childAssetType = ((GroupAsset) asset).getChildAssetType().map(childAssetTypeString -> TextUtil.isNullOrEmpty(childAssetTypeString) ? null : childAssetTypeString).orElseThrow(() -> {
                String msg = "Asset of type GROUP childAssetType attribute must be a valid string: asset=" + asset;
                LOG.info(msg);
                return new IllegalStateException(msg);
            });
            String existingChildAssetType = existingAsset != null ? ((GroupAsset) existingAsset).getChildAssetType().orElseThrow(() -> {
                String msg = "Asset of type GROUP childAssetType attribute must be a valid string: asset=" + asset;
                LOG.info(msg);
                return new IllegalStateException(msg);
            }) : childAssetType;
            if (!childAssetType.equals(existingChildAssetType)) {
                String msg = "Asset of type GROUP so childAssetType attribute cannot be changed: asset=" + asset;
                LOG.info(msg);
                throw new IllegalStateException(msg);
            }
        }
        // Update all empty attribute timestamps with server-time (a caller which doesn't have a
        // reliable time source such as a browser should clear the timestamp when setting an attribute
        // value).
        asset.getAttributes().forEach(attribute -> {
            if (!attribute.hasExplicitTimestamp()) {
                attribute.setTimestamp(timerService.getCurrentTimeMillis());
            }
        });
        // If username present
        User user = null;
        if (!TextUtil.isNullOrEmpty(userName)) {
            user = identityService.getIdentityProvider().getUserByUsername(asset.getRealm(), userName);
            if (user == null) {
                String msg = "User not found: " + userName;
                LOG.info(msg);
                throw new IllegalStateException(msg);
            }
        }
        T updatedAsset = em.merge(asset);
        if (user != null) {
            storeUserAssetLinks(em, Collections.singletonList(new UserAssetLink(user.getRealm(), user.getId(), updatedAsset.getId())));
        }
        return updatedAsset;
    });
}
Also used : ValuePredicate.asPredicateOrTrue(org.openremote.model.query.filter.ValuePredicate.asPredicateOrTrue) ClientRole(org.openremote.model.security.ClientRole) AuthContext(org.openremote.container.security.AuthContext) NoResultException(javax.persistence.NoResultException) ValueUtil(org.openremote.model.util.ValueUtil) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AttributeEvent(org.openremote.model.attribute.AttributeEvent) GroupAsset(org.openremote.model.asset.impl.GroupAsset) TextUtil(org.openremote.model.util.TextUtil) ConstraintViolation(javax.validation.ConstraintViolation) LogicGroup(org.openremote.model.query.LogicGroup) Attribute.getAddedOrModifiedAttributes(org.openremote.model.attribute.Attribute.getAddedOrModifiedAttributes) Predicate(java.util.function.Predicate) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) ACCESS_RESTRICTED_READ(org.openremote.model.value.MetaItemType.ACCESS_RESTRICTED_READ) Query(javax.persistence.Query) StringArrayType(com.vladmihalcea.hibernate.type.array.StringArrayType) org.openremote.model(org.openremote.model) RouteBuilder(org.apache.camel.builder.RouteBuilder) PERSISTENCE_TOPIC(org.openremote.container.persistence.PersistenceService.PERSISTENCE_TOPIC) AssetInfo(org.openremote.model.event.shared.AssetInfo) EventSubscription(org.openremote.model.event.shared.EventSubscription) TextUtil.isNullOrEmpty(org.openremote.model.util.TextUtil.isNullOrEmpty) SharedEvent(org.openremote.model.event.shared.SharedEvent) GatewayService(org.openremote.manager.gateway.GatewayService) java.sql(java.sql) IntStream(java.util.stream.IntStream) AttributeMap(org.openremote.model.attribute.AttributeMap) EventSubscriptionAuthorizer(org.openremote.manager.event.EventSubscriptionAuthorizer) java.util(java.util) ACCESS_PUBLIC_READ(org.openremote.model.value.MetaItemType.ACCESS_PUBLIC_READ) CLIENT_EVENT_TOPIC(org.openremote.manager.event.ClientEventService.CLIENT_EVENT_TOPIC) Collectors.groupingBy(java.util.stream.Collectors.groupingBy) Session(org.hibernate.Session) TypedQuery(javax.persistence.TypedQuery) Supplier(java.util.function.Supplier) Level(java.util.logging.Level) AbstractReturningWork(org.hibernate.jdbc.AbstractReturningWork) PGobject(org.postgresql.util.PGobject) Attribute(org.openremote.model.attribute.Attribute) PersistenceService(org.openremote.container.persistence.PersistenceService) org.openremote.model.query.filter(org.openremote.model.query.filter) BiConsumer(java.util.function.BiConsumer) ManagerWebService(org.openremote.manager.web.ManagerWebService) org.openremote.model.asset(org.openremote.model.asset) MessageBrokerService(org.openremote.container.message.MessageBrokerService) User(org.openremote.model.security.User) Access(org.openremote.model.query.AssetQuery.Access) ManagerIdentityService(org.openremote.manager.security.ManagerIdentityService) MetaItemType(org.openremote.model.value.MetaItemType) AssetQuery(org.openremote.model.query.AssetQuery) Pair(org.openremote.model.util.Pair) EntityManager(javax.persistence.EntityManager) Consumer(java.util.function.Consumer) EventRequestResponseWrapper(org.openremote.model.event.shared.EventRequestResponseWrapper) ClientEventService(org.openremote.manager.event.ClientEventService) ConstraintViolationException(javax.validation.ConstraintViolationException) TimerService(org.openremote.container.timer.TimerService) ConsoleResourceImpl(org.openremote.manager.asset.console.ConsoleResourceImpl) PredicateBuilder.or(org.apache.camel.builder.PredicateBuilder.or) PersistenceService.isPersistenceEventForEntityType(org.openremote.container.persistence.PersistenceService.isPersistenceEventForEntityType) User(org.openremote.model.security.User) GroupAsset(org.openremote.model.asset.impl.GroupAsset) ConstraintViolation(javax.validation.ConstraintViolation) GroupAsset(org.openremote.model.asset.impl.GroupAsset) ConstraintViolationException(javax.validation.ConstraintViolationException)

Example 18 with Attribute

use of org.openremote.model.attribute.Attribute in project openremote by openremote.

the class ProtocolUtil method createGenericAttributeMessageConsumer.

public static Consumer<String> createGenericAttributeMessageConsumer(String assetId, Attribute<?> attribute, AgentLink<?> agentLink, Supplier<Long> currentMillisSupplier, Consumer<AttributeState> stateConsumer) {
    ValueFilter[] matchFilters = agentLink.getMessageMatchFilters().orElse(null);
    ValuePredicate matchPredicate = agentLink.getMessageMatchPredicate().orElse(null);
    if (matchPredicate == null) {
        return null;
    }
    return message -> {
        if (!TextUtil.isNullOrEmpty(message)) {
            Object messageFiltered = applyValueFilters(message, matchFilters);
            if (messageFiltered != null) {
                if (matchPredicate.asPredicate(currentMillisSupplier).test(messageFiltered)) {
                    Protocol.LOG.finest("Inbound message meets attribute matching meta so writing state to state consumer for attribute: asssetId=" + assetId + ", attribute=" + attribute.getName());
                    stateConsumer.accept(new AttributeState(assetId, attribute.getName(), message));
                }
            }
        }
    };
}
Also used : NULL_LITERAL(org.openremote.model.util.ValueUtil.NULL_LITERAL) Protocol(org.openremote.model.asset.agent.Protocol) ArrayUtils(org.apache.commons.lang3.ArrayUtils) Hex(org.apache.commons.codec.binary.Hex) ValueUtil(org.openremote.model.util.ValueUtil) DYNAMIC_VALUE_PLACEHOLDER(org.openremote.model.asset.agent.Protocol.DYNAMIC_VALUE_PLACEHOLDER) AtomicReference(java.util.concurrent.atomic.AtomicReference) Supplier(java.util.function.Supplier) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) Level(java.util.logging.Level) ValueUtil.applyValueFilters(org.openremote.model.util.ValueUtil.applyValueFilters) AgentLink(org.openremote.model.asset.agent.AgentLink) Attribute(org.openremote.model.attribute.Attribute) Locale(java.util.Locale) TextUtil(org.openremote.model.util.TextUtil) JsonNodeType(com.fasterxml.jackson.databind.node.JsonNodeType) AttributeState(org.openremote.model.attribute.AttributeState) ValueType(org.openremote.model.value.ValueType) BinaryCodec(org.apache.commons.codec.binary.BinaryCodec) ValuePredicate(org.openremote.model.query.filter.ValuePredicate) Pair(org.openremote.model.util.Pair) Consumer(java.util.function.Consumer) ValueFilter(org.openremote.model.value.ValueFilter) TsIgnore(org.openremote.model.util.TsIgnore) Optional(java.util.Optional) AttributeLink(org.openremote.model.attribute.AttributeLink) AttributeExecuteStatus(org.openremote.model.attribute.AttributeExecuteStatus) AttributeState(org.openremote.model.attribute.AttributeState) ValuePredicate(org.openremote.model.query.filter.ValuePredicate) ValueFilter(org.openremote.model.value.ValueFilter)

Aggregations

Attribute (org.openremote.model.attribute.Attribute)18 Logger (java.util.logging.Logger)13 Level (java.util.logging.Level)11 AttributeEvent (org.openremote.model.attribute.AttributeEvent)10 Consumer (java.util.function.Consumer)9 Container (org.openremote.model.Container)9 ValueUtil (org.openremote.model.util.ValueUtil)9 java.util (java.util)8 AttributeState (org.openremote.model.attribute.AttributeState)8 SyslogCategory (org.openremote.model.syslog.SyslogCategory)8 ConnectionStatus (org.openremote.model.asset.agent.ConnectionStatus)7 AttributeRef (org.openremote.model.attribute.AttributeRef)7 Pair (org.openremote.model.util.Pair)7 MetaItemType (org.openremote.model.value.MetaItemType)7 Asset (org.openremote.model.asset.Asset)6 Map (java.util.Map)5 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)5 TimeUnit (java.util.concurrent.TimeUnit)5 Collectors (java.util.stream.Collectors)5 AbstractProtocol (org.openremote.agent.protocol.AbstractProtocol)5