Is an evaluated function in Nashorn reusable from different threads? - java

Is it possible to reuse one and the same Nashorn engine and one and the same JavaScriptObject, which results as the evaluation of a JS-function, for all servlet requests, if the function does not change any shared object but uses only the arguments given with the call? Look at the following example:
public class MyServlet extends HttpServlet {
private ScriptEngineManager factory;
private ScriptEngine engine;
private ScriptObjectMirror script;
#Override
public void init() throws ServletException {
try {
factory = new ScriptEngineManager();
engine = factory.getEngineByName("nashorn");
script = (ScriptObjectMirror)engine.eval("function(writer) {writer.print('Hello, World!');}");
} catch (ScriptException ex) {
Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
try (PrintWriter writer = res.getWriter()) {
script.call(null, writer);
writer.close();
} catch (IOException ex) {
Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
}
}
Is this thread-safe?
This is a follow-up to Reuse Nashorn ScriptEngine in Servlet
Edit:
I'm not sure what difference this makes for the question at hand, but to focus on the more interesting question, under which circumstances a call to an evaluated js-function is thread save, I made all fields final now. So the code is:
public class MyServlet extends HttpServlet {
final private ScriptEngineManager factory;
final private ScriptEngine engine;
final private ScriptObjectMirror script;
public MyServlet() {
factory = new ScriptEngineManager();
engine = factory.getEngineByName("nashorn");
ScriptObjectMirror _script = null;
try {
_script = (ScriptObjectMirror) engine.eval("function(writer) {writer.print('Hello, World!');}");
} catch (ScriptException ex) {
Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
}
script = _script;
}
#Override
public void init() throws ServletException {
}
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
try (PrintWriter writer = res.getWriter()) {
script.call(null, writer);
writer.close();
} catch (IOException ex) {
Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
}
}

None of your instance variables are safely published, so that's a big "no" right there. Also none of the documentation says that the classes you use are thread safe, so without some further documentation saying differently you have to assume that they are not thread safe.
Answer: nope.

Related

Data inconsistency in multithreaded environment

I have created an application which reads & writes into a remote file. I have different files (A.properties, B.properties, C.properties) in different directories (folder-1, folder-2, folder-3). Each directory has the same filename with different data.
I have implemented concurrency in my application by using the LockRegistry provided by this other answer. The issue is that if a thread is accessing A.properties while another thread accesses B.properties, the propertyMap displayed to the end user will contain both data from property files. How can I resolve this issue?
My code:
public class UDEManager
{
private Map<String, String> propertyMap = new TreeMap<>();
HttpSession session = null;
public UDEPropertyManager()
{
super();
}
public void init(ServletConfig config) throws ServletException
{
super.init(config);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Code for calling thread for read/write operations into remote
// file and fill the propertyMap
}
}
class WebAppProperty implements Runnable
{
private WebApp webapp; // folder-1
private String propertyFile; // A.properties
private String keyValue; //messages-title=Messages
private LockType mode;
public String getPropertyFile()
{
return propertyFile;
}
public void setPropertyFile(String propertyFile)
{
this.propertyFile = propertyFile;
}
#Override
public void run()
{
try {
LockRegistry.INSTANCE.acquire(propertyFile, mode);
if (this.mode == LockType.WRITE) {
writeToPropertyFile();
} else if (this.mode == LockType.READ) {
getProperty(this.webapp, this.propertyFile);
}
} catch (Exception ie) {
sysoutAndLog("Thread is Interrupted");
ie.printStackTrace();
} finally {
LockRegistry.INSTANCE.release(propertyFile, mode);
}
}
private boolean getProperty(WebApp webapp, String property)
{
try {
// read from file and put it into Map instance variable
// of calling class (UDEManager)
propertyMap.put(key, value);
} catch(Exception e) {
sysoutAndLog("Error while reading property ");
e.printStackTrace();
}
return false;
}
private void writeToPropertyFile()
{
try {
// Write data into remote file
} catch (Exception e) {
sysoutAndLog("exception while writing to file.");
e.printStackTrace();
}
}
}
You should associate the properties map with the user session or request

Setting the outer class field in an asynchronous class

I am trying to set a field from the outer class within an asynchronous class but it is not working for me.
public class FlinkJsonObject {
TrafficData jsonObject;
ObjectMapper mapper = new ObjectMapper();
public FlinkJsonObject(String url, int port) throws URISyntaxException {
final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(new URI("wss://city.up.us/outbound/SPPAnalyticsStatement"));
clientEndPoint.addMessageHandler(new WebsocketClientEndpoint.MessageHandler() {
#Override
public void handleMessage(String message) {
try {
// Using this does not work here
this.jsonObject = mapper.readValue(message, TrafficData.class);
} catch (IOException ex) {
Logger.getLogger(FlinkJsonObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
I have tried setting the field using an external method and calling it in the asynchronous class but it does not work for me.

How to catch already caught exception?

I have the follow the following filter:
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
try {
chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
} catch (XssAttackException e) {
request.getRequestDispatcher("/XssAttack").forward(request, response);
}
}
and the class XssAttackException is:
public class XssAttackException extends RuntimeException {
private static final long serialVersionUID = 1L;
}
after debugging the code, I realized that somewhere in the spring framework all the exceptions are being caught. Now I need a way that my catch bock also run.
UPDATE
inside XSSRequestWrapper we have:
#Override
public String getHeader(String name) {
String value = super.getHeader(name);
return stripXSS(value);
}
And
private String stripXSS(String value) {
if (value != null) {
value = persianUtf8(value);
if (!value.equals(Jsoup.parse(value).text())) {
throw new XssAttackException();
}
value = Jsoup.parse(value).text();
for (Pattern scriptPattern : patterns) {
if (scriptPattern.matcher(value).matches()) {
throw new XssAttackException();
}
value = scriptPattern.matcher(value).replaceAll("");
}
}
return value;
}
Please don't assume this is answer for your question.Assumed too long comment.
I created my CustomException class.
public class CustomException extends RuntimeException {
}
and created custom Servlet class as your XSSRequestWrapper and throw my custom exception in constructor.
public class MyServlet implements ServletRequest {
public MyServlet() {
throw new CustomException();
}
// other override methods go here
}
and in my filter class
try {
chain.doFilter(new MyServlet(), response);
} catch (CustomException e) {
System.out.println("xxxxxxxxxxxxxxx I got it xxxxxxxxxxxxxxxxxxx");
}
This code work fine. At your program , I think there has some exception has occured and you did not catch on them. So , this exception object has miss from your try block of your filter class and handled by Spring container.

How can this SwingWorker code be made testable

Consider this code:
public void actionPerformed(ActionEvent e) {
setEnabled(false);
new SwingWorker<File, Void>() {
private String location = url.getText();
#Override
protected File doInBackground() throws Exception {
File file = new File("out.txt");
Writer writer = null;
try {
writer = new FileWriter(file);
creator.write(location, writer);
} finally {
if (writer != null) {
writer.close();
}
}
return file;
}
#Override
protected void done() {
setEnabled(true);
try {
File file = get();
JOptionPane.showMessageDialog(FileInputFrame.this,
"File has been retrieved and saved to:\n"
+ file.getAbsolutePath());
Desktop.getDesktop().open(file);
} catch (InterruptedException ex) {
logger.log(Level.INFO, "Thread interupted, process aborting.", ex);
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
Throwable cause = ex.getCause() == null ? ex : ex.getCause();
logger.log(Level.SEVERE, "An exception occurred that was "
+ "not supposed to happen.", cause);
JOptionPane.showMessageDialog(FileInputFrame.this, "Error: "
+ cause.getClass().getSimpleName() + " "
+ cause.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
} catch (IOException ex) {
logger.log(Level.INFO, "Unable to open file for viewing.", ex);
}
}
}.execute();
url is a JTextField and 'creator' is an injected interface for writing the file (so that part is under test). The location where the file is written is hard coded on purpose because this is intended as an example. And java.util.logging is used simply to avoid an external dependency.
How would you chunk this up to make it unit-testable (including abandoning SwingWorker if needed, but then replacing its functionality, at least as used here).
The way I look at it, the doInBackground is basically alright. The fundamental mechanics are creating a writer and closing it, which is almost too simple to test and the real work is under test. However, the done method is quote problematic, including its coupling with the actionPerformed method the parent class and coordinating the enabling and disabling of the button.
However, pulling that apart is not obvious. Injecting some kind of SwingWorkerFactory makes capturing the GUI fields a lot harder to maintain (it is hard to see how it would be a design improvement). The JOpitonPane and the Desktop have all the "goodness" of Singletons, and exception handling makes it impossible to wrap the get easily.
So what would be a good solution to bring this code under test?
IMHO, that's complicated for an anonymous class. My approach would be to refactor the anonymous class to something like this:
public class FileWriterWorker extends SwingWorker<File, Void> {
private final String location;
private final Response target;
private final Object creator;
public FileWriterWorker(Object creator, String location, Response target) {
this.creator = creator;
this.location = location;
this.target = target;
}
#Override
protected File doInBackground() throws Exception {
File file = new File("out.txt");
Writer writer = null;
try {
writer = new FileWriter(file);
creator.write(location, writer);
}
finally {
if (writer != null) {
writer.close();
}
}
return file;
}
#Override
protected void done() {
try {
File file = get();
target.success(file);
}
catch (InterruptedException ex) {
target.failure(new BackgroundException(ex));
}
catch (ExecutionException ex) {
target.failure(new BackgroundException(ex));
}
}
public interface Response {
void success(File f);
void failure(BackgroundException ex);
}
public class BackgroundException extends Exception {
public BackgroundException(Throwable cause) {
super(cause);
}
}
}
That allows the file writing functionality to be tested independent of a GUI
Then, the actionPerformed becomes something like this:
public void actionPerformed(ActionEvent e) {
setEnabled(false);
Object creator;
new FileWriterWorker(creator, url.getText(), new FileWriterWorker.Response() {
#Override
public void failure(FileWriterWorker.BackgroundException ex) {
setEnabled(true);
Throwable bgCause = ex.getCause();
if (bgCause instanceof InterruptedException) {
logger.log(Level.INFO, "Thread interupted, process aborting.", bgCause);
Thread.currentThread().interrupt();
}
else if (cause instanceof ExecutionException) {
Throwable cause = bgCause.getCause() == null ? bgCause : bgCause.getCause();
logger.log(Level.SEVERE, "An exception occurred that was "
+ "not supposed to happen.", cause);
JOptionPane.showMessageDialog(FileInputFrame.this, "Error: "
+ cause.getClass().getSimpleName() + " "
+ cause.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
#Override
public void success(File f) {
setEnabled(true);
JOptionPane.showMessageDialog(FileInputFrame.this,
"File has been retrieved and saved to:\n"
+ file.getAbsolutePath());
try {
Desktop.getDesktop().open(file);
}
catch (IOException iOException) {
logger.log(Level.INFO, "Unable to open file for viewing.", ex);
}
}
}).execute();
}
Additionally, the instance of FileWriterWorker.Response can be assigned to a variable and tested independent of FileWriterWorker.
The current implementation couples together threading concerns, UI and file writing - and as you've discovered that coupling makes it hard to test the individual components in isolation.
This is quite a long response, but it boils down to pulling out these three concerns from the current implementation into separate classes with a defined interface.
Factor out Application Logic
To start with, focus on the core application logic and move that into a separate class/interface. An interface allows easier mocking, and use of other swing-threading frameworks. The separation means you can test your application logic entirely independently from the other concerns.
interface FileWriter
{
void writeFile(File outputFile, String location, Creator creator)
throws IOException;
// you could also create your own exception type to avoid the checked exception.
// a request object allows all the params to be encapsulated in one object.
// this makes chaining services easier. See later.
void writeFile(FileWriteRequest writeRequest);
}
class FileWriteRequest
{
File outputFile;
String location;
Creator creator;
// constructor, getters etc..
}
class DefualtFileWriter implements FileWriter
{
// this is basically the code from doInBackground()
public File writeFile(File outputFile, String location, Creator creator)
throws IOException
{
Writer writer = null;
try {
writer = new FileWriter(outputFile);
creator.write(location, writer);
} finally {
if (writer != null) {
writer.close();
}
}
return file;
}
public void writeFile(FileWriterRequest request) {
writeFile(request.outputFile, request.location, request.creator);
}
}
Separate out UI
With the application logic now separate, we then factor out the success and error handling. This means that the UI can be tested without actually doing the file writing. In particular, error handling can be tested without actually need to provoke those errors. Here, the errors are quite simple, but often some errors can be very difficult to provoke. By separating out the error handling, there is also chance for reuse, or replacing how the errors are handled. E.g. using a JXErrorPane later.
interface FileWriterHandler {
void done();
void handleFileWritten(File file);
void handleFileWriteError(Throwable t);
}
class FileWriterJOptionPaneOpenDesktopHandler implements FileWriterHandler
{
private JFrame owner;
private JComponent enableMe;
public void done() { enableMe.setEnabled(true); }
public void handleFileWritten(File file) {
try {
JOptionPane.showMessageDialog(owner,
"File has been retrieved and saved to:\n"
+ file.getAbsolutePath());
Desktop.getDesktop().open(file);
}
catch (IOException ex) {
handleDesktopOpenError(ex);
}
}
public void handleDesktopOpenError(IOException ex) {
logger.log(Level.INFO, "Unable to open file for viewing.", ex);
}
public void handleFileWriteError(Throwable t) {
if (t instanceof InterruptedException) {
logger.log(Level.INFO, "Thread interupted, process aborting.", ex);
// no point interrupting the EDT thread
}
else if (t instanceof ExecutionException) {
Throwable cause = ex.getCause() == null ? ex : ex.getCause();
handleGeneralError(cause);
}
else
handleGeneralError(t);
}
public void handleGeneralError(Throwable cause) {
logger.log(Level.SEVERE, "An exception occurred that was "
+ "not supposed to happen.", cause);
JOptionPane.showMessageDialog(owner, "Error: "
+ cause.getClass().getSimpleName() + " "
+ cause.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
Separate out Threading
Finally, we can also separate out the threading concerns with a FileWriterService. Using a FileWriteRequest above makes coding this simpler.
interface FileWriterService
{
// rather than have separate parms for file writing, it is
void handleWriteRequest(FileWriteRequest request, FileWriter writer, FileWriterHandler handler);
}
class SwingWorkerFileWriterService
implements FileWriterService
{
void handleWriteRequest(FileWriteRequest request, FileWriter writer, FileWriterHandler handler) {
Worker worker = new Worker(request, fileWriter, fileWriterHandler);
worker.execute();
}
static class Worker extends SwingWorker<File,Void> {
// set in constructor
private FileWriter fileWriter;
private FileWriterHandler fileWriterHandler;
private FileWriterRequest fileWriterRequest;
protected File doInBackground() {
return fileWriter.writeFile(fileWriterRequest);
}
protected void done() {
fileWriterHandler.done();
try
{
File f = get();
fileWriterHandler.handleFileWritten(f);
}
catch (Exception ex)
{
// you could also specifically unwrap the ExecutorException here, since that
// is specific to the service implementation using SwingWorker/Executors.
fileWriterHandler.handleFileError(ex);
}
}
}
}
Each part of the system is separately testable - the application logic, the presentation (success and error handling) and the threading implementation is also a separate concern.
This may seem like a lot of interfaces, but the implementation is mostly cut-and-paste from your original code. The interfaces provide the separation that is needed to make these classes testable.
I'm not much of a fan of SwingWorker's so keeping them behind an interface helps keep the clutter they produce out of the code. It also allows you to use a different implementation for implementing the separate UI/background threads. For example, to use Spin, you only need to provide a new implementation of FileWriterService.
Easy solution : a simple timer is best ; you lanch your timer, you launch your actionPerformed, and at the timeout the bouton must be enabled and so on.
Here is an very littel exemple with a java.util.Timer :
package goodies;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JButton;
public class SWTest
{
static class WithButton
{
JButton button = new JButton();
class Worker extends javax.swing.SwingWorker<Void, Void>
{
#Override
protected Void doInBackground() throws Exception
{
synchronized (this)
{
wait(4000);
}
return null;
}
#Override
protected void done()
{
button.setEnabled(true);
}
}
void startWorker()
{
Worker work = new Worker();
work.execute();
}
}
public static void main(String[] args)
{
final WithButton with;
TimerTask verif;
with = new WithButton();
with.button.setEnabled(false);
Timer tim = new Timer();
verif = new java.util.TimerTask()
{
#Override
public void run()
{
if (!with.button.isEnabled())
System.out.println("BAD");
else
System.out.println("GOOD");
System.exit(0);
}};
tim.schedule(verif, 5000);
with.startWorker();
}
}
Supposed Expert solution : a Swing Worker is a RunnableFuture, inside it a FutureTask imbeded in a callable, so you can use your own executor to launch it (the RunableFuture). To do that, you need a SwingWorker with a name class, not an anonymous. With your own executor and a name class, you can test all you want, the supposed expert says.

FacesMessages in MyFacesServlet Wrapper

I throw NullPointerException in a java bean and catch the exception in FacesServletWrapper.
in FacesServletWrapper I gets always only ServletException.
how can I catch the specific exception that I throw?
How can I continue from where I throws the exception?
in my bean:
public String getSize() {
try {
Object object = null;
object.equals("");
} catch (Exception e) {
throw new NullPointerException();
}
}
my servlet:
public class FacesServletWrapper extends MyFacesServlet {
public static final String CONFIG_FILES_ATTR = "javax.faces.CONFIG_FILES";
public static final String LIFECYCLE_ID_ATTR = "javax.faces.LIFECYCLE_ID";
private ServletConfig servletConfig;
private FacesContextFactory facesContextFactory;
private Lifecycle lifecycle;
#Override
public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException {
FacesContext facesContext = facesContextFactory.getFacesContext(servletConfig.getServletContext(), request, response, (javax.faces.lifecycle.Lifecycle) lifecycle);
try {
super.service(request, response);
} catch (Throwable e) {
Locale locale = (Locale) facesContext.getExternalContext().getSessionMap().get(Constants.LOCALE);
ServletContext context = servletConfig.getServletContext();
RequestDispatcher dispatcher = context.getRequestDispatcher("/errors/error.jsf");
if (e instanceof NullPointerException) {
//here I catch only ServletException
String error = ResourceUtil.getMessage("Login_failed", locale);
facesContext.getExternalContext().getSessionMap().put("error", error);
dispatcher.forward(request, response);
((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request).getContextPath() + "/errors/error.jsf");
}
}
}
public void destroy() {
servletConfig = null;
facesContextFactory = null;
lifecycle = null;
}
public ServletConfig getServletConfig() {
return servletConfig;
}
private String getLifecycleId() {
String lifecycleId = servletConfig.getServletContext().getInitParameter(LIFECYCLE_ID_ATTR);
return lifecycleId != null ? lifecycleId : LifecycleFactory.DEFAULT_LIFECYCLE;
}
#Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
this.servletConfig = servletConfig;
facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
lifecycle = (Lifecycle) lifecycleFactory.getLifecycle(getLifecycleId());
}
}
Thanks!
You're calling FacesServlet#service() here:
try {
super.service(request, response);
} catch (Throwable e) {
// ...
}
Here's an extract from its javadoc to learn what kind of exception it may throw:
If a FacesException is thrown in either case, extract the cause from the FacesException. If the cause is null extract the message from the FacesException, put it inside of a new ServletException instance, and pass the FacesException instance as the root cause, then rethrow the ServletException instance. If the cause is an instance of ServletException, rethrow the cause. If the cause is an instance of IOException, rethrow the cause. Otherwise, create a new ServletException instance, passing the message from the cause, as the first argument, and the cause itself as the second argument.
In other words, it will always throw either ServletException or IOException. You need to use Throwable#getCause() to extract the desired cause from the catched ServletException and then determine it further. E.g.
if (e.getCause() instanceof NullPointerException) {
// ...
}

Categories