Data inconsistency in multithreaded environment - java

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

Related

Something strange happend after spring-boot auto restart

I use a static threadlocal variable store per request sql query count.
As the code
public class App {
public static ThreadLocal<Integer> count = ThreadLocal.withInitial(() -> 0);;
}
And i count it when some sql execute
public class P6spyListener extends JdbcEventListener {
#Override
public void onAfterExecuteQuery(PreparedStatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
// System.out.println(statementInformation.getSqlWithValues());
log.info("又是这个问题.."+App.count.get().toString());
App.count.set(App.count.get() + 1);
log.info("execute query..." + statementInformation.getSqlWithValues());
}
#Override
public void onAfterExecuteUpdate(PreparedStatementInformation statementInformation, long timeElapsedNanos, int rowCount, SQLException e) {
App.count.set(App.count.get() + 1);
log.info("execute update.." + statementInformation.getSqlWithValues());
}
#Override
public void onAfterExecute(StatementInformation statementInformation, long timeElapsedNanos, String sql, SQLException e) {
App.count.set(App.count.get() + 1);
log.info("execute.." + statementInformation.getSqlWithValues());
}
}
then i log the total count afterCompletion
public class RequestInitInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info(String.format("count is %d",App.count.get()));
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info(String.format("finish request... 执行sql %d ", App.count.get()));
App.count.remove();
}
}
everything right,i can get success result
But when i edit anycode ,the springboot auto restart. then count is wrong.
the result always is zero.

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.

java servlet submit button doesn't work

I'm been writing a small login servlet. The login part works just fine, but when I press logout submit button - nothing happens.
Servlet code down bellow:
public class LoginServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 7638796169158385551L;
private Database database = Database.getInstance();
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.write("<html><head><title>Login form</title></head>");
if (!database.connected) {
outLoginForm(out);
} else {
out.write("Hello " + database.getLoginName() + "!");
outLogoutForm(out);
}
out.write("</body></html>");
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (request.getParameter("loginsub") != null) {
if (isParameterEmpty(request, "login")
|| isParameterEmpty(request, "pass")) {
response.getWriter().write("Some fields are empty");
doGet(request, response);
}
try {
database.connect(request.getParameter("login"),
request.getParameter("pass"));
} catch (ExceptionInInitializerError ex) {
response.getWriter().write("Login or password is incorrect");
}
} else if (request.getParameter("logoutsub") != null) {
database.disconnect();
}
doGet(request, response);
}
private boolean isParameterEmpty(HttpServletRequest request,
String parameter) {
if (request.getParameter(parameter).isEmpty())
return true;
return false;
}
protected void outLoginForm(PrintWriter out) {
out.write("<FORM method =\"POST\">");
out.write("Login:<input type=\"text\"name=\"login\"><br>");
out.write("Password:<input type=\"password\"name=\"pass\"><br>");
out.write("<input type=\"submit\"name=\"loginsub\" value=\"Login\"/><br>");
out.write("</FORM><br>");
}
protected void outLogoutForm(PrintWriter out) {
out.write("<FORM method =\"POST>\">");
out.write("<input type=\"submit\"name=\"logoutsub\" value=\"Logout\"/><br>");
out.write("</FORM><br>");
}
}
Can anyone help me find out what's wrong? I'm new to JSP and java servlets.
There is one problem is below line (one extra > after POST
out.write("<FORM method =\"POST>\">");
replace it with
out.write("<FORM method =\"POST\">");

Full duplex HTTP Upgrade using non-blocking Servlet 3.1 API

I asked a question regarding HTTP Upgrade handling in Servlet 3.1 on wildfly-dev mailing list how to develop simple bi-directional full-duplex echo protocol. After few days of discussion we concluded that the following example is somewhat correct:
#WebServlet(urlPatterns = "/upgrade")
public class AsyncEchoUpgradeServlet extends HttpServlet {
private static final long serialVersionUID = -6955518532146927509L;
#Override
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp) throws ServletException, IOException {
req.upgrade(Handler.class);
}
public static class Handler implements HttpUpgradeHandler {
#Override
public void init(final WebConnection wc) {
Listener listener = new Listener(wc);
try {
// we have to set the write listener before the read listener
// otherwise the output stream could be written to before it is
// in async mode
wc.getOutputStream().setWriteListener(listener);
wc.getInputStream().setReadListener(listener);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
#Override
public void destroy() {
}
}
private static class Listener implements WriteListener, ReadListener {
private final WebConnection connection;
private final Queue<String> queue = new ArrayDeque<String>();
private Listener(final WebConnection connection) {
this.connection = connection;
}
#Override
publicvoid onDataAvailable() throws IOException {
byte[] data = new byte[100];
while (connection.getInputStream().isReady()) {
int read;
if ((read = connection.getInputStream().read(data)) != -1) {
queue.add(new String(data, 0, read));
}
onWritePossible();
}
}
#Override
public void onAllDataRead() throws IOException {
}
#Override
public void onWritePossible() throws IOException {
while (!queue.isEmpty() && connection.getOutputStream().isReady()) {
String data = queue.poll();
connection.getOutputStream().write(data.getBytes());
}
}
#Override
public void onError(final Throwable t) {
}
}
}
It actually works and it is the only example exchanged during our discussion that works well and we don't have to create any additional threads to handle both input and output.
What bothers me in this example is that we call explicitly onWritePossible() from within onDataAvailable().
Does anyone have any other example on HTTP Upgrade using Servlet 3.1 API? Is the example shown above correct?

Spring-data-solr data import handler call

I'm using spring-data-solr and have data import handler(DIH) in solr. How can I call DIH by repository or SolrTemplate, or some else?
I'd recommend a Custom Respository using SolrCallback to execute desired request.
#Override
public SolrResponse dataImport(final String command) {
return solrTemplate.execute(new SolrCallback<SolrResponse>() {
#Override
public SolrResponse doInSolr(SolrServer solrServer) throws SolrServerException, IOException {
return new SolrRequest(METHOD.GET, "/dataimport?command=" + command) {
//..skipped some methods to shorten
#Override
public SolrResponse process(SolrServer server) throws SolrServerException, IOException {
SolrResponseBase response = new SolrResponseBase();
response.setResponse(server.request(this));
return response;
}
}.process(solrServer);
}
});
}
If someone else is struggling to get the DIH working in the current version (Solr 8.11) - this is what worked for me (be sure to adapt the core name):
solrTemplate.execute(new SolrCallback<SolrResponse>() {
#Override
public SolrResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException {
SolrRequest<SolrResponse> solrRequest = new SolrRequest<>(SolrRequest.METHOD.GET, "/<core_name>/dataimport?command=full-import&commit=true&clean=true") {
#Override
public SolrParams getParams() {
return null;
}
#Override
protected SolrResponse createResponse(SolrClient solrClient) {
SolrResponseBase response = new SolrResponseBase();
try {
response.setResponse(solrClient.request(this));
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
return response;
}
};
solrRequest.setResponseParser(new DelegationTokenResponse.JsonMapResponseParser());
return solrRequest.process(solrClient);
}
});

Categories