Resource not exported up in OSGi container - rest

I'm trying to expose a REST service through OSGi (using Apache Felix). I'm using the osgi-jax-rs-connector to publish the resource. Here is the resource interface:
#Path("/bingo")
public interface BingoService {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/lottery")
List<Integer> getLottery();
}
The implementation uses DS annotation to obtain reference to a provided service in container:
#Component(
immediate = true,
service = BingoService.class,
properties = "jersey.properties")
public class Bingo implements BingoService {
#Reference
private RandomNumberGenerator rng;
#Activate
public void activateBingo() {
System.out.println("Bingo Service activated using " +
rng.getClass().getSimpleName());
}
#Override
public List<Integer> getLottery() {
List<Integer> result = new ArrayList<>();
for (int i = 5; i > 0; i--) {
result.add(rng.nextInt());
}
return result;
}
}
jersey.properties simply contains this line
service.exported.interfaces=*
When I deploy the bundle it starts and register the service correctly. But if I go to http://localhost:8181/services/bingo/lottery I get 404.
Could someone point me to the issue or give me some advice on where to look?

On reading the documentation for OSGi - JAX-RS Connector, it expects to find the annotations #Path or #Provider on the service instance object. You have placed them instead on an interface implemented by the component.
I'm not sure what the purpose of the BingoService interface is. This is not required for JAX-RS services. Normally you would register the resource class using its own type (e.g. service=Bingo.class) or simply java.lang.Object.

Related

Calling services from other application in the cluster

Is it possible to call services or actors from one application to another in a Service Fabric Cluster ? When I tryed (using ActorProxy.Create with the proper Uri), I got a "No MethodDispatcher is found for interface"
Yes, it is possible. As long as you have the right Uri to the Service (or ActorService) and you have access to the assembly with the interface defining your service or actor the it should not be much different than calling the Service/Actor from within the same application. It you have enabled security for your service then you have to setup the certificates for the exchange as well.
If I have a simple service defined as:
public interface ICalloutService : IService
{
Task<string> SayHelloAsync();
}
internal sealed class CalloutService : StatelessService, ICalloutService
{
public CalloutService(StatelessServiceContext context)
: base(context) { }
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(this.CreateServiceRemotingListener);
}
public Task<string> SayHelloAsync()
{
return Task.FromResult("hello");
}
}
and a simple actor:
public interface ICalloutActor : IActor
{
Task<string> SayHelloAsync();
}
[StatePersistence(StatePersistence.None)]
internal class CalloutActor : Actor, ICalloutActor
{
public CalloutActor(ActorService actorService, ActorId actorId)
: base(actorService, actorId) {}
public Task<string> SayHelloAsync()
{
return Task.FromResult("hello");
}
}
running in a application like this:
Then you can call it from another application within the same cluster:
// Call the service
var calloutServiceUri = new Uri(#"fabric:/ServiceFabric.SO.Answer._41655575/CalloutService");
var calloutService = ServiceProxy.Create<ICalloutService>(calloutServiceUri);
var serviceHello = await calloutService.SayHelloAsync();
// Call the actor
var calloutActorServiceUri = new Uri(#"fabric:/ServiceFabric.SO.Answer._41655575/CalloutActorService");
var calloutActor = ActorProxy.Create<ICalloutActor>(new ActorId(DateTime.Now.Millisecond), calloutActorServiceUri);
var actorHello = await calloutActor.SayHelloAsync();
You can find the right Uri in the Service Fabric Explorer if you click the service and look at the name. By default the Uri of a service is: fabric:/{applicationName}/{serviceName}.
The only tricky part is how do you get the interface from the external service to your calling service? You could simply reference the built .exe for the service you wish to call or you could package the assembly containing the interface as a NuGet package and put on a private feed.
If you don't do this and you instead just share the code between your Visual Studio solutions the Service Fabric will think these are two different interfaces, even if they share the exact same signature. If you do it for a Service you get an NotImplementedException saying "Interface id '{xxxxxxxx}' is not implemented by object '{service}'" and if you do it for an Actor you get an KeyNotfoundException saying "No MethodDispatcher is found for interface id '-{xxxxxxxxxx}'".
So, to fix your problem, make sure you reference the same assembly that is in the application you want to call in the external application that is calling.

How to use regexmapper based routing in Zuul? PatternServiceRouteMapper not working?

What I try to achieve is a routing for example:
http://zuul-host:8080/v1/foo/hello to my service foo-v1, resource hello
I'm trying out the regexmapper example described at http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html
My problem is that I see that a service called foo-v1 gets mapped to /v1/foo in the PatternServiceRouteMapper but then I'm not able to call that route. It's also no visible at /mappings. Do I have to activate that route somewhere?
Setup
Foo Service
application.properties
server.port=9092
spring.application.name=foo-v1
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.instance.healthcheck.enable=true
Zuul
My configuration class Routings.java. I added some sysout log output for the service mapping and I get foo-v1 -> v1/foo in the log. Therefore this mapping should be active.
#Configuration
public class Routings {
#Bean
public PatternServiceRouteMapper serviceRouteMapper() {
return new PatternServiceRouteMapper(
"(?<name>^.+)-(?<version>v.+$)",
"${version}/${name}") {
#Override
public String apply(final String serviceId) {
String route = super.apply(serviceId);
System.out.println(serviceId + " -> " +route);
return route;
}
};
}
}
My ZuulApplication.java
#SpringBootApplication
#EnableZuulProxy
#ComponentScan
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
#RefreshScope
#ConfigurationProperties("zuul")
public ZuulProperties zuulProperties() {
return new ZuulProperties();
}
}
Ok, found the solution.
Remove ignoredServices: '*' from the zuul config.
This happens if you work through the examples. They start with explicitly configured routes and ignore dynamic routings. It's in the documentation but made no sense to me at that point :-)
To skip having a service automatically added, set zuul.ignored-services to a list of service id patterns.
When using the regexmapper we start using services that get added automatically and that's the feature we disabled with ignoredServices: '*'

CXF #CrossOriginResourceSharing Annotation

I am using CXF/Karaf, and I have many different RESTful resources within multiple packages/classes.
Question: Is there a way to avoid having to write annotations above every resource, such as #CrossOriginResourceSharing?
I would like to be able to put this in one place. Below is an example of how this is currently being used:
#CrossOriginResourceSharing(
allowOrigins = {"http://<ip>:<port>"}
)
#GET
#Path("/rest")
#Produces(MediaType.APPLICATION_JSON)
public String rest();
You can add this to the class instead of on each resource in the class (and I haven't tested this but you could possible create a super class with this annotation and extend it but I'm not sure if CXF will honour it):
#CrossOriginResourceSharing(
allowOrigins = {"http://<ip>:<port>"}
)
public class resourceGroup {
#GET
#Path("/rest")
#Produces(MediaType.APPLICATION_JSON)
public String rest();
}

