Spring MVC 3.x Setting Global Data - java

I have internationalization module and application runs in two different modes. To change the mode, we need to restart the tomcat server. Mode 1 supports two languages and mode 2 supports 5 languages. The languages are stored in a .json file.
Every time the user hits index.html, in the #RequestMapping of this page, I check the application mode. And based on this application mode I read the correct .json file. Extract the list of languages and set that in the model and then I return the page to the client.
Problems with this approach is - every time I hit the index.html file, the application reads the file from disk. which is not only unnecessary but also time consuming and it rings annoying bell to my developer ego.
What I'd like to have instead is, when the application boots up, I know the application mode.
How can get the spring MVC to read the file in the beginning and store this data as long as server is running? Is it even possible?
If yes, can you let me know what parts of Spring MVC do I need to look into?
I read about HandlerInterceptor and #ModelAttribute but it merely states how can I insert the data in each request. However, what I really want to know is how the persist the data read from the file once.

One of the approaches could be tohave a bean, which impements InitializingBean and loads the file in 'afterPropertiesSet' method. It would also have a method to return the list of languages and it could be wired into all other bean which need it.
You could also do it in 'HandlerInterceptor', just have it implement InitializingBean and store the list in the class variable.
e.g.
public MyInterceptor extends HandlerInterceptorAdaptor implements InitializingBean {
private List<String> languageList;
#Override
void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView)
throws Exception {
//set list in the model
}
#Override
public void afterPropetiesSet() {
languageList=...; //read file
}
}

Related

Is there a way to get a two-way connection from client-browser to server application simulating a shell?

Problem
Very short: I want to create Spring Shell, but as a web application.
I want to create a web-application (preferably using Spring Boot), where the frontend (ReactJS) looks like a terminal (or shell), and the backend processes inputted commands. Look at https://codepen.io/AndrewBarfield/pen/qEqWMq. I want to build a full web app for something that looks like that.
I want to build a framework, so that I can develop backend commands without knowing anything about the frontend/web application structure. I basically want to instantiate a "Terminal" object, where I give some kind of input-stream and output-stream. This way I can program this Terminal based on my given interfaces and structure, without the need of setting up all kind of front-end stuff.
A good summary of the question would be: how to send all keyboard inputs to the backend, and how to send all output to the frontend?
The reason I want to create a web application, is because I want it to be available online.
What I tried
I think the way of reaching this is using websockets. I have created a small web application using this (https://developer.okta.com/blog/2018/09/25/spring-webflux-websockets-react) tutorial, without the security part. The websocket part is almost suitable, I just cannot get an "input" and "output" stream-like object.
#Controller
public class WebSocketController {
private SimpMessagingTemplate simpMessagingTemplate;
#Autowired
public WebSocketController(SimpMessagingTemplate simpMessagingTemplate) {
this.simpMessagingTemplate = simpMessagingTemplate;
}
#MessageMapping("/queue")
#SendToUser("/topic/greetings")
public Greeting greeting(HelloMessage message, #Header(name = "simpSessionId") String sessionId) throws Exception {
System.out.println(sessionId);
// Do some command parsing or whatever.
String output = "You inputted:" + HtmlUtils.htmlEscape(message.getName());
return new Greeting(output);
}
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
return headerAccessor.getMessageHeaders();
}
Now with this code, you can parse a command. However, it doesn't keep any "state". I don't know how it works with states and websockets.
I saw you had this Spring Sessions + WebSockets (https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-websocket.html), but this is not really what I want.
I can send a message from the backend to the frontend by using this code:
simpMessagingTemplate.convertAndSendToUser(sessionId, "/topic/greetings", "hey", createHeaders(sessionId));
However, I want my terminal to be able to wait for input commands from the user. Seems like a stretch, but does anybody know how to achieve this?
What I sort of want
I basically want other people to program to this interface:
public interface ITerminal {
void setInputStream(Object someKindOfWrapperForTheInput);
void setOutputStream(Object someWrapperOfSimpMessagingTemplate);
void start();
}
When somebody opens the web application, they get a dedicated terminal object (so a single connection per user). Whever somebody enters a command in the frontend application, I want it to be received by the terminal object, processed, and response outputted to the frontend.
Reasons for doing this
I really like creating command-line applications, and I don't like building frontend stuff. I work as a software engineer for a company where we build a web application, where I mostly program backend stuff. All the frontend part is done by other people (lucky for me!). However, I like doing some projects at home, and this seemed cool.
If you have any thoughts or ideas on how to approach this, just give an answer! I am interested in the solution, using the SpringBoot framework is not a requirement. I ask this question using Spring Boot and ReactJS, because I have already built applications with that. A lot has been figured out already, and I think this probably exists as well.
The only requirement is that I can achieve this with Java on a tomcat-server. The rest is optional :)
Unclear?
I tried my best to make my story clear, but I am not sure if my purpose of what I want to achieve is clear. However, I don't know how to formulate it in such a way you understand. If you have any suggestions or questions, dont hesitate to comment!
If the only thing you want is a Live Spring shell that shows up in the browser it's fairly simple, all you need is to expose a standard WebSocket via the WebSocketConfigurer, then add a WebSocketHandler that executes the command and then returns the resulting String as a TextMessage.
Firstly the Socket configuration that allows clients to connect to the 'cli' endpoint
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(cliHandler(), "/cli").setAllowedOrigins("*");
}
#Bean
public CLIWebSocketHandler cliHandler() {
return new CLIWebSocketHandler();
}
}
Then the WebSocketHandler that executes the command. I recommend that for every #ShellMethod you specify the return type as String, don't use logging or System writes as they won't be returned during the evaluation.
#Component
public class CLIWebSocketHandler extends TextWebSocketHandler {
#Autowired
private Shell shell;
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String result = shell.evaluate(() -> message.getPayload()).toString();
session.sendMessage(new TextMessage(result));
}
}
You can use an extension like Simple WebSocket Client to test it, by going to ws://localhost:port/cli
This is the most basic solution, adding features like security should be easy after this. Notice that I don't use STOMP, because you probably want to isolate users. But it can work alongside STOMP based endpoints, so you can have pub-sub functionality for other parts of the project.
From the question I sense that answer you'd like is something that involved Input and OutputStreams. You could possibly look into redirecting the output of Spring Shell to a different stream then have them forwarded to the sessions but it's probably much more complicated and has other trade-offs. It's simpler to just return a String as the result, it looks better in print outs anyway.

