I'm a complete newb at this so I apologize in advance. I'm trying to create
an OSGi component that simply shows a hello world message and is configurable via the input from felix. Then spits it out on a jsp page. I'm using scr annotations to help do this. Here is my java code
package com.training.cq5.trainingApp;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
import org.apache.sling.commons.osgi.PropertiesUtil;
#Component(label= "Welcome Message",
description = "Welcome Message for the training excercise",
immediate = true, enabled = true, metatype=true)
#Properties({
#Property(name = "welcome.message", value = "WelcomeMessage")
})
#Service(WelcomeMessage.class)
public class WelcomeMessage {
private static String welcome_message = "Welcome";
#Activate
protected void activate(ComponentContext ctx) {
welcome_message = PropertiesUtil.toString(ctx.getProperties().get(welcome_message), welcome_message);
}
public static String getMessage() {
return welcome_message;
}
}
Here is were I am calling it in the JSP:
<%# page import="com.training.cq5.trainingApp.WelcomeMessage" %>
<h2><%= WelcomeMessage.getMessage() %></h2>
Is there any reason why it's not updating from felix? All I'm getting is the "Welcome"
text from the welcome_message string.
You are accessing WelcomeMessage.getMessage() as a static method, but what you want is the actual service. When you annotate a class with the #Service and #Component annotation, you indicate to the OSGI framework that you want an instance of this class registered as a service. This service instance is managed by the OSGI framework, in terms of its lifecycle (when its instantiated) or through which classloader the appropriate classes are loaded.
However in order to use the #Component and #Service annotations, you'll have to use the Apache Felix SCR plugin. Once that works, your service will be instantiated.
Then you'll have to access the service. The easiest way in Sling, which you appear to be using, is SlingScriptHelper.getService() which lets you lookup a service.
Update
In OSGI services are registered by their type. When you declare a service with #Service(MyClass.class), the service will be registered under the type MyClass. To retrieve it you would query the service registry for a service of the given type. In Java code you'd be using either getServiceReference(Class clazz)/getService(ServiceReference reference) the #Reference annotation.
In a JSP on a Sling system you can use the SlingScriptHelper, as outlined earlier. Here's a short code sample (assuming correct imports):
<%
SlingBindings bindings = (SlingBindings) req.getAttribute(SlingBindings.class.getName());
SlingScriptHelper scriptHelper = bindings.getSling();
MyService service = scriptHelper.getService(MyService.class);
// ... do stuff with service.
%>
If you are going to work more with OSGI, I highly recommend the OSGI specification. It's free to download and explains everything in great detail.
ilikeorangutans is correct that you don't want a static method on your OSGi service - the idea is that a service implements an interface, clients retrieve it from their OSGi context and use it via its service interface.
The Apache Sling webloader sample uses this technique to access a Webloader service in its request processing scripts. The scripts are ESP in this case (server-side javascript) but the principle is exactly the same with JSP.
The service interface is defined in Webloader.java, and WebLoaderImpl.java implements it as an OSGi service.
Then, the html.esp script gets the service using sling.getService:
var loader = sling.getService(Packages.org.apache.sling.samples.webloader.Webloader);
Change this line:-
welcome_message = PropertiesUtil.toString(ctx.getProperties().get(welcome_message), welcome_message);
to
welcome_message = PropertiesUtil.toString(ctx.getProperties().get("welcome.message"), welcome_message);
notice the difference :-ctx.getProperties().get(welcome_message) vs ctx.getProperties().get("welcome.message")
Related
I am currently debugging some code to optimize it and I am facing a puzzling situation :
Basically we are deploying a random web service and we are doing some dependency injection(actually I am taking over an already developped and working app, so I am still discovering the app's structure).
My question is pretty specific to the utilization of Spring AND jax-ws at the same time.
We have two classes : an interface and an implementation of this service which will be our web service. We then put two annotations on top of the description of our implementing class :
#Service("myService") //here we let Spring know that this class is a service called "myService"
#WebService(endPointInterface = "com.mydomain.myService") //we expose this service at the given endpoint
public class MyServiceImplementation implements MyServiceInterface(){
//some code
}
public Interface MyServiceInterface {
//some code
}
Here is my point : somewhere, the implementing class declares a property called otherService, this property's type is "MyServiceInterface" so basically it implements the same interface as MyServiceImplementation :
#Autowired
#Qualifier("myClient")
private MyServiceInterface otherService;
so if we put things back in the context :
#Service("myService")
#WebService(endPointInterface = "com.mydomain.myService")
public class MyServiceImplementation implements MyServiceInterface(){
#Autowired
#Qualifier("myClient")
private MyServiceInterface otherService;
//some code
}
If my understanding is good so far : MyService exposes its endpoint at "com.mydomain.myService" and when it is instantiated by the application, Spring automatically looks for the class associated with the qualifier "myClient" and which implements the interface MyServiceInterface to initiate the property otherService with an instance of that same class (which would be the basic principle of dependency injection right ?)
So following this logic, there should be, somewhere in my code, a class declared like this :
#Qualifier("myClient")
public RandomClass implements MyServiceInterface {
}
But there is not, and upon searching for the string "myClient" in the whole project, the only matching results are as follows :
< jaxws:client id="myClient" serviceClass="com.mydomain.myService"
address="some_address" />
which is located within the application context of the webApp
So I figured out, maybe the qualifier is referring to this jaxws client but then, this would be silly since this would mean that the service is actually trying to "call himself", wouldn't it?
If you could enlighten me on this, I would greatly appreciate it and hopefully this will show helpful to most of us too. Thank you !
in spring #qualifier goes along with autowiring in order to let spring know which beans you'd like to autowire.
To define the bean that matches this qualifier, you don't have to use the qualifier annotation, there are several other options:
- define it's id, like they do here
- if it's annotation based, use #Bean(name="myClient")
With the new Version 2.4/2.5 of the Play Framework they moved further towards injecting everything and removing the servers state. play.Play.application() is now deprecated. However, I need the application in my template (e.g. to get all supported languages displayed on all pages with play.i18n.Lang.availables(play.Play.application())).
I'm aware I could:
Pass play.Application explicitly to all of my templates.
Add an implicit parameter to my template like #()(implicit app: play.Application). However, in my Java-Project it's not really implicit, I have to pass it every time I render the template.
Create a Scala object providing the application implicitly. However, this also needs the deprecated play.api.Play.current.
How can I inject play.Application in my templates?
---- Update: ----
What I've tried so far, I created the following setup:
index.scala.html:
#(title: String)
#template(title) { //here is the play.Application obviously missing, however I don't want to pass it in every template - even worse in every Controller <-- this is the core of my question
Welcome to my page!
}
template.scala.html:
#(title: String)(content: Html)(implicit app: play.Application)
<html>
<head>
<title>#title</title>
</head>
<body>
<p>Is live? #app.isProd</p>
#content
</body>
</html>
Controller function:
public Result index() {
return ok(views.html.index.render("home"));
}
You can get an application with Play.current() or inject an application in controller like this is explained in this question. The template should get the argument of type play.Application.
It should be something like this.
The template, let's say is injectappexample.scala.html:
#(app: play.Application)
.... use the app object
The controller:
public class SomeController extends Controller {
Provider<Application> applicationProvider;
#Inject
public SomeController(Provider<Application> applicationProvider) {
this.applicationProvider = applicationProvider;
}
public Result injectAppExample() {
return ok(injectappexample.render(applicationProvider.get());
}
}
It worth to reconsider sending the application object to the template. If you should send a particular configuration property value, inject Configuration in the controller, get the value from configuration object and send it to the template. In this case injecting of application is not needed at all.
The template:
#(value: String)
.... use the value
The controller:
public class SomeController extends Controller {
Configuration configuration;
#Inject
public SomeController(Configuration configuration) {
this.configuration = configuration;
}
public Result injectAppExample() {
return ok(injectappexample.render(configuration.getString("SOME_PROPERTY"));
}
}
I just had to look into this for Play framework 2.6.x. It is possible to inject an object into a template according to the documentation: https://www.playframework.com/documentation/2.6.x/ScalaTemplatesDependencyInjection.
I implemented a simple sample (a bit contrived) and I used scala:
test.scala.html:
#this(configuration: play.api.Configuration)
#(key: String)
config = #configuration.get[Seq[String]](key).mkString(", ")
HomeController.scala
package controllers
import javax.inject._
import play.api._
import play.api.i18n._
import play.api.mvc._
/**
* This controller creates an `Action` to handle HTTP requests to the
* application's home page.
*/
#Singleton
class HomeController #Inject()(cc: ControllerComponents, testView: views.html.test) (implicit configuration: Configuration) extends AbstractController(cc) with I18nSupport{
def test() = Action { implicit request =>
Ok(testView("play.i18n.langs"))
}
}
routes:
GET /test controllers.HomeController.test()
The configuration object gets injected into views.html.test template and the view itself is injected into the controller. Note the #this(configuration: play.api.Configuration) statement in the template. Play will generate a class behind the template with a constructor that is injected the Configuration object.
Please note that the injected configuration into the controller doesn't have any role in this particular code. I experimented with other permutations before I found this solution ... Let's say that if you have an inner template used by an outer template called from the controller, and the inner template needs the configuration object you need to feed the configuration from the controller top down, and add an implicit configuration: play.api.Configuration parameter in all the templates in the hierarchy path right to the template that needs it, something like this: #(message: String)(implicit messagesProvider: MessagesProvider, configuration: play.api.Configuration)
. Then the controller injected configuration is fed to the top template all the way to the template that needs it.
It is generally discouraged to inject the Application itself, because that makes your code very cumbersome to test. Instead, think about what you actually need and inject that directly.
If you have a number of things you need in pretty much every template, my suggestion would be to create some sort of a context class that you can inject in your controller and then pass it on to the template.
First of all, though you are asking how to inject application what you really need is configuration.
You can do something like this in play 2.5. I'll show constructor injection you may use field injection as your requirement.
import com.google.inject.Inject;
import play.Configuration;
public class MyClass{
private Configuration conf;
#Inject
public MyClass(Configuration conf){
this.conf = conf;
}
}
Now you have your configuration class. Then specifically for your requirement posted in your comment, you can do this.
List<Object> langList = conf.getList("play.i18n.langs");
//conf.getList("") returns an object array.
//You can cast to Strings (assuming you are using Java8).
List<String> languages = new ArrayList<>(langList.size());
for (Object object : langList) {
languages.add(Objects.toString(object, null));
}
Now you can have your languages list in languages.
I've been trying to create a simple Restful WebService, using NetBeans Ide.
My Java EE Version is: Java EE 7 Web.
I created a new Java Web Application, setting this ContexPath: /DukesAgeService.
Now, running my application, browser display my Index.html page at:
http://localhost:8080/DukesAgeService/
so, everything works fine.
Then, I tried to create a simple restful resource using the RESTful Web Service Wizard.
So, I created this class:
package firstcup.webservice;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
/**
* REST Web Service
*
* #author nolanof
*/
#Path("dukesAge")
public class DukesAgeResource {
#Context
private UriInfo context;
/**
* Creates a new instance of DukesAgeResource
*/
public DukesAgeResource() {
}
/**
* Retrieves representation of an instance of firstcup.webservice.DukesAgeResource
* #return an instance of java.lang.String
*/
#GET
#Produces("text/plain")
public String getText() {
return "hello world";
}
}
But running my application, at url:
http://localhost:8080/DukesAgeService/dukesAge
I get a 404-not found page.
I exptected that any incoming get request that has the url of "/dukesAge" was handled by DukesAgeResource class getText method. Whats' wrong?
Thanks
You're probably missing the JAX-RS application servlet. You can either define it in the web.xml or if you want to go xml-less, you can use an Application subclass. The easiest way IMO is just to use the Application subclass annotated with #ApplicationPath. A servlet will be created and the servlet path will be set to the value in the annotation. Something like
#ApplicationPath("/rest")
public class RestApplication extends Application {
// All request scoped resources and providers
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(DukesAgeResource.class);
return classes;
}
// all singleton resources and providers
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
return singletons;
}
}
Then the resource should be accessed via
http://localhost:8080/DukesAgeService/rest/dukesAge.
There are other ways, but this is the portable way. Glassfish uses Jersey, but creating a Java EE web application from scratch in Netbeans will only import compile time Java EE standard classes (no Jersey dependencies). So the above is really your best bet to start off with.
You can see other deployment options at the Jersey Documentation. For some of the options, you may need to add some Jersey compile-time dependencies. That's why I just mentioned the above. No other jars needed.
Another thing that would cause a 404, is if you specify the JAX-RS servlet path as /*. This will conflict with the default servlet that serves the static resources like your html pages. That's why I set it to /rest.
UPDATE
It is also stated in the JAX-RS spec that if there are empty sets returned in the getClasses() and getSingletons(), implicit classpath scanning should occur. (provider) Classes annotated withe #Provider will by default be added as singletons and resource classes annotated with #Path will be per-request objects (meaning a new object is created each request). So you could alternatively just have
#ApplicationPath("/rest")
public class RestApplication extends Application {
// Left empty
}
and it should work just the same.
You may have initialized some path in your web.xml, probably that is why you are getting a 404 error while you call the service. Do check your web.xml and in case it is set to anything rather then * then please append that to your service call to get it working.
I have a Maven project with this structure:
-myproject
-myproject-ear
-myproject-service
-webservice
-myproject-ejb
In the myproject-ejb I have this java packages:
-src/main/java/
-src/test/java/
I have an EJB and the corresponding bean implementation in
-src/main/java/org/mypackage/MyBean.java
-src/main/java/org/mypackage/MyBeanImpl.java
In src/test/java/ I have a test called MyBeanTest.java with the following code:
import javax.ejb.EJB;
import org.mypackage.MyBean;
import org.junit.*;
public class MyBeanTest {
#EJB
private MyBean myBean;
#Test
public void testBean() {
System.out.println("myBean: "+myBean); // prints null
myBean.writeToDB("Hello", "World"); // fails since myBean is null
}
}
When I run the unit test, the myBean is null. I am wondering why the #EJB annotation does not work. The test package is in the same application as the bean, so #EJB should work.
Any ideas?
EDIT 1
I found this link with the same problem as I have, but the solution there doesn´t seem to work for me. Am I doing anything wrong?
package org.myproject.ejb;
import java.util.Hashtable;
import java.util.Properties;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import org.myproject.ejb.MyBean;
import org.jboss.ejb.client.ContextSelector;
import org.jboss.ejb.client.EJBClientConfiguration;
import org.jboss.ejb.client.EJBClientContext;
import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration;
import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector;
import org.junit.*;
public class MyBeanTest {
private MyBean myBean;
#Before
public void init() {
try {
Properties clientProp = new Properties();
clientProp.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
clientProp.put("remote.connections", "default");
clientProp.put("remote.connection.default.port", "4447");
clientProp.put("remote.connection.default.host", "localhost");
clientProp.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(clientProp);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);
Properties env = new Properties();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
env.put(Context.SECURITY_PRINCIPAL, "admin");
env.put(Context.SECURITY_CREDENTIALS, "testing");
InitialContext ctx = new InitialContext(env);
myBean = (MyBean) ctx.lookup("java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl");
}
catch(NamingException ex) {
ex.printStackTrace();
}
}
#Test
public void testBean() {
System.out.println("ejb: "+myBean); // prints null
}
}
The error I get with the above configuration is:
WARN: Unsupported message received with header 0xffffffff
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344)
Container resource injection, such as #EJB, requires a populated JNDI directory and only works within Java EE managed components executing in a Java EE container. Is a challenge for unit testing. See JSR318 Java EE 6 Platform Spec, section EE.5 Resources, Naming, and Injection.
You're now attempting JNDI lookup - Java SE unit test app remotely connecting its JNDI Context. Disadvantages: must deploy full Java EE 6 app as precondition to run test; test-bugfix-build-deploy-retest lifecycle can slow things.
Some issues:
Your username/password properties are different than JBoss doc;
From doc it appears JNDI lookup name needs to be "ejb:..." rather than "java:app/..." because the JBoss EJB-client-project code uses this to intercept the lookup. Also from Java EE 6 platform spec EE.5.2.2: Names in java:app namespace are shared by all components in all modules in a single Java EE app. If your test is a separate JSE app using java:app, I suspect JBoss treats it as separate to the single Java EE application, and lookup will fail.
Make sure you lookup the interface, not the implementation class (i.e. the EJB no interface view) for remote access
You're refering to an unusual reference showing direct use of EJBClientConfiguration & EJBClientContext. It seems this is not required/preferred.
Try these actions:
Include these properties:
clientProp.put("remote.connection.default.username", "admin");
clientProp.put("remote.connection.default.password", "testing");
Change client reference:
java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl to
ejb:<app-ear-name>/<module-jar-name>/<jboss-optional-distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>
E.g. if MyBean is a stateless EJB deployed in myproject-ejb-1.0-SNAPSHOT.jar (without any ear). Then:
ejb:/myproject-ejb-1.0-SNAPSHOT//MyBeanImpl!org.mypackage.MyBean
If it's a stateful EJB, then add "?stateful" to string.
Setup ejb-client.properties directly (via file or program) and apply directly to JNDI Context. See https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+client+using+JNDI and https://docs.jboss.org/author/display/AS72/Scoped+EJB+client+contexts and http://middlewaremagic.com/jboss/?p=1177
In future: use CDI for injection; JUnit + CDI #Mock for "POJO" unit testing; Arquillian for "Java EE" unit/module testing in containers. Then you could avoid/reduce tests like (2) above (JSE client -> EJB).
CDI supports:
Java EE resource injection into POJOs (including #EJB annotation). This still requires a deployed Java EE app/component and populated JNDI directory to lookup.
Managed beans as POJOs or Java EE components (incl. EJBs) - inject "any" to "any" with superior #Inject annotation. Works without JNDI directory, is typesafe & bean scope-aware.
Supports unit testing via simple mocking. Use #Mock & #Specializes to declare replacement version for any bean. Test EJB clients without EJBs. Test EJBs as POJOs.
To enable CDI, include a beans.xml file (can be empty, if all config via annotation).
To declare a managed bean:
optional scope above class e.g. #SessionScoped
no-arg constructor / #Inject on constructor
Use this to inject a reference:
#Inject (optional #MyDeclaredQualifier) private MyBean myBean;
Arquillian ("JUnit for Java EE 6") runs test code itself on a Java EE server. It dynamically deploys test code to configured container(s) and runs tests. It supports #EJB annotation, JNDI connection becomes simple and you can include Java EE classes in unit tests without mocking, or refactoring to abstract away from them.
1) Annotation injection is done by container. So the class which is not managed(container managed) will not be able to do annotation injection.
2) Now, in this scenarios, you will have to make a manual call to JNDI and retrieve EJB instance:
ie:
InitialContext ctx = new InitialContext();
MyBean bean = (MyBeanRemote) ctx.lookup("java:global/<portable jndi name of your bean>");
Note: The use of no arg constructor InitialContext(). Because your java class is deployed in a server I presume. Or else you may need to specify context factory class if your class is a standalone java class, depending on the vendor.
Note: You will need Bean Remote interface if you are making a call to EJB from a different application (ie: different war, ear ...) or else Local interface is enough.
This exception is thrown when no initial context implementation can be created. The policy of how an initial context implementation is selected is described in the documentation of the InitialContext class.
This exception can be thrown during any interaction with the InitialContext, not only when the InitialContext is constructed. For example, the implementation of the initial context might lazily retrieve the context only when actual methods are invoked on it. The application should not have any dependency on when the existence of an initial context is determined.
I'm currently converting a piece of code from plain Java code to OSGi Declarative Services.
Original plain Java code
new AggregateServiceImpl(
new ChildServiceImpl1(),
new ChildServiceImpl2(),
new ChildServiceImpl3()
);
The classes are declared as so:
class AggregateServiceImpl implements Service
class ChildServiceImpl1 implements Service
class ChildServiceImpl2 implements Service
class ChildServiceImpl3 implements Service
So all classes implement Service, but the Aggregate implementation is capable of deferring to child Services when called upon.
AggregateServiceImpl itself does not know of the other implementations' existence. Its constructor is originally declared as:
public class AggregateServiceImpl(Service... children)
Clarification: the interface name 'Service' is intended generically and is not meant to represent an OSGi DS or Service concept.
Converting to OSGi
First I move each implementation into its own bundle. Then I declare my components (service implementations). I happen to be using bnd, so I use service annotations. For example:
#Component
class ChildServiceImpl1 implements Service
In the client class, we can look up the Service using the low level OSGi API or use DS in that bundle to create the object for us.
Problem
What's the best way of looking up a 'Service'? I want the AggregateServiceImpl but I might receive one of the ChildServiceImpls.
Is it best to use a separate service type or add a property to one of the components (e.g. "isRootService") to use as a filter when looking up ServiceReferences?
The best way is to use service registration properties
#Component
#Service
#Property(name = "service.id", value = "<some service unique ID")
class ChildServiceImpl1 implements Service{...}
When you look for some specific services you can use service filter:
bc.getServiceReferences(Service.class.getName(), "(service.id=<some value>)");
or if you like to use it in DS component as service reference:
#Reference(target = "(service.id=<some value>)", cardinality = ...)
private Service service;
If the AggregateServiceImpl is the only Service being used by other bundles, then it should be the only one you register.
From the code you have currently shown, we cannot tell if the AggregateServiceImpl class has dependencies on Service or the actual implementations.
If it has dependencies directly on other implementations, not the Service interface (as you have currently described it) the aggregate bundle should create the other implementation classes it requires directly and then register the AggregateServiceImpl as a Service.
If the other implementations need to be used elsewhere as well, then you should use properties (as you suggested) so consumers can distinguish between them. In this case, you still cannot use DS to construct your aggregate, since it doesn't have a dependencies on Service