Non-serializable attributes in Struts Action class - java

I am working on refactoring our code according to Sonar and Kiuwan analyzers recommendations. Our architecture is standard MVC Java Web App based on Struts 2.x framework deployed on Apache Tomcat 9.x. App itself is basically an information system that allows users to browse pdf documents and perform actions on them.
I have run into a design flaw which I am not sure how to solve or if it even is an problem all togther.
During http request processing we set set up Hibernate's Entity Manager instance in Interceptor class before Struts Actions are called. We are using this EM instance for the whole lifecycle of the Struts action. When the action finishes the interceptor closes the EM instance. The EM instance is saved into instance of action class as an class attribute. Snippet below.
class BaseAction extends ActionSupport implements EntityManagerAware { //EntityManagerAware my interface that allows interceptor to inject em instance into underlying Action class
private EntityManager em;
private String someParam;
#Action(value = "welcome", results = {#Result(name = SUCCESS, type = "tiles", location = "welcome")})
public String input() {
em.doStuffWithEntities();
log.trace("Some param": + someParam);
return SUCCESS;
}
...
}
I have always thought this is solution is OK, but now we introduced Sonar. Sonar marks em attribute as - Make "em" transient or serializable. I understand that Sonar thinks it is an attribute that might be passed during HttpRequests, line someParam attribute in the snippet above.
My question is do Struts action attributes need to be Serializable (even the ones like "em") ? Can I somehow solve this with perhaps Struts annotation or simply with transient flag? When does serialization of Action class instance occur ? Can it occur ?
Basically can somebody explain this in greater detail (I can always just mark this Sonar issue as false positive, but I really do not know how this works) ? I have googled and googled but came up empty handed.
Thank you very much,
Jiri

EntityManager should be a persistent dependency, for example:
#PersistenceUnit(unitName = "QueryPersistenceUnit")
private EntityManagerFactory entityManagerFactory;
public EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}

Related

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.

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.

How to wrap Wicket page rendering in a Spring / Hibernate transaction?

My application loads entities from a Hibernate DAO, with OpenSessionInViewFilter to allow rendering.
In some cases I want to make a minor change to a field -
Long orderId ...
link = new Link("cancel") {
#Override public void onClick() {
Order order = orderDAO.load(orderId);
order.setCancelledTime(timeSource.getCurrentTime());
};
but such a change is not persisted, as the OSIV doesn't flush.
It seems a real shame to have to call orderDOA.save(order) in these cases, but I don't want to go as far as changing the FlushMode on the OSIV.
Has anyone found any way of declaring a 'request handling' (such as onClick) as requiring a transaction?
Ideally I suppose the transaction would be started early in the request cycle, and committed by the OSIV, so that all logic and rendering would take place in same transaction.
I generally prefer to use additional 'service' layer of code that wraps basic DAO
logic and provides transactions via #Transactional. That gives me better separation of presentation vs business logic and is
easier to test.
But since you already use OSIV may be you can just put some AOP interceptor around your code
and have it do flush()?
Disclaimer : I've never actually tried this, but I think it would work. This also may be a little bit more code than you want to write. Finally, I'm assuming that your WebApplication subclasses SpringWebApplication. Are you with me so far?
The plan is to tell Spring that we want to run the statements of you onClick method in a transaction. In order to do that, we have to do three things.
Step 1 : inject the PlatformTransactionManager into your WebPage:
#SpringBean
private PlatformTransactionManager platformTransactionManager;
Step 2 : create a static TransactionDefinition in your WebPage that we will later reference:
protected static final TransactionDefinition TRANSACTION_DEFINITION;
static {
TRANSACTION_DEFINITION = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
((DefaultTransactionDefinition) TRANSACTION_DEFINITION).setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
}
Feel free to change the TransactionDefinition settings and/or move the definition to a shared location as appropriate. This particular definition instructs Spring to start a new transaction even if there's already one started and to use the maximum transaction isolation level.
Step 3 : add transaction management to the onClick method:
link = new Link("cancel") {
#Override
public void onClick() {
new TransactionTemplate(platformTransactionManager, TRANSACTION_DEFINITION).execute(new TransactionCallback() {
#Override
public Object doInTransaction(TransactionStatus status) {
Order order = orderDAO.load(orderId);
order.setCancelledTime(timeSource.getCurrentTime());
}
}
}
};
And that should do the trick!

looking up entity manager in EJB Helper classes

I am trying to inject entity manager in some helper class, I can pass it to the helper from the session bean, but the problem is I need to use the entity manager in the static init block of the helper class (some thing like):
class MySessionBeanHelperClass
{
// staff here...
static
{
SomeClass s = new SomeClass(entityManager);
}
}
So, I think the only way is to lookup the entity manager instead of injecting it. and also using the passed SessionContent will not work here. (is it????) (this is the first question)
The second question is:
If I used the ordinary way to lookup a resource (in this case the entity manager) (something like the following:)
Context ic = new InitialContext();
em = (EntityManager) ic.lookup("java:comp/env/persistence/em");
Is this will convert all transactions used by this entity manager to Bean-managed transaction??
Thanks!
I don't think it's a good idea to do that from static initializer. You have to be sure that all necessary services (such as JNDI, JPA) are up before the lookup occurs, but you can't guarantee that when you do it from a static initializer.
It's a known problem in EJB that there is no "standard" way of performing one-time task upon app. start/stop, but you can use the trick in the following link:
How to perform a DB cleanup operation upon shutdown in an EJB container
The example is for performing action upon app. stop, but you can override Servlet#init instead.
Answer to your second question, No.
First question, its not really a good idea. BTW, what are you up to? In case you need EntityManager in your helper class, its better to make it a private instance level variable, and pass that from your session bean using helper class constructor.

Categories

Resources