Java Web Service Object (JAX-WS) lifetime - java

I am currently developing a Java web application that exposes a web service interface. The class definition of my web service is as follows:
#WebService()
public class ETL_WS {
private String TOMCAT_TEMP_DIR;
private final int BUFFER_SIZE = 10000000;
private ConcurrentHashMap myMap;
private String dbTable = "user_preferences";
public ETL_WS() {
Context context = null;
try {
context = (Context) new InitialContext().lookup("java:comp/env");
this.TOMCAT_TEMP_DIR = (String) context.lookup("FILE_UPLOAD_TEMP_DIR");
}catch(NamingException e) {
System.err.println(e.getMessage());
}
public long getCouponMapCreationTime() {
return couponMap.getCreationTime();
}
}
Due to the fact that I need all the requests to see the same ConcurrentHashMap myMap instance, I would like to know what is the lifetime of a web service object. To be specific, I know that it is initialized at the first client request. But, will all the clients see the same instance of the myMap object? If not, how is this possible?
Thank you for your time.

Short answer: No, you have no control over how many instances of this class will be created by the application server. The only sure thing is that at least one object will be instantiated before the first request.
Typically, application servers create one instance per worker thread, which means tens of object of the same class.
However, it's possible to have common data among these instances, the most simple solution is to use static member variables. Static members are guaranteed to be unique among every objects, since they belong to the class.
#WebService()
public class ETL_WS {
// ...
private static ConcurrentHashMap myMap;
// ...
}

One way that I can think of will be to maintain this in a singleton behind the Webservice, this way the WS lifecycle does not really matter (It is a singleton - but the purpose of the WS interface is to simply get the request in, it would be better to encapsulate the core logic of the application behind it in a service).

Related

Spring - Storing volatile data in memory

I'm developing a SpringBoot web application for managing gaming servers.
I want to have a cronjob that queries the servers, checks whether they have crashed and collects relevant data, such as the number of players online etc. This data needs to be stored and shared among services that require it. Since this data will change often and will become invalid after the whole application stops, I don't want to persist these stats in the database, but in the application memory.
Current implementation
Currently, my implementation is pretty naive - having a collection as a member field of the corresponding Spring service and storing the server statuses there. However I feel this is a really bad solution, as the services should be stateless and also I don't take concurrency into account.
Example code:
#Service
public class ServersServiceImpl implements ServersService {
private final Map<Long, ServerStats> stats = new HashMap<>(); // Map server ID -> stats
...
public void startServer(Long id) {
// ... call service to actually start server process
serverStats.setRunning(true);
stats.put(id, serverStats);
}
...
}
Alternative: Using #Repository classes
I could move the collection with the data to classes with #Repository annotation, which would be semantically more correct. There, I would implement a thread-safe logic of storing the data in java collection. Then I would inject this repository into relevant services.
#Repository
public class ServerStatsRepository {
private final Map<Long, ServerStats> stats = new ConcurrentHashMap<>();
...
public ServerStats getServerStats(Long id) {
return stats.get(id);
}
public ServerStats updateServerStats(Long id, ServerStats serverStats) {
return stats.put(id, serverStats);
}
...
}
Using Redis also came to mind, but I don't want to add too much complexity to the app.
Is my proposed solution a valid approach? Would there be any better option of handling this problem?

Danger of instantiating a class in a verticle vert.x

I explain my problem, I have a verticle in which I defined all the routes. And I have simple java classes that contain methods that I call in my verticle depending on the route. For example, my downloadFile() method is in the MyFile class like this:
public class MyFile {
public final void downloadFile(RoutingContext rc, Vertx vertx) {
final HttpServerResponse response = rc.response();
response.putHeader("Content-Type", "text/html");
response.setChunked(true);
rc.fileUploads().forEach(file -> {
final String fileNameWithoutExtension = file.uploadedFileName();
final JsonObject jsonObjectWithFileName = new JsonObject();
response.setStatusCode(200);
response.end(jsonObjectWithFileName.put("fileName", fileNameWithoutExtension).encodePrettily());
});
}
public final void saveFile(RoutingContext rc, Vertx vertx) {
//TODO
}
}
And I use this class in my verticle like this:
public class MyVerticle extends AbstractVerticle{
private static final MyFile myFile = new MyFile();
#Override
public void start(Future<Void> startFuture) {
final Router router = Router.router(vertx);
final EventBus eventBus = vertx.eventBus();
router.route("/getFile").handler(routingContext -> {
myFile.downloadFile(routingContext, vertx);
});
router.route("/saveFile").handler(routingContext -> {
myFile.saveFile(routingContext, vertx);
});
}
}
My colleague tells me that it is not good to instantiate a class in a verticle and when I asked him why, he replied that it becomes stateful and I have doubts about what he says to me because I don't see how. And as I declared my MyFile class instance "static final" in my verticle, I want to say that I even gain in performance because I use the same instance for each incoming request instead of creating a new instance .
If it's bad to instantiate a class in a verticle, please explain why?
In addition I would like to know what is the interest of using 2 verticles for a treatment that only one verticle can do?
For example, I want to build a JsonObject with the data I select in my database, why send this data to another verticle knowing that this verticle does nothing but build the JsonObject and wait for it to answer me for sent the response to the client so that I can build this JsonObject in the verticle where I made my request and immediately sent the response to the client.I put you a pseudo code to see better :
public class MyVerticle1 extends AbstractVerticle{
public void start(Future<Void> startFuture) {
connection.query("select * from file", result -> {
if (result.succeeded()) {
List<JsonArray> rowsSelected = result.result().getResults();
eventBus.send("adress", rowsSelected, res -> {
if (res.succeded()) {
routinContext.response().end(res.result().encodePrettily());
}
});
} else {
LOGGER.error(result.cause().toString());
}
});
}
}
public class MyVerticle2 extends AbstractVerticle{
public void start(Future<Void> startFuture) {
JsonArray resultOfSelect = new JsonArray();
eventBus.consumer("adress", message -> {
List<JsonArray> rowsSelected = (List<JsonArray>) message.body();
rowsSelected.forEach(jsa -> {
JsonObject row = new JsonObject();
row.put("id", jsa.getInteger(0));
row.put("name", jsa.getString(1));
resultOfSelect.add(row);
});
message.reply(resultOfSelect);
});
}
}
I really do not see the point of making 2 verticles since I can use the result of my query in the first verticle without using the second verticle.
For me, EventBus is important for transmitting information to verticles for parallel processing.
bear in mind... the answers you're looking for are unfortunately very nuanced and will vary depending on a number of conditions (e.g. the experience of whoever is answering, design idioms in the codebase, tools/libraries at your disposal, etc). so there aren't an authoritative answers, just whatever suits you (and your co-workers).
My colleague tells me that it is not good to instantiate a class in a
verticle and when I asked him why, he replied that it becomes stateful
and I have doubts about what he says to me because I see not how.
your colleague is correct in the general sense that you don't want to have individual nodes in a cluster maintaining their own state because that will in fact hinder the ability to scale reliably. but in this particular case, MyFile appears to be stateless, so introducing it as a member of a Verticle does not automagically make the server stateful.
(if anything, i'd take issue with MyFile doing more than file-based operations - it also handles HTTP requests and responses).
And as I declared my MyFile class instance "static final" in my
verticle, I want to say that I even gain in performance because I use
the same instance for each incoming request instead of creating a new
instance .
i'd say this goes to design preferences. there isn't any real "harm" done here, per se, but i tend to avoid using static members for anything other than constant literals and prefer instead to use dependency injection to wire up my dependencies. but maybe this is a very simple project and introducing a DI framework is beyond the complexity you wish to introduce. it totally depends on your particular set of circumstances.
In addition I would like to know what is the interest of using 2
verticles for a treatment that only one verticle can do?
again, this depends on your set of circumstances and your "complexity budget". if the processing is simple and your desire is to keep the design equally simple, a single Verticle is fine (and arguably easier to understand/conceptualize and support). in larger applications, i tend to create many Verticles along the lines of the different logical domains in play (e.g. Verticles for authentication, Verticles for user account functionality, etc), and orchestrate any complex processing through the EventBus.

Java Jersey: Whats the best way to share data between the Main-object and the Webservice

Lets say I have a Jersey-service inside a grizzles server and I like to share data between the server and the service-implementation (e.g. mydata).
public class MyServer
{
String mydata="";
public static void main (String [] args)
{
ResourceConfig rc = new ResourceConfig ().packages (MyServer.class.getPackage ().getName ());
HttpServer hs = GrizzlyHttpServerFactory.createHttpServer (URI.create ("http://localhost/myserver"), rc);
for (int i = 0; i < 10; i ++)
{
mydata += "bla";
}
hs.shutdown ();
}
}
#Path ("myservice")
public class MyService
{
#GET
public String getIt()
{
// how to access mydata?
}
}
Whats the best way to share that data?
I can think of a singleton or make mydata static. But maybe there is a standard-way I do not see here?
Thanks!
You can make mydata static or instance variable of singleton if and only if mydata is really static and cannot be changed by multiple threads (e.g. inside your getIt() method of the service).
Such technique applies and uses usually for common configuration properties.
In general it is a standard way for such situation. BTW you can keep your mydata not necessary in the Server class, but make another class to keep such common data there (if there are bunch of them) , but it is a matter of choice.
Also it is more standard to do not make actual mydata field public , but provide getter/setter pair for it.
Finally, if such common/static value can be changed by multiple threads you need to make it synchronized to avoid concurrent modifications.
There are much more different approaches to handle concurrency and make code thread-safe, but it belongs to your actual needs. Anyway all of them end up to static/singleton synchronized implementation.
PS. Be careful, if it is a common static data you have to populate it before start the server not after (as in your example) - otherwise there is a possibility that request may come before data ready to use by service thread.

Session - servlets, in a sevlet i set a static variable to something and this remains the same for all the sessions

i have a simple Jsp page that hits to servlet and in the servlet i call a method from another class and in this method i am declaring a static variable globally and setting a value to it and then the servlet's task is over so the control is back to the jsp page (or to a page that i forward the request and response to).
so wat just happened is termed a session???
the value set to that static variable remains the same for all the sessions that are coming next!! why is this happening. dint the earlier session end ?? if it has ended, then why is the value for the static variable that i have set is still remaining like that only in my subsequent sessions?? please correct me if i am wrong. Help me to learn! stackoverflow has never let me down!!!! thanks in advance
static fields in a class will live until the class itself is unloaded and garbage collected. So, static fields in a serlvet will not only live across all the sessions but across the whole application, in this case, until the web application is undeployed.
In fact, it is not wise to have any field in a servlet unless this field cannot be modified after being initialized or if it is injected by the container like an EJB or a CDI bean. This is because a single Servlet instance will be used to attend several requests made to the server, so even if you have a non-static field in your servlet and you update it through requests, its value can be modified by two or several requests happening at the same time. Try to keep the variables to the shortest possible scope, for example, inside a method only.
More info:
How do servlets work? Instantiation, sessions, shared variables and multithreading
From comments, looks like your real problem is about a design to support synchronization across several threads. A better option would be creating an object instance that will be shared among your threads, then use a final non-static field to handle the synchronization:
class MyClass {
final Object lock = new Object();
//other fields in the class...
}
class Multijobs {
class Job implements Runnable {
MyClass myClass;
public Job(MyClass myClass) {
this.myClass = myClass;
}
#Override
public void run() {
//handle the job here...
//using the synchronization point
synchronize(myClass.lock) {
}
}
}
static final int NUM_THREADS = 10;
public void executeSeveralJobs() {
ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
MyClass myClass = new MyClass();
executorService.execute(new Job(myClass));
executorService.execute(new Job(myClass));
//initialize the jobs and add them to the ExecutorService
//...
executorService.shutdown();
//...
}
}

Utility Class with static reference of a client

I came across a code where a utility class has a static reference of a client of a service. Here is the simplified version of the code
public class MyHelper {
//assume that prime service checks if the number is prime
private static PrimeService client;
public static void setClient(PrimeService client) {
MyHelper.client = client;
}
public static boolean isIntegerPrime(int i) {
return client.isIntegerPrime(i);
}
}
Any thoughts on the design of this class? Apart from accidently setting the client to null, I could not think of any downside of such utility classes with static references of remote service clients. I am interested in knowing the correctness of this class from design perspective.
Your setMethod is of no use as it is not setting the static variabl.
public static void setClient(PrimeService client) {
client = client; //the assignment to this variable has no effect. }
You need to change this to
public static void setClient(PrimeService client) {
MyHelper .client = client;
}
Well, if the client is set before the 1st call of "isIntegerPrime" you would not see any NullPointerExceptions.
You might get problems with parallel access to that client. Thus when synchronization is an issue.
If PrimeService is also under your control and usage like that is ok, it might also be an option to make the method in PrimeService static.
The biggest problem you might run into with this design (aside from concurrent access and the programming error mentioned in Juned's Answer) is that you might share state inadvertently. There is no way that MyHelper can be sure that the passed client reference is not used elsewhere. This might pose an encapsulation problem. Consider the concurrent access problem. Even if you make the method isPrime(int i) synchronized, some other thread might call isIntegerPrime on the PrimeService instance passed to MyHelper.

Categories

Resources