io.resys.hdes.client.spi.HdesInMemoryStore Maven / Gradle / Ivy
package io.resys.hdes.client.spi;
/*-
* #%L
* hdes-client-api
* %%
* Copyright (C) 2020 - 2021 Copyright 2020 ReSys OÜ
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.resys.hdes.client.api.HdesComposer.StoreDump;
import io.resys.hdes.client.api.HdesStore;
import io.resys.hdes.client.api.ImmutableStoreEntity;
import io.resys.hdes.client.api.ImmutableStoreState;
import io.resys.hdes.client.api.ast.AstBody.AstBodyType;
import io.resys.hdes.client.api.ast.AstBody.AstSource;
import io.resys.hdes.client.api.ast.AstCommand;
import io.resys.hdes.client.api.ast.AstTag;
import io.resys.hdes.client.api.ast.AstTag.AstTagValue;
import io.resys.hdes.client.spi.staticresources.Sha2;
import io.resys.hdes.client.spi.staticresources.StoreEntityLocation;
import io.resys.hdes.client.spi.util.HdesAssert;
import io.smallrye.mutiny.Uni;
public class HdesInMemoryStore implements HdesStore {
private static final Logger LOGGER = LoggerFactory.getLogger(HdesInMemoryStore.class);
private final Map entities;
private final StoreState state;
public HdesInMemoryStore(Map entities) {
super();
this.entities = entities;
final var builder = ImmutableStoreState.builder();
for(final var entity : entities.values()) {
switch (entity.getBodyType()) {
case DT: builder.putDecisions(entity.getId(), entity); break;
case FLOW: builder.putFlows(entity.getId(), entity); break;
case FLOW_TASK: builder.putServices(entity.getId(), entity); break;
default: continue;
}
}
this.state = builder.build();
}
@Override
public Uni create(CreateStoreEntity newType) {
throw new RuntimeException("read only store!");
}
@Override
public Uni update(UpdateStoreEntity updateType) {
throw new RuntimeException("read only store!");
}
@Override
public Uni delete(DeleteAstType deleteType) {
throw new RuntimeException("read only store!");
}
@Override
public QueryBuilder query() {
return new QueryBuilder() {
@Override
public Uni get(String id) {
return Uni.createFrom().item(() -> entities.get(id));
}
@Override
public Uni get() {
return Uni.createFrom().item(() -> state);
}
};
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private ObjectMapper objectMapper;
private final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
private final StoreEntityLocation location = new StoreEntityLocation("classpath*:assets/");
private final TypeReference> ref = new TypeReference>() {};
private List readCommands(String commands) {
try {
if(commands.startsWith("{")) {
final var tree = objectMapper.readTree(commands);
return objectMapper.convertValue(tree.get("commands"), ref);
}
return objectMapper.readValue(commands, ref);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private List list(String location) {
try {
LOGGER.debug("Loading assets from: " + location + "!");
List files = new ArrayList<>();
for (Resource resource : resolver.getResources(location)) {
files.add(resource);
}
return files;
} catch (Exception e) {
throw new RuntimeException("Failed to load asset from: " + location + "!" + e.getMessage(), e);
}
}
private AstTag readRelease(String json) {
try {
return objectMapper.readValue(json, AstTag.class);
} catch (Exception e) {
throw new RuntimeException("Failed to load asset from: " + location + "!" + e.getMessage(), e);
}
}
private StoreDump readDump(String json) {
try {
return objectMapper.readValue(json, StoreDump.class);
} catch (Exception e) {
throw new RuntimeException("Failed to load asset from: " + location + "!" + e.getMessage(), e);
}
}
private ImmutableStoreEntity.Builder readStoreEntity(Resource resource) {
final var content = readContents(resource);
return ImmutableStoreEntity.builder()
.id(resource.getFilename())
.hash(Sha2.blob(content))
.body(readCommands(content));
}
private String readContents(Resource entry) {
try {
return IOUtils.toString(entry.getInputStream(), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException("Failed to load asset content from: " + entry.getFilename() + "!" + e.getMessage(), e);
}
}
public Builder objectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
return this;
}
public HdesInMemoryStore build() {
HdesAssert.notNull(objectMapper, () -> "objectMapper must be defined!");
final var migLog = new StringBuilder();
final var entities = new HashMap();
list(location.getMigrationRegex()).stream().forEach(r -> {
final Map order = Map.of(
AstBodyType.DT, 1,
AstBodyType.FLOW_TASK, 2,
AstBodyType.FLOW, 3);
migLog
.append("Loading assets from release: " + r.getFilename()).append(System.lineSeparator());
final var assets = new ArrayList<>(readRelease(readContents(r)).getValues());
assets.sort((AstTagValue o1, AstTagValue o2) ->
Integer.compare(order.get(o1.getBodyType()), order.get(o2.getBodyType()))
);
for(final var asset : assets) {
migLog.append(" - ")
.append(asset.getHash()).append("/").append(asset.getBodyType()).append("/").append(asset.getHash())
.append(System.lineSeparator());
final var id = UUID.randomUUID().toString();
final var entity = ImmutableStoreEntity.builder()
.id(id)
.hash(asset.getHash())
.body(asset.getCommands())
.bodyType(asset.getBodyType())
.build();
entities.put(id, entity);
}
});
list(location.getDumpRegex()).stream().forEach(r -> {
final Map order = Map.of(
AstBodyType.DT, 1,
AstBodyType.FLOW_TASK, 2,
AstBodyType.FLOW, 3);
migLog
.append("Loading assets from dump: " + r.getFilename()).append(System.lineSeparator());
final var assets = new ArrayList<>(readDump(readContents(r)).getValue());
assets.sort((AstSource o1, AstSource o2) ->
Integer.compare(order.get(o1.getBodyType()), order.get(o2.getBodyType()))
);
for(final var asset : assets) {
migLog.append(" - ")
.append(asset.getId()).append("/").append(asset.getBodyType()).append("/").append(asset.getHash())
.append(System.lineSeparator());
final var entity = ImmutableStoreEntity.builder()
.id(asset.getId())
.hash(asset.getHash())
.body(asset.getCommands())
.bodyType(asset.getBodyType())
.build();
entities.put(entity.getId(), entity);
}
});
migLog.append(System.lineSeparator());
// Decision tables
list(location.getDtRegex()).stream().forEach(r -> {
final var entity = readStoreEntity(r).bodyType(AstBodyType.DT).build();
migLog.append(" - ")
.append(entity.getId()).append("/").append(entity.getBodyType()).append("/").append(entity.getHash())
.append(System.lineSeparator());
entities.put(entity.getId(), entity);
});
// Flow tasks
list(location.getFlowTaskRegex()).stream().forEach(r -> {
final var entity = readStoreEntity(r).bodyType(AstBodyType.FLOW_TASK).build();
migLog.append(" - ")
.append(entity.getId()).append("/").append(entity.getBodyType()).append("/").append(entity.getHash())
.append(System.lineSeparator());
entities.put(entity.getId(), entity);
});
// Flow
list(location.getFlowRegex()).stream().forEach(r -> {
final var entity = readStoreEntity(r).bodyType(AstBodyType.FLOW).build();
migLog.append(" - ")
.append(entity.getId()).append("/").append(entity.getBodyType()).append("/").append(entity.getHash())
.append(System.lineSeparator());
entities.put(entity.getId(), entity);
});
LOGGER.debug(migLog.toString());
return new HdesInMemoryStore(entities);
}
}
@Override
public HistoryQuery history() {
throw new IllegalArgumentException("not implemented");
}
@Override
public StoreRepoBuilder repo() {
throw new IllegalArgumentException("not implemented");
}
@Override
public Uni> batch(ImportStoreEntity batchType) {
throw new IllegalArgumentException("not implemented");
}
@Override
public String getRepoName() {
return "in-memory";
}
@Override
public String getHeadName() {
return "in-memory";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy