I am running a javaee web application from the ground up using wildfly and simply want to expose some RESTful web services. My wildfly application server is running with the defaults it shipped with and I am not using any database entities although I do have a persisitance.xml to make wildfly happy. My application deploys fine as indicated by log messages below.
12:50:38,585 INFO [org.jboss.resteasy.spi.ResteasyDeployment] (MSC service thread 1-5) Deploying javax.ws.rs.core.Application: class org.netbeans.rest.application.config.ApplicationConfig
12:50:38,585 INFO [org.jboss.resteasy.spi.ResteasyDeployment] (MSC service thread 1-5) Adding class resource os.acquisition.acq.Acquisition from Application class org.netbeans.rest.application.config.ApplicationConfig
12:50:38,588 INFO [org.wildfly.extension.undertow] (MSC service thread 1-5) JBAS017534: Registered web context: /acq-1.0
12:50:38,712 INFO [org.jboss.as.server] (management-handler-thread - 29) JBAS018565: Replaced deployment "acq-1.0.war" with deployment "acq-1.0.war"
My issue comes when trying to call the GET request below. (always returns 404)
#Path("/acq")
public class Acquisition {
#GET
#Path("ping")
public Response ping(#Context HttpServletRequest req) {
return Response.ok().entity(GenericResponse.OK).build();
}
}
I have also used the standard IDE generated ApplicationConfig.java which has this service as one of its resources.
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(os.acquisition.acq.Acquisition.class);
}
}
I have been using a short curl script to call the rest service and have tried every possible combination of #Path params and URL configurations to no avail.
#!/bin/bash
curl -v -X GET http://localhost:8080/acq-1.0/acq/ping
Additionally, when curl -v -X GET http://localhost:8080/acq-1.0/ is called it returns to me the index.html page as I expect.
It seems that I am missing something fundimental here. Any ideas?
#ApplicationPath's value is appended to the resource URI before the individual resource paths. Looks like your curl request is missing the "webresources" portion.
Related
I want to create a simple JAX-RS REST Service for Wildfly 10. My issue is that my REST Service is not found. Result in browser is 404 not found. I am not sure what exactly the issue is. I get no error or exception in wildfly log file. I am using eclipse neon 3 and wildfly 10. My project is using JAX-RS not resteasy.
Here my project setup and code:
I have created a Dynamic Web Project in Eclipse.
I have set JAX-RS(REST Service) support in the project facets. JAX-RS version is 2.0 (also tried with version 1.1)
I have create a subclass which extends Application (javax.ws.rs.core.Application)
I added the annotation #ApplicationPath("/yoshi-rest") to the class which extends Application.
I have created a class which contains my rest service method. The class itself has the #Path("/StatusService") annotation.
The affected method has the annotations #Get and #Path("/getStatus").
Due to I have the subclass of Application I didn't set the servlet mapping in web.xml.
Here the code:
Subclass of Application(RESTConfig):
#ApplicationPath("/yoshi-rest")
public class RESTConfig extends Application {
}
REST Service class(StatusService):
#Path("/StatusService")
public class StatusService {
#Get
#Path("/getStatus")
public String getStatus() {
return "Yoshi is up and running";
}
}
I can see during startup of wildfly that the subclass RESTConfig is deployed:
11:09:23,777 INFO [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 61) RESTEASY002225: Deploying javax.ws.rs.core.Application: class XXXX.yoshi.rest.services.RESTConfig
If I call the rest service url (http://localhost:8080/yoshi-rest/StatusService/getStatus) in browser, I get a '404 - Not found' as result.
Any idea what I am doing wrong?
You need to register service to connect to your RESTConfig:
#ApplicationPath("/yoshi-rest")
public class RESTConfig extends ResourceConfig {
public RESTConfig() {
register(StatusService.class);
}
See more on ResourceConfig configuration options
Standard JAX-RS uses an Application as its configuration class. ResourceConfig extends Application.
Putting the project name in the url solved the issue.
Thanks for help.
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.
I have migrated my EJB application from jboss 5.0.1 to JBOSS EAP 7.
I want to pass user data from EJB client to my EJB.
I'm using this code to pass custom attribute to ejb server but it does not work anymore.
Client:
public class CustomData extends SimplePrincipal{
String userData1;
public CustomData(String userData1){
this.userData1 = userData1;
}
SecurityClient client = SecurityClientFactory.getSecurityClient();
client.setSimple(new CustomData("MyData"), credentials.getPass());
client.login();
Server:
#Resource
SessionContext ejbCtx;
Principal data= ejbCtx.getCallerPrincipal();
data.getName() --- anonymous
How to fix it on new JBOSS ?
1.Create the client side interceptor
This interceptor must implement the org.jboss.ejb.client.EJBClientInterceptor. The interceptor is expected to pass the additional security token through the context data map, which can be obtained via a call to EJBClientInvocationContext.getContextData().
2.Create and configure the server side container interceptor
Container interceptor classes are simple Plain Old Java Objects (POJOs). They use the #javax.annotation.AroundInvoke to mark the method that is invoked during the invocation on the bean.
a.Create the container interceptor
This interceptor retrieves the security authentication token from the context and passes it to the JAAS (Java Authentication and Authorization Service) domain for verification
b. Configure the container interceptor
3.Create the JAAS LoginModule
This custom module performs the authentication using the existing authenticated connection information plus any additional security token.
Add the Custom LoginModule to the Chain
You must add the new custom LoginModule to the correct location the chain so that it is invoked in the correct order. In this example, the SaslPlusLoginModule must be chained before the LoginModule that loads the roles with the password-stacking option set.
a.Configure the LoginModule Order using the Management CLI
The following is an example of Management CLI commands that chain the custom SaslPlusLoginModule before the RealmDirect LoginModule that sets the password-stacking option.
b. Configure the LoginModule Order Manually
The following is an example of XML that configures the LoginModule order in the security subsystem of the server configuration file. The custom SaslPlusLoginModule must precede the RealmDirect LoginModule so that it can verify the remote user before the user roles are loaded and the password-stacking option is set.
Create the Remote Client
In the following code example, assume the additional-secret.properties file accessed by the JAAS LoginModule
See the link:
https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.2/html/Development_Guide/Pass_Additional_Security_For_EJB_Authentication.html
I have done with this way:
Client:
Properties properties = new Properties();
properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
properties.put("org.jboss.ejb.client.scoped.context", "true");
properties.put("remote.connection.default.username", "MyData");
Server:
public class MyContainerInterceptor{
#AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
Connection connection = RemotingContext.getConnection();
if (connection != null) {
for (Principal p : connection.getPrincipals()) {
if (p instanceof UserPrincipal) {
if (p.getName() != null && !p.getName().startsWith("$"))
System.out.println(p.getName()); //MyData will be printed
}
}
}
return ctx.proceed();
}
}
Don't forget to configure container interceptor in jboss-ejb3.xml (not in ejb-jar.xml)
<?xml version="1.0" encoding="UTF-8"?>
<jee:assembly-descriptor>
<ci:container-interceptors>
<jee:interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>package...MyContainerInterceptor</interceptor-class>
</jee:interceptor-binding>
</ci:container-interceptors>
</jee:assembly-descriptor>
I try to build a Java EE 7 app with Rest services and EJB injection.
I created a multi module maven project which I deploy on Glassfish 4. My final EAR contain a JAR with my EJBs, with for example my Rest services definitions :
#Stateless
#Path("countries")
public class CountryRest {
//#EJB
//StockService stockService;
#GET
public Response getCountries() {
//stockService.getAll(); --> firing a NPE, stockService is Null
return Response.ok().build();
}
}
#Stateless
#Remote(IStockService.class)
public class StockService implements IStockService {
#Override
public List<Stock> getAllStock() {
return new ArrayList<Stock>();
}
}
When I deploy my app, I see the following logs which seems ok. Even if I wonder why it defines "java:global" JNDI since by default #Stateless EJB is #Local :
Portable JNDI names for EJB CountryRest: [java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/CountryRest, java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/CountryRest!com.tomahim.geodata.rest.CountryRest]
Portable JNDI names for EJB StockService: [java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/StockService, java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/StockService!com.tomahim.geodata.services.IStockService]
Then when I'm doing a GET on /rest/countries, the status is 200 as expected but I have a NameNotFoundException / NamingException :
Avertissement: An instance of EJB class, com.tomahim.geodata.rest.CountryRest, could not be looked up using simple form name. Attempting to look up using the fully-qualified form name.
javax.naming.NamingException: Lookup failed for 'java:module/CountryRest' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: No object bound to name java:module/CountryRest]
I see that the lookup for "java:module/ContryRest" is not matching "java:global/.../CountryRest" but what am I doing wrong ?
EDIT 1 : I was able to make #Ejb injection work by placing my Rest definitions ans EJBs in my webapp maven module deploy as a WAR. So it seems that the problem occur only when I deploy my EJB in a JAR. Any idea ? What could be the difference between JAR and WAR deployment ?
It is required by the JAX-RS spec that all REST endpoints must live within your WAR file. Do you really need an EAR file?
My end goal is simple. I am building a website that has three components: a mobile interface, an admin web interface, and a web user interface. I plan to put each of these modules into separate WAR files and, together with an EJB module & possibly a common library module, bundle them all into a EAR for deployment on JBoss AS 7.1.
But first things first, can I deploy a very simple WAR file and get it to work - NO!
My war file has the following structure:
project-mobile.war:
META-INF/MANIFEST.MF
WEB-INF/jboss-web.xml
WEB-INF/classes/org/dobbo/project/mobile/Accounts.class
index.html
The manifest.mf file as the following content:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.0
Created-By: 1.6.0_18-b18 (Sun Microsystems Inc.)
Built-By: steve
The jboss-web.xml file's content are:
<?xml version="1.0"?>
<jboss-web>
<context-root>/mobile</context-root>
</jboss-web>
The Accounts.java file was based on the Library.java example from https://docs.jboss.org/author/display/AS71/Java+API+for+RESTful+Web+Services+(JAX-RS)
I did make some changes, added the Application subclassing and the AppicationPath annotation as this got me a little further in getting the deployment to work.
package org.dobbo.<project>.mobile;
import javax.ws.rs.*;
import javax.ws.rs.core.Application;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#ApplicationPath("/accounts")
#Consumes({"application/xml"})
#Produces({"application/xml"})
public class Accounts
extends Application {
...
#GET
#Path("/list")
public Collection<UUID> getAccounts() {
Collection<UUID> list = uuids.values();
log.info("getAccounts: " + list);
return list;
}
...
}
So far so good.
When I deploy I get the following logged to the JBoss console (timestamp & log level INFO removed):
[org.jboss.as.repository] (management-handler-thread - 12) JBAS014900: Content added at location /home/jboss/jboss-7.1.1/standalone/data/content/11/e8cdaea9dfa4e984ada3e22b0c890970f0ba75/content
[org.jboss.as.server.deployment] (MSC service thread 1-3) JBAS015877: Stopped deployment sokoban-mobile.war in 60ms
[org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "project-mobile.war"
[org.jboss.web] (MSC service thread 1-2) JBAS018210: Registering web context: /mobile
[org.jboss.as.server] (management-handler-thread - 12) JBAS018565: Replaced deployment "project-mobile.war" with deployment "project-mobile.war"
So far all seems well. But when I point my browser at jboss-server:8080/mobile/accounts/list I get a:
HTTP Status 404 - Could not find resource for relative : /list of full path: http://jboss-server:8080/mobile/accounts/list
type Status report
message Could not find resource for relative : /list of full path: http://jboss-server:8080/mobile/accounts/list
description The requested resource (Could not find resource for relative : /list of full path: http://jboss-server:8080/mobile/accounts/list) is not available.
However, something is working because pointing the broswer at jboss-server:8080/mobile/ successfully returns the index.html file also included in the WAR file.
It's probably just a simple configuration error on my part, but I can't work it out for the life of me. Many thanks to all that take the trouble to read this issue and even more thanks for posting any ideas you have.
Steve
The logs shows that no REST resource is loaded.
The resource is missing the #Path annotation.
You need on Application class with the #ApplicationPath annotation (The class will be empty).
Then you need to add the #Path annotation to your resource class (Accounts for your case)
So you will have:
#ApplicationPath("/")
public class AccountApp
extends Application {}
And:
#Path("accounts")
#Consumes({"application/xml"})
#Produces({"application/xml"})
public class Accounts{
...
#GET
#Path("/list")
public Collection<UUID> getAccounts() {
Collection<UUID> list = uuids.values();
log.info("getAccounts: " + list);
return list;
}
...
}