Test the remote client jndi lookup using arquillian

Setup: arquillian, jboss as 7.1.1.final as a managed Container
I am currently migrating an EJB application from EJB 2.x to 3.x and JBoss 3.x to JBoss AS 7.1.
During this process i would like to get most classes under test and stumbled over arquillian.
While arquillian seems to offer some nice features on inter-bean-functionality i cannot figure out whether or not the testing of remote client features using jndi lookups works or not.
I used the Arquillian Getting started guides on my beans which worked, but since these are using #Inject and in my application jndi lookups are used everywhere i (at least think that i) need to swerve from that path.
Here is the TestCase i created based on Arquillian Getting Started. I explicitly left in all attempts using jndi properties of which i thought they might help.
The Test
should_create_greeting()
works if the Greeter bean using a separate Producer.
#RunWith(Arquillian.class)
public class GreeterTest {
public static final String ARCHIVE_NAME = "test";
Logger logger = Logger.getLogger(GreeterTest.class.getName());
#Deployment
public static Archive<?> createDeployment() {
JavaArchive jar = ShrinkWrap.create(JavaArchive.class, ARCHIVE_NAME + ".jar").addPackage(Greeter.class.getPackage())
.addAsManifestResource("test-persistence.xml", "persistence.xml").addAsManifestResource("OracleGUIDS-ds.xml")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
return jar;
}
/**
* #Inject works using a producer with {#code #Produces}
*/
// #Inject
// Greeter greeter;
#ArquillianResource
Context context;
GreeterRemote greeter;
#Before
public void before() throws Exception {
Map<String, String> env = new HashMap<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.as.naming.InitialContextFactory");
env.put("jboss.naming.client.ejb.context", "true");
// env.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT",
// "false");
// env.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS",
// "false");
// env.put("jboss.naming.client.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED",
// "false");
for (Map.Entry<String, String> entry : env.entrySet()) {
context.addToEnvironment(entry.getKey(), entry.getValue());
}
greeter = (GreeterRemote) context.lookup(ARCHIVE_NAME + "/" + Greeter.class.getSimpleName() + "!"
+ GreeterRemote.class.getName());
}
#Test
public void should_create_greeting() {
Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling"));
greeter.greet(System.out, "Earthling");
}
}
Is it possible to get this test running with jndi lookup? Am i missing something?
If you want to test the Remote features of a EJB you probably want to run on the client side and not in container.
You can configure the Deployment to be only client side by using #Deployment(testable=false). The #Test methods will then run as if you were a remote client.
Beyond that you can just lookup the bean via the injected Context if you want.
I had the same issue, so in a workaround i just added on the method to be tested the remoteejb as a parameter.
On my ejb:
public List localBean.obtain(RemoteEJB remoteEjb){
return remoteEjb.obtain();
}
Then on the arquillian test :
#Inject
private LocalBean localBean;
#Inject
private RemoteEJB remoteEjb;
#Test
public void test(){
List<Vo>voList = localBean.obtain(remoteEjb);
}
The best part is the remote ejb its injected and on the caller method original
#EJB(lookup="java:global/ear/ejb/RemoteEjb")
private RemoteEJB remoteEjb;

