install4j: how can i pass command line arguments to windows service - install4j

I've created a windows service using install4j and everything works but now I need to pass it command line arguments to the service. I know I can configure them at service creation time in the new service wizard but i was hoping to either pass the arguments to the register service command ie:
myservice.exe --install --arg arg1=val1 --arg arg1=val2 "My Service Name1"
or by putting them in the .vmoptions file like:
-Xmx256m
arg1=val1
arg2=val2
It seems like the only way to do this is to modify my code to pick up the service name via exe4j.launchName and then load some other file or environment variables that has the necessary configuration for that particular service. I've used other service creation tools for java in the past and they all had straightforward support for command line arguments registered by the user.

I know you asked this back in January, but did you ever figure this out?
I don't know where you're sourcing val1, val2 etc from. Are they entered by the user into fields in a form in the installation process? Assuming they are, then this is a similar problem to one I faced a while back.
My approach for this was to have a Configurable Form with the necessary fields (as Text Field objects), and obviously have variables assigned to the values of the text fields (under the 'User Input/Variable Name' category of the text field).
Later in the installation process I had a Display Progress screen with a Run Script action attached to it with some java to achieve what I wanted to do.
There are two 'gotchas' when optionally setting variables in install4j this way. Firstly, the variable HAS to be set no matter what, even if it's just to the empty string. So, if the user leaves a field blank (ie they don't want to pass that argument into the service), you'll still need to provide an empty string to the Run executable or Launch Service task (more in that in a moment) Secondly, arguments can't have spaces - every space-separated argument has to have its own line.
With that in mind, here's a Run script code snippet that might achieve what you want:
final String[] argumentNames = {"arg1", "arg2", "arg3"};
// For each argument this method creates two variables. For example for arg1 it creates
// arg1ArgumentIdentifierOptional and arg1ArgumentAssignmentOptional.
// If the value of the variable set from the previous form (in this case, arg1) is not empty, then it will
// set 'arg1ArgumentIdentifierOptional' to '--arg', and 'arg1ArgumentAssignmentOptional' to the string arg1=val1 (where val1
// was the value the user entered in the form for the variable).
// Otherwise, both arg1ArgumentIdentifierOptional and arg1ArgumentAssignmentOptional will be set to empty.
//
// This allows the installer to pass both parameters in a later Run executable task without worrying about if they're
// set or not.
for (String argumentName : argumentNames) {
String argumentValue = context.getVariable(argumentName)==null?null:context.getVariable(argumentName)+"";
boolean valueNonEmpty = (argumentValue != null && argumentValue.length() > 0);
context.setVariable(
argumentName + "ArgumentIdentifierOptional",
valueNonEmpty ? "--arg": ""
);
context.setVariable(
argumentName + "ArgumentAssignmentOptional",
valueNonEmpty ? argumentName+"="+argumentValue : ""
);
}
return true;
The final step is to launch the service or executable. I'm not too sure how services work, but with the executable, you create the task then edit the 'Arguments' field, giving it a line-separated list of values.
So in your case, it might look like this:
--install
${installer:arg1ArgumentIdentifierOptional}
${installer:arg1ArgumentAssignmentOptional}
${installer:arg2ArgumentIdentifierOptional}
${installer:arg2ArgumentAssignmentOptional}
${installer:arg3ArgumentIdentifierOptional}
${installer:arg3ArgumentAssignmentOptional}
"My Service Name1"
And that's it. If anyone else knows how to do this better feel free to improve on this method (this is for install4j 4.2.8, btw).

Related

Protractor Custom Locator: Not available in production, but working absolutely fine on localhost

I have added a custom locator in protractor, below is the code
const customLocaterFunc = function (locater: string, parentElement?: Element, rootSelector?: any) {
var using = parentElement || (rootSelector && document.querySelector(rootSelector)) || document;
return using.querySelector("[custom-locater='" + locater + "']");
}
by.addLocator('customLocater', customLocaterFunc);
And then, I have configured it inside protractor.conf.js file, in onPrepare method like this:
...
onPrepare() {
require('./path-to-above-file/');
...
}
...
When I run my tests on the localhost, using browser.get('http://localhost:4200/login'), the custom locator function works absolutely fine. But when I use browser.get('http://11.15.10.111/login'), the same code fails to locate the element.
Please note, that the test runs, the browser gets open, user input gets provided, the user gets logged-in successfully as well, but the element which is referred via this custom locator is not found.
FYI, 11.15.10.111 is the remote machine (a virtual machine) where the application is deployed. So, in short the custom locator works as expected on localhost, but fails on production.
Not an answer, but something you'll want to consider.
I remember adding this custom locator, and encounter some problems with it and realised it's just an attribute name... nothing fancy, so I thought it's actually much faster to write
let elem = $('[custom-locator="locator"]')
which is equivalent to
let elem = element(by.css('[custom-locator="locator"]'))
than
let elem = element(by.customLocator('locator'))
And I gave up on this idea. So maybe you'll want to go this way too
I was able to find a solution to this problem, I used data- prefix for the custom attribute in the HTML. Using which I can find that custom attribute on the production build as well.
This is an HTML5 principle to prepend data- for any custom attribute.
Apart from this, another mistake that I was doing, is with the selector's name. In my code, the selector name is in camelCase (loginBtn), but in the production build, it was replaced with loginbtn (all small case), that's why my custom locater was not able to find it on the production build.