How to call a Servlet/Filter before a JSP is executed in CQ5?

In a Spring MVC application we have a Controller that would execute before calling the JSP. The Controller would prefetch some values from the database and set them in the model and forward the control to JSP.
How do I implement this feature in CQ 5? I want the SlingFilter to execute before the JSP is executed. And the JSP is not a page component but a component that appears in the side kick.
Note:
I can do this by writing my own SlingSerlvet that would prefetch my required values and use the RequestDispatcher to forward to the JSP.
But by this method I would have to go through a URL like "/bin/.*". And this is again at a page level I want this kind of functionality at component level.
So to answer your specific question, if you want a filter to be executed before a component is called you would create a filter that is listening to Component level filter scope.
See
http://sling.apache.org/documentation/the-sling-engine/filters.html
You would then have your filter change the incoming request to a SlingServletRequest and determine if the target resource is the one that you are looking for.
However this filter would be executed on every single component that is being included on a page. The reverse process of this that may be useful to you is the ResourceDecorator.
http://sling.apache.org/documentation/the-sling-engine/wrap-or-decorate-resources.html
These are executed when the resource is identified, prior to the servlet and filter calls, which would allow you to verify if a resource is a type that you are interested in, and then allows you to add additional information to the resource object.However this is, once again a service that would be applied to every resource that is identified.
However, if what you are looking for is a filter that is only executed for a specific path, then no. Sling doesn't do that. You mentioned Spring MVC and Spring MVC works on a completely different concept of MVC then what Slings version of MVC does.
EDIT
So in a traditional web app, the servlet would be at a fixed position and all filters are applied prior to the call to that servlet. In Sling you are dynamically wiring servlets together to generate the resulting page. So each time that you are in a servlet and call directly or indirectly the request dispatcher, it's executing the resolution process again and applying a series of filters again before the new servlet is executed.
To prevent a high level filter that needs to applied only to the main request being applied on every single internal dispatch, they came up with the idea of contexts, or chains of filters that are applied at different times and associated with different types of includes.
Here is a basic filter that will log a message when it's called. I did this from memory so you'll need to dink with it.
#SlingFilter(scope = SlingFilterScope.COMPONENT, order = Integer.MIN_VALUE)
public class SampleFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(SampleFilter.class);
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
Resource res = slingRequest.getResource();
if (!(res == null || ResourceUtil.isNonExistingResource(res))) {
LOG.error("this servlet is called before resource {} at path {}", res.getName(),res.getPath());
}
chain.doFilter(request, response);
}
}
The important part of this is scope = SlingFilterScope.COMPONENT take a look at the page I had listed earlier and try out different combinations of slignfilterscope and you'll see how it's being applied at different times. scope = SlingFilterScope.REQUEST would be once at a top level on a per page basis.
JE Bailey's answer is correct as far as Filters are concerned, but I suspect your problem might be solved in a different way that better fits Sling's view of the world.
Sling promotes the use of OSGi services for business logic, and scripts should be a thin layer above that. Moving your logic to OSGi services and calling those from your scripts is the recommended way.
You might also have a look at Sling Models which can include processing steps (with #PostConstruct) before the rendering scripts kick in.
But by this method I would have to go through a URL like "/bin/.*".
You can also register a servlet against a resource type, as well as by path, e.g. (from the Sling documentation):
#SlingServlet(
resourceTypes = "sling/servlet/default",
selectors = "hello",
extensions = "html",
methods = "GET")
public class MyServlet extends SlingSafeMethodsServlet {
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
...
}
}
If you remove the "selectors", "extensions" and "methods" parameters on the annotation, this servlet would bind against all calls to sling/servlet/default without requiring binding against a set path.

