This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit 51ea8b0cb3f8c4bbaba04406e5f143352edc6e78 Author: Alex Heneveld <[email protected]> AuthorDate: Fri Nov 4 16:28:42 2022 +0000 add load workflow step --- .../core/workflow/steps/LoadWorkflowStep.java | 105 +++++++++++++++++++++ .../core/workflow/steps/SetSensorWorkflowStep.java | 2 +- .../apache/brooklyn/util/core/ResourceUtils.java | 11 +++ .../brooklyn/core/workflow/WorkflowBasicTest.java | 1 + .../workflow/WorkflowInputOutputExtensionTest.java | 9 ++ karaf/init/src/main/resources/catalog.bom | 7 +- .../org/apache/brooklyn/util/stream/Streams.java | 14 ++- 7 files changed, 146 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/LoadWorkflowStep.java b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/LoadWorkflowStep.java new file mode 100644 index 0000000000..73ccd2afb8 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/LoadWorkflowStep.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.brooklyn.core.workflow.steps; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.reflect.TypeToken; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils; +import org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonType; +import org.apache.brooklyn.core.workflow.WorkflowStepDefinition; +import org.apache.brooklyn.core.workflow.WorkflowStepInstanceExecutionContext; +import org.apache.brooklyn.util.collections.CollectionMerger; +import org.apache.brooklyn.util.collections.MutableList; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.core.ResourceUtils; +import org.apache.brooklyn.util.core.flags.TypeCoercions; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.javalang.Boxing; +import org.apache.brooklyn.util.text.QuotedStringTokenizer; +import org.apache.brooklyn.util.text.Strings; +import org.apache.brooklyn.util.yaml.Yamls; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.Charset; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class LoadWorkflowStep extends WorkflowStepDefinition { + + private static final Logger log = LoggerFactory.getLogger(LoadWorkflowStep.class); + + public static final String SHORTHAND = + "[ \"charset\" ${charset} ] [ ${variable.type} ] ${variable.name} [ \"=\" ${url...} ]"; + + public static final ConfigKey<TypedValueToSet> VARIABLE = ConfigKeys.newConfigKey(TypedValueToSet.class, "variable"); + public static final ConfigKey<Object> URL = ConfigKeys.newConfigKey(Object.class, "url"); + public static final ConfigKey<String> CHARSET = ConfigKeys.newStringConfigKey("charset"); + + @Override + public void populateFromShorthand(String expression) { + populateFromShorthandTemplate(SHORTHAND, expression, true); + } + + @Override + public void validateStep() { + super.validateStep(); + if (!input.containsKey(VARIABLE.getName())) { + throw new IllegalArgumentException("Variable name is required"); + } + if (!input.containsKey(URL.getName())) { + throw new IllegalArgumentException("url is required"); + } + } + + @Override + protected Object doTaskBody(WorkflowStepInstanceExecutionContext context) { + TypedValueToSet variable = context.getInput(VARIABLE); + if (variable ==null) throw new IllegalArgumentException("Variable name is required"); + String name = context.resolve(variable.name, String.class); + if (Strings.isBlank(name)) throw new IllegalArgumentException("Variable name is required"); + TypeToken<?> type = context.lookupType(variable.type, () -> TypeToken.of(String.class)); + + Object url = context.getInput(URL); + + ResourceUtils r = ResourceUtils.create(context.getEntity()); + + String csName = context.getInput(CHARSET); + String data; + if (Strings.isNonBlank(csName)) { + data = r.getResourceAsString("" + url, Charset.forName(csName)); + } else { + data = r.getResourceAsString("" + url); + } + Object resolvedValue = context.resolve(data, type); + + Object oldValue = context.getWorkflowExectionContext().getWorkflowScratchVariables().put(name, resolvedValue); + + if (oldValue!=null) context.noteOtherMetadata("Previous value", oldValue); + return context.getPreviousStepOutput(); + } +} diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/SetSensorWorkflowStep.java b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/SetSensorWorkflowStep.java index f22cc4f517..36154b7f7b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/SetSensorWorkflowStep.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/SetSensorWorkflowStep.java @@ -52,8 +52,8 @@ public class SetSensorWorkflowStep extends WorkflowStepDefinition { String sensorName = context.resolve(sensor.name, String.class); if (Strings.isBlank(sensorName)) throw new IllegalArgumentException("Sensor name is required"); TypeToken<?> type = context.lookupType(sensor.type, () -> TypeToken.of(Object.class)); - Object resolvedValue = context.getInput(VALUE.getName(), type); Entity entity = sensor.entity; + Object resolvedValue = context.getInput(VALUE.getName(), type); if (entity==null) entity = context.getEntity(); AttributeSensor<Object> s = (AttributeSensor<Object>) Sensors.newSensor(type, sensorName); Object oldValue = entity.sensors().set( s, resolvedValue); diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java index 1191b05125..2ec9da8b6e 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java @@ -30,6 +30,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; +import java.nio.charset.Charset; import java.util.List; import java.util.NoSuchElementException; import java.util.function.Supplier; @@ -538,6 +539,16 @@ public class ResourceUtils { } } + /** takes {@link #getResourceFromUrl(String)} and reads fully, into a string */ + public String getResourceAsString(String url, Charset charset) { + try { + return Streams.readFullyStringAndClose(getResourceFromUrl(url), charset); + } catch (Exception e) { + log.debug("ResourceUtils got error reading "+url+(context==null?"":" "+context)+" (rethrowing): "+e); + throw Throwables.propagate(e); + } + } + /** @see #checkUrlExists(String, String) */ public String checkUrlExists(String url) { return checkUrlExists(url, null); diff --git a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java index 8de3bf29b9..9788b088b4 100644 --- a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java @@ -85,6 +85,7 @@ public class WorkflowBasicTest extends BrooklynMgmtUnitTestSupport { addRegisteredTypeBean(mgmt, "set-sensor", SetSensorWorkflowStep.class); addRegisteredTypeBean(mgmt, "clear-sensor", ClearSensorWorkflowStep.class); addRegisteredTypeBean(mgmt, "let", SetVariableWorkflowStep.class); + addRegisteredTypeBean(mgmt, "load", LoadWorkflowStep.class); addRegisteredTypeBean(mgmt, "set-workflow-variable", SetVariableWorkflowStep.class); addRegisteredTypeBean(mgmt, "clear-workflow-variable", ClearVariableWorkflowStep.class); addRegisteredTypeBean(mgmt, "wait", WaitWorkflowStep.class); diff --git a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowInputOutputExtensionTest.java b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowInputOutputExtensionTest.java index 33ebd0242a..3f335b089d 100644 --- a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowInputOutputExtensionTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowInputOutputExtensionTest.java @@ -491,4 +491,13 @@ public class WorkflowInputOutputExtensionTest extends BrooklynMgmtUnitTestSuppor "1", "3", "4", "12" )); } + + @Test + public void testLoadData() throws Exception { + Object output = invokeWorkflowStepsWithLogging(MutableList.of( + "load x = classpath://hello-world.txt", + "return ${x}")); + Asserts.assertStringContains((String)output, "The file hello-world.war contains its source code."); + } + } diff --git a/karaf/init/src/main/resources/catalog.bom b/karaf/init/src/main/resources/catalog.bom index bd9472ea1d..b5cbfbfbdd 100644 --- a/karaf/init/src/main/resources/catalog.bom +++ b/karaf/init/src/main/resources/catalog.bom @@ -19,7 +19,7 @@ brooklyn.catalog: version: "1.1.0-SNAPSHOT" # BROOKLYN_VERSION items: - # provides aliases for the most common items + # provides aliases for the most common items # (used to import the other bundles but now this is done by dist feature catalog-core) - id: server iconUrl: classpath://brooklyn/icons/server.svg @@ -129,6 +129,11 @@ brooklyn.catalog: itemType: bean item: type: org.apache.brooklyn.core.workflow.steps.WaitWorkflowStep + - id: load + format: java-type-name + itemType: bean + item: + type: org.apache.brooklyn.core.workflow.steps.LoadWorkflowStep - id: return format: java-type-name itemType: bean diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java b/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java index a14f8b2feb..c6456f2e8c 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java @@ -86,6 +86,7 @@ public class Streams { } public static Reader reader(InputStream stream, Charset charset) { + if (charset==null) return new InputStreamReader(stream); return new InputStreamReader(stream, charset); } @@ -128,8 +129,19 @@ public class Streams { } public static String readFullyStringAndClose(InputStream is) { + return readFullyStringAndClose(is, null); + } + + /** + * Consider using {@link #readFullyStringAndClose(InputStream)} instead. + */ + public static String readFullyString(InputStream is, Charset charset) { + return readFully(reader(is, charset)); + } + + public static String readFullyStringAndClose(InputStream is, Charset charset) { try { - return readFullyString(is); + return readFullyString(is, charset); } finally { Streams.closeQuietly(is); }