CQ5 / AEM5.6 Workflow: Access workflow instance properties from inside OR Split

TL;DR version:
In CQ workflows, is there a difference between what's available to the OR Split compared to the Process Step?
Is it possible to access the /history/ nodes of a workflow instance from within an OR Split?
How?!
The whole story:
I'm working on a workflow in CQ5 / AEM5.6.
In this workflow I have a custom dialog, which stores a couple of properties on the workflow instance.
The path to the property I'm having trouble with is: /workflow/instances/[this instance]/history/[workItem id]/workItem/metaData and I've called the property "reject-or-approve".
The dialog sets the property fine (via a dropdown that lets you set it to "reject" or "approve"), and I can access other properties on this node via a process step (in ecma script) using:
var actionReason;
var history = workflowSession.getHistory(workItem.getWorkflow());
// loop backwards through workItems
// and as soon as we find a Action Reason that is not empty
// store that as 'actionReason' and break.
for (var index = history.size() - 1; index >= 0; index--) {
var previous = history.get(index);
var tempActionReason = previous.getWorkItem().getMetaDataMap().get('action-message');
if ((tempActionReason != '')&&(tempActionReason != null)) {
actionReason = tempActionReason;
break;
}
}
The process step is not the problem though. Where I'm having trouble is when I try to do the same thing from inside an OR Split.
When I try the same workflowSession.getHistory(workItem.getWorkflow()) in an OR Split, it throws an error saying workItem is not defined.
I've tried storing this property on the payload instead (i.e. storing it under the page's jcr:content), and in that case the property does seem to be available to the OR Split, but my problems with that are:
This reject-or-approve property is only relevant to the current workflow instance, so storing it on the page's jcr:content doesn't really make sense. jcr:content properties will persist after the workflow is closed, and will be accessible to future workflow instances. I could work around this (i.e. don't let workflows do anything based on the property unless I'm sure this instance has written to the property already), but this doesn't feel right and is probably error-prone.
For some reason, when running through the custom dialog in my workflow, only the Admin user group seems to be able to write to the jcr:content property. When I use the dialog as any other user group (which I need to do for this workflow design), the dialog looks as though it's working, but never actually writes to the jcr:content property.
So for a couple of different reasons I'd rather keep this property local to the workflow instance instead of storing it on the page's jcr:content -- however, if anyone can think of a reason why my dialog isn't setting the property on the jcr:content when I use any group other than admin, that would give me a workaround even if it's not exactly the solution I'm looking for.
Thanks in advance if anyone can help! I know this is kind of obscure, but I've been stuck on it for ages.
a couple of days ago i ran into the same issue. The issue here is that you don't have the workItem object, because you don't really have an existing workItem. Imagine the following: you are going through the workflow, you got a couple of workItems, with means, either process step, either inbox item. When you are in an or split, you don't have existing workItems, you can ensure by visiting the /workItems node of the workflow instance. Your workaround seems to be the only way to go through this "issue".
I've solved it. It's not all that elegant looking, but it seems to be a pretty solid solution.
Here's some background:
Dialogs seem to reliably let you store properties either on:
the payload's jcr:content node (which wasn't practical for me, because the payload is locked during the workflow, and doesn't let non-admins write to its jcr:content)
the workItem/metaData for the current workflow step
However, Split steps don't have access to workItem. I found a fairly un-helpful confirmation of that here: http://blogs.adobe.com/dmcmahon/2013/03/26/cq5-failure-running-script-etcworkflowscriptscaworkitem-ecma-referenceerror-workitem-is-not-defined/
So basically the issue was, the Dialog step could store the property, but the OR Split couldn't access it.
My workaround was to add a Process step straight after the Dialog in my workflow. Process steps do have access to workItem, so they can read the property set by the Dialog. I never particularly wanted to store this data on the payload's jcr:content, so I looked for another location. It turns out the workflow metaData (at the top level of the workflow instance node, rather than workItem/metaData, which is inside the /history sub-node) is accessible to both the Process step and the OR Split. So, my Process step now reads the workItem's approveReject property (set by the Dialog), and then writes it to the workflow's metaData node. Then, the OR Split reads the property from its new location, and does its magic.
The way you access the workflow metaData from the Process step and the OR Split is not consistent, but you can get there from both.
Here's some code: (complete with comments. You're welcome)
In the dialog where you choose to approve or reject, the name of the field is set to rejectApprove. There's no ./ or anything before it. This tells it to store the property on the workItem/metaData node for the current workflow step under /history/.
Straight after the dialog, a Process step runs this:
var rejectApprove;
var history = workflowSession.getHistory(workItem.getWorkflow());
// loop backwards through workItems
// and as soon as we find a rejectApprove that is not empty
// store that as 'rejectApprove' and break.
for (var index = history.size() - 1; index >= 0; index--) {
var previous = history.get(index);
var tempRejectApprove = previous.getWorkItem().getMetaDataMap().get('rejectApprove');
if ((tempRejectApprove != '')&&(tempRejectApprove != null)) {
rejectApprove = tempRejectApprove;
break;
}
}
// steps up from the workflow step into the workflow metaData,
// and stores the rejectApprove property there
// (where it can be accessed by an OR Split)
workItem.getWorkflowData().getMetaData().put('rejectApprove', rejectApprove);
Then after the Process step, the OR Split has the following in its tabs:
function check() {
var match = 'approve';
if (workflowData.getMetaData().get('rejectApprove') == match) {
return true;
} else {
return false;
}
}
Note: use this for the tab for the "approve" path, then copy it and replace var match = 'approve' with var match = 'reject'
So the key here is that from a Process step:
workItem.getWorkflowData().getMetaData().put('rejectApprove', rejectApprove);
writes to the same property that:
workflowData.getMetaData().get('rejectApprove') reads from when you execute it in an OR Split.
To suit our business requirements, there's more to the workflow I've implemented than just this, but the method above seems to be a pretty reliable way to get values that are entered in a dialog, and access them from within an OR Split.
It seems pretty silly that the OR Split can't access the workItem directly, and I'd be interested to know if there's a less roundabout way of doing this, but for now this has solved my problem.
I really hope someone else has this same problem, and finds this useful, because it took me waaay to long to figure out, to only apply it once!

