Shorten path of REST service in JBoss Seam application - rest

I'm pretty new to JBoss and Seam. My project has a REST service of the style
#Path("/media")
#Name("mediaService")
public class MediaService {
#GET()
#Path("/test")
public Response getTest() throws Exception {
String result = "this works";
ResponseBuilder builder = Response.ok(result);
return builder.build();
}
}
I can reach this at http://localhost:8080/application/resource/rest/media/test. However, I don't like this URL at all and would prefer something much shorter like http://localhost:8080/application/test.
Can you please point me in the right direction on how to configure the application correctly? (Developing using Eclipse)

web.xml will contain seam resource servlet mapping , this should be modified to /*, and if you have more configuration to the path it will be in components.xml ,if it is resteasy seam is configured to use, it will look like the following
<resteasy:application resource-path-prefix="/rest"/>

Related

How do I access DispatcherServlet with MockMvc?

I have a basic SpringMVC Application which is running (and mapping) fine.
Now I wanted to set up my UnitTests with MockMvc to perform get requests and stuff.
But if I run the test there is an AssertionError "Status expected: <200> but was: <404>" and my console gives warning "No mapping found for HTTP request with URI [/] in DispatcherServlet with name ''".
I get the feeling my MockMvc cant communicate with my DispatcherServlet, so how do I define this connection?
Here is my short test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration
public class HomeControllerTest {
private MockMvc mvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() throws ServletException {
mvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
public void testLandingPagePath() throws Exception {
mvc.perform(get("/")).andExpect(status().isOk());
}
}
So I expected MockMvc to get the location of my DispatcherServlet by default. But it actually doesn't call it for mapping.
I have my "web.xml" and "dispatcher-servlet.xml" located in "WEB-INF" folder and no extra configuration defined.
I got the feeling the problem is based on my project structure, but this is a basic eclipse "Dynamic Web Application", the tests are located in "src/test/java", parallel to "src/main/java".
I appreciate any help, since I spend last 2 hours on reading for solutions but not getting the trick.
After some more time I got things right now:
There is still no way for me to access the dispatcher-servlet.xml in WEB-INF folder. I added a new "config" package to my test-package in parallel to my "controller" test package and put a copy of the dispatcher-servlet.xml in there, called "test-dispatcher-servlet.xml".
Now my test class is able to access this with
#ContextConfiguration("../config/test-dispatcher-servlet.xml")
public class HomeControllerTest {
Hope this can help others who start with spring mvc testing :-)

Swagger + jaxrs + embedded jetty + no web.xml

I have maven project with embedded jetty server.
I have already created apis using JAX-RS, which are working properly. Now I want to create swagger documentation for my apis.
To start with swagger I have added servlet configuration as describe below :
#WebServlet(name = "SwaggerConfig")
public class SwaggerServlet extends HttpServlet {
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("init SwaggerServlet");
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.0");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:8082");
beanConfig.setBasePath("/api");
beanConfig.setResourcePackage("com.myCompany.myApisResourcePackage");
beanConfig.setScan(true);
}
}
Also, in main method,
along with my jersey configuration I have added following code :
//swagger
ServletHolder swaggerServletHolder = new ServletHolder(SwaggerServlet.class);
swaggerServletHolder.setInitOrder(1);
swaggerServletHolder.setInitParameter("swagger.api.basepath", "http://localhost:8082");
context.addServlet(swaggerServletHolder, "/api/*");
//swagger end
So, the problem is, I am not able to find where swagger.json will be created.
In this case, swagger scans packages as server log says it, but swagger.json still not getting created.
Note: I am currently not adding swagger-ui as I think it is not mandatory for creating swagger.json
I got swagger json by hitting url "localhost:8082/swagger.json". I used same configuration as posted in my question.

Is it possible to write JUnit tests that are agnostic to your JAX-RS implementation?

I wrote a REST web service using JAX-RS that knows nothing about the specific JAX-RS implementation I chose. I happen to be using TomEE which means my JAX-RS implementation is ApacheCXF.
I'd like to write unit tests for the web service that also know nothing about the JAX-RS implementation. Is this possible? So far every example I've found involves using classes from a specific JAX-RS implementation (JAXRSClientFactory for ApacheCXF, Jersey Test Framework, etc).
I've started experimenting with tomee-embedded and am able to test my EJB's but it doesn't seem to startup the REST services.
My solution was to use Arquillian paired with an Embedded TomEE. Arquillian provides a ton of functionality but I'm only using it to start/stop the Embedded TomEE. Therefore, all I needed to do was add this to my pom.xml:
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>arquillian-tomee-embedded</artifactId>
<version>${tomee.version}</version>
<scope>test</scope>
</dependency>
Then I could write a JUnit test with a little extra Arquillian stuff and plain JAX-RS:
#RunWith(Arquillian.class)
public class MyServiceIT {
#ArquillianResource
private URL webappUrl;
#Deployment()
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
.addClasses(MyService.class)
.addAsWebInfResource("META-INF/persistence.xml") //Refers to src/main/resources/META-INF/persistence.xml
.addAsWebInfResource("test-resources.xml", "resources.xml") //Refers to src/test/resources/test-resources.xml
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#Test
public void randomTest() throws URISyntaxException {
//Get data from the web service.
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(webappUrl.toURI().resolve("myentity"));
Response response = webTarget.request(MediaType.APPLICATION_JSON).get();
int status = response.getStatus();
List<MyEntity> myEntities = response.readEntity(new GenericType<List<MyEntity>>() {});
//Perform some tests on the data
}
}

java ee lookup ejbs from from different app

Java EE Tutorial is not helpful at all. Internet search was underwhelming.
I have an EJB module that is deployed to glassfish by itself. It has #Local and #Remote annotated iterfaces which are both implemented by the concrete class.
Then i have a REST resource that needs to get a reference to that ejb module and invoke some methods.
Can you give me a barebones, simple example of how that is done? I mean, i can't even inject SessionContext into my rest app, as it crashes... Please, keep it simple.
The ejb should just have a:
public String getMsg(){
return "ohai";
}
The rest service:
#GET
#Produces("text/plain")
public String asd(){
return <the myterious ejb that was injected somehow>.getMsg();
}
Thanks.
Alright, i figured it out. Using NetBeans, but probably applicable to Eclipse. Server - glassfish
Create webapp, an EJB -> call EJB from webapp. All these run inside the same server as separate modules.
First: create an EJB module, it will be deployed on its own:
remote interface:
package main;
import javax.ejb.Remote;
#Remote
public interface YourRemoteInterface{
public String tellMeSomething();
public void otherMethod(); //etc...
}
then create the EJB implementation class:
concrete implementation
package main;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.EJB; //crucial to JNDI lookup
#Remote(RemoteInterface.class)
#Stateless
#EJB(name="java:global:/MYSTUFF", beanInterface=YourRemoteInterface.class)
public class YourConcreteClass implements YourRemoteInterface{
#Override
public String tellMeSomething(){//...} //and do the other methods
}
#EJB name attribute names your bean, that you will use to look it up. Can by any name. For ex: "some-name", or "java:global/YourConcreteClass"
Part two - webapp:
For web app i used a rest service, but surely can be another EJB or a SE client app. For SE client you'd need to set connection info, but that for another life.
#Path("/somePath")
public class Service{
#GET
#Produces("text/plain")
public String qwe(){
try{
javax.naming.InitialCOntext ic = new javax.naming.InitialContext();
YourRemoteInterface rb = (YourRemoteInterface)ic.lookup("java:global:/MYSTUFF");
return rb.tellMeSomething();
} catch (Exception ex) {
return "F*uck your life";
}
}
}
Now, from Project Properties of your webapp, you need to:
1) add the ejb jar file to Libraries so it shows in the Compile tab. I used the "Add project" button
2) Build -> Packaging: add the ejb jar file to WAR content. I used "Add file/folder", where i navigated to NetBeans projects / the EJB module / build / dist
note: you may experience an error when trying to deploy the ejb, or redeploy it. Error name is: java.lang.RuntimeException: Error while binding JNDI name main.RemoteInterface#main.RemoteInterface for EJB RemoteBean . Skipping the vague explanation, to cure it, you need to execute a command in glassfish:
asadmin set server.ejb-container.property.disable-nonportable-jndi-names="true"
Now, you can compile the webapp and deploy it. Should work.
At the end it's that simple. I swear i've eaten the WHOLE ejb section in glassfish tutorial and nowhere do they tell you this stuff. It's so annoying.

Configuring one ear to call remote ejb3 on another ear in JBoss

I am new to EJB3 and am missing something when it comes to accessing a #Remote #Stateless bean deployed as an ejb module inside an ear file. I want to access a remote bean in lima.ear from soup.ear.
Here is what I am doing now (somewhat abbreviated):
//deployed under lima.ear
#Remote
#Stateless
public interface LimaBean {
String sayName();
}
I want to put LimaBean in the Soup:
//deployed in soup.ear
#Stateless
public class Soup implements SoupLocal {
#EJB
private LimaBean limaBean;
public String taste() {
return limaBean.sayName();
}
}
When I start JBoss I get the following error:
java.lang.RuntimeException: could not resolve global JNDI name for #EJB for container Soup: reference class: com.example.LimaBean ejbLink: not used by any EJBs
I have had a hard time finding out what this ejbLink is about, if that is the right path to go down.
If I deploy LimaBean as a jar file in jboss then everything works great!
I ran accross an article that had a section called "2.5.3. References between beans in different jars and different ears"
(http://jonas.ow2.org/doc/howto/jboss2_4-to-jonas3_0/html/x111.html)
Example of jboss.xml file for SB_BrowseRegions:
<jboss>
<session>
<ejb-name>SB_BrowseRegions</ejb-name>
<ejb-ref>
<ejb-ref-name>ejb/Region</ejb-ref-name>
<jndi-name>protocol://serverName/directory/RegionHome</jndi-name>
</ejb-ref>
</session>
</jboss>
If I touch the soup.ear, after JBoss starts up then it deploys fine, so I am assuming I need to specify a dependency like the above article says.
But even after it deploys then I get an error when accessing the remote LimaBean:
Caused by: java.lang.IllegalArgumentException: Can not set com.soup.LimaBean field com.soup.Soup.limaBean to $Proxy147
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at org.jboss.injection.JndiFieldInjector.inject(JndiFieldInjector.java:115)
... 49 more
I have tried a few things but, if anyone can point me in the right direction about this I would appreciate it.
It looks like the JNDI properties need to be set as if it were a remote client outside of the app server because of the ear isolation we have setup.
properties.put(Context.PROVIDER_URL, url);
InitialContext ctx = new InitialContext(properties);
Just specify the URL for the InitialContext and that should do the trick.