How to call session bean from jsp - ejb

I'm new to ejb. Actually I've created one ejb and I added reference to a web application which will call the session bean simply. How to call the session bean from the jsp file?

I could also prefer you to use the MVC model for your application. In that case there is no need to call a session bean from the jsp, you can call it from the servlets itself.
Check out this link to call a EJB from a servlet.
Click

I've tried to do that on Wildfly, but without success using #EJB annotation, probabily JSP don't have CDI. So I've implemented it on another way (not so bright):
Before the :
<%
LoginAction loginAction;
try {
Properties properties = new Properties();
properties.put("jboss.naming.client.ejb.context", true);
properties.put(Context.URL_PKG_PREFIXES,"org.jboss.ejb.client.naming");
Context ctx=new InitialContext(properties);
loginAction = (LoginAction) ctx.lookup("java:module/LoginAction");
session.setAttribute("loginAction", loginAction); //this is to be able to use loginAction on EL Expressions!
} catch (Exception e) {
e.printStackTrace();
}
%>
And all the rest stays the same!

1) the first way will be to create a direct object
use import tag to import ur class
< % # page import = packageName.Classname %>
<%
#EJB
Classname object = new Classname();
%>
and then access methods using normal jsp
<%=object.callmethod()%>
2) the other way will be to use standard actions
<jsp:useBean id="beanId' class="packagename.ClassName" />
<jsp:getStudentInfo name="beanId" property="name"/>

As you are using EJB at service layer and in MVC , I will never advice to call a session bean from your view or jsp.you can call the session beans method by injection EJB reference using #EJB annotation.

Simple..Override Jsp's jspInit method and create InitialContext object.. InitialContext object can access all the resources that have JNDI name assigned..
<%!
BeanIntefaceName instanceName;
%>
<%
public void jspInit()
{
instanceName = (BeanIntefaceName)new InitialContext().lookup("java:global/[application_name]/[module_name]/[enterprise_bean_name]/[inteface_name]");
}
instanceName.yourMethodName();
%>

You can mix and match to support multiple application servers in the best way.
The code below uses the #EJB injection for WebSphere Liberty and the InitialContext for JBoss Wildfly
<%!
#EJB
GitlabHelper gitAPI;
public void jspInit() {
if (gitAPI == null) {
try {
gitAPI = (GitlabHelper) new InitialContext().lookup("java:module/GitlabHelper");
System.out.println("<!-- initContext has been used -->");
} catch (Exception e) {
e.printStackTrace();
}
}
}
%>

Related

Can't use a session ejb in my managed bean cause i get a Null Pointer Exception

First of all I want to say I'm pretty new in programming with ejb and jsf, and I'm trying to complete a project started by a friend of mine.
I'm getting a NullPointerException caused by the invoke of the method utenteSessionBean.CheckUtentebyId(username) of the session bean object called utenteSessionBean, declared inside the managed bean called Neo4jMBean.
I learned that it's not necessary creating and initializing a session bean (as you must do with a normal java object) in managed bean, but it's enough declaring it.
Here is the code of the session bean, which retrieves data from a DB
#Stateless
#LocalBean
public class UtenteSessionBean {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EnterpriseApplication2-ejbPU");
public boolean CheckUtentebyId(String username){
EntityManager em = emf.createEntityManager();
Query query = em.createNamedQuery("Utente.findByUsername");
query.setParameter("username", username);
List<Utente> Res=query.getResultList();
//completare funzione ctrl+spazio
System.out.println("pre");
System.out.println("pre"+Res.isEmpty());
em.close();
System.out.println("post");
System.out.println("post"+Res.isEmpty());
if(Res.size()>=1)
{
return true;
}
else
{
return false;
}
}
}
Here's the code of the managed bean:
#ManagedBean
#ViewScoped
public class Neo4jMBean {
#EJB
private UtenteSessionBean utenteSessionBean;
static String SERVER_ROOT_URI = "http://localhost:7474/db/data/";
public Neo4jMBean() {
}
public boolean getUser(String username) {
return utenteSessionBean.CheckUtentebyId(username);
}
}
I've searched on StackOverFlow many times a solution for fixing this problem, but I haven't found something that works for me yet.
I fixed it accessing the EJB Components using JNDI.
In few words, if i use an EJB in a managed bean method, i need to add the next lines of code:
InitialContext ic = new InitialContext();
SessionBeanName = (SessionBeanClass) ic.lookup("java:global/NameOfTheApplication/NameOfTheEJBpackage/NameOfTheSessionBean");
It must be surronded by a try-catch statement
Create empty beans.xml file in your WEB-INF folder to enable CDI

How to make this Spring Injection work

