-
1. Re: Best Process for calling another application from seam application
stefanotravelli Jan 28, 2009 6:55 PM (in response to valatharv)In a similar scenario I found asynchronous events the perfect solution.
Call your external application in a Stateless Seam component with an @Observer method and raise an asynchronous event in the seam application.
@Name("externalApplicationInvoker") @Scope(ScopeType.STATELSS) public class ExternalApplicationInvoker { @Observer("somethingOccurred") @Transactional public void doStuff(Long param) { // do whatever } }
In the Seam application, when you want the external process to be invoked:
Events.instance().raiseAsynchronousEvent("somethingOccurred", param);
-
2. Re: Best Process for calling another application from seam application
valatharv Jan 28, 2009 7:41 PM (in response to valatharv)Thanks for replying, I need few clarification:
I need to call a function of external application and pass some arguments including Experiment ID from persist(); as per code below.
So, as per your valuable suggestion, please suggest :
a) I should use either (b) or (c) ?
b) INSTEAD OF DIRECTLY CALLING ExternalApplication function (executeExternalApplication) from "experimentHome.persist()". I should call externalApplicationInvoker.doStuff(args...) from "experimentHome.persist()"
In this case, will I get "persisted" message and be able to continue navigating seam pages.
Simultaneously, ExternalApplication process will continue ?
c) Events.instance().raiseAsynchronousEvent("somethingOccurred", param);
How can I invoke "ExternalApplication" using this ?, any code sample...
//SEAM APPLICATION
@Name("experimentHome")
public class experimentHome extends EntityHome<Experiment> {
public String persist(){
String persistResult = super.update();
//INSTEAD OF DIRECTLY CALLING ExternalApplication here I should call ExternalApplicationInvoker here ?
//Note I need to pass some arguments including Experiment ID
//executeItraqAnalysisSql("Argxxx",this.getInstance().getId().toString());
return persistResult;
}
}
@Name("externalApplicationInvoker")
@Scope(ScopeType.STATELSS)
public class ExternalApplicationInvoker
{
@Observer("somethingOccurred")
@Transactional
public void doStuff(Long param)
{
// do whatever
executeExternalApplication(param);
}
//EXTERNAL APPLICATION
public void executeExternalApplication(String quantType, String qHjid) {
String[] args=new String[]{quantType, qHjid};
ExternalApplication externalApplication=new ExternalApplication();
externalApplication.run(args);
}
} -
3. Re: Best Process for calling another application from seam application
stefanotravelli Jan 28, 2009 8:42 PM (in response to valatharv)What I was suggesting is the use of the seam event infrastructure, so option (c). This way you can decouple your ExternalApplication avoiding dependencies.
The call to the doStuff() method happens as follow: since the method is annotated with @Observer("somethingOccured"), Seam will invoke it when an event of type
somethingOccurred
is raised.In order to raise an event of type
somethingOccurred
you use the API Events.instance().raiseEvent("somethingOccurred").For instance:
@Override public String persist() { String result = super.persist(); Events.instance().raiseEvent("somethingOccurred"); return result; }
At this point you have several options.
First, you can add a parameter to the event. Seam expects this parameter in the observer method signature:
@Override public String persist() { String result = super.persist(); Events.instance().raiseEvent("somethingOccurred", getId()); return result; }
Then you can choose to raise the event asynchronously, so that navigation continue while the method processing goes in background (in a separate transaction).
@Override public String persist() { String result = super.persist(); Events.instance().raiseAsynchronousEvent("somethingOccurred", getId()); return result; }
Finally, It should be pointed out that EntityHome objects are already raising events while performing CRUD operations.
In fact, EntityHome.persist() raises an event of type org.jboss.seam.afterTransactionSuccess.Experiment, where Experiment is the name of your class.
So, without touching your application, you can write an observer that will be notified of the entity being persisted, updated, etc.
Such events are raised in a special manner, that is after the transaction is successfully committed.
In the following code an observer listen for afterTransactionSuccess event end raises an asynchronous event in order to call the external application in background:
@In(create = true) ExperimentHome experimentHome; @Observer("org.jboss.seam.afterTransactionSuccess.Experiment") public void experimentSaved() { // get the id of the saved instance Long id = experimentHome.getExperimentId(); ExternalApplication externalApplication=new ExternalApplication(); externalApplication.run(id); }
This should work without any change in the EntityHome.
Hope this helps
stefano
-
4. Re: Best Process for calling another application from seam application
valatharv Jan 29, 2009 1:21 AM (in response to valatharv)I am really thankful to you and I am also digging/ reading more into this interesting (Seam's one more wonderful) approach. I am new to this so I might ask basic questions but please bear with me...
When I click "Save"..
a) quantExperimentHome.persist() is called, Experiment is created and I get correct message as "Successfully created".
Please consider Experiment as QuantExperiment (refactored...)
b) Control goes to externalApplicationInvoker but I get the following exception.
I didn't changed any thing in quantExperimentHome.persist() and below is the code.
-------------------------------------------------------------
ERROR [org.jboss.seam.transaction.SynchronizationRegistry] Exception processing transaction Synchronization after completion
org.jboss.seam.RequiredException: @In attribute requires non-null value: externalApplicationInvoker.quantExperimentHome
at org.jboss.seam.Component.getValueToInject(Component.java:2178)
at org.jboss.seam.Component.injectAttributes(Component.java:1601)
----------------------------------------------------------------
-- quantExperimentHome.persist()
public String persist(){
return super.persist();
}
-- For testing I am just printing id. This is ExternalApplicationInvoker. Even if I comment "Long id", exception is same.
@Name("externalApplicationInvoker")
@Scope(ScopeType.STATELESS)
public class ExternalApplicationInvoker
{
@In(create = true)
QuantExperimentHome quantExperimentHome;
@Observer("org.jboss.seam.afterTransactionSuccess.QuantExperiment")
public void experimentSaved()
{
System.out.println("************** ExternalApplicationInvoker.experimentSaved(), ENTERED ");
// get the id of the saved instance
Long id = experimentHome.getQuantExperimentHjid();
System.out.println("************** ExternalApplicationInvoker.experimentSaved(), id = "+id);
//ExternalApplication externalApplication=new ExternalApplication();
//externalApplication.run(id);
}
} -
5. Re: Best Process for calling another application from seam application
stefanotravelli Jan 29, 2009 10:58 AM (in response to valatharv)Check if the name of the home component is exactly "quantExperimentHome".
The injection that occurs with:
@In QuantExperimentHome quantExperimentHome; <<= THIS NAME...
requires that the name of the variable quantExperimentHome corresponds exactly to the name of the component:
@Name("quantExperimentHome") <<= ... SHOULD BE EQUAL TO THIS NAME public class QuantExperimentHome extends EntityHome<....
-
6. Re: Best Process for calling another application from seam application
valatharv Jan 29, 2009 9:27 PM (in response to valatharv)Thanks a lot, I am able to execute external application (GenerateItraqAnalysisSql) using the code below.
I am facing other issues, not sure if I should place a separate request for it ?
Our external application is packaged as a jar and we are invoking it from Seam using externalApplicationInvoker code below.
This external application uses hibernate to communicate with the same database which seam uses and does some processing correctly (generates a sql file).
When I call this from seam it does the processing but gives below exception :
ERROR [org.hibernate.impl.SessionFactoryObjectFactory] Invalid JNDI name:
javax.naming.InvalidNameException
at org.jnp.server.NamingServer.rebind(NamingServer.java:159)
Please suggest what configuration I am doing wrong.
------------------------------------------
@Name("externalApplicationInvoker")
@Scope(ScopeType.STATELESS)
public class ExternalApplicationInvoker
{
@In(create = true)
QuantExperimentHome quantExperimentHome;
@Observer("org.jboss.seam.afterTransactionSuccess.QuantExperiment")
public void experimentSaved()
{
Long qHjid = quantExperimentHome.getInstance().getHjid();
String quantType = quantExperimentHome.getInstance().getQuantitationType();
try {
String[] args=new String[]{quantType, qHjid.toString()};
System.out.println("************** ExternalApplicationInvoker.experimentSaved(), calling GenerateItraqAnalysisSql.run with args : "+quantType+", and "+qHjid);
GenerateItraqAnalysisSql generateItraqAnalysisSql=new GenerateItraqAnalysisSql();
generateItraqAnalysisSql.run(args);
System.out.println("************** ExternalApplicationInvoker.experimentSaved(), CALLED GenerateItraqAnalysisSql.run");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
------------------------------------------
Console output:
---------------
INFO [STDOUT] ************** ExternalApplicationInvoker.experimentSaved(), calling GenerateItraqAnalysisSql.run with args : -Litraq4, and 31
INFO [org.hibernate.cfg.Configuration] configuring from resource: /hibernate.cfg.xml
INFO [org.hibernate.cfg.Configuration] Configuration resource: /hibernate.cfg.xml
INFO [org.hibernate.cfg.Configuration] Configured SessionFactory:
INFO [org.hibernate.cfg.AnnotationBinder] Binding entity from annotated class: com.entity.QuantExperiment
INFO [org.hibernate.cfg.annotations.EntityBinder] Bind entity com.entity.QuantExperiment on table MET_QUANT_EXPERIMENT
.....
INFO [org.hibernate.connection.DriverManagerConnectionProvider] Using Hibernate built-in connection pool (not for production use!)
INFO [org.hibernate.connection.DriverManagerConnectionProvider] Hibernate connection pool size: 20
.....
INFO [org.hibernate.cfg.SettingsFactory] Echoing all SQL to stdout
....
INFO [org.hibernate.impl.SessionFactoryImpl] building session factory
INFO [org.hibernate.impl.SessionFactoryObjectFactory] Factory name:
INFO [org.hibernate.util.NamingHelper] JNDI InitialContext properties:{}
ERROR [org.hibernate.impl.SessionFactoryObjectFactory] Invalid JNDI name:
javax.naming.InvalidNameException
at org.jnp.server.NamingServer.rebind(NamingServer.java:159)
at org.jnp.interfaces.NamingContext.rebind(NamingContext.java:516)
at javax.naming.InitialContext.rebind(InitialContext.java:371)
at org.hibernate.util.NamingHelper.bind(NamingHelper.java:74)
at org.hibernate.impl.SessionFactoryObjectFactory.addInstance(SessionFactoryObjectFactory.java:90)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:306)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
at util.HibernateUtil.<clinit>(Unknown Source)
at com.GenerateItraqAnalysisSql.<init>(Unknown Source)
at com.session.ExternalApplicationInvoker.experimentSaved(ExternalApplicationInvoker.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)
at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31)
..
at org.jboss.seam.Component.callComponentMethod(Component.java:2092)
...
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
at java.lang.Thread.run(Thread.java:595)
INFO [STDOUT] GenerateItraqAnalysisSql run Entered, args are :-Litraq4, 31
INFO [STDOUT] GenerateItraqAnalysisSql start processing
INFO [STDOUT] GenerateItraqAnalysisSql, args are : -Litraq4, 31
INFO [STDOUT] GenerateItraqAnalysisSql.getQuantExperimentEntityInstance, Check connection, isConnected :true
INFO [STDOUT] ====> Final SQL is : 'gdfgdfg' AS TREATMENT_1_COMPOUND, 2220.0 AS TREATMENT_1_CONCENTRATION, 'nM' AS TREATMENT_1_CONCENTRATION_UNIT, 111 AS TREATMENT_1_TIME, 'Seconds' AS TREATMENT_1_TIME_UNIT,
INFO [STDOUT] GenerateItraqAnalysisSql SQL processed, End.
INFO [STDOUT] ************** ExternalApplicationInvoker.experimentSaved(), CALLED GenerateItraqAnalysisSql.run
WARN [javax.enterprise.resource.webcontainer.jsf.renderkit] 'for' attribute cannot be null -
7. Re: Best Process for calling another application from seam application
valatharv Jan 30, 2009 4:29 PM (in response to valatharv)How can I get return message for remove like (
Successfully deleted
) ExternalApplicationInvoker.Observer is working fine, and function
experimentSavedOrUpdated
is called on Create, Update and Delete.I need to provide condition that call to
executeGenerateItraqAnalysisSql
should not be made on DELETE.@Name(
externalApplicationInvoker
)
@Scope(ScopeType.STATELESS)
public class ExternalApplicationInvoker
{@Observer(
org.jboss.seam.afterTransactionSuccess.QuantExperiment
)
public void experimentSavedOrUpdated()
{
//PROVIDE CONDITION here DO NOT CALL ON DELETE
executeGenerateItraqAnalysisSql(getQuantitationType(), getExperimentHjid());
}
} -
8. Re: Best Process for calling another application from seam application
vaughnb.vaughn.butt.datacom.co.nz Dec 6, 2009 9:47 PM (in response to valatharv)I think you get the error message:
ERROR [org.hibernate.impl.SessionFactoryObjectFactory] Invalid JNDI name:
javax.naming.InvalidNameException
at org.jnp.server.NamingServer.rebind(NamingServer.java:159)when your hibernate configuration specifies an empty string for the session-factory name :
<hibernate-configuration>
<session-factory name="">
<property name="show_sql">false</property>
...
</hibernate-configuration>Removing the name attribute from session element will fix this problem. So will making the name attribute non-empty. See the documentation here.
Setting org.hibernate logging to INFO and looking for "INFO [org.hibernate.impl.SessionFactoryObjectFactory] Factory name:" will show you that hibernate is trying to register the SessionFactory with a name with no non-whitespace.