Overriding java backed webscripts and changing the WebScriptRequest req-param - spring

#Override
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
SiteInfo site = siteService.getSite(req.getParameter(PARAM_SITE));
//Making sure that the site exists
if(site!=null){
//Making sure that the site preset is of type municipality
String preset = site.getSitePreset();
if(preset.equals(PARAM_MUNICIPALITY)){
NodeRef noderef = site.getNodeRef();
WebScriptRequest req2 = req;
//dreamscenario req2.setParameter("nodeRef", nodeRef);
super.serviceRegistry = this.serviceRegistry;
super.execute(req2, res);
}else{
res.getWriter().write("Site preset is not of municipality");
}
}else{
res.getWriter().write("Site was not found");
}
}
This is my class that overrides/extends the web script method called execute. I want to change the parameter WebScriptRequest req
//dreamscenario req2.setParameter("nodeRef", nodeRef);
is basically what I want to achieve. So whenever the super class calls:
req.getParameter("nodeRef")
it will get whatever parameter I put in my method.
Obviously this approach is not working. I could just override the entire super class that im extending, but that doesn't feel like the correct solution if "all" I want to do is change the parameter.

Related

Call several different JavaScript within AjaxLink one after the other

When I click on an AjaxLink, I would like to have a validation via JavaScript on the client side first (because the LocalStorage is queried) and then depending on the result, further JavaScript calls are made. How can i achieve this?
In a pseudo code it would look like this:
new AjaxLink<>("myId", myModel) {
#Override
public void onClick(AjaxRequestTarget target) {
boolean isCounterValid = target.appendJavaScript(checkCounter()); // i know that this is not possible, therefore pseudo code
if(isCounterValid) {
target.appendJavaScript(someOtherJavaScript());
}
else {
target.appendJavaScript(anotherJavaScript());
}
}
private String checkCounter() {
return "var count = window.localStorage.getItem('myCounter'); return count !== 1;";
}
private String someOtherJavaScript() {
return "change something";
}
private String anotherJavaScript() {
return "change other thing";
}
};
You need to send extra request parameters with the Ajax call when the link is clicked. For that you should override updateAjaxAttributes(AjaxRequestAttributes attributes) method of AjaxLink:
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
attributes.getDynamicExtraParameters().add("var count = window.localStorage.getItem('myCounter'); return [{\"name\":\"count\", \"value\": count}]");
}
This way inside AjaxLink#onClick() you can read the count via:
int count = getRequest().getRequestParameters().getParameterValue("count").toInt();
AJAX components and behaviors can customize AJAX attributes overriding updateAjaxAttributes and using a custom implementation of AjaxCallListener which exposes different method to hook into the AJAX request cycle. In you case you could use AjaxCallListener#getBeforeSendHandler.
For a full introduction to this topic (with examples) see user guide:
https://ci.apache.org/projects/wicket/guide/8.x/single.html#_ajax_request_attributes_and_call_listeners

Referencing Action Parameters from ExceptionLogger