I have this inside my spring xml file:
<object type="Test.Web.Utilities.TestClass, Test.Web" singleton="false" id="TestClass">
<property name="TestService" ref="TestService"/>
</object>
In the TestClass I have this:
public ITestService TestService { get; set; }
and this:
public void TestMethod()
{
var x = TestService.ExampleMethod();
}
next, inside my controller I have this:
TestClass t = new TestClass();
t.TestMethod();
However, I don't seem to get this to work. other spring related stuff on the controller works well.
Any ideas how can I get this to work?
EDIT: Forgot to add, the error I get is a NullReferenceException
This cannot work since you're creating TestClass instance via new and Spring is of course not aware to inject dependencies into objects created via the frameworks new. You'll not find a .NET IOC framework that can do this (for good reasons!).
So what you need to do is to inject instances of TestClass into your controller. You could register these instances with a request or prototype scope.
You cannot use the normal "new" keyword, because this is handled via the .NET VM. You actually need to call Spring's Activator Context to give you an instance.
First you acquire the Spring.NET Activator context by calling:
IApplicationContext ctx = ContextRegistry.GetContext();
Then you can get an instance of your class specified in your configuration xml:
ITestService svc = (ITestService)ctx.GetObject("TestClass");
This enables you to configure via your XML file what concrete implementation class that implements the ITestService interface.

SessionContext.getBusinessObject() in EJB3 & JNDI lookup

In EJB2, one needed to use getEJBBusinessObject() method in a EJB to pass reference to itself when calling another (local/remote) bean.
Does the same apply for EJB3?
e.g.
#Stateless
public class MyBean implements MyBeanLocal {
#Resource private SessionContext sessionContext;
public void myMethod() {
OtherBeanLocal otherBean = ...; // getting reference to other local EJB.
MyBeanLocal myBean = sessionContext.getBusinessObject(MyBeanLocal.class);
b.aMethod(myBean);
}
// Edit: calling myMethodTwo() from inside of myMethodOne()
public void myMethodOne() {
MyBeanLocal myBean = sessionContext.getBusinessObject(MyBeanLocal.class);
myBean.myMethodTwo();
}
public void myMethodTwo() {
...
}
...
}
Also, if I fetch my local bean using getBusinessObject() method, is it the same as if I use common JNDI lookup?
I've tested both approach, and both work, but I'm not sure if bean object is processed the same way by the container.
Edit:
Is fetching the reference to ejb itself, when calling myMethodTwo() from inside myMethodOne() of the same ejb, in EJB3, still needed? Is it allowed to call methods inside the same ejb through this reference?
How will this address transactions, if I decide to use some?
Yes, the same applies to EJB 3. Yes, getBusinessObject is the EJB 3 analog to getEJBObject (or getEJBLocalObject). All of those methods return a proxy for the current bean object. For stateless session beans, this is basically the same as looking up through JNDI, though it's likely to perform better since it avoids JNDI overhead.

Using Autofac for DI into WCF service hosted in ASP.NET application

