Search in sources :

Example 11 with Asset

use of org.openremote.model.asset.Asset in project openremote by openremote.

the class UpnpProtocol method storeAssets.

protected void storeAssets(AssetAttribute protocolConfiguration, Device device) {
    String parentId = protocolConfigsGroupAssetId.get(protocolConfiguration.getReferenceOrThrow());
    LOG.fine("Storing UPnP device as child assets of " + parentId + ": " + device);
    Asset asset = createAsset(parentId, device);
    asset = assetService.mergeAsset(asset);
}
Also used : Asset(org.openremote.model.asset.Asset)

Example 12 with Asset

use of org.openremote.model.asset.Asset in project openremote by openremote.

the class AbstractVelbusProtocol method discoverLinkedAssetAttributes.

@Override
public Asset[] discoverLinkedAssetAttributes(AssetAttribute protocolConfiguration, FileInfo fileInfo) throws IllegalStateException {
    Document xmlDoc;
    try {
        String xmlStr = fileInfo.isBinary() ? new String(CodecUtil.decodeBase64(fileInfo.getContents()), "UTF8") : fileInfo.getContents();
        LOG.info("Parsing VELBUS project file: " + fileInfo.getName());
        xmlDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(xmlStr)));
    } catch (Exception e) {
        throw new IllegalStateException("Failed to convert file into XML", e);
    }
    xmlDoc.getDocumentElement().normalize();
    NodeList modules = xmlDoc.getElementsByTagName("Module");
    LOG.info("Found " + modules.getLength() + " module(s)");
    List<Asset> devices = new ArrayList<>(modules.getLength());
    MetaItem agentLink = AgentLink.asAgentLinkMetaItem(protocolConfiguration.getReferenceOrThrow());
    for (int i = 0; i < modules.getLength(); i++) {
        Element module = (Element) modules.item(i);
        // TODO: Process memory map and add
        Optional<VelbusDeviceType> deviceType = EnumUtil.enumFromString(VelbusDeviceType.class, module.getAttribute("type").replaceAll("-", ""));
        if (!deviceType.isPresent()) {
            LOG.info("Module device type '" + module.getAttribute("type") + "' is not supported so ignoring");
            continue;
        }
        String[] addresses = module.getAttribute("address").split(",");
        Integer baseAddress = Integer.parseInt(addresses[0], 16);
        String build = module.getAttribute("build");
        String serial = module.getAttribute("serial");
        String name = module.getElementsByTagName("Caption").item(0).getTextContent();
        name = isNullOrEmpty(name) ? deviceType.toString() : name;
        Asset device = new Asset(name, AssetType.THING);
        device.setAttributes(new AssetAttribute("build", AttributeType.STRING, Values.create(build)).setMeta(new MetaItem(AssetMeta.LABEL, Values.create("Build")), new MetaItem(AssetMeta.READ_ONLY, Values.create(true))), new AssetAttribute("serialNumber", AttributeType.STRING, Values.create(serial)).setMeta(new MetaItem(AssetMeta.LABEL, Values.create("Serial No")), new MetaItem(AssetMeta.READ_ONLY, Values.create(true))));
        getLinkedAttributeDescriptors(deviceType.get(), baseAddress).forEach(descriptor -> {
            AssetAttribute attribute = new AssetAttribute(descriptor.getName(), descriptor.getAttributeType()).setMeta(agentLink, new MetaItem(AssetMeta.LABEL, Values.create(descriptor.getDisplayName()))).addMeta(descriptor.getMetaItems());
            if (descriptor.isReadOnly()) {
                attribute.addMeta(new MetaItem(AssetMeta.READ_ONLY, Values.create(true)));
            } else if (descriptor.isExecutable()) {
                attribute.addMeta(new MetaItem(AssetMeta.EXECUTABLE, Values.create(true)));
            }
            device.addAttributes(attribute);
        });
        devices.add(device);
    }
    return devices.toArray(new Asset[devices.size()]);
}
Also used : InputSource(org.xml.sax.InputSource) NodeList(org.w3c.dom.NodeList) Element(org.w3c.dom.Element) VelbusDeviceType(org.openremote.agent.protocol.velbus.device.VelbusDeviceType) Document(org.w3c.dom.Document) StringReader(java.io.StringReader) AssetAttribute(org.openremote.model.asset.AssetAttribute) Asset(org.openremote.model.asset.Asset)

Example 13 with Asset

use of org.openremote.model.asset.Asset in project openremote by openremote.

the class AgentResourceImpl method getParentAssetAndRealmId.

/**
 * Parent takes priority over realm ID (only super user can add to other realms)
 */
