/** * Return the type(s) a given stream app definition <em>could</em> have, in the * context of code completion. */ static ApplicationType[] determinePotentialTypes(StreamAppDefinition appDefinition, boolean multipleAppsInStreamDefinition) { Set<String> properties = appDefinition.getProperties().keySet(); if (properties.contains(BindingPropertyKeys.INPUT_DESTINATION)) { // Can't be source. For the purpose of completion, being the last app // (hence having BindingPropertyKeys.OUTPUT_DESTINATION not set) does NOT // guarantee we're dealing // with a sink (could be an unfinished "source | processor | processor" // stream) if (properties.contains(BindingPropertyKeys.OUTPUT_DESTINATION)) { return new ApplicationType[] { ApplicationType.processor }; } else { return new ApplicationType[] { ApplicationType.processor, ApplicationType.sink }; } } else { // Multiple apps and no binding properties indicates unbound app sequence (a,b,c) if (multipleAppsInStreamDefinition) { return new ApplicationType[] { ApplicationType.app }; } else { return new ApplicationType[] { ApplicationType.source, ApplicationType.app }; } } }
/** * Return the {@link ApplicationType} for a {@link AppDefinition} in the context of a * defined stream. * * @param appDefinition the app for which to determine the type * @return {@link ApplicationType} for the given app * @throws CannotDetermineApplicationTypeException Thrown if the * {@link ApplicationType} cannot be determined */ public static ApplicationType determineApplicationType(StreamAppDefinition appDefinition) { // Parser has already taken care of source/sink destinations, etc boolean hasOutput = appDefinition.getProperties().containsKey(BindingPropertyKeys.OUTPUT_DESTINATION); boolean hasInput = appDefinition.getProperties().containsKey(BindingPropertyKeys.INPUT_DESTINATION); if (hasInput && hasOutput) { return ApplicationType.processor; } else if (hasInput) { return ApplicationType.sink; } else if (hasOutput) { return ApplicationType.source; } else { throw new CannotDetermineApplicationTypeException( appDefinition.getName() + " had neither input nor " + "output set"); } } }
/** * Return the {@link ApplicationType} for a {@link AppDefinition} in the context of a * defined stream. * * @param appDefinition the app for which to determine the type * @return {@link ApplicationType} for the given app * @throws CannotDetermineApplicationTypeException Thrown if the * {@link ApplicationType} cannot be determined */ public static ApplicationType determineApplicationType(StreamAppDefinition appDefinition) { // Parser has already taken care of source/sink destinations, etc boolean hasOutput = appDefinition.getProperties().containsKey(BindingPropertyKeys.OUTPUT_DESTINATION); boolean hasInput = appDefinition.getProperties().containsKey(BindingPropertyKeys.INPUT_DESTINATION); if (hasInput && hasOutput) { return ApplicationType.processor; } else if (hasInput) { return ApplicationType.sink; } else if (hasOutput) { return ApplicationType.source; } else { throw new CannotDetermineApplicationTypeException( appDefinition.getName() + " had neither input nor " + "output set"); } } }
/** * Return a new app definition where definition-time and deploy-time properties have been * merged and short form parameters have been expanded to their long form (amongst the * whitelisted supported properties of the app) if applicable. */ /* default */ AppDefinition mergeAndExpandAppProperties(StreamAppDefinition original, Resource metadataResource, Map<String, String> appDeployTimeProperties) { Map<String, String> merged = new HashMap<>(original.getProperties()); merged.putAll(appDeployTimeProperties); merged = this.whitelistProperties.qualifyProperties(merged, metadataResource); merged.putIfAbsent(StreamPropertyKeys.METRICS_PROPERTIES, "spring.application.name,spring.application.index," + "spring.cloud.application.*,spring.cloud.dataflow.*"); merged.putIfAbsent(StreamPropertyKeys.METRICS_TRIGGER_INCLUDES, "integration**"); return new AppDefinition(original.getName(), merged); }
/** * Return a new app definition where definition-time and deploy-time properties have been * merged and short form parameters have been expanded to their long form (amongst the * whitelisted supported properties of the app) if applicable. */ /* default */ AppDefinition mergeAndExpandAppProperties(StreamAppDefinition original, Resource metadataResource, Map<String, String> appDeployTimeProperties) { Map<String, String> merged = new HashMap<>(original.getProperties()); merged.putAll(appDeployTimeProperties); merged = this.whitelistProperties.qualifyProperties(merged, metadataResource); merged.putIfAbsent(StreamPropertyKeys.METRICS_PROPERTIES, "spring.application.name,spring.application.index," + "spring.cloud.application.*,spring.cloud.dataflow.*"); merged.putIfAbsent(StreamPropertyKeys.METRICS_TRIGGER_INCLUDES, "integration**"); return new AppDefinition(original.getName(), merged); }
@Override public boolean addProposals(String text, StreamDefinition parseResult, int detailLevel, List<CompletionProposal> collector) { Set<String> propertyNames = new HashSet<>( parseResult.getDeploymentOrderIterator().next().getProperties().keySet()); propertyNames.removeAll(CompletionUtils.IMPLICIT_PARAMETER_NAMES); if (text.endsWith(" ") || propertyNames.isEmpty()) { return false; } String propertyName = recoverPropertyName(text); StreamAppDefinition lastApp = parseResult.getDeploymentOrderIterator().next(); String alreadyTyped = lastApp.getProperties().get(propertyName); AppRegistration lastAppRegistration = this.collectorSupport.findAppRegistration(lastApp.getName(), CompletionUtils.determinePotentialTypes(lastApp, parseResult.getAppDefinitions().size() > 1)); if (lastAppRegistration != null) { return this.collectorSupport.addAlreadyTypedValueHintsProposals(text, lastAppRegistration, collector, propertyName, valueHintProviders, alreadyTyped); } return false; }
@Override public boolean addProposals(String text, StreamDefinition streamDefinition, int detailLevel, List<CompletionProposal> collector) { StreamAppDefinition lastApp = streamDefinition.getDeploymentOrderIterator().next(); AppRegistration appRegistration = this.collectorSupport.findAppRegistration(lastApp.getName(), CompletionUtils.determinePotentialTypes(lastApp,streamDefinition.getAppDefinitions().size() > 1)); if (appRegistration != null) { Set<String> alreadyPresentOptions = new HashSet<>(lastApp.getProperties().keySet()); this.collectorSupport.addPropertiesProposals(text, "", appRegistration, alreadyPresentOptions, collector, detailLevel); } return false; } }
Map<String, String> props = appDefinition.getProperties(); String inputDestination = props.get(BindingPropertyKeys.INPUT_DESTINATION); String outputDestination = props.get(BindingPropertyKeys.OUTPUT_DESTINATION);
@Override public void addProposals(String dsl, CheckPointedParseException exception, int detailLevel, List<CompletionProposal> collector) { String safe = exception.getExpressionStringUntilCheckpoint(); StreamDefinition streamDefinition = new StreamDefinition("__dummy", safe); StreamAppDefinition lastApp = streamDefinition.getDeploymentOrderIterator().next(); AppRegistration appRegistration = this.collectorSupport.findAppRegistration(lastApp.getName(), CompletionUtils.determinePotentialTypes(lastApp, streamDefinition.getAppDefinitions().size() > 1)); if (appRegistration != null) { Set<String> alreadyPresentOptions = new HashSet<>(lastApp.getProperties().keySet()); this.collectorSupport.addPropertiesProposals(safe, "", appRegistration, alreadyPresentOptions, collector, detailLevel); } } }
Set<String> parameterNames = new HashSet<>(lastApp.getProperties().keySet()); parameterNames.removeAll(CompletionUtils.IMPLICIT_PARAMETER_NAMES); if (!parameterNames.isEmpty() || !text.endsWith(lastApp.getName())) {
/** * Redacts sensitive property values in a stream. * * @param streamDefinition the stream definition to sanitize * @return Stream definition text that has sensitive data redacted. */ public String sanitizeStream(StreamDefinition streamDefinition) { List<StreamAppDefinition> sanitizedAppDefinitions = streamDefinition.getAppDefinitions().stream() .map(app -> StreamAppDefinition.Builder .from(app) .setProperties(this.sanitizeProperties(app.getProperties())) .build(streamDefinition.getName()) ).collect(Collectors.toList()); return this.streamDslConverter.toDsl(sanitizedAppDefinitions); }
@Override public void addProposals(String dsl, CheckPointedParseException exception, int detailLevel, List<CompletionProposal> collector) { String safe = exception.getExpressionStringUntilCheckpoint(); StreamDefinition streamDefinition = new StreamDefinition("__dummy", safe); StreamAppDefinition lastApp = streamDefinition.getDeploymentOrderIterator().next(); AppRegistration appRegistration = this.collectorSupport.findAppRegistration(lastApp.getName(), CompletionUtils.determinePotentialTypes(lastApp, streamDefinition.getAppDefinitions().size() > 1)); if (appRegistration != null) { String startsWith = ProposalsCollectorSupportUtils.computeStartsWith(exception); Set<String> alreadyPresentOptions = new HashSet<>(lastApp.getProperties().keySet()); this.collectorSupport.addPropertiesProposals(safe, startsWith, appRegistration, alreadyPresentOptions, collector, detailLevel); } } }
/** * Redacts sensitive property values in a stream. * * @param streamDefinition the stream definition to sanitize * @return Stream definition text that has sensitive data redacted. */ public String sanitizeStream(StreamDefinition streamDefinition) { List<StreamAppDefinition> sanitizedAppDefinitions = streamDefinition.getAppDefinitions().stream() .map(app -> StreamAppDefinition.Builder .from(app) .setProperties(this.sanitizeProperties(app.getProperties())) .build(streamDefinition.getName()) ).collect(Collectors.toList()); return this.streamDslConverter.toDsl(sanitizedAppDefinitions); }
/** * Create a new builder that is initialized with properties of the given * definition. Useful for "mutating" a definition by building a slightly different * copy. * * @param definition the StreamAppDefinition to create a new Builder instance with * stream name, registeredAppName, label, and properties populated * @return a StreamAppDefinition builder */ public static Builder from(StreamAppDefinition definition) { Builder builder = new Builder(); builder.setStreamName(definition.getStreamName()).setRegisteredAppName(definition.getRegisteredAppName()) .setApplicationType(definition.getApplicationType()) .setLabel(definition.getName()).addProperties(definition.getProperties()); return builder; }