I have a JBoss 7.1.2 application server up and running and now I wanted to deploy a OSGi bundle in it which registers a servlet. (kind of Hello World, but via a servlet)
Probably it is possible to archive this via a WAB, but as in OSGi, I thought it should also work in a simple, non wab bundle.
I created a bundle with an Activator as follows:
snip..
public void start(BundleContext bundleContext) throws Exception {
ServiceReference<?> httpServiceReference = bundleContext.getServiceReference(HttpService.class.getName());
System.out.println("ref: " + httpServiceReference);
HttpService httpService = (HttpService) context.getService(httpServiceReference);
System.out.println(httpService.getClass().getName());
try {
httpService.registerServlet("testservlet", new MyServlet() , null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
After deploying and starting the bundle, the httpServiceReference is null.
I think this is strange, because when I look at the felix web console, there actually is HtttpService available. (from pax-web)
Does anyone know why my reference could be null here?
Thanks!
I think you are making the classical OSGi mistake. In the start(BundleContext context) method you are obtaining the reference to HttpService assuming its already started. The OSGi container starts bundles in some order. If your application bundle starts before the bundle that registers HttpService you will get a null reference. I suspect that's what is going on. You might be better off using ServiceTracker instead.
public void start(BundleContext bundleContext) throws Exception {
ServiceTracker httpServiceTracker = new ServiceTracker(bundleContext, HttpService.class, new ServiceTrackerCustomizer() {
#Override
public Object addingService(ServiceReference srf) {
HttpService httpService = bundleContext.getService(srf);
try {
httpService.registerServlet("testservlet", new MyServlet() , null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void modifiedService(ServiceReference arg0, Object arg1) {
}
#Override
public void removedService(ServiceReference arg0, Object arg1) {
}
});
httpServiceTracker.open();
}
Related
I have a spring boot application which I am trying to deploy on AWS lambda .
I added StreamLambdaHandler as the handler class
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
//handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(SituationalFlexibilityApp.class);
// For applications that take longer than 10 seconds to start, use the async builder:
handler = new SpringBootProxyHandlerBuilder<AwsProxyRequest>()
.defaultProxy()
.asyncInit()
.springBootApplication(SituationalFlexibilityApp.class)
.buildAndInitialize();
// we use the onStartup method of the handler to register our custom filter
handler.onStartup(servletContext -> {
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter",CognitoIdentityFilter.class);
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
});
} catch (ContainerInitializationException e) {
// if we fail here. We re-throw the exception to force another cold start
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
public StreamLambdaHandler() {
Timer.enable();
}
/*
* public StreamLambdaHandler() throws ContainerInitializationException {
*
* handler = new SpringBootProxyHandlerBuilder() .defaultProxy() .asyncInit()
* .springBootApplication(SlowApplication.class) .buildAndInitialize(); }
*/
#Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
handler.proxyStream(input, output, context);
}
When I test it on AWS lambda I get below exception
com.amazonaws.serverless.exceptions.ContainerInitializationException: Could not initialize framework within the 20000ms timeout
so I updated the lambda configuration for a timeout of 5 mins and added below line in the static block of the StreamLambdaHandler class
LambdaContainerHandler.getContainerConfig().setInitializationTimeout(2000000);
Now, I am seeing below exception
Exception in thread "Thread-0" java.lang.IllegalArgumentException: Could not find timer SPRINGBOOT2_COLD_START
Can someone please point me in the correct direction as I a noob in AWS services and lambda
I am not seeing this error after commenting out the below code in StreamLambdaHandler method
// Timer.enable();
Is there any reference guide for spring boot admin upgrade?
I have a legacy app that I need to upgrade from 1.5 to 2.0, but the entire API has changed & there is 0 info in the official reference guide. https://codecentric.github.io/spring-boot-admin/current/
For example, the main domain class now seems to be InstanceEvent, whereas it used to be 'Application'; but they hold completely different info.
Same with the class 'AbstractStatusChangeNotifier'; which now seems to use InstanceEvent & Spring webflux...
My more specific question is:
How can I get application info from spring boot admin 2.0?
I used to be able to do this; which now no longer exists in the api.
public class XXXMailNotifier extends AbstractStatusChangeNotifier {
#Override
protected void doNotify(ClientApplicationEvent event) {
try {
helper.setText(mailContentGenerator.statusChange(event), true);
} catch (IOException | MessagingException e) {
logger.error(e.getMessage());
}
}
String statusChange(ClientApplicationEvent event) throws IOException {
ImmutableMap.Builder<String, Object> content = ImmutableMap.<String, Object>builder()
.put("name", event.getApplication().getName())
.put("id", event.getApplication().getId())
.put("healthUrl", event.getApplication().getHealthUrl())
.put("managementUrl", event.getApplication().getManagementUrl())
.put("serviceUrl", event.getApplication().getServiceUrl())
.put("timestamp", DATE_TIME_FORMATTER.print(new LocalDateTime(event.getApplication().getInfo().getTimestamp())));
Well, if it might help anyone...
I looked in the code and found that I can get the info from the instance.registration object.
You can change the above in the below:
#Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
try {
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setSubject(format(subject, environment, pool, instance.getRegistration().getName(), event.getInstance().getValue()));
helper.setText(mailContentGenerator.statusChange(event, instance, getLastStatus(event.getInstance())), true);
public String statusChange(InstanceEvent event, Instance instance, String lastStatus) throws IOException {
Registration registration = instance.getRegistration();
ImmutableMap.Builder<String, Object> content = ImmutableMap.<String, Object>builder()
.put("name", registration.getName())
.put("id", instance.getId().getValue())
.put("healthUrl", registration.getHealthUrl())
.put("managementUrl", registration.getManagementUrl())
.put("serviceUrl", registration.getServiceUrl())
.put("timestamp", DATE_TIME_FORMATTER.print(new LocalDateTime(instance.getStatusTimestamp())));
I want my jersey tests to run on one instance of tomcat which has the rest services running at
http://myhost:port/contexpath/service1/
http://myhost:port/contexpath/service2/
..so on
I have both in memory and external container dependencies
[ group: 'org.glassfish.jersey.test-framework.providers', name: 'jersey-test-framework-provider-inmemory', version: '2.17'],
[group: 'org.glassfish.jersey.test-framework.providers', name: 'jersey-test-framework-provider-external' , version: '2.17'],
Then in the test i over ride the below method to decide which container to choose
#Override
public TestContainerFactory getTestContainerFactory() {
System.setProperty("jersey.test.host", "localhost");
System.setProperty("jersey.config.test.container.port", "8000");
//how to set the context path ??
return new ExternalTestContainerFactory();
}
The in memory test works because the services are deployed by the framework at path which it knows(it does not have a context path anyway)
When i run on external container it tries to connect to http://myhost:port/service1/ instead of http://myhost:port/contexpath/service1/ thus getting 404 not found
To run on an external container how do i specify the context path ?
The documentation specifies only host and port property.Is there any property for context path ?
I am using Jersey 2.17
Finally I figured out a solution
#Override
public TestContainerFactory getTestContainerFactory() {
return new ExternalTestContainerFactory(){
#Override
public TestContainer create(URI baseUri, DeploymentContext context)
throws IllegalArgumentException {
try {
baseUri = new URI("http://localhost:8000/contextpath");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.create(baseUri, context);
}
};
}
If you have your external servlet:
Import the jersey-test-framework-core apis to implement your own TestContainerFactory
testCompile 'org.glassfish.jersey.test-framework:jersey-test-framework-core:2.22.2'
.
Let JerseyTest know you will have your own provider through SystemProperties
systemProperty 'jersey.config.test.container.factory', 'my.package.MyTestContainerFactory'
.
Create your own provider (better and more custom configurable than their jersey-test-framework-provider-external)
import org.glassfish.jersey.test.spi.TestContainer;
import org.glassfish.jersey.test.spi.TestContainerFactory;
public class MyTestContainerFactory implements TestContainerFactory {
#Override
public TestContainer create(URI baseUri, DeploymentContext deploymentContext) {
return new TestContainer(){
#Override
public ClientConfig getClientConfig() {
return null;
}
#Override
public URI getBaseUri() {
return URI.create("http://localhost:8080/myapp/api");
}
#Override
public void start() {
// Do nothing
}
#Override
public void stop() {
// Do nothing
}
};
}
}
I'm currently trying to write an OSGI integration tests using PAX-EXAM+KARAF and faced a problem that pax exam trying to execute test methods before dependent bundles are actually started/initialized in container. What's strange, sometimes test succeeds, and in that case all bundles/contexts are started and logged, but the majority of times it does not. Delays in methods won't help:( Anyone could help with this issue?
I'm using
PAX-EXAM 2.6.0,
org.apache.karaf.tooling.exam.container 2.3.0,
apache-karaf 2.3.0.
Code:
#Inject
BundleContext bundleContext;
#Inject
EntityManagerFactoryService entityManagerFactoryService;//Service exposed trough OSGI
protected EntityManager entityManager;
#Before
public void init() throws InterruptedException {
entityManager = entityManagerFactoryService.getEntityManagerFactory().createEntityManager();
}
#Configuration
public static Option[] configuration() throws Exception {
return new Option[] {
karafDistributionConfiguration().frameworkUrl(maven().groupId("org.apache.karaf").artifactId("apache-karaf").type("zip").versionAsInProject())
.karafVersion("2.3.0").name("Apache Karaf"),
mavenBundle("com.google.guava", "guava", "13.0.1").startLevel(30),
mavenBundle("com.mysql.jdbc", "com.springsource.com.mysql.jdbc", "5.1.6").startLevel(30),
mavenBundle("javax.persistence", "com.springsource.javax.persistence", "2.0.0").startLevel(30),
mavenBundle("org.apache.commons", "com.springsource.org.apache.commons.lang", "2.6.0").startLevel(30),
...the rest of bundles
junitBundles(), };
Test method:
#Test
public void contextNotNull() {
Assert.assertNotNull(entityManagerFactoryService);
}
The log:
java.lang.ClassNotFoundException: com.startjg.crp.core.dao.service.EntityManagerFactoryService not found by PAXEXAM-PROBE-749fa717-8bdc-4d9a-9803-bdaf6d4edac0 [144]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Full log:
https://www.dropbox.com/s/v12r15sbmtu9svp/log.txt
Also tried with no luck:
protected <T> Object getService(Class<T> serviceClass) {
int maxCount = 5;
int delay = 5000;
for (int i = 0; i <= maxCount; i++) {
if (bundleContext.getServiceReference(serviceClass) != null) {
ServiceReference<T> serviceReference = bundleContext.getServiceReference(serviceClass);
return bundleContext.getService(serviceReference);
} else {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return null;
}
#Before
public void init() throws InterruptedException {
EntityManagerFactoryService emfs = (EntityManagerFactoryService) getService(EntityManagerFactoryService.class);
entityManager = entityManagerFactoryService.getEntityManagerFactory().createEntityManager();
}
Are you sure your EntityManager is working and available as Service?
You are most probably missing some dependencies, that's why your bundle containing the service isn't fully started.
The current pax exam 3.3.0 now fully supports karaf as a container. The former karaf exam code now fully moved to pax exam.
I am trying to run a demo application for OSGi EventAdmin service, but the EventHandler I implemented fails to listen the events posted by the EventAdmin publisher:
Below is the code for Event Publisher, followed by the code for Listener(EventHandler):
public class Publisher implements BundleActivator{
static EventAdmin eventAdmin;
ServiceReference ref;
static HashMap properties= null;
#Override
public void start(BundleContext context) throws Exception {
ref=context.getServiceReference(EventAdmin.class.getName());
if(ref==null){
System.err.println("Unable to aquire EventAdmin Ser Ref.");
}
eventAdmin=(EventAdmin) context.getService(ref);
if(eventAdmin==null){
System.err.println("unable to get service:EventAdmin");
}
properties=new HashMap();
properties.put("XYZ", "Test");
Event event = new Event("lnu/test/event/Demo", properties);
eventAdmin.postEvent(event);
System.out.println("event posted");
}
#Override
public void stop(BundleContext context) throws Exception {
// TODO Auto-generated method stub
}
}
Code for Listener:
public class Listener implements BundleActivator, EventHandler {
public void start(BundleContext context) {
Dictionary d = new Hashtable();
d.put(EventConstants.EVENT_TOPIC, "lnu/test/event/Demo" );
context.registerService( EventHandler.class.getName(),
this, d );
System.out.println("event handler is registered now");
}
public void stop( BundleContext context) {}
public void handleEvent(Event event ) {
System.err.println("Event has been captured");
System.out.println("getTopic: "+event.getTopic());
System.out.println("getproperty: "+event.getProperty("XYZ"));
}
}
The print statements in the code show that the event has been posted by the publisher and the Listener is registered with the EventHandler service but still it does not invokes handleEvent method on the listener side, I don't know why? and can't understand what is happening behind the scene. There are no runtime exceptions/errors.
The IDE used is Eclipse Juno Build id: 20120614-1722 with Equinox.
Following Target Platform bundles are included in the run configuration:
org.eclipse.osgi
org.eclipse.equinox.event
org.eclipse.equinox.util
org.eclipse.osgi.services
Can some one point me what I am missing or doing wrong? Or if you have some link to working example of OSGi EventAdmin service?
I would guess that your listener bundle is being registered after the publisher bundle has already posted the Event.
Testing this in the start methods of the bundles is error prone for this reason unless you control the start order of the bundles. I would suggest for this simple test that you start a separate thread in your publisher to post an event every few seconds. The listener should start getting them once it is registered.
Confirm that your listener bundle is importing the same org.osgi.service.event package as the EventAdmin bundle. It is possible that your listener bundle includes the org.osgi.service.event package and is thus not using the same org.osgi.service.event package as the EventAdmin bundle. This could be why the EventAdmin bundle does not call your EventHandler service. It may be something else, but this is something to check.