Spring SpEL to set RequestMapping path with a list - spring-restcontroller

I want to programmatically set the paths on a rest service. I have this bean method which has all the paths.
public List<String> getSubscribeChannelsForRest() { .. }
This is the rest service
#RestController
public class RestMessageController {
#PostMapping(
path = { "#{somebean.getSubscribeChannelsForRest()[0]}",
"#{somebean.getSubscribeChannelsForRest()[1]}",
"#{somebean.getSubscribeChannelsForRest()[2]}"
})
public String processMessage(#RequestBody String messageBody, HttpServletRequest request) { .. }
The above code works but I want to avoid hard coding the array numbers. There is what I tried.
#PostMapping(
path = { "#{somebean.getSubscribeChannelsForRest()}",
This doesn't work because the spring method RequestMappingHandlerMapping.resolveEmbeddedValuesInPatterns(String[] patterns) takes the above SpEL as a single element array. I've checked the trace logs and all the element in the given list get concatenated .

Related

Extract org.restlet.http.headers value from Camel headers inside a .choice()

I'm trying to extract a value from org.restlet.http.headers header collection in a Camel route.
My incoming POST has a http header property called IncomingRequestType: ABCD.
Camel moves this inside the exchange headers collection, but it is buried inside org.restlet.http.headers which is in-itself a collection of headers.
I can extract the value in a process using the code below:
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
org.restlet.util.Series<Header> httpHeaders = null;
httpHeaders = (Series<Header>) exchange.getIn().getHeader("org.restlet.http.headers");
String reqType = httpHeaders.getValues("IncomingRequestType").toString();
}})
Outside of a process I need to access the IncomingRequestType inside a .choice().when()
e.g. i want to be able to do:
.choice()
.when(header("org.restlet.http.headers")["IncomingRequestType"]).isEqualTo("ABCD"))
Any suggestions on how this can be done. I've tried creating predicates but cannot get a suitable solution.
This can be done in the simple language:
.choice()
.when(simple("${in.header.org.restlet.http.headers[IncomingRequestType]} == 'ABCD'"))

RazorEngine Error trying to send email

