Is there a difference when putting a null value into the context of velocity or not putting the variable at all.
VelocityContext ctx = new VelocityContext();
ctx.put("v", null);
or
VelocityContext ctx = new VelocityContext();
-- no put
It looks like there is no because velocity does not check for existance.
Instead it grabs the variable from the map and gets in both cases a null.
You can put the context into itself:
ctx.put("ctx", ctx);
and then in VTL:
#if($ctx.containsKey('v'))
...
#else
...
#end
Related
I'm having score corruption exception with construction heuristic phase with FULL_ASSERT:
java.lang.IllegalStateException: VariableListener corruption: the
entity (Task{6661-30})'s shadow variable (Task.plannedDateTime)'s
corrupted value (null) changed to uncorrupted value (2018-06-04T07:00)
after all VariableListeners were triggered without changes to the
genuine variables. Maybe the VariableListener class
(VrpTaskStartTimeListener) for that shadow variable
(Task.plannedDateTime) forgot to update it when one of its sources
changed after completedAction (Task{6661-30} {Shift{Tech1:2018-06-04}
-> Shift{Tech1:2018-06-04}}).
at
org.optaplanner.core.impl.score.director.AbstractScoreDirector.assertShadowVariablesAreNotStale(AbstractScoreDirector.java:462)
at
org.optaplanner.core.impl.solver.scope.DefaultSolverScope.assertShadowVariablesAreNotStale(DefaultSolverScope.java:140)
at
org.optaplanner.core.impl.phase.scope.AbstractPhaseScope.assertShadowVariablesAreNotStale(AbstractPhaseScope.java:171)
at
org.optaplanner.core.impl.phase.AbstractPhase.predictWorkingStepScore(AbstractPhase.java:169)
at
org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase.doStep(DefaultConstructionHeuristicPhase.java:108)
at
org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase.solve(DefaultConstructionHeuristicPhase.java:95)
at
org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:87)
at
org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:173)
at...
Now while looking at DefaultConstructionHeuristicPhase.doStep , it does:
private void doStep(ConstructionHeuristicStepScope<Solution_> stepScope) {
Move<Solution_> nextStep = stepScope.getStep();
nextStep.doMove(stepScope.getScoreDirector()); //Step-1
predictWorkingStepScore(stepScope, nextStep);
...
}
predictWorkingStepScore() calls AbstractScoreDirector.assertShadowVariablesAreNotStale() and assertShadowVariablesAreNotStale() is:
public void assertShadowVariablesAreNotStale(Score expectedWorkingScore, Object completedAction) {
SolutionDescriptor<Solution_> solutionDescriptor = getSolutionDescriptor();
//Step2
Map<Object, Map<ShadowVariableDescriptor, Object>> entityToShadowVariableValuesMap = new IdentityHashMap<>();
...
entityToShadowVariableValuesMap.put(entity, shadowVariableValuesMap);
}
//Step3
variableListenerSupport.triggerAllVariableListeners();
for (Iterator<Object> it = solutionDescriptor.extractAllEntitiesIterator(workingSolution); it.hasNext();) {
Object entity = it.next();
EntityDescriptor<Solution_> entityDescriptor
= solutionDescriptor.findEntityDescriptorOrFail(entity.getClass());
Collection<ShadowVariableDescriptor<Solution_>> shadowVariableDescriptors = entityDescriptor.getShadowVariableDescriptors();
Map<ShadowVariableDescriptor, Object> shadowVariableValuesMap = entityToShadowVariableValuesMap.get(entity);
for (ShadowVariableDescriptor shadowVariableDescriptor : shadowVariableDescriptors) {
Object newValue = shadowVariableDescriptor.getValue(entity);
Object originalValue = shadowVariableValuesMap.get(shadowVariableDescriptor);
//Step4
if (!Objects.equals(originalValue, newValue)) {
throw new IllegalStateException(VariableListener.class.getSimpleName() + " corruption:"
}
}
Here's the description, which I believe:
Step 1: execute step's move (it also executes shadow var listeners)
Step 2: get current entities shadow vars values.(Here shadow vars
wont have valid value)
Step 3: execute ShadowsVariable listehttp://example.comners(now
shadows will have right values)
Step 4: Get new values and compare
with Step2.
Now, the problem is for a custom listener on a genuine variable, here is the order:
Inverse relation shadow variable listener
Custom listener
Anchor shadow variable
What can I do to make above order such that custom listener executes last?
Configure the sources attribute of #CustomShadowVariable correctly.
There is this guarantee:
There's a variable persistence concept I have integrated multiple times:
// Standard initialiation
boolean save = true;
Map<String, Object> dataHolder;
// variables to persist
int number = 10;
String text = "I'm saved";
// Use the variables in various ways in the project
void useVariables() { ... number ... text ...}
// Function to save the variables into a datastructure and for example write them to a file
public Map<String, Object> getVariables()
{
Map<String, Object> data = new LinkedHashMap<String, Object>();
persist(data);
return(data);
}
// Function to load the variables from the datastructure
public void setVariables(Map<String, Object> data)
{
persist(data);
}
void persist(Map<String, Object> data)
{
// If the given datastructure is empty, it means data should be saved
save = (data.isEmpty());
dataHolder = data;
number = handleVariable("theNumber", number);
text = handleVariable("theText", text);
...
}
private Object handleVariable(String name, Object value)
{
// If currently saving
if(save)
dataHolder.put(name, value); // Just add to the datastructure
else // If currently writing
return(dataHolder.get(name)); // Read and return from the datastruct
return(value); // Return the given variable (no change)
}
The main benefit of this principle is that you only have a single script where you have to mention new variables you add during the development and it's one simple line per variable.
Of course you can move the handleVariable() function to a different class which also contains the "save" and "dataHolder" variables so they wont be in the main application.
Additionally you could pass meta-information, etc. for each variable required for persisting the datastructure to a file or similar by saving a custom class which contains this information plus the variable instead of the object itself.
Performance could be improved by keeping track of the order (in another datastructure when first time running through the persist() function) and using a "dataHolder" based on an array instead of a search-based map (-> use an index instead of a name-string).
However, for the first time, I have to document this and so I wondered whether this function-reuse principle has a name.
Does someone recognize this idea?
Thank you very much!
I have a table which gets its data server-side, using custom server-side initialization params which vary depending upon which report is produced. Once the table is generated, the user may open a popup in which they can add multiple additional filters on which to search. I need to be able to use the same initialization params as the original table, and add the new ones using fnServerParams.
I can't figure out how to get the original initialization params using the datatables API. I had thought I could get a reference to the object, get the settings using fnSettings, and pass those settings into a new datatables instance like so:
var oSettings = $('#myTable').dataTable().fnSettings();
// add additional params to the oSettings object
$('#myTable').dataTable(oSettings);
but the variable returned through fnSettings isn't what I need and doesn't work.
At this point, it seems like I'm going to re-architect things so that I can pass the initialization params around as a variable and add params as needed, unless somebody can steer me in the right direction.
EDIT:
Following tduchateau's answer below, I was able to get partway there by using
var oTable= $('#myTable').dataTable(),
oSettings = oTable.fnSettings(),
oParams = oTable.oApi._fnAjaxParameters(oSettings);
oParams.push('name':'my-new-filter', 'value':'my-new-filter-value');
and can confirm that my new serverside params are added on to the existing params.
However, I'm still not quite there.
$('#myTable').dataTable(oSettings);
gives the error:
DataTables warning(table id = 'myTable'): Cannot reinitialise DataTable.
To retrieve the DataTables object for this table, please pass either no arguments
to the dataTable() function, or set bRetrieve to true.
Alternatively, to destroy the old table and create a new one, set bDestroy to true.
Setting
oTable.bRetrieve = true;
doesn't get rid of the error, and setting
oSettings.bRetrieve = true;
causes the table to not execute the ajax call. Setting
oSettings.bDestroy = true;
loses all the custom params, while setting
oTable.bDestroy = true;
returns the above error. And simply calling
oTable.fnDraw();
causes the table to be redrawn with its original settings.
Finally got it to work using fnServerParams. Note that I'm both deleting unneccessary params and adding new ones, using a url var object:
"fnServerParams": function ( aoData ) {
var l = aoData.length;
// remove unneeded server params
for (var i = 0; i < l; ++i) {
// if param name starts with bRegex_, sSearch_, mDataProp_, bSearchable_, or bSortable_, remove it from the array
if (aoData[i].name.search(/bRegex_|sSearch_|mDataProp_|bSearchable_|bSortable_/) !== -1 ){
aoData.splice(i, 1);
// since we've removed an element from the array, we need to decrement both the index and the length vars
--i;
--l;
}
}
// add the url variables to the server array
for (i in oUrlvars) {
aoData.push( { "name": i, "value": oUrlvars[i]} );
}
}
This is normally the right way to retrieve the initialization settings:
var oSettings = oTable.fnSettings();
Why is it not what you need? What's wrong with these params?
If you need to filter data depending on your additional filters, you can complete the array of "AJAX data" sent to the server using this:
var oTable = $('#myTable').dataTable();
var oParams = oTable.oApi._fnAjaxParameters( oTable );
oParams.push({name: "your-additional-param-name", value: your-additional-param-value });
You can see some example usages in the TableTools plugin.
But I'm not sure this is what you need... :-)
I try to simply change value of SSIS variable doing this code in ScriptTask:
string path = Dts.Connections["BazyPobrane"].ConnectionString.ToString();
string[] nameZIParray = Directory.GetFiles(path, "*.ZIP");
string[] nameRARarray = Directory.GetFiles(path, "*.RAR");
foreach (string nameZIP in nameZIParray) //search new ZIP
{
if (File.GetCreationTime(nameZIP) > DateTime.Now.AddDays(-1))
{
Dts.Variables["User::NazwaPliku"].Value = Path.GetFileName(nameZIP);
}
}
foreach (string nameRAR in nameRARarray) //search new RAR
{
if (File.GetCreationTime(nameRAR) > DateTime.Now.AddDays(-1))
{
Dts.Variables["User::NazwaPliku"].Value = Path.GetFileName(nameRAR);
}
}
Dts.TaskResult = (int)ScriptResults.Success;
After executing ScriptTask it simply don't change the variable Value. Debug mode seems fine. Maybe i miss some component settings?
Thx!
Some things to check:
Are you sure the variable isn't changing? If you put a subsequent script task with a MessageBox in place, does it show the correct value?
I don't think you need the variable type, i.e. remove "user::"
Make sure the variable is in the ReadWriteVariables property, as suggested by #OcasoP
What's the scope of the variable? Make sure you don't have two copies at different scopes, or that at least the one you do have is visible from the scope of the script
You could try locking the variable before writing to it (which should be equivalent to (3) above)
Code example for the last point:
IDTSVariables100 variables = null;
this.VariableDispenser.LockOneForWrite("NazwaPliku",ref variables);
variables[0].Value = myValue;
variables.Unlock();
debug your script task adding MsgBox(variable_name) and see its value through the execution.
Best debugging option :)
I have the following script that is calling a text file:
/* first create a new instance of the LoadVars object */
myVariables = new LoadVars();
myVariables.load("myFile.txt");
myVariables.onLoad = function(getreading):String{
var ODOMETER2:String=myVariables.ACADEMICWATER;
return ODOMETER2;
trace (ODOMETER2);
}
trace(getreading());
The text file contains the following:
ACADEMICWATER=3002&elec=89
I am able to import the value of 3002 into the function and I can trace it. However, I Should be able to trace it outside the function using trace(getreading()); as shown on the last line. This only returns an "UNDEFINED" value. I am stumped.
You are declaring an anonymous function (see AS3 Syntax and language / Functions) which can't be referenced by name. getreading is declared in your code as an untyped parameter of this function.
If you want to trace the result of this function, then you should declare a named function like this:
function getReading(): String {
var ODOMETER2:String=myVariables.ACADEMICWATER;
return ODOMETER2;
}
myVariables.onLoad = getReading;
trace(getReading());
getreading is not the name of the function in this case, but the name of a parameter to the anonymous function that is run on the onLoad event of the myVariables object.
Place the variable ODOMETER2 outside the function and set it's value inside the anonymous function. Then you will be able to access it outside the function as well.
/* first create a new instance of the LoadVars object */
var ODOMETER2:String;
myVariables = new LoadVars();
myVariables.load("myFile.txt");
myVariables.onLoad = function(){
ODOMETER2=myVariables.ACADEMICWATER;
}
trace(ODOMETER2);
LoadVars.onLoad is an event handler. It is called by LoadVars as soon as it finishes with the asynchronous load operation. It takes a boolean argument, indicating success or failure of the operation. It does not return anything.
LoadVars.onLoad documentation
In that function, you typically act upon the data you received, like storing and processing it. Here's a very simple example showing some basic use cases:
var ODOMETER2:String;
var myVariables = new LoadVars();
myVariables.load("myFile.txt");
myVariables.onLoad = function(success) {
trace(success);
ODOMETER2 = myVariables.ACADEMICWATER;
processResults();
}
function processResults() {
trace(ODOMETER2);
trace(myVariables.ACADEMICWATER);
}
// traces:
// true
// 3002
// 3002