Pass dynamic parameters in the keyvalue (message key) to package.properties - struts2

I have tried to pass dynamic parameters to keyvalue(message to display) which I will get from package.properties to the Action class through the getText() method. To get the message, we can use getText(String keyvalue) method. What should I do to pass some parameters and retrieve the parameters with the message through the getText() method?
I saw some API's to pass dynamic parameters. But I don't know how to use, these are the following API's, click here to see the Struts 2 API Documentation.
getText(String aTextName, List<Object> args)
getText(String key, String[] args)
getText(String key, String defaultValue, String[] args)
Thanks in advance..

I suppose that you have following properties in your package.properties
username.required=user name is required
password.required=password is required
you can use getText() as
getText("username.required")
getText("password.required")
Now if we want to use getText(String key, String[] args) we have to pass following parameters
aTextName - the resource bundle key that is to be searched for
args - a list args to be used in a MessageFormat message
That means the message format pattern and other static strings will, of course, be obtained from resource bundles. Other parameters will be dynamically determined at runtime.
example
we have following entry in resource file
disk.data=The disk \"{0}\" artist name is {1}.
in this {1} and {0} are the dynamic parameters and will be determined at run time so args will contain the value of these parameters.
String artistName= demo;
String diskName = "Artist";
String[] testArgs = {artistName, diskName};
So final call will be getText(disk.data, testArgs);
and it will show
The disk demo artist name is Artist.
Please go through MessageFormat to know how this work

Related

DartPad keeps saying expecting 2, receiving 3 arguments in constructor

Email( List<String> to, String from, {String subject:null, String message:null, DateTime datetime:null, HashMap<String, List<String>> meta:null, List<Attachment> attachments:null})
get this error:
Uncaught NoSuchMethodError: incorrect number of arguments passed to method named ''
Receiver: ""
Tried calling: (Instance of 'JSArray<String>', "will#fallenreaper.com", Instance of '_HashMap<String, Object>')
Found: (to, from, subject, message, datetime, meta, attachments)
My class is:
class Email{
Email( List<String> to, String from, {String subject:null, String message:null, DateTime datetime:null, HashMap<String, List<String>> meta:null, List<Attachment> attachments:null}){
//do stuff.
}
}
im trying to make it such that to and from are required, but the rest are optionally going to be passed in, in a map. I thought i was doing this right, but it doesnt seem to be correct.
The DartPad is at: https://dartpad.dartlang.org/4d32b88095a6509da511
Search for TODO
The Composer class is the part im implementing, leveraging the Email class i created.
Add some text to the Subject, and then click the "Send" button
Your Email class' constructor
Email( List<String> to, String from, {String subject:null, String message:null, DateTime datetime:null, HashMap<String, List<String>> meta:null, List<Attachment> attachments:null}) { ... }
has 2 positional arguments and 5 optional named arguments.
You can simply pass positional parameters like you did in
new Email(map["to"], map["from"], map);
but optional names parameters need to be "named" like
new Email(map["to"], map["from"], subject: map);
If you want the optional parameters to be positional you need to change the constructor to
Email( List<String> to, String from, [String subject=null, String message=null, DateTime datetime=null, HashMap<String, List<String>> meta=null, List<Attachment> attachments=null]) { ... }
You can't have optional named and optional positional arguments at the same time. If you have a longer parameter list like in your Email constructor, named optional arguments are usually better because you can specify with a name which parameter the passed value should be assigned to and there is no need to pass nulls or ''s for parameters you want to skip.

Jenkins form validation with objects as parameters

