class A
if(userAuthenticated)
ArrayList accounts = getAccountForUser(customerId);
UserInfo userinfo = new UserInfo();
userinfo.getUserInfo(accounts);
}
==============
class UserInfo
{
public ArrayList<String> getUserInfo(ArrayList list) {
ArrayList useraccounts = list;
return useraccounts;
}
}
===============
Now inside Class C i will have a String and i need to check , if that String Value exists then do something else do soemthing
The Problem is as this being a WebApplication , i cannot use instance varaibe in the Application .
class C
{
public String makeDBCALL(String account)
{
Here i need to get that ArrayList of UserInfo and check if taht list.contains(account))
could anybody please tell me how can do this .
}
}
Context
You need context.
Servlet classes need to be given that context.
DB or memory
You could have a reference to a DB (a Datasource) and query every time the DB, or have something in memory (that list by example).
Any way if C is a servlet class that knows it's inside a servlet environment you could ask for the app context. If it's a business class, something more agnostic then it's better to receive by parameter or property the context it needs.
Setting a context
If you use Spring configuration (Spring IOC) you could set what the classes needs writing the correct xml.
If you don't, then, at some place you'll need to look for DB connection, or initialize that list and give other classes a reference.
At last, a concrete solution
Write a context listener that generates this needed context at initialization (onContextCreated) and hangs it from the application context:
class MyListener implements ServletContextListener
{
contextInitialized(ServletContextEvent event) {
// Create theObjWEhatYouNeed
event.getServletContext().setAttribute("whatINeed", theObjWhatYouNeed);
}
}
Configure your web.xml to use MyListener
<listener>
<listener-class>MyListener</listener-class>
</listener>
Then use it from your servlet class (there can be a lot of instances of the same servlet class, have that in mind)
doGet(...) {
MyObj myObj = (MyObj) request.getSession().getServletContext().getAttribute("whatINeed");
}
Related
It's RESTful web app. I am using Hibernate Envers to store historical data. Along with revision number and timestamp, I also need to store other details (for example: IP address and authenticated user). Envers provides multiple ways to have a custom revision entity which is awesome. I am facing problem in setting the custom data on the revision entity.
#RevisionEntity( MyCustomRevisionListener.class )
public class MyCustomRevisionEntity extends DefaultRevisionEntity {
private String userName;
private String ip;
//Accessors
}
public class MyCustomRevisionListener implements RevisionListener {
public void newRevision( Object revisionEntity ) {
MyCustomRevisionEntity customRevisionEntity = ( MyCustomRevisionEntity ) revisionEntity;
//Here I need userName and Ip address passed as arguments somehow, so that I can set them on the revision entity.
}
}
Since newRevision() method does not allow any additional arguments, I can not pass my custom data (like username and ip) to it. How can I do that?
Envers also provides another approach as:
An alternative method to using the org.hibernate.envers.RevisionListener is to instead call the getCurrentRevision( Class revisionEntityClass, boolean persist ) method of the org.hibernate.envers.AuditReader interface to obtain the current revision, and fill it with desired information.
So using the above approach, I'll have to do something like this:
Change my current dao method like:
public void persist(SomeEntity entity) {
...
entityManager.persist(entity);
...
}
to
public void persist(SomeEntity entity, String userName, String ip) {
...
//Do the intended work
entityManager.persist(entity);
//Do the additional work
AuditReader reader = AuditReaderFactory.get(entityManager)
MyCustomRevisionEntity revision = reader.getCurrentRevision(MyCustomRevisionEntity, false);
revision.setUserName(userName);
revision.setIp(ip);
}
I don't feel very comfortable with this approach as keeping audit data seems a cross cutting concern to me. And I obtain the userName and Ip and other data through HTTP request object. So all that data will need to flow down right from entry point of application (controller) to the lowest layer (dao layer).
Is there any other way in which I can achieve this? I am using Spring.
I am imagining something like Spring keeping information about the 'stack' to which a particular method invocation belongs. So that when newRevision() in invoked, I know which particular invocation at the entry point lead to this invocation. And also, I can somehow obtain the arguments passed to first method of the call stack.
One good way to do this would be to leverage a ThreadLocal variable.
As an example, Spring Security has a filter that initializes a thread local variable stored in SecurityContextHolder and then you can access this data from that specific thread simply by doing something like:
SecurityContext ctx = SecurityContextHolder.getSecurityContext();
Authorization authorization = ctx.getAuthorization();
So imagine an additional interceptor that your web framework calls that either adds additional information to the spring security context, perhaps in a custom user details object if using spring security or create your own holder & context object to hold the information the listener needs.
Then it becomes a simple:
public class MyRevisionEntityListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
// If you use spring security, you could use SpringSecurityContextHolder.
final UserContext userContext = UserContextHolder.getUserContext();
MyRevisionEntity mre = MyRevisionEntity.class.cast( revisionEntity );
mre.setIpAddress( userContext.getIpAddress() );
mre.setUserName( userContext.getUserName() );
}
}
This feels like the cleanest approach to me.
It is worth noting that the other API getCurrentRevision(Session,boolean) was deprecated as of Hibernate 5.2 and is scheduled for removal in 6.0. While an alternative means may be introduced, the intended way to perform this type of logic is using a RevisionListener.
I want to implement a setUserIfPresent() method that puts a user object into the context like Http.Context.current().args.put("user", user);
This method should be applied before every controller method so that views have access implicit access to the user.
With Play1 I create a BaseController that invokes this method before all requests (#Before filter) and extended all other controllers from this one.
How to achieve something like this in play2 using Java API?
Seems like there is something for Scala but for Java? http://www.playframework.com/documentation/2.2.x/ScalaHttpFilters
Cheers
While you could use filters (or Interceptors) in the "traditional" webapp framework way, the Play-preferred way seems to definitely be to compose custom Action methods; see the documentation on Action Composition.
If you follow their style, you'll define a new Action implementation like this:
public class UserContextInjectingAction extends play.mvc.Action.Simple {
public F.Promise<SimpleResult> call(Http.Context ctx) throws Throwable {
Logger.info("Injecting user data into context " + ctx);
injectUser(ctx); // Written by you
return delegate.call(ctx);
}
}
And you'd end up with controller code that looks like this:
#With(UserContextInjectingAction.class)
public static Result showHomePage() {
return ok("Welcome");
}
I am facing a problem in converting my state pattern using plain java to spring DI since I am new to spring.
Actually I made a project using state pattern but I took the approach that every state knows it successive states not the context class.
The context class has a field "currentState" its type is IState, and it has method setState(IState state).
The IState has one method geNext(Context context).
And in the context class I made a while(keepOn) keepOn is true and it become false in ExitState to stop processing, in this loop I call currentState.goNext().
Each state make some database transactions and webservice's calls and depending on the result it set the next state using context.setState(new StateFour()) -for example-.
The first state is set by the client after creating the context.
Code sample:
public interface IState{public void goNext(Context context);}
public class StateOne implements IState{
public void goNext(Context context){
//do some logic
if(user.getTitle.equals("manager"){context.setState(new StateThree());}
else if(user.getTitle.equals("teamLead"){context.setState(new StateTwo());}
else{context.setState(new ExitState());}
}
}
public class Context{
private boolean keepOn = true;
private IState currentState;
public void setState(IState state){
currentState = state;
}
while(keepOn){currentState.goNext(this);}
}
Now I am trying to use spring DI annotation-based, the problem I am facing is that the context will annotated "currentState field" with #Autowired but I need the spring container to do the same logic if I am in state one and "if statement" success inject state three "else if" inject state two otherwise inject exitState.
If I use #Qualifier(value ="stateOne") it will specify only the first state which implements the interface but the other states which I set depending on the situation I don't know how to specify it in spring.
Also org.springframework.core.Ordered need specifying the orders of the beans in advance but I don't know the values I will receive from the database or webservice in advance, it should be specified at runtime.
So is it possible to replace this plain java with spring DI and how?
Thanks in advance for any help and sorry for lengthening.
You should use ApplicationContext. Example below:
// Inject application context into your bean
#Autowired
ApplicationContext applicationContext;
// Get bean from the context (equivalent to #Autowired)
applicationContext.getBean(StateThree.class);
The most versatile way to auto wire the state is by registering a resolvable dependency with a ConfigurableListableBeanFactory. As a dependency you could drop in your implementation of org.springframework.beans.factory.ObjectFactory<T> which will get the current user and creates/fetches the state to be injected.
This is exactly what happens when you, for instance, auto wire a field of type HttpServletRequest. A RequestObjectFactory will get the current request and inject it using this implementation.
// org.springframework.web.context.support.WebApplicationContextUtils
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
#Override
public ServletRequest getObject() {
return currentRequestAttributes().getRequest();
}
#Override
public String toString() {
return "Current HttpServletRequest";
}
}
Note: this is not cross-posting (although it's related to my other question shared objects between webapps of the same tomcat)
I have 2 webapps running at two contexts: c1, c2 (both immediately after the root). I put a startupListener in c1 to share a variable, and another one in c2 to retrieve it. The problem is if I share an object of built-in datatypes (like HashMap, Integer,...) it is ok, but custom datatype can't be cast. For example, if I have a custom class named User, and pass an object of that type around, ClassCastError happened.
My startuplistener in c1 is:
public void contextInitialized(ServletContextEvent sce) {
User user = new user("name");
Integer exampleInt = 1;
ServletContext context = sce.getServletContext().getContext("/c1");
if (context!=null)
{
context.setAttribute("user", user);
context.setAttribute("id", exampleInt);
}
}
In c2 app, it is like this:
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext().getContext("/c1");
Integer integer = (Integer) context.getAttribute("id");//this line is OK
Object object = context.getAttribute("user");
User userObject = (User) object; //this line triggered error
User user = (User) context.getAttribute("user");// also trigger error
}
Why so? (a class complain about casting to itself?). Any workaround: I want to share my objects between contexts of the same jvm.
Tks.
The class of the object in the first webapp is loaded by the first webapp classloader. A class with the same name is loaded in the second webapp, by the second webapp classloader. So, even if both apps have access to a class with the same name, they're two different classes, because they're not loaded by the same classloader.
I wouldn't try to share objects between apps this way. It won't work in a clustered environment anyway, and a more secure container could return null when asked for another servlet context. Consider sharing a database between the two applications, and storing the shared data in the shared database.
If you still want to go this route, then make sure the shared classes are in the container's classpath, and not in each webapp classpath.
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).