I just want to create a Portlet and to use an EJB in this Portlet.
Iam using JBoss 7.1 and Liferay 6.2.
I create a EJB project and a liferay plugin project.
I just want to call a method from the EJB, shown here:
#Local
public class PortletController {
public PortletController() {
}
public String getUserName() {
return "foobar";
}
}
My portlet tries to get the username, shown here:
public class ABPortlet extends MVCPortlet {
private String userName;
#EJB
PortletController controller;
public ABPortlet() {}
public void doView(RenderRequest rr, RenderResponse rp) throws IOException, PortletException {
userName = controller.getUserName();
if(userName==null) {
userName = "nope";
}
rr.setAttribute("userName", userName);
super.doView(rr, rp);
}
}
Have I already done something wrong? I read in a tutorial that i can access a local bean without lookup if the bean runs in the same JRE like the portlet.
How do i deploy both projects correctly? I exported the EJB project as jar and added it as dependency to the portlet project, but I just got a NullpointerException in the doView methode, at this line:
userName = controller.getUserName();
I read in a tutorial that i can access a local bean without lookup if the bean runs in the same JRE like the portlet.
You meant in the same JVM when you mentioned the JRE, and yes that is right you don't have to bother about JNDI lookups if your portlet and ejb module runs both locally in the same JVM instance.
Regarding the way you packaged your application, I will advice not to do so (ejb and portlet in the same jar) because it is known from best practices that you would better separate your business module (ejb) from you view module (portlet).
So you may need to package each separately, the portlet goes to a war archive and your ejb to its own jar/module one.
Now going back to your code, you have some things to review following enterprise archive coding conventions:
Use a POJI to declare your local bean skeleton:
#Local
public interface PortletControllerLocal
{
public String getUserName();
}
Implement your Stateless/Stateful session bean and do specify its name annotation property:
#Statefull
#EJB(name = "portletControllerBean")
public class PortletControllerBean implements PortletConrollerLocal
{
public String getUsername()
{
//Do you stuff
}
}
Inject your bean under your portlet controller class with a beanName property:
public class ABPortlet extends MVCPortlet
{
private String userName;
#EJB(beanName = "portletControllerBean")
PortletControllerBean controller;
public ABPortlet() {}
public void doView(RenderRequest rr, RenderResponse rp) throws IOException,PortletException
{
userName = controller.getUserName();
if(userName==null) {
userName = "nope";
}
rr.setAttribute("userName", userName);
super.doView(rr, rp);
}
}
Related
I have a e4 application project which consists of following projects
app
app.feature
app.product
app.releng
then 2 plugin projects
app.service
app.ui
I have created a simple login dialog page on a handler, I inject the service on this Dialog and then it successfully authenticates on the server.
#Creatable
public class AuthenticationService {
#Inject
public AuthenticationService() {
}
private Token token;
public Token getToken() {
return token;
}
private void setToken(Token token) {
this.token = token;
}
public Token authenticate(String username, String password) {
//authenticate and set token here
}
}
The issue is that when I inject the same authentication service on a Part class, the retrieved token is null. i need it on a Part class since i will call another REST service to have a list of items to be displayed.
the Dialog and Part class reside on app.ui plugin project, while the authentication service is on app.service plugin project
If you just use #Creatable a new instance of the class is created each time you inject it. Here you want there to be only one instance of the service class so that you get the same one every time.
To do this specify the #Singleton annotation:
#Creatable
#Singleton
public class AuthenticationService {
I want to build a JEE plugin based architecture. The main idea is do something similar to what eclipse is, but in the context of JEE.
My goal is to have a minimum of modules as the core, and allow others modules extend its functionality.
To this, I have implemented a test using 4 modules:
gauges: Defines and implements a gaugesregistry service, also defines a gauge POJO.
cashgauges: implements a gauge producer using CDI. this is a plugin mock.
othergauges: implements a gauge producer using CDI. this is a second plugin mock.
gauges-web: Contains a basic JSF view to query the gauges registry.
dependencies are as follows:
cashgauges --> gauges
othergauges --> gauges
gauges-web --> gauges
This is done by using jboss-deployment-structure.xml on each deployed file.
The deployment is done as individual files:
gauges.jar
cashgauges.jar
othergauges.jar
gauges-web.war
All services start, but what I see is, my gaugesregistry is instantiated several times. I started wildfly in debug mode and what I see is each module has its own instance of gaugesregistry: cashgauges and othergauges call same method (addGauge) on registry, but instances of this registry are not the same.
This happens in both cases, using #ApplicationScoped and #Singleton annotations. What am I doing wrong?
Source code is available on https://github.com/hatit/research
After a couple of days, I'm considering using a ServiceLocator pattern and remote references instead of CDI. Any suggestions?
Great, i got twice -2 votes (-4 reputation) because i asked an advanced topic for software developers?
I searched in about stackoverflow and found this
Founded in 2008, Stack Overflow is the largest, most trusted online community for developers to learn, share their knowledge, and build their careers...
If any interested in this topic, then:
After some hours understanding differences between CDI Beans and EJBs lifecycle when used as independent modules (JBoss Modules), i found:
Singleton CDI Beans are instantiated one time per module, not really singleton among all modules.
To avoid this i had to create Registry as a Singleton Enterprise Session Bean.
This cames with new problems, CDI injection doesn't works among modules, so i had to package a CDI producer (i don't care if it's singleton or not, its only a producer) which can be instantiated by any module. Main responsibility of this producer is to lookup Registry EJB, this to avoid hardcoding jndi path each time i need access the Registry.
I changed my trivial example to support JSF plugins also, this is an example of what i am using currently.
Module facelets:
Registry interface:
public interface FaceletsModuleRegistry {
void registerModule(String module);
List<String> getRegisteredModules();
}
Registry implementation:
#Local(FaceletsModuleRegistry.class)
#Singleton(name="FaceletsModuleRegistry")
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
#Vetoed
public class FaceletsModuleRegistryImpl implements FaceletsModuleRegistry {
private Set<String> registeredModuleNames = new TreeSet<>();
#Override
public void registerModule(String module) {
registeredModuleNames.add(module);
}
#Override
public List<String> getRegisteredModules() {
return Collections.unmodifiableList(new ArrayList<>(registeredModuleNames));
}
}
Registry producer:
#ApplicationScoped
public class FaceletsModuleRegistryBuilder {
#EJB(lookup="java:global/facelets/FaceletsModuleRegistry!co.hatit.enterprise.facelets.services.FaceletsModuleRegistry")
protected FaceletsModuleRegistry faceletsModuleRegistry;
#Produces
public FaceletsModuleRegistry getFaceletsModuleRegistry(){
return faceletsModuleRegistry;
}
}
Any other module that i want to plugin implements this code (please see #Inject can be used on any module requiring access the Registry singleton instance):
#ApplicationScoped
public class InmueblesActivator {
#Inject
private FaceletsModuleRegistry faceletsModuleRegistry;
public void init(#Observes #Initialized(ApplicationScoped.class) Object init){
String moduleName = Module.getCallerModule().getIdentifier().getName();
String name = StringUtils.substringBetween(moduleName, "deployment.", ".jar");
faceletsModuleRegistry.registerModule(name);
}
}
Then i can reference Registry from any module as a really singleton instance (solved my problem having multiple instances of same class when used CDI singleton beans among several modules).
Now, i can plugin JEE modules, not just java code, but facelets resources also:
public class FaceletsResourceHandler extends ResourceHandlerWrapper {
Logger logger = LoggerFactory.getLogger(FaceletsResourceHandler.class);
#Inject
FaceletsModuleRegistry faceletsModuleRegistry;
private ResourceHandler wrapped;
public FaceletsResourceHandler(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewResource createViewResource(FacesContext context, final String name) {
ViewResource resource = super.createViewResource(context, name);
if (resource == null) {
resource = new ViewResource() {
#Override
public URL getURL() {
try {
//iterates over plugins to find the required resource.
for(String module : faceletsModuleRegistry.getRegisteredModules()){
URL resource = Module.getCallerModule().getModuleLoader()
.loadModule(ModuleIdentifier.create("deployment." + module + ".jar"))
.getExportedResource("META-INF/resources" + name);
if (resource != null) return resource;
}
} catch (ModuleLoadException e) {
throw new FacesException(e);
}
return null;
}
};
}
return resource;
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
}
I've created an Enterprise Application project with an EJB project and one web project and it runs fine. Now I would like to get the IP address of the remote client in the EJB project for some logic in my application. I tried to create a context class in the web part as the following:
Context.java
public class Context {
private static ThreadLocal<Context> instance = new ThreadLocal<Context>();
private HttpServletRequest request;
private Context(HttpServletRequest request) {
this.request = request;
}
public static Context getCurrentInstance() {
return instance.get();
}
public static Context newInstance(HttpServletRequest request) {
Context context = new Context(request);
instance.set(context);
return context;
}
public HttpServletRequest getRequest() {
return request;
}
}
And from class in EJB I tried to call the context class like:
public String setIPAddress() {
HttpServletRequest request = Context.getCurrentInstance().getRequest();
String remoteIPAddress = request.getRemoteAddr();
return remoteIPAddress;
}
My problem is I can't call context.java from EJB class and if I include the classe context in the EJB part I get the NullPointerException. I'v tried also to include the web project in EJB projcet properties and I get the error "Can't add cyclic references". I'm using Netbeans. How can I get the remote IP address in this case?
It is not advisable to do so, but if you need it can use this:
import javax.ejb.Stateless;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
#Stateless
public class MyServiceBean {
public void initialize() {
final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
System.out.println("IP:" + request.getRemoteAddr());
// load data
}
}
Having web code (ServletContext etc) in EJB layer is not a good idea, that makes your business logic tightly coupled to the presentation layer.
A better solution will be to pass the IP address from the presentation logic, rather than, making the EJB later do the work.
I'm using Guice in a Restlet web server, and there's one pattern I can't figure out: how to inject objects that are specific to a certain user or a certain request.
Say we have a request to list all the Widgets that belong to a project. The service that looks up Widgets requires a Project instance. There are many Projects in the system.
My code currently looks something like this:
public class WidgetResource extends ServerResource {
//path: project/{project}/widgets
private final WidgetService service;
private final ProjectLookup projectLookup;
#Inject
public WidgetResource(WidgetService service, ProjectLookup projectLookup) {
this.service = service;
this.projectLookup = projectLookup;
}
#Get
public WidgetCollection getWidgets() {
String projectName = getAttribute("project"); //restlet lookup of path var
Project project = projectLookup.get(projectName);
WidgetCollection widgets = service.getWidgetsFor(project);
return widgets;
}
}
This works well enough, but it's clumsy, and I hope there's a better way. It would be great to inject the correct Project object directly. Is there a way to do this?
So far I've explored AssistedInject, which gives a factory object very similar to my Lookup. I came close to an answer with custom annotations/injections, but dead-ended because the Restlet attributes map isn't populated until after injection. Have read the GitHub docs and the User's Guide. Can't spot anything.
I'd like to end up with something like this:
public class WidgetResource extends ServerResource {
private final WidgetService service;
#Inject
public WidgetResource(WidgetService service) {
this.service = service;
}
#Inject
#Get
public WidgetCollection getWidgets(#PathName("project") Project project) {
WidgetCollection widgets = service.getWidgetsFor(project);
return widgets;
}
with (of course) a #Provides method in the configuration that would look up the path variable and use the lookup. However, I can't figure out a way to hand a provider method the path name or the Resource instance as variables. Is this possible? Any help appreciated!
To your vision: You can not inject into "getWidgets" ... injection happens the very moment your widgetResource is created, so basically once your application/server starts.
Besides that, it looks perfectly fine. You have a REST resource that takes a project parameter and uses a service to look up widgets.
If you know all possible project names in advance, you could use guice' mapBinder instead of the service.
public class WidgetsModule extends AbstractModule {
protected void configure() {
MapBinder<String, WidgetCollection> mapbinder
= MapBinder.newMapBinder(binder(), String.class, WidgetCollection.class);
mapbinder.addBinding("project1").toInstance(...);
mapbinder.addBinding("project2").toProvider(...);
mapbinder.addBinding("project3").to(...);
}
}
I'm using a singleton bean to provide configuration values stored in a database to my Java EE application.
#Singleton
public class ConfigurationProvider {
private final Map<String, ConfigurationEntity> configMap = new HashMap<>();
#PersistenceContext(unitName = DatabaseConstants.PERSISTENCE_UNIT)
private EntityManager em;
public String getConfiguration(String key) {
if (configMap.containsKey(key)) {
return configMap.get(key).getValue();
}
ConfigurationEntity config = em.find(ConfigurationEntity.class, key);
em.detach(config);
if (config == null) {
throw new RuntimeException("Configuration not found for " + key);
}
configMap.put(key, config);
return config.getValue();
}
public void clear() {
configMap.clear();
}
public Collection<ConfigurationEntity> getCurrentConfigurationState() {
return configMap.values();
}
}
A Producer let me inject the values
public class ConfigurationProducer {
#Inject
private ConfigurationProvider configProvider;
#Produces
#ConfigurationValue
public String getConfiguration(InjectionPoint ip) {
String key = createKey(ip);
return configProvider.getConfiguration(key);
}
Here an example
#Inject
#ConfigurationValue
private Instance<String> endpoint;
This loads the endpont from the database. For testing reasons, the value should be changeable.
So what you saw is part of an ejb module.
To reload the values, I created a REST-Interface that provides the functionality. This REST-Service is part of an additional WAR packaged together with the ejb module in one ear file.
#Path("/configuration")
public class ConfigurationResource {
#EJB
private ConfigurationProvider configurationProvider;
#GET
#Path("/current")
#Produces({ "application/json" })
public Collection<ConfigurationEntity> getCurrentConfiguration() {
return configurationProvider.getCurrentConfigurationState();
}
}
But the problem is, that the war has it's own instance of the configuration provider. So I cannot reaload the 'cache'.
Why I have two instance of my singleton in the same ear?
I don't think you can use the ConfigurationProvider EJB that way. That EJB would need to have a remote interface, and you would access it as any remote EJB from the external WAR. The external WAR has a different class loader, hence it will not find EAR singleton EJBs.
It seems that you are using both CDI's #Inject and EJB's #EJB to inject your ConfigurationProvider instance. Considering that you are not synchronizing access to map and that you are using EntityManager, which is not thread safe, you propably should be using #EJB.
That said, you need just a minor change in your code:
public class ConfigurationProducer {
#EJB
private ConfigurationProvider configProvider;
#Produces
#ConfigurationValue
public String getConfiguration(InjectionPoint ip) {
String key = createKey(ip);
return configProvider.getConfiguration(key);
}
Solution:
Maven packaged the ejb module a second time in the war's lib folder. I had to set the scope in the pom.xml to provided. With ejb modules it works without any exclutions but for the war you have to do it manually.
Now it works.