Is there a simple way of taking the value of a property and then copy it to another property with certain characters replaced?
Say propA=This is a value. I want to replace all the spaces in it into underscores, resulting in propB=This_is_a_value.
Here is the solution without scripting and no external jars like ant-conrib:
The trick is to use ANT's resources:
There is one resource type called "propertyresource" which is like a source file, but provides an stream from the string value of this resource. So you can load it and use it in any task like "copy" that accepts files
There is also the task "loadresource" that can load any resource to a property (e.g., a file), but this one could also load our propertyresource. This task allows for filtering the input by applying some token transformations. Finally the following will do what you want:
<loadresource property="propB">
<propertyresource name="propA"/>
<filterchain>
<tokenfilter>
<filetokenizer/>
<replacestring from=" " to="_"/>
</tokenfilter>
</filterchain>
</loadresource>
This one will replace all " " in propA by "_" and place the result in propB. "filetokenizer" treats the whole input stream (our property) as one token and appies the string replacement on it.
You can do other fancy transformations using other tokenfilters: http://ant.apache.org/manual/Types/filterchain.html
Use the propertyregex task from Ant Contrib.
I think you want:
<propertyregex property="propB"
input="${propA}"
regexp=" "
replace="_"
global="true" />
Unfortunately the examples given aren't terribly clear, but it's worth trying that. You should also check what happens if there aren't any underscores - you may need to use the defaultValue option as well.
If ant-contrib isn't an option, here's a portable solution for Java 1.6 and later:
<property name="before" value="This is a value"/>
<script language="javascript">
var before = project.getProperty("before");
project.setProperty("after", before.replaceAll(" ", "_"));
</script>
<echo>after=${after}</echo>
In case you want a solution that does use Ant built-ins only, consider this:
<target name="replace-spaces">
<property name="propA" value="This is a value" />
<echo message="${propA}" file="some.tmp.file" />
<loadfile property="propB" srcFile="some.tmp.file">
<filterchain>
<tokenfilter>
<replaceregex pattern=" " replace="_" flags="g"/>
</tokenfilter>
</filterchain>
</loadfile>
<echo message="$${propB} = "${propB}"" />
</target>
Output is ${propB} = "This_is_a_value"
Use some external app like sed:
<exec executable="sed" inputstring="${wersja}" outputproperty="wersjaDot">
<arg value="s/_/./g"/>
</exec>
<echo>${wersjaDot}</echo>
If you run Windows get it googling for "gnuwin32 sed".
The command s/_/./g replaces every _ with .
This script goes well under windows. Under linux arg may need quoting.
Two possibilities :
via script task and builtin javascript engine (if using jdk >= 1.6)
<project>
<property name="propA" value="This is a value"/>
<script language="javascript">
project.setProperty('propB', project.getProperty('propA').
replace(" ", "_"));
</script>
<echo>$${propB} => ${propB}</echo>
</project>
or using Ant addon Flaka
<project xmlns:fl="antlib:it.haefelinger.flaka">
<property name="propA" value="This is a value"/>
<fl:let> propB := replace('${propA}', '_', ' ')</fl:let>
<echo>$${propB} => ${propB}</echo>
</project>
to overwrite exisiting property propA simply replace propB with propA
Here's a more generalized version of Uwe Schindler's answer:
You can use a macrodef to create a custom task.
<macrodef name="replaceproperty" taskname="#{taskname}">
<attribute name="src" />
<attribute name="dest" default="" />
<attribute name="replace" default="" />
<attribute name="with" default="" />
<sequential>
<loadresource property="#{dest}">
<propertyresource name="#{src}" />
<filterchain>
<tokenfilter>
<filetokenizer/>
<replacestring from="#{replace}" to="#{with}"/>
</tokenfilter>
</filterchain>
</loadresource>
</sequential>
</macrodef>
you can use this as follows:
<replaceproperty src="property1" dest="property2" replace=" " with="_"/>
this will be pretty useful if you are doing this multiple times
Adding an answer more complete example over a previous answer
<property name="propB_" value="${propA}"/>
<loadresource property="propB">
<propertyresource name="propB_" />
<filterchain>
<tokenfilter>
<replaceregex pattern="\." replace="/" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
Just an FYI for answer Replacing characters in Ant property - if you are trying to use this inside of a maven execution, you can't reference maven variables directly. You will need something like this:
...
<target>
<property name="propATemp" value="${propA}"/>
<loadresource property="propB">
<propertyresource name="propATemp" />
...
Properties can't be changed but antContrib vars (http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html ) can.
Here is a macro to do a find/replace on a var:
<macrodef name="replaceVarText">
<attribute name="varName" />
<attribute name="from" />
<attribute name="to" />
<sequential>
<local name="replacedText"/>
<local name="textToReplace"/>
<local name="fromProp"/>
<local name="toProp"/>
<property name="textToReplace" value = "${#{varName}}"/>
<property name="fromProp" value = "#{from}"/>
<property name="toProp" value = "#{to}"/>
<script language="javascript">
project.setProperty("replacedText",project.getProperty("textToReplace").split(project.getProperty("fromProp")).join(project.getProperty("toProp")));
</script>
<ac:var name="#{varName}" value = "${replacedText}"/>
</sequential>
</macrodef>
Then call the macro like:
<ac:var name="updatedText" value="${oldText}"/>
<current:replaceVarText varName="updatedText" from="." to="_" />
<echo message="Updated Text will be ${updatedText}"/>
Code above uses javascript split then join, which is faster than regex. "local" properties are passed to JavaScript so no property leakage.
Or... You can also to try Your Own Task
JAVA CODE:
class CustomString extends Task{
private String type, string, before, after, returnValue;
public void execute() {
if (getType().equals("replace")) {
replace(getString(), getBefore(), getAfter());
}
}
private void replace(String str, String a, String b){
String results = str.replace(a, b);
Project project = getProject();
project.setProperty(getReturnValue(), results);
}
..all getter and setter..
ANT SCRIPT
...
<project name="ant-test" default="build">
<target name="build" depends="compile, run"/>
<target name="clean">
<delete dir="build" />
</target>
<target name="compile" depends="clean">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes" includeantruntime="true"/>
</target>
<target name="declare" depends="compile">
<taskdef name="string" classname="CustomString" classpath="build/classes" />
</target>
<!-- Replacing characters in Ant property -->
<target name="run" depends="declare">
<property name="propA" value="This is a value"/>
<echo message="propA=${propA}" />
<string type="replace" string="${propA}" before=" " after="_" returnvalue="propB"/>
<echo message="propB=${propB}" />
</target>
CONSOLE:
run:
[echo] propA=This is a value
[echo] propB=This_is_a_value
I have 3 spring web-flows - flow1, flow2, flow3. flow2 and flow 3 have assigned parent flow1 like this :
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
parent="flow1">
In flow1 i have a global-transition and an end-state :
<end-state id="flowInterrupted" view="flowInterruptedPage"/>
<global-transitions>
<transition on-exception="com.core.exceptions.policy.InvalidPolicyContactException" to="flowInterrupted">
<evaluate expression="webFlowService.clearCurrentInterruptCause()"/>
</transition>
</global-transitions>
At some point in my application, in flow2 a subflow flow3 is called
<subflow-state id="stateInFlow2WhereSubFlow3IsDefined" subflow="flow3">
</subflow-state>
, and in flow3, an InvalidPolicyContactException is thrown. It is properly found in flow1 (as its get's to clearCurrentInterruptCause()) but later an exception is thrown, that the flowInterrupted transition is not found in flow2 - and that's true, cause it's in flow1 (where the global-transition is defined). Here is the exception :
org.springframework.webflow.engine.NoMatchingTransitionException: No transition found on occurence of event 'flowInterrupted' in state 'stateInFlow2WhereSubFlow3IsDefined' of flow 'flow2' -- valid transitional criteria are array<TransitionCriteria>[exit, contactSelected] -- likely programmer error, check the set of TransitionCriteria for this state at org.springframework.webflow.engine.TransitionableState.getRequiredTransition(TransitionableState.java:93) at org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:119)
at org.springframework.webflow.engine.SubflowState.handleEvent(SubflowState.java:116)
at org.springframework.webflow.engine.Flow.handleEvent(Flow.java:555)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:388)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.endActiveFlowSession(FlowExecutionImpl.java:412)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.endActiveFlowSession(RequestControlContextImpl.java:238)
When I change end-state id="flowInterrupted" to view-state it works fine. when it's called from other flows, that have flow1 as parent it works also fine. When I remove parent=flow1 from flow3, I wouldn't catch an exceptin on global-transition. The only problem is, when an exception is raised from a subflow.
Any help would be appreciated - I can of course put flowInterrupted state in flow2 and solve the problem, but I would like to understand, why this is happening
Thanks.
add
<transition on="flowInterrupted" to="flowInterrupted"/>
in your global transition
I'm using Spring Web Flow in my webapp and i would like to know if there is a general way to prevent some subflows to be accessed directly. These subflows are meant to be accessed just from certain flows, not directly by the url, so in these subflows i would like to check "if i was called from a flow".
is there any mechanisms to achieve it? I was looking at spring security but i couldn't find any useful feature to make this kind of restriction.
Thanks you!
You can check this by using input mapper attribute as shown below. Suppose you have a parent flow which invokes 'subflow-flow'. You need to pass an input value containing the name of the parent flow as:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
...
<subflow-state id="subflow-flow" subflow="subflow-flow">
<!--flowInitiatedBy should be different for each different parent flow-->
<input name="flowInitiatedBy" value="'parentFlowName'"/>
<transition on="invalidAccess" to="someViewWithMessage"/>
<transition on="processedSubflow" to="someOtherState"/>
</subflow-state>
...
</flow>
Then in subflow you can retrieve the parentflowname and perform the check in yourAction class. You can define subflow as:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
start-state="start">
<input name="flowInitiatedBy" type="java.lang.String"/>
<action-state id="start">
<evaluate expression="yourAction.checkAccessibility(flowRequestContext)"/>
<transition on="invalidAccess" to="verifyWhetherDraftsExists"/>
<transition on="continue" to="continueToState"/>
</action-state>
<!--define other states for continue transition -->
...
<end-state id="invalidAccess"/>
<end-state id="processedSubflow"/>
</flow>
In your action class:
public class YourAction{
...
public String checkAccessibility(RequestContext context){
String flowInitiatedBy = context.getFlowScope().get("flowInitiatedBy");
//flowInitiatedBy will be empty if initiated by url.
if(flowInitiatedBy is empty){
return "invalidAccess";
}else{
// dosomething
return "continue";
}
}
...
}
Hope this helps.
I also wish there was some kind of built-in, simple mechanism. However, I just did this a slightly different way I thought I'd share. That is, since my Subflow knows its own name, I just had the first state in the Flow configuration check whether or not the Flow ID (name) matches that hardcoded name:
<decision-state id="subOnly">
<if test="flowExecutionContext.definition.id == 'thisSubflowFlowName'" then="invalidAccess" else="mySubflowFirstState"/>
</decision-state>
Where "invalidAccess" is an end-state like the prior answer shows.
I am new to spring web flow , my requirement is return a set object to spring web flow action state by evaluating an expression .I am facing problem with below code please correct me.
<action-state id="openDocument">
<set name="requestScope.startPoint" value="requestParameters.startPoint" />
<set name="requestScope.fileName" value="requestParameters.fileName" />
<set name="requestScope.ext" value="requestParameters.ext" />
<evaluate expression="workflowController.workflowopenFile(requestScope.startPoint,requestScope.fileName,requestScope.ext)"></evaluate>
</action-state>
return the expected object from workflowopenFile() , and set it to a variable in flow with result attribute.
I solved my problem. the problem was in
add return attribute to evaluate tag . (result = "workflowSet").
In my Spring web flow app, one of my action-state transitions looks like this:
<transition on-exception="com.foo.BarException" to="barView">
<set name="flowScope.error" value="foo.bar" type="string" />
</transition>
I would like to set flowScope.error to the literal String "foo.bar", but Spring interprets this as a reference to the foo object's bar attribute. How can I force Spring to take the String literally?
I figured it out: the value needs needs to be enclosed in single quotes:
<set name="flowScope.error" value="'foo.bar'" type="string" />