Play Framework 2.1: Overriding configuration file programmatically in Global settings

I'm working to develop a multi-tenant Play Framework 2.1 application. I intend to override the onRequest method of the GlobalSettings class to load and set a custom configuration based on the subdomain of the request. Problem is, I don't see how this would be possible in Play 2.x.
I can override system properties at the command line when starting the server, but how can I do this programmatically in Java code for each request?
The code would look something like this (I assume):
#Override
public play.mvc.Action onRequest(Request request, Method actionMethod) {
//Look up configuration settings in Cache based on request subdomain
//(i.e. Cache.get("subdomain.conf"))
//if not in cache:
//load appropriate configuration file for this subdomain (java.io.File)
//set new configuration from file for this request
//cache the configuration for future use in a new thread
//else
//set configuration from cache for this request
return super.onRequest(request, actionMethod);
}
}
Looking up the URL and getting/setting the cache is easy, but I cannot figure out how to SET a new configuration programmatically for Play Framework 2.1 and the documentation is a little light on things like this.
Any thoughts? Anyone know a better, more efficient way to do this?
So, in a sort of roundabout way, I created the basis for a multi-tenant Play application using a Scala Global. There may be a more efficient way to implement this using a filter, but I'm finding this seems to work so far. This does not appear to be as easily implemented in Java.
Instead of using the configuration file, I'm using the database. I assume it would be far more efficient to use a key-value cache, but this seems to work for now.
In Global.scala:
object Global extends GlobalSettings {
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.session.get("site").isEmpty){
val id = models.Site.getSiteIDFromURL(request.host)
request.session.+("site" -> id)
}
super.onRouteRequest(request)
}
}
And then, obviously, you have to create a database model to query the site based on the request domain and/or the session value set in the request. If anyone knows a better way I'd love to hear it.

Questions about the correct way of using servlets

