Search in sources :

Example 1 with GroupAsset

use of org.openremote.model.asset.impl.GroupAsset in project openremote by openremote.

the class ConsoleResourceImpl method getConsoleParentAsset.

public static Asset<?> getConsoleParentAsset(AssetStorageService assetStorageService, Tenant tenant) {
    // Look for a group asset with a child type of console in the realm root
    GroupAsset consoleParent = (GroupAsset) assetStorageService.find(new AssetQuery().select(new AssetQuery.Select().excludeAttributes()).names(CONSOLE_PARENT_ASSET_NAME).parents(new ParentPredicate(null)).types(GroupAsset.class).tenant(new TenantPredicate(tenant.getRealm())).attributes(new AttributePredicate("childAssetType", new StringPredicate(ConsoleAsset.DESCRIPTOR.getName()))));
    if (consoleParent == null) {
        consoleParent = new GroupAsset(CONSOLE_PARENT_ASSET_NAME, ConsoleAsset.class);
        consoleParent.setChildAssetType(ConsoleAsset.DESCRIPTOR.getName());
        consoleParent.setRealm(tenant.getRealm());
        consoleParent = assetStorageService.merge(consoleParent);
    }
    return consoleParent;
}
Also used : ConsoleAsset(org.openremote.model.asset.impl.ConsoleAsset) ParentPredicate(org.openremote.model.query.filter.ParentPredicate) StringPredicate(org.openremote.model.query.filter.StringPredicate) AssetQuery(org.openremote.model.query.AssetQuery) GroupAsset(org.openremote.model.asset.impl.GroupAsset) TenantPredicate(org.openremote.model.query.filter.TenantPredicate) AttributePredicate(org.openremote.model.query.filter.AttributePredicate)

Example 2 with GroupAsset

use of org.openremote.model.asset.impl.GroupAsset 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)

Aggregations

GroupAsset (org.openremote.model.asset.impl.GroupAsset)2 AssetQuery (org.openremote.model.query.AssetQuery)2 StringArrayType (com.vladmihalcea.hibernate.type.array.StringArrayType)1 java.sql (java.sql)1 java.util (java.util)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 BiConsumer (java.util.function.BiConsumer)1 Consumer (java.util.function.Consumer)1 Predicate (java.util.function.Predicate)1 Supplier (java.util.function.Supplier)1 Level (java.util.logging.Level)1 Logger (java.util.logging.Logger)1 Collectors (java.util.stream.Collectors)1 Collectors.groupingBy (java.util.stream.Collectors.groupingBy)1 IntStream (java.util.stream.IntStream)1 EntityManager (javax.persistence.EntityManager)1 NoResultException (javax.persistence.NoResultException)1 Query (javax.persistence.Query)1 TypedQuery (javax.persistence.TypedQuery)1 ConstraintViolation (javax.validation.ConstraintViolation)1