I have an MVC 4 application that sends out multiple emails. For example, I have an email template for submitting an order, a template for cancelling an order, etc...
I have an Email Service with multiple methods. My controller calls the Send method which looks like this:
public virtual void Send(List<string> recipients, string subject, string template, object data)
{
...
string html = GetContent(template, data);
...
}
The Send method calls GetContent, which is the method causing the problem:
private string GetContent(string template, object data)
{
string path = Path.Combine(BaseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml"));
string content = File.ReadAllText(path);
return Engine.Razor.RunCompile(content, "htmlTemplate", null, data);
}
I am receiving the error:
The same key was already used for another template!
In my GetContent method should I add a new parameter for the TemplateKey and use that variable instead of always using htmlTemplate? Then the new order email template could have newOrderKey and CancelOrderKey for the email template being used to cancel an order?
Explanation
This happens because you use the same template key ("htmlTemplate") for multiple different templates.
Note that the way you currently have implemented GetContent you will run into multiple problems:
Even if you use a unique key, for example the template variable, you will trigger the exception when the templates are edited on disk.
Performance: You are reading the template file every time even when the template is already cached.
Solution:
Implement the ITemplateManager interface to manage your templates:
public class MyTemplateManager : ITemplateManager
{
private readonly string baseTemplatePath;
public MyTemplateManager(string basePath) {
baseTemplatePath = basePath;
}
public ITemplateSource Resolve(ITemplateKey key)
{
string template = key.Name;
string path = Path.Combine(baseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml"));
string content = File.ReadAllText(path);
return new LoadedTemplateSource(content, path);
}
public ITemplateKey GetKey(string name, ResolveType resolveType, ITemplateKey context)
{
return new NameOnlyTemplateKey(name, resolveType, context);
}
public void AddDynamic(ITemplateKey key, ITemplateSource source)
{
throw new NotImplementedException("dynamic templates are not supported!");
}
}
Setup on startup:
var config = new TemplateServiceConfiguration();
config.Debug = true;
config.TemplateManager = new MyTemplateManager(BaseTemplatePath);
Engine.Razor = RazorEngineService.Create(config);
And use it:
// You don't really need this method anymore.
private string GetContent(string template, object data)
{
return Engine.Razor.RunCompile(template, null, data);
}
RazorEngine will now fix all the problems mentioned above internally. Notice how it is perfectly fine to use the name of the template as key, if in your scenario the name is all you need to identify a template (otherwise you cannot use NameOnlyTemplateKey and need to provide your own implementation).
Hope this helps.
(Disclaimer: Contributor of RazorEngine)

How to get mapped path in jersey

Please refer following code. /hello/from/JohnDoe will hit the method sayPlainTextHello. When "/hello/from/JohnDoe" is accessed, I want to store the mapped path which is /hello/from/{name} in a log. Please note that I can't modify below code but can add filter, etc. to the app. How to get the mapped path "/hello/from/{name}" ?
#Path("hello")
public class GenericResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/from/{name}")
public String sayPlainTextHello(#PathParam("name") String fromName) {
return "Hello Jersey - " + fromName;
}
}

How do I achieve through Jboss Resteasy interceptors?

I am working on the Jboss Resteasy API to implement the REST services on Jboss server.I am new to this area. Can someone help me out here...
There is a Rest Service method with custom annotation(VRestAuto) like below.
#POST
#Produces("text/json")
#Path("/qciimplinv")
#Interceptors(VRestInterceptor.class)
public String getInvSummary(#VRestAuto("EnterpriseId") String enterpriseId,String circuitType){
....
businessMethod(enterpriseId,circuitType);
....
}
#VRestAuto annotation tell us 'enterpriseId' value is available in the user session.
User pass the circuitType alone as the POST parameter in the Rest Client tool.Should ideally read the enterpriseid from session and invoke the Rest service with these two parameters(enterpriseid,circuitType).
To achieve the above functionality, implemented the Interceptors class (VRestInterceptor) like below:
public class VRestInterceptor implemnets PreProcessInterceptor,AcceptedByMethod {
public boolean accept(Class declaring, Method method) {
for (Annotation[] annotations : method.getParameterAnnotations()) {
for (Annotation annotation : annotations) {
if(annotation.annotationType() == VRestAuto.class){
VRestAuto vRestAuto = (VRestAuto) annotation;
return vRestAuto.value().equals("EnterpriseId");
}
}
}
return false;
}
Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
throws Failure, WebApplicationException { ......}
}
I was able to verify the VRestAuto annotation in the accept method. But in the preProcess Method, how can I call the REST method with two parameters(enterpriseid, circuitType)?
if these interceptors are not suits, Are there any other interceptors best to this functionality?
Your help is highly appreciated .
Why not forget setting the enterpriseId value when the method is called and instead just inject the HttpServletRequest and use that to grab the session and value?
#POST
#Produces("text/json")
#Path("/qciimplinv")
public String getInvSummary(String circuitType, #Context HttpServletRequest servletRequest) {
HttpSession session = servletRequest.getSession();
String enterpriseId = session.getAttribute("EnterpriseId").toString();
....
businessMethod(enterpriseId,circuitType);
....
}

Can I stop my WCF generating ArrayOfString instead of string[] or List<string>

I am having a minor problem with WCF service proxies where the message contains List<string> as a parameter.
I am using the 'Add Service reference' in Visual Studio to generate a reference to my service.
// portion of my web service message
public List<SubscribeInfo> Subscribe { get; set; }
public List<string> Unsubscribe { get; set; }
These are the generated properties on my MsgIn for one of my web methods.
You can see it used ArrayOfString when I am using List<string>, and the other takes List<SubscribeInfo> - which matches my original C# object above.
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
get {
return this.SubscribeField;
}
set {
if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
this.SubscribeField = value;
this.RaisePropertyChanged("Subscribe");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
get {
return this.UnsubscribeField;
}
set {
if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
this.UnsubscribeField = value;
this.RaisePropertyChanged("Unsubscribe");
}
}
}
The ArrayOfString class generated looks like this. This is a class generated in my code - its not a .NET class. It actually generated me a class that inherits from List, but didn't have the 'decency' to create me any constructors.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
[System.SerializableAttribute()]
public class ArrayOfString : System.Collections.Generic.List<string> {
}
The problem is that I often create my message like this :
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.ToList()
});
I really like the clean look this gives me.
Now for the actual problem :
I cant assign a List<string> to the Unsubscribe property which is an ArrayOfString - even though it inherits from List. In fact I cant seem to find ANY way to assign it without extra statements.
I've tried the following :
new ArrayOfString(unsubscribeFrom.ToList()) - this constructor doesn't exist :-(
changing the type of the array used by the code generator - doesn't work - it always gives me ArrayOfString (!?)
try to cast List<string> to ArrayOfString - fails with 'unable to cast', even though it compiles just fine
create new ArrayOfString() and then AddRange(unsubscribeFrom.ToList()) - works, but I cant do it all in one statement
create a conversion function ToArrayOfString(List<string>), which works but isn't as clean as I want.
Its only doing this for string, which is annoying.
Am i missing something? Is there a way to tell it not to generate ArrayOfString - or some other trick to assign it ?
Any .NET object that implements a method named "Add" can be initialized just like arrays or dictionaries.
As ArrayOfString does implement an "Add" method, you can initialize it like this:
var a = new ArrayOfString { "string one", "string two" };
But, if you really want to initialize it based on another collection, you can write a extension method for that:
public static class U
{
public static T To<T>(this IEnumerable<string> strings)
where T : IList<string>, new()
{
var newList = new T();
foreach (var s in strings)
newList.Add(s);
return newList;
}
}
Usage:
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});
I prefer not to return generic types across a service boundary in the first place. Instead return Unsubscribe as a string[], and SubscriptionInfo as SubscriptionInfo[]. If necessary, an array can easily be converted to a generic list on the client, as follows:
Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);
Too late but can help people in the future...
Use the svcutil and explicitly inform the command line util that you want the proxy class to be serialized by the XmlSerializer and not the DataContractSerializer (default). Here's the sample:
svcutil /out:c:\Path\Proxy.cs /config:c:\Path\Proxy.config /async /serializer:XmlSerializer /namespace:*,YourNamespace http://www.domain.com/service/serviceURL.asmx
Note that the web service is an ASP.NET web service ok?!
If you are using VS 2008 to consume service then there is an easy solution.
Click on the "Advanced..." button on the proxy dialog that is displayed when you add a Service Reference. In the Collection Type drop down you can select System.Generic.List. The methods returning List should now work properly.
(Hope this is what you were asking for, I'm a little tired and the question was a tad difficult for me to read.)