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;
}
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;
});
}
Aggregations