protected Pair<Asset, String> getParentAssetAndRealmId(String parentId, String realmId) {
    if (isRestrictedUser()) {
        throw new ForbiddenException("User is restricted");
    }
    // Assets must be added in the same realm as the user (unless super user)
    Asset parentAsset = isNullOrEmpty(parentId) ? null : assetStorageService.find(parentId);
    if (parentAsset == null && !isNullOrEmpty(parentId)) {
        // Either invalid asset or user doesn't have access to it
        LOG.info("User is trying to import with an invalid or inaccessible parent");
        throw new BadRequestException("Parent either doesn't exist or is not accessible");
    }
    Tenant tenant = parentAsset != null ? identityService.getIdentityProvider().getTenantForRealmId(parentAsset.getRealmId()) : !isNullOrEmpty(realmId) ? identityService.getIdentityProvider().getTenantForRealmId(realmId) : getAuthenticatedTenant();
    if (!isTenantActiveAndAccessible(tenant)) {
        String msg = "The requested parent asset or realm is inaccessible";
        LOG.fine(msg);
        throw new ForbiddenException(msg);
    }
    return new Pair<>(parentAsset, tenant.getId());
}
Also used : Tenant(org.openremote.model.security.Tenant) ServerAsset(org.openremote.manager.asset.ServerAsset) Asset(org.openremote.model.asset.Asset) Pair(org.openremote.model.util.Pair)

Example 14 with Asset

use of org.openremote.model.asset.Asset in project openremote by openremote.

the class AgentResourceImpl method searchForLinkedAttributes.

@Override
public Asset[] searchForLinkedAttributes(RequestParams requestParams, String agentId, String protocolConfigurationName, String parentId, String realmId) {
    AttributeRef protocolConfigRef = new AttributeRef(agentId, protocolConfigurationName);
    Pair<Asset, String> parentAndRealmId = getParentAssetAndRealmId(parentId, realmId);
    // TODO: Allow user to select which assets/attributes are actually added to the DB
    Asset[] assets = withAgentConnector(agentId, agentConnector -> {
        LOG.finer("Asking connector '" + agentConnector.value.getClass().getSimpleName() + "' to do linked attribute discovery for protocol configuration: " + protocolConfigRef);
        return agentConnector.value.getDiscoveredLinkedAttributes(protocolConfigRef);
    });
    try {
        persistAssets(assets, parentAndRealmId.key, parentAndRealmId.value);
        return assets;
    } catch (IllegalArgumentException e) {
        LOG.log(Level.WARNING, e.getMessage(), e);
        throw new NotFoundException(e.getMessage());
    } catch (UnsupportedOperationException e) {
        LOG.log(Level.WARNING, e.getMessage(), e);
        throw new NotSupportedException(e.getMessage());
    }
}
Also used : AttributeRef(org.openremote.model.attribute.AttributeRef) ServerAsset(org.openremote.manager.asset.ServerAsset) Asset(org.openremote.model.asset.Asset)

Example 15 with Asset

use of org.openremote.model.asset.Asset in project openremote by openremote.

the class AssetProcessingService method configure.