I'm building a plugin for Jenkins and I'm trying to validate my form (connection test method). This worked fine when all #QueryParameter were Strings.
Now I'm trying to send my form validation method an Object like this:
public FormValidation doTestConnection(
#QueryParameter("url") final String url,
#QueryParameter("timeout") final String timeout,
#QueryParameter("bypassProxy") final boolean bypassProxy,
#QueryParameter("deployerCredentialsConfig") final CredentialsConfig deployerCredentialsConfig,
#QueryParameter("resolverCredentialsConfig") final CredentialsConfig resolverCredentialsConfig
) throws ServletException {
In my global.jelly file I have this:
<f:validateButton
title="${%Test Connection}" progress="${%Testing...}"
method="testConnection"
with="url,timeout,bypassProxy,deployerCredentialsConfig,resolverCredentialsConfig"/>
My CredentialConfig class implements Serializable but I guess that is not enough becuase I'm getting this when clicking the "Test Connection" button:
java.lang.IllegalArgumentException: Failed to invoke public hudson.util.FormValidation
org.jfrog.hudson.MyBuilder$DescriptorImpl.doTestConnection(java.lang.String,java.lang.String,boolean,org.jfrog.hudson.CredentialsConfig,org.jfrog.hudson.CredentialsConfig) throws javax.servlet.ServletException
Jenkins has no good documentation for using objects inside of FormValidation calls.
Looking at the Jenkins documentation and the code behind <f:validateButton/>, I believe it's impossible have objects bind in validation logic.
The docs say (https://wiki.jenkins-ci.org/display/JENKINS/Jelly+form+controls):
The 'with' attribute specifies the input fields sent to the server for
the validation. They are matched against the field attribute or the
name attribute of other input controls. The values of the nearest
input fields above the are sent to the server, so
this means the button has to come after the input fields. Multiple
fields can be specified by using ','.
The code simply gets fields by the names - there is no "object assembly" (I believe it's only done during actual config submission).
https://github.com/jenkinsci/jenkins/blob/96ec7a267e0efba2ec99590c871db0940e35920f/war/src/main/webapp/scripts/hudson-behavior.js#L2856
I bumped into a similar problem. Looking at the code, it seems stapler tries to convert your parameter to the type you provided in the doCheck function declaration.
class HandlerImpl extends AnnotationHandler<QueryParameter> {
public Object parse(StaplerRequest request, QueryParameter a, Class type, String parameterName) throws ServletException {
String name = a.value();
if(name.length()==0) name=parameterName;
if(name==null)
throw new IllegalArgumentException("Parameter name unavailable neither in the code nor in annotation");
String value = request.getParameter(name);
if(a.required() && value==null)
throw new ServletException("Required Query parameter "+name+" is missing");
if(a.fixEmpty() && value!=null && value.length()==0)
value = null;
return convert(type,value); // <--- HERE
}
}
As a workaround, I changed the type to boolean, like so:
public FormValidation doTestConnection(
#QueryParameter("url") final String url,
#QueryParameter("timeout") final String timeout,
#QueryParameter("bypassProxy") final boolean bypassProxy,
#QueryParameter("deployerCredentialsConfig") final boolean deployerCredentialsConfig,
#QueryParameter("resolverCredentialsConfig") final boolean resolverCredentialsConfig
) throws ServletException {
This allows me to at least check if the variable is set. It might not be enough for your use case, though.

OData routing for function with 2 parameters

Im creating OData controller and want it to support function with 2 params.
Here is my current code.
OData cofig:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "hop";
builder.EntitySet<ScheduleDTO>("Schedules");
var function = builder.Function("GetByEntityAndJurisdiction");
function.Parameter<Guid>("EntityId");
function.Parameter<Guid>("JurisdictionId");
function.ReturnsCollectionFromEntitySet<ScheduleDTO>("Schedules");
Controller:
[ODataRoutePrefix("Schedules")]
public class ScheduleODataController : BaseODataManager, IScheduleODataManager
{
[ODataRoute]
public async Task<IHttpActionResult> GetAsync(ODataQueryOptions<ScheduleDTO> options)
{
.....
return Ok(schedules.Select(x => Mapper.Map<ScheduleDTO>(x)));
}
[HttpGet]
[ODataRoute("GetByEntityAndJurisdiction(EntityId={entityId}, JurisdictionId={jurisdictionId})")]
public async Task<IHttpActionResult> GetByEntityAndJurisdiction(ODataQueryOptions<ScheduleDTO> options, [FromODataUri] Guid entityId, [FromODataUri] Guid jurisdictionId)
{
.....
return Ok(schedules.Select(x => Mapper.Map<ScheduleDTO>(x)));
}
}
Starting my app, I have following error:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Web.OData.dll
Additional information: The path template 'Schedules/GetByEntityAndJurisdiction(EntityId={entityId}, JurisdictionId={jurisdictionId})' on the action 'GetByEntityAndJurisdiction' in controller 'ScheduleOData' is not a valid OData path template. The request URI is not valid. Since the segment 'Schedules' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource.
How to resolve this problem? Thanks in advance.
#Vladimir
In your controller, you add a prefix attribute [ODataRoutePrefix("Schedules")] on the controller. Doing so will add the prefix string at head of all the [ODataRoute] in the same controller. So, for below action
public async Task<IHttpActionResult> GetByEntityAndJurisdiction(ODataQueryOptions<ScheduleDTO> options, [FromODataUri] Guid entityId, [FromODataUri] Guid jurisdictionId)
{...}
the full Uri template should be:
Schedules/GetByEntityAndJurisdiction(EntityId={entityId}, JurisdictionId={jurisdictionId})
Obviously, This Uri is invalid because:
The collection of Schedules doesn't have a bound function named GetByEntityAndJurisdiction
Even though GetByEntityAndJurisdiction is a bound function, you should call the bound function through it's namespace-qualified function name.
Maybe, It's confused that you have build the function as the following codes:
var function = builder.Function("GetByEntityAndJurisdiction");
However, it means to build an unbound function. An unbound function is called through function import by issuing a GET request to a URL identifying the function import and passing parameter values using inline parameter syntax. The canonical URL for a function import is the service root, followed by the name of the function import.
So, you can change your codes as follows to make it work:
If you want to keep the model schema unchanged, that is to build GetByEntityAndJurisdiction as unbound function, please remove the ODataRoutePrefix("Schedules")] from your controller. Or create a new controller (any controller), move the action into the new controller but don't add the Prefix attribute.
If you want to change the schema and keep the controller unchanged, that is to GetByEntityAndJurisdiction as bound function.
Please do as follows :
var entity = builder.EntitySet<ScheduleDTO>("Schedules").EntityType;
var function = entity.Collection.Function("GetByEntityAndJurisdiction");
...
For more information about function, you can refer to OData.Org or Function Sample page, or Function blog.

Dynamically add query parameters without value to Retrofit request

I have request that set list of services that are turned on for user.
Request has following format:
https://myserver.com/setservices?param1=val1&param2=val2&service[10]&service[1000]&service[10000]
List of service parameters ("service[10]&service[1000]&service[10000]") is created dynamically and each parameter doesn't have value. Is it possible to achive this using Retrofit?
From the retrofit documentation:
For complex query parameter combinations a Map can be used.
#GET("/group/{id}/users")
List<User> groupList(#Path("id") int groupId, #QueryMap Map<String, String> options);
I guess this will make what you want to achieve.
I found workaround how to do this.
#GET("/setservices{services_query}")
ServicesSetResponse setServices(#EncodedPath("services_query") String servicesQuery);
And then:
getService().setServices("?param1=val1&param2=val2" + "&services[10]&services[100000]&services[1000000]")
We can pass using the #QueryMap as below:
GET("/movies")
Call<List<Movies>> getMovies(
#QueryMap Map<String, String> options
);
To build the parameters:
Map<String, String> data = new HashMap<>();
data.put("director", "Haresh");
data.put("page", String.valueOf(2));
It will generate the Url like:
http://your.api.url/movies?page=2&director=Haresh

ServiceStack PostFIleWithRequest "has" hard coded content-disposition name field

I have an issue with the PostFileWithRequest<> method in ServiceStack in that the name of the file field is hard coded to the word "upload">
Part of the data stream
Content-Disposition: form-data;name="upload";filename="Julie.mp3"
And this is from line 407 in the file ServiceClientBase.cs
stream.Write("Content-Disposition: form-data;name=\"{0}\";filename=\"{1}\"{2}{3}".FormatWith(new object[] { "upload", fileName, text, text }));
This is contained in a virtual method but I do not know how I can change that in a derived class as there are other methods that are not accessible to my new class.
public virtual TResponse PostFileWithRequest<TResponse>(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileName, object request)
Any ideas?
This look like a bug to me as the name of the form-data;name should be configurable and not hard coded.
In my case I need the file to be in a name called "File" in order to use a specific API.
Chris
I submitted a pull request to ServiceStack (albeit v4) which has been accepted and will be included in the next version 4.0.14.
This adds an optional parameter of fieldName to the PostFileWithRequest<TResponse> method which allows you to specify the field name instead of being stuck with upload.
So the new signature of the method:
public virtual TResponse PostFileWithRequest<TResponse>(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileName, object request, string fieldName = "upload")

Resources