Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.synapse.core.SynapseEnvironment;
import org.apache.synapse.mediators.Value;
import org.apache.synapse.registry.Registry;
import org.apache.synapse.util.DynamicControlOperationResult;
import org.apache.synapse.util.xpath.SynapseXPath;
import org.jaxen.JaxenException;
import org.wso2.securevault.SecretResolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import org.apache.synapse.aspects.flow.statistics.data.artifact.ArtifactHolder;
import org.apache.synapse.commons.util.PropertyHelper;
import org.apache.synapse.core.SynapseEnvironment;
import org.apache.synapse.registry.Registry;
import org.apache.synapse.util.DynamicControlOperationResult;
import org.apache.synapse.startup.AbstractStartup;
import org.apache.synapse.startup.tasks.MessageInjector;
import org.apache.synapse.task.SynapseTaskManager;
Expand All @@ -54,7 +56,7 @@ public class StartUpController extends AbstractStartup implements AspectConfigur
private static final Log logger = LogFactory.getLog(StartUpController.class.getName());

private SynapseEnvironment synapseEnvironment;

private TaskDescription taskDescription;

private SynapseTaskManager synapseTaskManager;
Expand All @@ -63,6 +65,15 @@ public class StartUpController extends AbstractStartup implements AspectConfigur

private Object task = null;

private Registry registry;

private enum StartUpControllerState {
INITIAL, ACTIVE, INACTIVE
}

private static final String REG_STARTUP_CONTROLLER_BASE_PATH = "/repository/components/org.apache.synapse.startup/";
private static final String STARTUP_CONTROLLER_STATE = "TASK_STATE";

Comment on lines +70 to +76
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd modules/core/src/main/java/org/apache/synapse/startup/quartz && wc -l StartUpController.java

Repository: wso2/wso2-synapse

Length of output: 87


🏁 Script executed:

# Search for INITIAL state usage in StartUpController.java
rg -n "INITIAL" modules/core/src/main/java/org/apache/synapse/startup/quartz/StartUpController.java

Repository: wso2/wso2-synapse

Length of output: 97


🏁 Script executed:

# Find setStartupControllerStateInRegistry method
rg -n -A 10 "setStartupControllerStateInRegistry" modules/core/src/main/java/org/apache/synapse/startup/quartz/StartUpController.java

Repository: wso2/wso2-synapse

Length of output: 1873


🏁 Script executed:

# Search for task name assignments and validation
rg -n -C 3 "getName\(\)|setName|TaskDescription" modules/core/src/main/java/org/apache/synapse/startup/quartz/StartUpController.java

Repository: wso2/wso2-synapse

Length of output: 10296


🏁 Script executed:

# Check TaskDescription class for name validation
fd TaskDescription.java | head -5 | xargs -I {} wc -l {}

Repository: wso2/wso2-synapse

Length of output: 137


🏁 Script executed:

# Search for where task names are used in registry paths
rg -n "REG_STARTUP_CONTROLLER_BASE_PATH" modules/core/src/main/java/org/apache/synapse/startup/quartz/StartUpController.java

Repository: wso2/wso2-synapse

Length of output: 292


🏁 Script executed:

# Examine TaskDescription class for name validation
fd TaskDescription.java -type f | xargs cat | head -100

Repository: wso2/wso2-synapse

Length of output: 231


🏁 Script executed:

# Check if there's any name validation in TaskDescription setName method
rg -n -A 5 "setName\s*\(" modules/tasks/src/main/java/org/apache/synapse/task/TaskDescription.java

Repository: wso2/wso2-synapse

Length of output: 257


🏁 Script executed:

# Check the entire setName method and getName method
rg -n -B 2 -A 8 "public.*setName|public.*getName" modules/tasks/src/main/java/org/apache/synapse/task/TaskDescription.java

Repository: wso2/wso2-synapse

Length of output: 461


🏁 Script executed:

# Search for any task name validation or constraints in the codebase
rg -n "TaskDescription|task.*name.*valid|task.*name.*constraint" modules/tasks/src/main/java/org/apache/synapse/task/ --type java | grep -i "valid\|constraint\|sanitize\|name" | head -20

Repository: wso2/wso2-synapse

Length of output: 3102


🏁 Script executed:

# Check the validateTaskDescription method
rg -n -A 15 "validateTaskDescription" modules/tasks/src/main/java/org/apache/synapse/task/TaskDescriptionRepository.java

Repository: wso2/wso2-synapse

Length of output: 761


🏁 Script executed:

# Also check if task names come from configuration files or user input
rg -n "TaskDescription\(\)|setName|taskName.*=" modules/core/src/main/java/org/apache/synapse/startup/ --type-list | head -30

Repository: wso2/wso2-synapse

Length of output: 450


🏁 Script executed:

# Search for TaskDescription instantiation to see where names come from
rg -n -B 2 -A 2 "new TaskDescription" modules/ --type-list | head -50

Repository: wso2/wso2-synapse

Length of output: 450


🏁 Script executed:

# Check validateName and validateUniqueness methods
rg -n -A 10 "private void validateName|private void validateUniqueness" modules/tasks/src/main/java/org/apache/synapse/task/TaskDescriptionRepository.java