I'm wanting to make use of the new method for globally logging errors. I've written a class that inherits ExceptionLogger and overrides the Log() method. Then registered it as a replacement.
public class TraceExceptionLogger : ExceptionLogger
{
public async override void Log(ExceptionLoggerContext context)
{
// This is always empty string
var content = await context.Request.Content.ReadAsStringAsync();
// This is almost always null
var actionContext = context.ExceptionContext.ActionContext;
}
}
I can dig through the ExceptionLoggerContext object's properties to get pretty much everything I need, EXCEPT for action parameters. There is indeed an ActionContext property but I've only seen it null and this wiki page states that ActionContext and ControllerContext will almost always be null.
Also, I can't get the content stream because its stream is already read before it gets to my logger. So there's no way for me to get any posted json from the request's content.
Is there maybe a way to get the posted data from HttpContext.Current or in some other way?
Ok it looks like I can get the body text from HttpContext by reading InputStream on the Request object like this:
string bodyText = string.Empty;
using (var sr = new StreamReader(HttpContext.Current.Request.InputStream))
{
sr.BaseStream.Seek(0, SeekOrigin.Begin);
bodyText = sr.ReadToEnd();
}
This code has been successful me so far for getting my posted json data.
Here's action parameters for future reference
public class HomeController : ApiController {
public string Get(string id, [FromHeader] Whoever whoever) {
public string Post(Whatever whatever) {
var args = ((ApiController) context.ExceptionContext
.ControllerContext.Controller)).ActionContext.ActionArguments
if (args.ContainsKey("whatever")) {
var whatever = (Whatever)args["whatever"];

How to check attribute of action from HttpRequest

I've followed this Prevent Forms authentication in order to try and handle redirecting from ajax gracefully. However I need to be able to determine if certain attributes are decorating the action that this call was made for as I only want to do this for some occasions. Can I get this information from the HttpRequest object that is accessible within this method?.
Essentially taking the part from the code above that I would like to manipulate:
public class SuppressFormsAuthenticationRedirectModule : IHttpModule {
private void OnPostReleaseRequestState(object source, EventArgs args) {
var context = (HttpApplication)source;
var response = context.Response;
var request = context.Request; // request is HttpRequest
if (response.StatusCode == 401 && request.Headers["X-Requested-With"] ==
"XMLHttpRequest") {
// TODO HERE: Check that the controller action contains a particular attribute
// and if so do not suppress redirect
SuppressAuthenticationRedirect(context.Context);
}
}
}
UPDATE:
It's probably worth noting that this code is held within a compiled DLL project that is then encorporated into a host MVC application (which we don't have access to). In that case I don't really have access to changing default implementations unless I can ensure it doesn't effect the rest of the controllers in the application.
I tried to use as much of the framework as possible, which is why I chose to expose the GetControllerType method from the DefaultControllerFactory. You'll notice that routeData contains the area, controller and action, so with a bit of reflection, you can bypass having to create a derived controller factory.
This is definitely not production ready. It is just a way to get the custom attributes from the requested action.
Edit: instead of setting the current controller factory, create a new DerivedControllerFactory
var httpApplication = (HttpApplication)sender;
var httpContext = new HttpContext(httpApplication.Request, new HttpResponse(new StringWriter()));
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
//var factory = ControllerBuilder.Current.GetControllerFactory() as DerivedControllerFactory;
var factory = new DerivedControllerFactory();
var controllerType = factory.GetControllerType(new RequestContext(new HttpContextWrapper(httpContext), routeData), routeData.Values["controller"].ToString());
var methodInfo = controllerType.GetMethod(routeData.Values["action"].ToString());
var attributes = methodInfo.GetCustomAttributes(true);
public class DerivedControllerFactory : DefaultControllerFactory
{
public new Type GetControllerType(RequestContext requestContext, string controllerName)
{
return base.GetControllerType(requestContext, controllerName);
}
}

Display image in jsp using servlet

I am working on an application where the information of users gets added and modified(updated).
In add module, admin enters user details and unique-id(abc001) gets generated at "add" button. and admin also saves the image/picture(name : abc001) of the user in server location (//some-location-ip address/D drive/images).
In "update" module, admin can modify the user details, but can not modify id.
I need some direction in couple of scenarios.
If an Admin "updates" a particular user, the image of that user which is present in the server should gets displayed on the page as soon as the admin hit the update button.
Image code in JSP :
<img height="100px;" width="100px;" src="........." alt="Candidate Image"></img>
I have written a servlet, but don't know how to call different images corresponding to different users and display the image on the profile page.
user A profile will display user A image
user B profile will display user B image
and so on
Servlet code Snippet
public class UpDatePhoto extends HttpServlet {
public UpDatePhoto () {
super();
// TODO Auto-generated constructor stub
}
private static final long serialVersionUID = -8071854868821235857L;
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
private String imagePath;
*public void init() throws ServletException {
this.imagePath = "D:\\photo_not_available_large.png";
}*
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String requestedImage = request.getPathInfo();
if (requestedImage == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
File image = new File(imagePath, URLDecoder.decode(requestedImage, "UTF-8"));
String contentType = getServletContext().getMimeType(image.getName());
if (contentType == null || !contentType.startsWith("image")) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(image.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
close(output);
close(input);
}
}
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The image is not http accessible but is only accessible as a file, the servlet would have to open the image file, read in the contents and place those in the response buffer" ....not sure if i am correct.
Can somebody guide me to the direction and help me out as how to fetch the image from the server directory location and display the correct image for a user.
I have a hard time in understanding the concrete problem, but I believe that your root problem is that you don't know how to set the imagePath accordingly? It has namely a wrong value.The code shows that it should be set to the root folder where all images are been placed. In the underlying operating system platform, you need to map //some-location-ip address/D drive/images as a network drive in Windows explorer, e.g. Z: and then use that in your imagePath instead.
this.imagePath = "Z:";
It also expects the image file name as request pathinfo. So, assuming that your servlet is mapped on an URL pattern of /images/*, then your <img src> should look basically like this
<img src="images/filename.png" />
You could also fill it dynamically with EL. E.g. with the unique username of the logged-in user:
<img src="images/${user.name}.png" />
As to using the "D:\\photo_not_available_large.png" replacement image, you could set that when File#exists() returns false.

Play Framework: Image Display question

ref:
http://www.lunatech-research.com/playframework-file-upload-blob
I'm uneasy about one point in this example
#{list items:models.User.findAll(), as:'user'}
<img src="#{userPhoto(user.id)}">
#{/list}
At this point I'm already holding the user object (including the image blob). Yet the userPhoto() method makes another dip into the backend to get the Image user.photo
public static void userPhoto(long id) {
final User user = User.findById(id);
notFoundIfNull(user);
response.setContentTypeIfNotSet(user.photo.type());
renderBinary(user.photo.get());
}
Any way to avoid this unnecessary findById call?
You're not actually holding the user object any more though, because the userPhoto action is invoked in a separate request that's sent when the browser tries to load the image from the URL generated by #{userPhoto(user.id)}.
Of course, you could use the cache to store data from each user's photo Blob, which would reduce the likelihood that you had to go to the database on the image request. It's more trouble than it's worth in this case though since you're just doing a simple primary key lookup for the user object, and that should be relatively inexpensive. Plus Blobs aren't serializable, so you have to pull out each piece of information separately.
Still, if you were to try that it might look something like this:
// The action that renders your list of images
public static void index() {
List<User> users = User.findAll();
for (User user : users) {
cachePhoto(user.photo);
}
render(users);
}
// The action that returns the image data to display
public static void userPhoto(long id) {
InputStream photoStream;
String path = Cache.get("image_path_user_" + id);
String type = Cache.get("image_type_user_" + id);
// Was the data we needed in the cache?
if (path == null || type == null) {
// No, we'll have to go to the database anyway
User user = User.findById(id);
notFoundIfNull(user);
cachePhoto(user.photo);
photoStream = user.photo.get();
type = user.photo.type();
} else {
// Yes, just generate the stream directly
try {
photoStream = new FileInputStream(new File(path));
} catch (Exception ex) {
throw new UnexpectedException(ex);
}
}
response.setContentTypeIfNotSet(type);
renderBinary(photoStream);
}
// Convenience method for caching the photo information
private static void cachePhoto(Blob photo) {
if (photo == null) {
return;
}
Cache.set("image_path_user_" + user.id,
photo.getFile.getAbsolutePath());
Cache.set("image_type_user_" + user.id,
photo.getType());
}
Then you'd still have to worry about appropriately populating/invalidating the cache in your add, update, and delete actions too. Otherwise your cache would be polluted with stale data.

Resources