Mercurial pretag hook called even with --remove option

I am a newbie to Mercurial and I am writing a pretag hook to check policy on tag names.
I have the below code.
version_re = r'(ver-\d+\.\d+\.\d+|tip)$'
def invalidtag(ui, repo, hooktype, node, tag, **kwargs):
assert(hooktype == 'pretag')
....
if not re_.match(tag):
ui.warn('Invalid tag name "%s".\n' % tag)
return True
return False
This hooks works perfect when I am tagging. But this hook is also executed when I want to remove invalid tags with --remove options.
So, is there any way to avoid his situation?
When a tag is marked for removal the node passed to the hook is the nullid from mercurial.node.
So you should be able to check this the node against the nullid from mercurial.node.
You should convert the node to the hexadecimal representation with the "hex" function from mercurial.node. This hex function has a different behavior than the built-in one from python.

How to support powershell tab expansion in psprovider?

I'm implementing Powershell PSProvider for some internal hierarchical data. Everything works fine, I can navigate through the tree with usual cd/dir commands, the only thing doesn't work is tab completion.
What I can see is that Powershell calls function GetChildName() with an asterisk in the path when Tab is pressed (if I type "dir c" and press Tab, GetChildName() function will be called with string "c*", several times). I tried to return all child names from the folder that begins with "c", but Powershell always displays just the first child name in the front. I can't find any documentation about this behavior, what I'm missing?
Are you sure you aren't just seeing normal behavior? With the default Tab Expansion, you will only see the first result. Pressing tab additional times will cycle through the list of returned results from the provider.
There are some quirks with providers. I have been working on one using the Script Provider project. I put debug code in all my methods to see which ones PowerShell was calling, when, and with what arguments.
I found where's the problem - function GetChildName() in the provider shouldn't try to expand given file name if asterisk is part of the name; The function should return child name if it can find an exact match, or call base.GetChildName() in any other case. Something like this:
protected override string GetChildName(string path) {
string name = SomeFunctionThatTriesToFindExactMatchForGivenPath(path);
if(string.IsNullOrEmpty( ret ) )
ret = base.GetChildName( path );
return ret;
}
BTW, I found that default tab expansion is very forgiving about stuff that can be returned from GetChildName() function - even if return value have slash/backslash in the front/back, tab expansion will work. But PowerTab, popular tab expansion module, is much more picky about return values.