Repository: wso2/wso2-synapse

Length of output: 756


🏁 Script executed:

# Search for where TaskDescription names are assigned in configuration parsing
rg -n "setName\|getName" modules/core/src/main/java/org/apache/synapse/config/xml/ | grep -i task | head -20

Repository: wso2/wso2-synapse

Length of output: 43


🏁 Script executed:

# Check if task names are parsed from XML configuration
fd -e xml modules/core/src/main/resources | head -5 | xargs grep -l "task\|startup" 2>/dev/null | head -3

Repository: wso2/wso2-synapse

Length of output: 490


🏁 Script executed:

# Check for task configuration parsing to see if names come from user input
rg -n "task.*name\|Task.*name" modules/core/src/main/java/org/apache/synapse/config/xml/StartupFactoryDeserializer.java

Repository: wso2/wso2-synapse

Length of output: 189


🏁 Script executed:

# Look at how task startup elements are configured
fd StartupFactoryDeserializer.java | xargs cat | head -150

Repository: wso2/wso2-synapse

Length of output: 43


🏁 Script executed:

# Check Registry interface for constraints on resource paths
fd Registry.java | xargs cat | grep -A 5 "newNonEmptyResource\|interface\|class"

Repository: wso2/wso2-synapse

Length of output: 3178


🏁 Script executed:

# Check what characters are allowed/constrained in registry paths
rg -n "path.*valid\|path.*sanitize\|special.*char" modules/ -i | head -20

Repository: wso2/wso2-synapse

Length of output: 43


🏁 Script executed:

# Look at the actual registry implementation details for path handling
fd -e java | xargs rg -l "newNonEmptyResource" | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && grep -A 15 "newNonEmptyResource" {}'

Repository: wso2/wso2-synapse

Length of output: 3989


🏁 Script executed:

# Check if task names are used directly from user configuration (XML/YAML)
rg -n "taskName\|task.*name" modules/core/src/main/java/org/apache/synapse/config/ | grep -i "xml\|parse\|config" | head -15

Repository: wso2/wso2-synapse

Length of output: 43


🏁 Script executed:

# Check if there are any test cases or examples showing task names with special characters
rg -n "setName\|getName" modules/core/src/test modules/tasks/src/test -i | grep -i "task.*name\|special\|char\|path" | head -20

Repository: wso2/wso2-synapse

Length of output: 43


🏁 Script executed:

# Look for task configuration examples in test resources
fd -e xml modules/*/src/test/resources | xargs grep -l "task\|startup" | head -3 | xargs cat | grep -A 2 -B 2 "name" | head -40

Repository: wso2/wso2-synapse

Length of output: 502


🏁 Script executed:

# Search for any error handling or issues with registry paths containing special characters
rg -n "resource.*path\|registry.*path" modules/core/src/main/java/org/apache/synapse/registry/ -A 3 | head -40

Repository: wso2/wso2-synapse

Length of output: 43


🏁 Script executed:

# Check if there are any path sanitization utilities in the codebase
rg -n "sanitize\|escape.*path\|encode.*path" modules/ -i | head -15

Repository: wso2/wso2-synapse

Length of output: 43


🏁 Script executed:

# Look at where task names are parsed from configuration - likely XML parsers
fd StaxBuilder.java | xargs cat 2>/dev/null | grep -A 10 "task\|startup" | head -50

Repository: wso2/wso2-synapse

Length of output: 43


Remove the unused INITIAL state or document its purpose.

The INITIAL state in the enum is never used in the code. Only ACTIVE and INACTIVE states are persisted to the registry. Either remove INITIAL if it's not needed, or document its purpose if it represents a default/uninitialized state.

Regarding registry path construction at line 269 (REG_STARTUP_CONTROLLER_BASE_PATH + getName()): while task name validation only enforces non-null and non-empty constraints without character restrictions, the current approach mirrors patterns used elsewhere in the codebase (e.g., ScheduledMessageProcessor, InboundEndpoint). If task names are controlled through configuration schemas, this may be acceptable, but consider documenting this assumption.

🤖 Prompt for AI Agents
In
modules/core/src/main/java/org/apache/synapse/startup/quartz/StartUpController.java
around lines 70-76, the enum StartUpControllerState declares INITIAL which is
never referenced and should be removed to avoid dead code, or if intended as a
default/uninitialized marker add a short Javadoc on the enum explaining its
purpose and where it would be used; additionally, add a brief comment near the
REG_STARTUP_CONTROLLER_BASE_PATH + getName() usage (around line ~269)
documenting the assumption that task names are validated via configuration
schemas and may contain characters used directly in registry paths (or introduce
explicit sanitization if that assumption is false).

public QName getTagQName() {
return SimpleQuartzFactory.TASK;
}
Expand All @@ -82,7 +93,7 @@ public void destroy(boolean removeTask) {
//Need to re initialize startup controller to support updates from source view
if (!synapseTaskManager.isInitialized() && synapseEnvironment != null) {
init(synapseEnvironment);
}
}
if (synapseTaskManager.isInitialized()) {
TaskScheduler taskScheduler = synapseTaskManager.getTaskScheduler();
if (taskScheduler != null && taskScheduler.isTaskSchedulerInitialized() && removeTask) {
Expand Down Expand Up @@ -137,6 +148,128 @@ public boolean activateTask() {
return taskScheduler.resumeTask(taskDescription.getName());
}

/**
* Activates the startup controller task.
* <p>
* This method synchronizes access to ensure thread safety while activating the startup controller task.
* It calls the underlying to perform the activation logic.
* If the activation is successful, updates the startup controller task's state in the registry
* to {@link StartUpController.StartUpControllerState#ACTIVE}
* </p>
*/
public synchronized DynamicControlOperationResult activate() {
String errorMessage = "";
boolean isSuccess = false;
logger.info("Activating the Task: " + getName());
try {
if (this.activateTask()) {
logger.info("Task [" + getName() + "] is successfully activated.");
setStartupControllerStateInRegistry(StartUpController.StartUpControllerState.ACTIVE);
isSuccess = true;
} else {
errorMessage = "Failed to activate the Task: " + getName();
logger.error(errorMessage);
}
} catch (UnsupportedOperationException e) {
errorMessage = "Activate operation is not supported for the Task " + getName();
logger.warn(errorMessage, e);
} catch (Exception e) {
errorMessage = "Failed to activate the Task: " + getName();
logger.error(errorMessage, e);
}

return new DynamicControlOperationResult(isSuccess, errorMessage);
}