@Override
public void configure() throws Exception {
    // A client wants to write attribute state through event bus
    from(CLIENT_EVENT_TOPIC).routeId("FromClientUpdates").filter(body().isInstanceOf(AttributeEvent.class)).setHeader(HEADER_SOURCE, () -> CLIENT).to(ASSET_QUEUE);
    // Process attribute events
    /* TODO This message consumer should be transactionally consistent with the database, this is currently not the case

         Our "if I have not processed this message before" duplicate detection:

          - discard events with source time greater than server processing time (future events)
          - discard events with source time less than last applied/stored event source time
          - allow the rest (also events with same source time, order of application undefined)

         Possible improvements moving towards at-least-once:

         - Make AssetUpdateProcessor transactional with a two-phase commit API
         - Replace at-most-once ClientEventService with at-least-once capable, embeddable message broker/protocol
         - See pseudocode here: http://activemq.apache.org/should-i-use-xa.html
         - Do we want JMS/AMQP/WSS or SOME_API/MQTT/WSS? ActiveMQ or Moquette?
        */
    from(ASSET_QUEUE).routeId("AssetQueueProcessor").filter(body().isInstanceOf(AttributeEvent.class)).doTry().process(exchange -> withLock(getClass().getSimpleName() + "::processFromAssetQueue", () -> {
        AttributeEvent event = exchange.getIn().getBody(AttributeEvent.class);
        LOG.finest("Processing: " + event);
        if (event.getEntityId() == null || event.getEntityId().isEmpty())
            return;
        if (event.getAttributeName() == null || event.getAttributeName().isEmpty())
            return;
        Source source = exchange.getIn().getHeader(HEADER_SOURCE, () -> null, Source.class);
        if (source == null) {
            throw new AssetProcessingException(MISSING_SOURCE);
        }
        // Process the asset update in a database transaction, this ensures that processors
        // will see consistent database state and we only commit if no processor failed. This
        // still won't make this procedure consistent with the message queue from which we consume!
        persistenceService.doTransaction(em -> {
            ServerAsset asset = assetStorageService.find(em, event.getEntityId(), true);
            if (asset == null)
                throw new AssetProcessingException(ASSET_NOT_FOUND);
            AssetAttribute oldAttribute = asset.getAttribute(event.getAttributeName()).orElse(null);
            if (oldAttribute == null)
                throw new AssetProcessingException(ATTRIBUTE_NOT_FOUND);
            // Agent attributes can't be updated with events
            if (asset.getWellKnownType() == AssetType.AGENT) {
                throw new AssetProcessingException(ILLEGAL_AGENT_UPDATE);
            }
            // For executable attributes, non-sensor sources can set a writable attribute execute status
            if (oldAttribute.isExecutable() && source != SENSOR) {
                Optional<AttributeExecuteStatus> status = event.getValue().flatMap(Values::getString).flatMap(AttributeExecuteStatus::fromString);
                if (status.isPresent() && !status.get().isWrite()) {
                    throw new AssetProcessingException(INVALID_ATTRIBUTE_EXECUTE_STATUS);
                }
            }
            switch(source) {
                case CLIENT:
                    AuthContext authContext = exchange.getIn().getHeader(Constants.AUTH_CONTEXT, AuthContext.class);
                    if (authContext == null) {
                        throw new AssetProcessingException(NO_AUTH_CONTEXT);
                    }
                    // Check realm, must be accessible
                    if (!identityService.getIdentityProvider().isTenantActiveAndAccessible(authContext, asset)) {
                        throw new AssetProcessingException(INSUFFICIENT_ACCESS);
                    }
                    // Check read-only
                    if (oldAttribute.isReadOnly() && !authContext.isSuperUser()) {
                        throw new AssetProcessingException(INSUFFICIENT_ACCESS);
                    }
                    // Regular user must have write assets role
                    if (!authContext.hasResourceRoleOrIsSuperUser(ClientRole.WRITE_ASSETS.getValue(), Constants.KEYCLOAK_CLIENT_ID)) {
                        throw new AssetProcessingException(INSUFFICIENT_ACCESS);
                    }
                    // Check restricted user
                    if (identityService.getIdentityProvider().isRestrictedUser(authContext.getUserId())) {
                        // Must be asset linked to user
                        if (!assetStorageService.isUserAsset(authContext.getUserId(), event.getEntityId())) {
                            throw new AssetProcessingException(INSUFFICIENT_ACCESS);
                        }
                        // Must be writable by restricted client
                        if (!oldAttribute.isAccessRestrictedWrite()) {
                            throw new AssetProcessingException(INSUFFICIENT_ACCESS);
                        }
                    }
                    break;
                case SENSOR:
                    Optional<AssetAttribute> protocolConfiguration = getAgentLink(oldAttribute).flatMap(agentService::getProtocolConfiguration);
                    // Sensor event must be for an attribute linked to a protocol configuration
                    if (!protocolConfiguration.isPresent()) {
                        throw new AssetProcessingException(INVALID_AGENT_LINK);
                    }
                    break;
            }
            // Either use the timestamp of the event or set event time to processing time
            long processingTime = timerService.getCurrentTimeMillis();
            long eventTime = event.getTimestamp() > 0 ? event.getTimestamp() : processingTime;
            // the attribute until after that time (maybe that is desirable behaviour)
            if (eventTime - processingTime > 0) {
                // TODO: Decide how to handle update events in the future - ignore or change timestamp
                throw new AssetProcessingException(EVENT_IN_FUTURE, "current time: " + new Date(processingTime) + "/" + processingTime + ", event time: " + new Date(eventTime) + "/" + eventTime);
            }
            // Check the last update timestamp of the attribute, ignoring any event that is older than last update
            // TODO This means we drop out-of-sequence events but accept events with the same source timestamp
            // TODO Several attribute events can occur in the same millisecond, then order of application is undefined
            oldAttribute.getValueTimestamp().filter(t -> t >= 0 && eventTime < t).ifPresent(lastStateTime -> {
                throw new AssetProcessingException(EVENT_OUTDATED, "last asset state time: " + new Date(lastStateTime) + "/" + lastStateTime + ", event time: " + new Date(eventTime) + "/" + eventTime);
            });
            // Create a copy of the attribute and set the new value and timestamp
            AssetAttribute updatedAttribute = oldAttribute.deepCopy();
            updatedAttribute.setValue(event.getValue().orElse(null), eventTime);
            // Validate constraints of attribute
            List<ValidationFailure> validationFailures = updatedAttribute.getValidationFailures();
            if (!validationFailures.isEmpty()) {
                throw new AssetProcessingException(ATTRIBUTE_VALIDATION_FAILURE, validationFailures.toString());
            }
            // Push through all processors
            boolean consumedCompletely = processAssetUpdate(em, asset, updatedAttribute, source);
            // Publish a new event for clients if no processor consumed the update completely
            if (!consumedCompletely) {
                publishClientEvent(asset, updatedAttribute);
            }
        });
    })).endDoTry().doCatch(AssetProcessingException.class).process(handleAssetProcessingException(LOG));
}
Also used : ClientRole(org.openremote.model.security.ClientRole) AuthContext(org.openremote.container.security.AuthContext) AssetDatapointService(org.openremote.manager.datapoint.AssetDatapointService) Date(java.util.Date) CLIENT_EVENT_TOPIC(org.openremote.manager.event.ClientEventService.CLIENT_EVENT_TOPIC) ValidationFailure(org.openremote.model.ValidationFailure) Exchange(org.apache.camel.Exchange) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) Processor(org.apache.camel.Processor) Container(org.openremote.container.Container) ContainerService(org.openremote.container.ContainerService) RulesService(org.openremote.manager.rules.RulesService) AttributeEvent(org.openremote.model.attribute.AttributeEvent) PersistenceService(org.openremote.container.persistence.PersistenceService) AgentService(org.openremote.manager.agent.AgentService) AgentLink.getAgentLink(org.openremote.model.asset.agent.AgentLink.getAgentLink) MessageBrokerService(org.openremote.container.message.MessageBrokerService) ManagerIdentityService(org.openremote.manager.security.ManagerIdentityService) Asset(org.openremote.model.asset.Asset) AssetType(org.openremote.model.asset.AssetType) EntityManager(javax.persistence.EntityManager) Constants(org.openremote.model.Constants) Logger(java.util.logging.Logger) MessageBrokerSetupService(org.openremote.container.message.MessageBrokerSetupService) Collectors(java.util.stream.Collectors) Reason(org.openremote.manager.asset.AssetProcessingException.Reason) AssetResource(org.openremote.model.asset.AssetResource) HEADER_SOURCE(org.openremote.model.attribute.AttributeEvent.HEADER_SOURCE) Value(org.openremote.model.value.Value) ClientEventService(org.openremote.manager.event.ClientEventService) List(java.util.List) RouteBuilder(org.apache.camel.builder.RouteBuilder) TimerService(org.openremote.container.timer.TimerService) Optional(java.util.Optional) Source(org.openremote.model.attribute.AttributeEvent.Source) Values(org.openremote.model.value.Values) AssetAttribute(org.openremote.model.asset.AssetAttribute) Protocol(org.openremote.agent.protocol.Protocol) AttributeExecuteStatus(org.openremote.model.attribute.AttributeExecuteStatus) GlobalLock.withLock(org.openremote.container.concurrent.GlobalLock.withLock) AuthContext(org.openremote.container.security.AuthContext) AttributeEvent(org.openremote.model.attribute.AttributeEvent) Source(org.openremote.model.attribute.AttributeEvent.Source) Date(java.util.Date) ValidationFailure(org.openremote.model.ValidationFailure) AttributeExecuteStatus(org.openremote.model.attribute.AttributeExecuteStatus) AssetAttribute(org.openremote.model.asset.AssetAttribute)

Aggregations

Asset (org.openremote.model.asset.Asset)19 WebApplicationException (javax.ws.rs.WebApplicationException)5 ServerAsset (org.openremote.manager.asset.ServerAsset)5 AssetAttribute (org.openremote.model.asset.AssetAttribute)5 PersistenceService (org.openremote.container.persistence.PersistenceService)3 TimerService (org.openremote.container.timer.TimerService)3 ManagerIdentityService (org.openremote.manager.security.ManagerIdentityService)3 AssetRuleset (org.openremote.model.rules.AssetRuleset)3 ArrayList (java.util.ArrayList)2 Logger (java.util.logging.Logger)2 Collectors (java.util.stream.Collectors)2 EntityManager (javax.persistence.EntityManager)2 RouteBuilder (org.apache.camel.builder.RouteBuilder)2 Container (org.openremote.container.Container)2 ContainerService (org.openremote.container.ContainerService)2 GlobalLock.withLock (org.openremote.container.concurrent.GlobalLock.withLock)2 MessageBrokerService (org.openremote.container.message.MessageBrokerService)2 MessageBrokerSetupService (org.openremote.container.message.MessageBrokerSetupService)2 AgentService (org.openremote.manager.agent.AgentService)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1