Servicestack (rest) incorrect WSDL with mono

I've written a simple self-hosted (in a ConsoleApplication) rest service with service stack 3.9.70.
using System;
using System.Runtime.Serialization;
// service stack support
using ServiceStack.ServiceHost;
using ServiceStack.WebHost.Endpoints;
namespace HelloWorldConsole
{
namespace DTO
{
[DataContract(Namespace = "http://localhost:8080/types")]
[Route("/hello/{Name}")]
class Hello : IReturn<HelloResponse>
{
[DataMember]
public string Name { get; set; }
}
[DataContract(Namespace = "http://localhost:8080/types")]
class HelloResponse
{
[DataMember]
public string Response { get; set; }
}
}
class HelloService : IService
{
public Object Any(DTO.Hello request)
{
return new DTO.HelloResponse { Response = "Hello " + request.Name };
}
}
public class HelloHost : AppHostHttpListenerBase
{
public HelloHost()
: base("Hello Service Self-Host",
typeof(HelloService).Assembly)
{ }
public override void Configure(Funq.Container container)
{
SetConfig(new EndpointHostConfig
{
DebugMode = true,
WsdlServiceNamespace = "http://localhost:8080/",
WsdlSoapActionNamespace = "http://localhost:8080/",
SoapServiceName = "HelloService"
});
}
}
class MainClass
{
public static void Main (string[] args)
{
string listenOn = "http://localhost:8080/";
HelloHost host = new HelloHost ();
host.Init ();
host.Start (listenOn);
Console.WriteLine ("AppHost created at {0} on {1}",
DateTime.Now, listenOn);
Console.ReadKey ();
}
}
}
Under Windows the generated WSDL is good, and if I try to create a client application and add a web reference to the soap service on localhost, I'm able to call Hello.
If I run the same code under Linux using Mono, the generated WSDL does not contain the types defined inside the DTO namespace. If I try to add a web service reference on a client, I'm not able to exploit hello method.
At this link I've read that by default the same ServiceStack Console app binary runs on both Windows/.NET and Mono/Linux as-is. I've tried to launch the binary under windows; the service runs but the generated WSDL is incorrect (without types defined in DTO namespace).
I use mono 2.10.8.1.
Does anyone have any suggestion?
I also have another question. If I use new version Servicestack last release (4.0.33) I'm not able to exploit soap endpoint.
At this link I've read that SOAP endpoints are not available when hosted on a HttpListener Host. Is it a feature introduced with new version 4.0?
Isn't there the posbility to exploit soap endpoints with servicestack releases higher than 3.9?
Any help is appreciated.
Mono has a weak and partial WCF/SOAP support which will fail to generate WSDLs for many non-trivial Service definitions. This situation may improve in the near future now that Microsoft has Open Sourced .NET server libraries, but in the interim I recommend avoiding Mono if you want to use SOAP.