/**
* Deactivates the startup controller task.
* <p>
* This method synchronizes access to ensure thread safety while deactivating the startup controller task.
* It calls the underlying to perform the deactivation logic.
* If the deactivation is successful, the method updates the startup controller task's state in the
* registry to {@link StartUpController.StartUpControllerState#INACTIVE}.
* </p>
*/
public synchronized DynamicControlOperationResult deactivate() {
String errorMessage = "";
boolean isSuccess = false;
logger.info("Deactivating the Task: " + getName());

try {
if (this.deactivateTask()) {
logger.info("Task [" + getName() + "] is successfully deactivated.");
setStartupControllerStateInRegistry(StartUpController.StartUpControllerState.INACTIVE);
isSuccess = true;
} else {
errorMessage = "Failed to deactivate the Task: " + getName();
logger.error(errorMessage);
}
} catch (UnsupportedOperationException e) {
errorMessage = "Deactivate operation is not supported for the Task: " + getName();
logger.warn(errorMessage, e);
} catch (Exception e) {
errorMessage = "Failed to deactivate the Task: " + getName();
logger.error(errorMessage, e);
}
return new DynamicControlOperationResult(isSuccess, errorMessage);
}

/**
* Trigger the startup controller task.
* <p>
* This method synchronizes access to ensure thread safety while trigger the startup controller task.
* It calls the underlying to perform the task trigger logic.
* </p>
*/
public synchronized DynamicControlOperationResult trigger() {
String errorMessage = "";
boolean isSuccess = false;
logger.info("Triggering the Task: " + getName());

try {
if (this.isTaskActive()) {
if (task instanceof Task) {
((Task) task).execute();
logger.info("Task [" + getName() + "] is successfully triggered.");
isSuccess = true;
} else {
errorMessage = "Cannot trigger the task: " + getName() +
". Task implementation does not implement Task interface.";
logger.error(errorMessage);
}
} else {
errorMessage = "Cannot trigger the task: " + getName() + ". The task is not active";
logger.error(errorMessage);
}
} catch (UnsupportedOperationException e) {
errorMessage = "Trigger operation is not supported for the Task: " + getName();
logger.warn(errorMessage, e);
} catch (Exception e) {
errorMessage = "Failed to trigger the Task: " + getName();
logger.error(errorMessage, e);
}
return new DynamicControlOperationResult(isSuccess, errorMessage);
}


/**
* Updates the state of the startup controller task in the registry.
*
* <p>This method ensures that the state of the startup controller task is persisted in
* the registry for future reference. If the registry is unavailable and state
* preservation is enabled, a warning is logged, and the state will not be updated.
* </p>
* @param state the {@link StartUpController.StartUpControllerState} to be saved in the registry
*/
private void setStartupControllerStateInRegistry(StartUpController.StartUpControllerState state) {
if (Objects.isNull(registry)) {
logger.warn("Registry not available! The state of the Task will not be saved.");
return;
}
registry.newNonEmptyResource(REG_STARTUP_CONTROLLER_BASE_PATH + getName(), false, "text/plain",
state.toString(), STARTUP_CONTROLLER_STATE);
}

/**
* Checks if the associated task is currently active.
*
Expand All @@ -159,6 +292,7 @@ public boolean isTaskActive() {

public void init(SynapseEnvironment synapseEnvironment) {
this.synapseEnvironment = synapseEnvironment;
registry = synapseEnvironment.getSynapseConfiguration().getRegistry();
if (taskDescription == null) {
handleException("Error while initializing the startup. TaskDescription is null.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* under the License.
*/

package org.apache.synapse.inbound;
package org.apache.synapse.util;

public class DynamicControlOperationResult {
private final boolean success;
Expand Down
Loading