I'm having trouble injecting services dependencies into my WCF service using Autofac 1.4.5. I've read and followed the Autofac wiki page on WcfIntegration but my debugging shows me that my WCF service is created by the System.ServiceModel.Dispatcher.InstanceBehavior.GetInstance() method and not by the AutofacWebServiceHostFactory. What am I doing wrong?
I've set up my ajax.svc file to look like the one in the example for use with WebHttpBinding:
<%# ServiceHost Language="C#" Debug="true"
Service="Generic.Frontend.Web.Ajax, Generic.Frontend.Web"
Factory="Autofac.Integration.Wcf.AutofacWebServiceHostFactory,
Autofac.Integration.Wcf" %>
My WCF service class Ajax is defined like this:
namespace Generic.Frontend.Web
{
[ServiceContract]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Ajax
{
public MapWebService MapWebService { get; set;}
public Ajax() {
// this constructor is being called
}
public Ajax(MapWebService mapWebService)
{
// this constructor should be called
MapWebService = mapWebService;
}
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract(Name = "mapchange")]
public MapChangeResult ProcessMapChange(string args)
{
// use the injected service here
var result = MapWebService.ProcessMapChange(args);
return result;
}
}
}
Now I've used the wiring up in the Global.asax.cs as shown in the wiki mentioned above:
var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacModuleWebservice());
var container = builder.Build();
AutofacServiceHostFactory.Container = container;
with
class AutofacModuleWebservice : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register<Ajax>();
builder.Register<MapWebService>().ContainerScoped();
}
}
In my web.config I have
<services>
<service name="Generic.Frontend.Web.Ajax">
<endpoint address="http://mysite.com/ajax.svc/" binding="webHttpBinding"
contract="Generic.Frontend.Web.Ajax" />
</service>
</services>
.
The service already works fine but I can't get the Autofac bits (read: creation/injection) to work. Any ideas?
Edit:
Removing the default constructor unfortunately leads to the following exception:
System.InvalidOperationException:
The service type provided could not be loaded as a service because it does not
have a default (parameter-less) constructor. To fix the problem, add a default
constructor to the type, or pass an instance of the type to the host.
Cheers, Oliver
Is your service setup with InstanceContextMode.Single? If it is then wcf will create your service using the default constructor. To get around this change your instance context mode and let autofac manage the lifetime of your service.
Try deleting the default Ajax constructor and modifying your constructor to this. If it gets run with mapWebService == null that would indicate a resolution problem.
public Ajax(MapWebService mapWebService = null)
{
// this constructor should be called
MapWebService = mapWebService;
}
I just got the same System.InvalidOperationException and solved it by changing the ServiceBehavior InstanceContextMode of the implementation from InstanceContextMode.PerCall to InstanceContextMode.PerSession, perhaps your AutoFac lifetime scope is out of sync with your web service implementation?
For testing AutoFac service creation I recommend creating a unit test and directly resolving them as this will highlight any issues and give more meaningful exception messages. For services with a request lifetime scope create a test aspx page and again resolve them directly.
I had the same problem and came across this question while searching for an answer.
In my case, using property injection worked, and the code in the question already has a property that can be used:
namespace Generic.Frontend.Web
{
[ServiceContract]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Ajax
{
// inject the dependency here
public MapWebService MapWebService { get; set;}
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract(Name = "mapchange")]
public MapChangeResult ProcessMapChange(string args)
{
// use the injected service here
var result = MapWebService.ProcessMapChange(args);
return result;
}
}
}
and register to use property injection (sample code from the wiki and syntax has changed as this is now using version 2.5.2.830):
builder.RegisterType<Ajax>().PropertiesAutowired();
Following the instructions solved it for me:
code.google.com/p/autofac/wiki/… I simply do : builder.RegisterType();
and I've followed their instuructions for changing the .svc file.
When you look at your .svc file you do not get any hints about something being wrong there btw?
You host it throu the iis and do not utilize WAS, I do not see your code for overriding global.asax.cs
Add the global file to your solution and there you implement:
protected void Application_Start(object sender, EventArgs e)
{
// build and set container in application start
IContainer container = AutofacContainerBuilder.BuildContainer();
AutofacHostFactory.Container = container;
}
AutofacContainerBuilder is my container builder.

ASP.Net MVC: How do you access the session from a different project within the solution?

I have 2 projects in my solution.
MVC Web application
Class library
The MVC Web application references the class library.
The class library contains a class that extends the default ASP.Net Controller.
I'm putting a variable in session in the application's Global.asax.
protected void Session_Start(object sender, EventArgs args)
{
HttpContext.Current.Session["DomainName"] = Request.Url.Host;
}
In the class library I'm trying to get the value from the HttpContext.Session, but HttpContext.Session keeps coming up null.
public class MyController : System.Web.Mvc.Controller
{
public MyController () : base()
{
//HttpContext.Session is always null at this point
ViewData["DomainName"] = HttpContext.Session["DomainName"];
}
}
HttpContext.Current.Session doesn't seem to be an option in controllers. Any ideas?
Two issues -- the HttpContext property in the Controller class is the current session. Unfortunately, it's not available in the constructor of the controller. Obviously because it's not passed in the constructor, it has to be set via the property afterwards. You might consider adding a property to hold the domain name and referencing the session from it -- that way it would be available for use when needed.
protected string DomainName
{
get { return this.HttpContext.Session["DomainName"] as string; }
}
The set it in ViewData in your actions or in OnActionExecuting/OnActionExecuted.
protected override void OnActionExecuted( ActionExecutedContext context )
{
ViewData["DomainName"] = this.HttpContext.Session["DomainName"];
// or ViewData["DomainName"] = this.DomainName; // if you used the property
}
If you're just trying to add ViewData from the session, try doing it in the OnActionExecuting method. This is where I typically add ViewData I want for every View.
You just use Session by itself (it's a property of Controller), but that just maps to Controller.HttpContext.Session (in other words, what you're already using), so it won't solve your problem, which must be elsewhere.
I'm not sure why you're putting this in the Session, though, as you can read Request.Url.Host directly during the Action.
When you create cookie then you must write
Response.AppendCookie("Your cookie name");
And if you want to get that then something like this
if (Request.Cookies["Your cookie name"] != null)
{
string value = Request.Cookies["Your cookie name"].Value;
}
and must if there are different solutions
then
machineKey
need to be same which is under
system.web
in web.config and then write
<httpCookies domain=".yourdomainname.com" />

Resources