State Pattern using Spring DI - java

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";
}
}

Related

Providers for lazy loading in Guice

In the official document, I read an article about Providers for lazy loading. However, I can't understand why this below code means the delay of creating a provider because I can't find any annotation or any code which is corresponding with the lazy loading.
And the code is this code.
public class DatabaseTransactionLog implements TransactionLog {
private final Provider<Connection> connectionProvider;
#Inject
public DatabaseTransactionLog(Provider<Connection> connectionProvider) {
this.connectionProvider = connectionProvider;
}
public void logChargeResult(ChargeResult result) {
/* only write failed charges to the database */
if (!result.wasSuccessful()) {
Connection connection = connectionProvider.get();
}
}
Where in the world can we see the special point which causes a delay of loading?
creating a connection may be expensive, and it may not alway be needed. Therefore, rather than creating a connection at injection time, the guice framework allows the injection of a 'provider', which will create the dependency when the get() method is called.
The delay is in the way you call provider.get(), and it's delayed relative to the time the constructors are called for each dependency. In the example you have, the constructor for DatabaseTransactionLog gets called, but no connection is created at that time. A Connection is only created when the method logChargeResult is called (because of the provider.get() call in it).

transactional method throwing "no transactional entityManager available"

I have a method that is defined as #transactional. In fact I have a method calling a method that calls a method and all three are #transactional. The transactional logic worked fine, until I pulled a few methods out into an abstract class for some code reuse, which appears to have broken my logic somehow.
The transactional method is from an abstract class, here is a partial snippet of the relevant parts (I have to rewrite this by hand so forgive me for typos):
public abstract class ReadWriteService<ReadEntityTempalte extends IEntity, WriteEntityTemplate extends IEntity>
//extends jpaRepository, created using #enableJpaRepositories
private searchRepository<WriteEntityTemplate, String> writeRepository;
#PersistenceContext
private EntityManager em;
#transactional
public ReadEntityTemplate save(final WriteEntityTemplate entity){
if(entity == null) return null;
WriteEntityTemplate returnValue = writeRepository_.save(entity);
postSave(returnValue); //checks our security logic
flush();
ReadEntityTemplate returnEntity = find(returnValue.getId());
//required to detect changes made to the view by our save
em.refresh(returnEntity);
}
It's written this way because we are using views so the return value may be modified in the find() to the view. This logic worked in the past, and still works for a number of calls.
The method that fails is:
#Override
#transational
public void configure(EntityFileConfig config) throws ClassNotFoundException{
//load config from file
for(EntityConfig entityConfig: entityConfigs){
EntityType entityType=EntityTypeService_.find(entityConfig.getKey());
if(entityType==null){
entityType = EntityType.createByRequiredFields(entityConfig.getKey());
}
//update entityType to reflect config file.
entityType = entityTypeService_.save(entityType);
for(String permissionName: entityConfig.getPermissions()){
if(!entityTypeService_.hasPermission(entityType, permissionName)){
Permission permission = permissionSetup.getPermission(permissionName);
if(permission!=null)
//fails on below lines
permissionService._.addPermission(entityType, permission);
}
}
}
}
both the entityTypeService and the permissionService extend the above abstract class and use the same save method without alteration, addPermissions is a forloop that calls save on each permission.
The entityTypeService works, but the permissionService fails. When The permission service is called if I do em.isTransactionalEntity it returns false.
All #transactional annotations are using the spring annotation, not the javax one.
Actually, it seems as if a few of the permissions would save and others wouldn't, almost as if it's non-deterministic, but this may simple be due to modifying a database file that had some of the values already set and thus didn't need to run some of the logic the first time through.
I've done quite a bit of stumbling around but am no closer to determining what would cause my transaction to end. I had thought perhaps it was the #persistenceContext, since the JPARepos get their entityManager through a different approach then autowireing with #persistenceContext, but if that were the case everything would fail?
Any help would be appreciated, I'm pretty stumped on the cause of this.
Assuming you have enabled #EnableTransactionManagement on #Configuration class.
Since you didn't set any propagation on #Transaction the default value is Required. It means all methods must be part of transaction. Since one of your abstract methods is not part of the #Transactional hence the error.
For more information on Spring Transactions.
Note: Image taken from above link.

E4 EPartService findPart() throwing java.lang.Null Pointer Exception

New to Eclipse RCP (e4), am trying to get a handler to update a UI widget within a Part.
I have tried injecting the EPartService to first access the Part by ID, like so:
public class Example {
public static final String PART_ID = “au.org.example.app.part”;
#Inject
private EPartService partService;
public void eventOccured()
{
MPart part = partService.findPart(PART_ID); // exception thrown here
}
}
But this is throwing a NPE.
findPart() should at least safely return null if the ID were incorrect? So what am I missing?
Am also open to suggestions of relevant tutorials (have worked through some of Lars Vogella's great tutorials, but to no avail for this problem).
Any further info required please let me know.
EDIT : Looks like EPartService is not being injected? Have I not added it correctly?
Injection is only done automatically on objects which are known to the Application Model - things like parts and handlers.
For objects which you create you can do injection using the ContextInjectionFactory. You can create an object with:
#Inject
IEclipseContext context;
...
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
or you can do injection on an existing class instance with:
ContextInjectionFactory.inject(myClass, context);
in this case injection is not done on the class constructor.
There are other variants of make and inject which have a second context which allows additional values to be added to the context being injected.

Java EE Firing an Event creates a new Instance

I have two ManagedBeans.
Concerning my problem, they do the following:
First:
#ManagedBean
public class Provider {
private Event<ProvideEvent> event;
private static boolean handling = false;
public provide(#Observes ConsumeEvent consume){
if(!handling){
//provide some stuff
event.fire(new ProvideEvent(ProvidedStuff stuff);
}
}
}
Second:
#ManagedBean
#SessionScoped
public class Consumer {
private Event<ConsumeEvent> event;
#PostConstruct
public void initialize(){
event.fire(new ConsumeEvent());
}
private static boolean handling = false;
public consume(#Observes ProvideEvent providedStuff){
if(!handling){
//use the provided stuff
}
}
}
This happens, when the website is called:
1. Consumer is instantiated.
2. Consumer fires the event.
3. Provider is instantiated.
4. provide() is called.
5. A NEW CONSUMER IS INSTANTIATED
6. consume() is called.
As you can see, I had to use a boolean "handling" to keep the application from looping infinitly.
Why is the container not using the instantiated SessionScoped ManagedBean? I thought SessionScoped ManagedBeans are like Singleton for the Session?
I guess I could work around this by:
A: Using static variables for the changed properties.
B: Implementing the Observer-Pattern manually.
But there has to be an easier way here!?
I believe the problem could be that you fire the event in the #PostConstruct method of your Customer.
From the javadocs:
This method MUST be invoked before the class is put into service.
As far as I understand, that results in a race condition. The Provider is probably firing the second event earlier than your Customer instance finishes executing initialize() and the container puts it into service. Hence, it won't receive the event. I'm too inexperienced with Java EE to give good advice how to prevent that race condition though. I would probably work around it with an ugly SynchronousQueue as a meeting point.
Additional info: the default with #Observes is to create a new instance of the event receiver if none exists (is in service). That's why another customer is created. Use #Observes(notifyObserver = Reception.IF_EXISTS) to only notify existing instances that are in service.
I thought SessionScoped ManagedBeans are like Singleton for the Session?
No, it just defines the lifetime of the object(s). It doesn't really enforce session-singleton behavior. The container would probably prefer the existing instance though, if it was in service at the time the second event is fired.

Using a Singleton to create a default administrative account

I never used the #Singleton new feature of JavaEE 6 and i want to give it a try.
I was thinking in creating s Singleton to just hold a password that will allow the app adiministrator(The person that knows the password),to access some content of the app.
I tried to implement it following this tutorial, but it does not work.
This is what i did:
I created the singleton bean:
#Singleton
#Startup
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class AdminAcountEJB implements IAdminAcountEJB {
private String password;
#PostConstruct
public void init() {
password = "password";
}
#Lock(LockType.READ)
public String getPassword() {
return password;
}
}
I extracted an interface
public interface IAdminAcountEJB {
public abstract String getPassword();
}
Then i try to inject the singleton in a managed bean using #EJB
#Named("managementBB")
#SessionScoped
public class ManagementBB implements Serializable{
#EJB
private IAdminAcountEJB managementEJB;
private String input;
private boolean authorized;
public String seeWhatsUp() {
if(input.equals(managementEJB.getPassword())) {
authorized = true;
return "manage?faces-redirect=true;";
}
return "index?faces-redirect=true;";
}
//Get set methods...
}
The last thing i do is create some markup that is displayed in case the correct password is entered:
<h:form rendered="#{managementBB.authorized == false}">
<h:inputSecret value="#{managementEJB.input}"/>
<h:commandButton value="..." action="#{managementEJB.seeWhatsUp}"/>
</h:form>
<h:form rendered="#{managementBB.authorized}">
CORRECT PASSWORD!!
</h:form>
It all seems ok to me, but when i access the page, the console says:
javax.naming.NameNotFoundException:
ejbinterfaces.IAdminAcountEJB#ejbinterfaces.IAdminAcountEJB not found
I don't understand why it don't work, this is how i inject other EJB's that are not Singletones but with #Singleton it does not work.
-How can i fix it?
-I am also interested in knowing what do you think about using a singletone for this purpose, you think is a good and safe idea?
I guess the problem is, that since you refer to your singleton within an EL expression in the view, it has to be annotated with #Named. If you use your beans only within others, this is not necessary.
Concerning your design, my 2 pennies are these:
Since you are using Java EE 6, you won't need to specify an interface for it. If you want/need it nevertheless, don't call it ISomething (except you work for Apple ;-) but give it a domain related name.
Using a singleton which allows concurrent read access is ok for core data. Only, I wouldn't put the password within the code, but into a database table, preferrably hashed and use the singleton as a provider for that which reads the table at startup.
Singletons in general may always introduce a bottleneck into the application because by definition they don't scale. So for your use case it's ok, since we can assume the access rate is very low. The other problem which might be introduced are race conditions (also not in your case) if we have data that changes, since we only have one instance being called in parallel.

Categories

Resources