How do I pass build number from Nant back to Cruise Control

I have a Nant build script which CruiseControl uses to build a solution on-demand.
However, we only recently got CruiseControl so our official build number is different from what is listed in CruiseControl.
I know CruiseControl injects some properties into build scripts so that I can access the CC build number in the script (CCNetLabel) but how do I pass a value back to CC to use as the build number on the UI screen?
Example, CC says build number 2
nAnt script increments a buildnumber.xml value every build, and the official build number is on 123.
I want the CC UI to show last successful build number: 123, not 2, so how do I pass that value back up?
A custom build labeler is required for this. Perforce is our source control provider and we derive our version number from it. The code is as follows:
/// <summary>
/// Gets the latest change list number from perforce, for ccnet to consume as a build label.
/// </summary>
[ReflectorType( "p4labeller" )]
public class PerforceLabeller : ILabeller
{
// perforce executable (optional)
[ReflectorProperty("executable", Required = false)]
public string P4Executable = "p4.exe";
// perforce port (i.e. myserver:1234)
[ReflectorProperty("port", Required = false)]
public string P4Port = String.Empty;
// perforce user
[ReflectorProperty("user", Required = false)]
public string P4User = String.Empty;
// perforce client
[ReflectorProperty("client", Required = false)]
public string P4Client = String.Empty;
// perforce view (i.e. //Dev/Code1/...)
[ReflectorProperty("view", Required = false)]
public string P4View = String.Empty;
// Returns latest change list
public string Generate( IIntegrationResult previousLabel )
{
return GetLatestChangelist();
}
// Stores latest change list into a label
public void Run( IIntegrationResult result )
{
result.Label = GetLatestChangelist();
}
// Gets the latest change list
public string GetLatestChangelist()
{
// Build the arguments to pass to p4 to get the latest changelist
string theArgs = "-p " + P4Port + " -u " + P4User + " -c " + P4Client + " changes -m 1 -s submitted " + P4View;
Log.Info( string.Format( "Getting latest change from Perforce using --> " + theArgs ) );
// Execute p4
ProcessResult theProcessResult = new ProcessExecutor().Execute( new ProcessInfo( P4Executable, theArgs ) );
// Extract the changelist # from the result
Regex theRegex = new Regex( #"\s[0-9]+\s", RegexOptions.IgnoreCase );
Match theMatch = theRegex.Match( theProcessResult.StandardOutput );
return theMatch.Value.Trim();
}
}
The method, GetLatestChangelist, is where you would probably insert your own logic to talk to your version control system. In Perforce there is the idea of the last changelist which is unique. Our build numbers, and ultimately version numbers are based off of that.
Once you build this (into an assembly dll), you'll have to hook it into ccnet. You can just drop the assembly into the server directory (next to ccnet.exe).
Next you modify your ccnet project file to utilize this labeller. We did this with the default labeller block. Something like the following:
<project>
<labeller type="p4labeller">
<client>myclient</client>
<executable>p4.exe</executable>
<port>myserver:1234</port>
<user>myuser</user>
<view>//Code1/...</view>
</labeller>
<!-- Other project configuration to go here -->
</project>
If you're just wanting the build number to show up in ccnet then you're done and don't really need to do anything else. However, you can access the label in your NAnt script if you wish by using the already provided CCNetLabel property.
Hope this helps some. Let me know if you have any questions by posting to the comments.
Did you try to use some environment variables? I believe CCNet can handle these.
I'll dig a bit on this.
Well I see a solution, quite dirty, but anyhow:
1- Add a defaultlabeller section in your CCNET project definition. It will contains the pattern of the build number you want to display.
2- Within NAnt, have a script to update your configuration file, inserting the build number you want to see.
3- Touch (in the Unix sense) the ccnet.exe.config file so as to make it re-load the projects configuration files.
et voilĂ .
We had this problem as well. I ended up writing a special CC labelling plugin.
If your build numbers are sequential, you can just hack the cruise control state file to give it the correct build number to start with. Your looking for a file called [projectName].state.
I changed the Label element to the correct number and the LastSuccessfulIntegrationLabel to be the new number.
However, we only recently got
CruiseControl so our official build
number is different from what is
listed in CruiseControl.
Sort of along the lines of what gbanfill said, you can tell CC what build numbers to start from, but there's no need to hack the .ser file. You can use the JMX interface to set the current build number to get it in sync with your NAnt build number.
You can also set the default label value to to your current build number, delete the .ser file and restart CC.
But maybe the easiest thing is to write the build number into a property file from NAnt and then use the property file label incrementer to read that file. (Be sure to to set setPreBuildIncrementer="true")