I want to create a servlet that will allow me to upload image files from the client to the server. I am helping myself with the tutorial i found at apache site:
http://commons.apache.org/fileupload/using.html
On my way i am finding some complications and doubts:
Question 1
I would like my servlet to prepare an object with all the values from the request(included images as byte[]) and pass it to an #EJB that will insert all in the database.
Is that possible? Could you give some pseudo code tips on how to improve my current servlet to do that?
#WebServlet(name="uploadServlet")
public class FileUpload extends HttpServlet {
#EJB
private DBAccessEJB ejb;
private static final long serialVersionUID = -1062753489906645120L;
// Will be triggered when a post method is sent by the user(Example: Form
// submit)
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Check if the request is multipart
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
// Create the object that willBe passed to the EJB
Thing thing = new Thing();
if (isMultipart) {
// If it is multipart, save the items in a FileItemfactory
FileItemFactory factory = new DiskFileItemFactory();
// Create an upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
try {
// Get the files out of the request
List items = upload.parseRequest(req);
Iterator iterator = items.iterator();
while (iterator.hasNext()) {
// Get each of the items inside the items list
FileItem item = (FileItem) iterator.next();
// If the item does not come from a field
if (!item.isFormField()) {
//transform the uploaded images to byte[]
//setTheImageValues of the object
}
else {
//set the text values of the object
}
}
//Pass the prepared object to the EJB to be inserted in DB
ejb.save(thing)
} catch (FileUploadException fue) {
fue.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Question 2
I thought about passing the request to the servlet through the managaged bean, instead from the JSF page, but i don't really know how to do it. Could you give me some tips? I also don't know how to do it in the normal way, from the page,what do you think would be the best way?
This is what i did so far regarding to the managed bean:
public void save() {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletRequest req = (HttpServletRequest)fc.getExternalContext().getRequest();
//What else do i need here to pass the request to the server?
}
This would be at the page inside a multipart form:
<h:commandButton value="Submit" action="myBackingBean.save"/>
Question 3
In my JSF page i have more or less 10 values almost all are Strings. I take them from the JSF and temporary store them in the JSF page. If the servlet could take all the values from the request, there would be no need for this attributes in the backing bean. Do you think is this approach a good thing to do? Will this be process transaction secure, or is there any risk?
Doubt #1 :
It looks like you use the EJB here as a service layer containing a DAO annotated with EJB annotations to make it a session bean. I do not like this approach and you'll run into issues caused by the difference of the EJB world and the HTTP request world.
It is important to note that one of the biggest reasons to use EJB's is to manage transactions and transaction have to remain short, in the order of ms. This is for a number of reasons, like for example locks on the database. However when dealing with http requests with uploads, this is no longer valid.
From another perspective is that a service layer should represent an abstraction of the database model and should show what you can do with the model from a user perspective. The user does not want to save an image to the database, the user wants to add a portrait to his profile.
instead of
ejb.save(thing)
I prefer functions like
profileService.addPortrait(uid, byte[] image);
This explicitely states what it does, and also satisfies the requirement of short transactions. This means the profile entity is available for other requests which may come concurrently (like some status image, or inbox status, ...)
Doubt #2 :
When in Rome, do as the Romans do...
and start by learning some basics of the language. In this case learn JSF from some tutorials.
Doubt #3 :
Intercepting the request parameter in flight between the browser and the JSF component breaks the component architecture and the data hiding principle. It will also bypass any security measures and validation implemented in the server side parts of the JSF components.
If you use the JSF component framework, it makes sense to only ask the values from the components, not from the request itself.
From your 3 doubts I feel you have a bigger doubt : Should I be using JSF?
If it is mandated by your employer : suck it up, and start hitting the books... Learn which problems JSF and EJB's solve and frame your work in terms of those problems.
If you have the freedom to choose : choose a lighter framework, e.g. Spring + Spring MVC. You'll gain experience and encounter those problems at your own pace.
Question 1-
Absolutely you will need Unique Identifiers for your files, but that becomes less complicated if you do things like storing files in folders by date/username, etc...
Here is a basic workflow for your program that you could use, based on what you have shown so far:
Client computer -> FileUploadServlet (utilizing Apache Commons File Upload)
Once inside the FileUploadServlet:
a) Save the information from the request to a Database by way of your EJB including the file name, Mime Type, information, etc...
b) While still inside the servlet, upload the file to your server, or if you need to, use a commercial solution such as Amazon S3 or Google Storage (by way of a Java API such as JetS3t)
Afterwards, return any necessary information to the client.
Question 2 -
What is your reasoning for requesting throught the Bean, why not just make the Servlet the action instead, and collect the information from the request? I would not make the Bean's save method available on the JSF, as that sounds insecure and un-authenticated.
Question 3 -
Same as above, why store information, even if temporarily, when it is available elsewhere?

Creating an application scoped bean in spring MVC

Good day Everyone,
I want to explain my current legacy application before i ask my question.
I have a servlet in a Tomcat in which i load a non-changing database table into memory in the init() using Hibernate. Because this is defined in the init(), it is called only once and its available across all subsequent requests to the servlet, this is used because it improved application performance because of less round trips to the database.
I have recently started to use Spring 3 and i want to change this set up (servlet class is now a controller) to Spring but my challenge is how do i create the ArrayList of domain object (as i do in the init()) at Spring load time for efficiency and have it available across all calls to the controller class without accessing the database every time a request comes in. If this is not possible, then what options do i have?
Any help would be very appreciated.
Pop that static data into the RequestInterceptor
public class RequestInterceptor extends HandlerInterceptorAdapter {
#Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
....
modelAndView.addObject("variableName", dataIWantToHaveAvailableAllOverThePlace);
....
super.postHandle(request, response, handler, modelAndView);
}
}
how do i create the ArrayList of domain object (as i do in the init()) at Spring load time for efficiency and have it available across all calls to the controller class without accessing the database every time a request comes in. If this is not possible, then what options do i have?
I would design this almost identically in your scenario as I would if the data was constantly changing and had to be read from the database on each request:
The controller is wired up with an instance of the MyService interface which has operations for retrieving the data in question.
Optionally, depending on if you separate your DAO layer from your service layer, the MyService implementation is wired up with a MyDAO bean.
The MyService implementation is marked as InitializingBean, and in the afterPropertiesSet() method you retrieve the one-time-load data from the database.
With this design, your controller does not know where it's data is coming from, just that it asks a MyService implementation for the data. The data is loaded from the database when the MyService implementing bean is first created by the Spring container.
This allows you to easily change the design to load the data on each request (or to expire the data at certain times, etc) by swapping in a different implementation of MyService.

Categories

Resources