Twitter

miercuri, 2 decembrie 2015

Push/pull a Docker image to/from Docker Hub using Virtual Box on Windows

! INSTEAD OF anghelleonard USE YOUR NAME

In the previous post, I've created a Docker image for running OmniFaces Showcase WAR under WildFly 8.2.0 Final. If you followed the previous posts, then you should be able to start my-machine (just open Virtual Box locate the machine and hit start) and run docker images command:


Push to Docker Hub 
Further, let's share the anghelleonard/omnifaceswildfly image with other Docker users. For this, we can use Docker Hub. Currently, Docker Hub contains 100,000+ free apps, public and private registries, so is a pretty large repository with great visibility on Internet.

1. First, you need to create your account on Docker Hub. After you accomplish this simple step, you are ready to push images. For this, you need to create a repository:


2. Now, you should see the GUI for creating your repository. The important thing here is to select a namespace and to provide the repository name. In our case, the image is named anghelleonard/omnifaceswildfly. The anghelleonard part represent the user id (default namespace), while the  omnifaceswildfly represents the repository name. So, I can simply select the anghelleonard namespace, and type omnifaceswildfly name. For the moment I leave un-filled the rest of fields and click the Create button:


3. Further, you should see something like below:


4. At this point, we are ready to push the image on this repository. Get back to my-machine console and login to this repo. In order to login, you need to provide the user, email and password used to create your Docker Hub account:

Command: docker login


5. Finally, we can push the desired image in the repository. For this, just type the following command (notice that this will take a while!):

Command: docker push anghelleonard/omnifaceswildfly


6. After the process stops, you can check the available Tags in your repository; we didn't specify a tag at push time, so you will see the latest tag (do not forget to refresh page):


7. Finally, switch to Repo Info and fill the desired information:



Done! You successfully pushed and shared an image on Docker Hub.

Pull to Docker Hub 
Docker Hub allows us to share images, but it also allows us to pull images. For example, let's pull our image to see if everything works fine:

1. We can pull an image via the docker pull command. For example for anghelleonard/omnifaceswildfly image, we type the following command:

Command: docker pull anghelleonard/omnifaceswildfly


2. Well, instead of pulling the image from Docker Hub, we see a message of type "Image is up to date for anghelleonard/omnifaceswildfly". This message appears because we have this image "locally" on my-machine, and is up to date. In order to perform the pull, we need to delete the local image and try again. In order to delete a single image, you can use docker rmi image_name command, but we will delete all containers and images. For this we need two commands:

Command (remove all containers): docker rm $(docker ps -a -q)


Command (remove all images): docker rmi $(docker images -q)


3. Now, you can try to pull the anghelleonard/omnifaceswildfly image again - notice that this time the image is downloaded from Docker Hub:

Command: docker pull anghelleonard/omnifaceswildfly


Done! You have successfully pulled an image from Docker Hub.

A quick docker images command will reveal that images is on my-machine:


Finally, you can run the image and enjoy with OmniFaces Showcase application as you saw in "Create and run a Docker image from Dockerfile on Windows 7 via Command Prompt "

Note: In order to see all the options for docker-machine command try:

Command: docker-machine --help

miercuri, 25 noiembrie 2015

Create and run a Docker image from Dockerfile on Windows via Command Prompt

! INSTEAD OF anghelleonard USE YOUR NAME

As you may know from the previous post (Create a new Docker machine on Windows via Command Prompt), I've created a Docker machine named my-machine.

1. Now, I want to create an image on my-machine. For this, I need to write a Dockerfile using the Docker commands (see Docker Reference). My image will be pretty simple, and it will consist in a Docker image for running OmniFaces Showcase WAR under WildFly 8.2.0 Final. So, I need the following commands; this is the content of my Dockerfile:

FROM jboss/wildfly:8.2.0.Final

MAINTAINER Anghel Leonard

CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-c", "standalone-full.xml", "-b", "0.0.0.0"]

RUN curl -L https://github.com/AnghelLeonard/OmniFaces/blob/master/OmniFacesShowcase.war?raw=true -o /opt/jboss/wildfly/standalone/deployments/Showcase.war

EXPOSE 8080

Putting this in words, sound like this: give me the WildFly 8.2.0 Final server in standalone mode, and deploy and expose on port 8080 the OmniFaces Showcase WAR.

2. The my-machine is not running, so I need to start it and get the environment commands:

Command: docker-machine start my-machine
Command: docker-machine env --shell cmd my-machine
Command: FOR /f "tokens=*" %i IN ('docker-machine env --shell cmd my-machine') DO %i   


3. Before I build this image, I checked to see if I have any images or containers running. This is just a check, not a mandatory step:

- list of available images
Command: docker images

- list of available running containers
Command: docker ps

- list of recently containers activity
Command: docker ps -a

Since this is a new machine, I have no images or containers (running/history):


3. In order to obtain the image from the above Dockerfile, I need to build that file. So, I navigated to the Dockerfile location and execute the below command (my image name will be anghelleonard/omnifaceswildfly). This step will take some time depending on your Interner connection since the image is built by downloading the WildFly and OmniFaces Showcase from the Internet. Well, at further uses, these resources will be taken by default from cache.

Command: docker build -t anghelleonard/omnifaceswildfly .


4. Now, I want to see if the image was created. As you can see in the below figure, I have two images, one is jboss/wildfly (run only the WildFly container) and the other one is anghelleonard/omnifaceswildfly:

Command: docker images


5. Further, I can run and test my image, anghelleonard/omnifaceswildfly. For this, I will need the below command (notice in figure below that WildFly has started and the OmniFaces Showcase application was deployed successfullly):

Command: docker run -t -p 8080:8080 anghelleonard/omnifaceswildfly


6. Open your browser and type in browser address bar: http://192.168.99.100:8080/. You should see the WildFly welcome page from below:


Now, add /Showcase to this URL: http://192.168.99.100:8080/Showcase. You should see the OmniFaces Showcase running as below:


Note The 192.168.99.100 is the Docker host (this may differ in your test). You can easily pick up this IP via the below command. You can easily gain the Command Prompt control by pressing the CTRL+C. Don't worry, this will not stop WildFly!

Command: env | greep DOCKER


7. You can check to see the currently running containers (you can easily identify our container):

Command: docker ps


8. If you check carefully the above image, you can notice that our container is named, dreamy_leavitt (this may differ in your case since Docker has randomly generated it).  This is a Docker convention for naming containers when we don't indicate explicitly a name. This name can be useful for many furher operations, like stopping the container:

Command: docker stop dreamy_leavitt


You can easily check that the container has stopped by trying to refresh the http://192.168.99.100:8080/Showcase or by running again the docker ps command (as you can see from the below image, there is no container running):


However, you can still check the containers running history via, docker ps -a command.

9. For now, we finish this Docker lesson by stopping the machine. In the next post, you will see how I've pushed this image on DockerHub.

Command: docker-machine stop my-machine

Note: In order to see all the options for docker-machine command try:

Command: docker-machine --help

luni, 16 noiembrie 2015

Create a new Docker machine on Windows via Command Prompt

As you may know from the previous post (How I've installed Docker on Windows 7), I've just installed Docker on my Windows. Now, if you are in my case also, and you want to create a new Docker machine, here it is how I did it:

1. In order to create a new Docker machine via Windows Command Prompt, you need to set the ssh.exe in your PATH environment variable. This is in the Git\bin\ folder, which is commonly installed in C:\Program Files or C:\Program Files(x86).So, I opened a new Command Prompt, and add ssh.exe in PATH.

Command: set PATH=%PATH%; C:\Program Files\Git\bin


2. Further, we can list the existing Docker machines like this (we do this now, and after we add the new machine). As you can see, I have a single Docker machine, the default one.

Command: docker-machine ls


3. Now, I will use the same virtualbox driver to create a new machine named, my-machine.

Command: docker-machine create --driver virtualbox my-machine


4. Further, we need to connect the Docker with this machine.

Command: docker-machine env my-machine


5. Next, get the environment commands for my-machine.

Command: docker-machine env --shell cmd my-machine


6.This points a new command as you can see in the above picture.

Command: FOR /f "tokens=*" %i IN ('docker-machine env --shell cmd my-machine') DO %i


7. Run the hello-world container.

Command: docker run hello-world


Done!

You can list the Docker machines again and notice that my-machine is active and running:


You can easy stop/start the Docker machine:

Command start: docker-machine stop my-machine
Command stop: docker-machine start my-machine

Note: In order to see all the options for docker-machine command try:

Command: docker-machine --help

marți, 10 noiembrie 2015

How I've installed Docker on Windows

How I've installed Docker on Windows ?


2. The big button labeled Download (Windows) was exactly what I was looking for. The download started directly (nice, no intermediate steps). After download I obtained an exe:


3. Obviously, I run the exe file. The welcome page appears like below (personally, I've un-ticked the checkbox - is my first Docker hit :) so help to improve is faaar away). Click on Next:


4. Nothing fancy further, the usual way to set up the local path for installing the new software (I've selected D:\DockerToolbox, you can select whatever you find convenient). Click Next.


5. Well, now I was asked to select the Docker components to be installed. Since I'm not familiar with Docker I'll go with the default selections and click Next:


6. Some additional tasks very common to Windows apps. Click Next:


7. Ready to install! Final report! Click Finish!


8. And ... here we go! During installation I was agree with installing a few Oracle add-ons also.


9. Finally, it looks like I've done a good job.


Well, now I was impatient to start doing something. Actually to run the first test, running the first container:

docker run hello-world

But, where to write this? Well, I've checkout my desktop and found these icons:


Docker Quickstart Terminal sound good! Since I did not have any machine, Docker tried to install one for me named, default. Unfortunately, my enthusiasm was shot down by an error related to the virtualization disabled. It looks like Docker want this enabled!

I had a small free inspection tool installed named, Speccy. Run it, switch to CPU tab and here we go, virtualization supported, but disabled:


Ok! Restart, go to bios, find the security setting and enable it. With virtualization enabled, tried again the Docker Quickstart Terminal. Well, total success! After doing its job, Docker reported that the default machine was created and is running, so I was opened the Docker VirtualBox Manager and spot it there:


Click on Show button and finally run the hello-world container. Total success again:


This was fun! Next, I'll try to put an Ubuntu machine here.

luni, 19 octombrie 2015

Bind HTML form parameters value to JAX-RS resource

In this post, you can see how to bind HTML form parameters value to JAX-RS resource

In order to accomplish this task, you have to follow two steps:

- indicate the JAX-RS resource path in the action attribute of the form
- use @FormParam to obtain the submitted values

Let's suppose that we have a JAX-RS resource that respond to the following path:

http://localhost:8080/JaxrsBindHTMLFormToResource_EE7/resources/user/order

Then the resources/user/order should be indicated in the action attribute as:
<form id="addId" method="post" action="resources/user/order">
 ...
</form>
Let's take the below HTML form:
<form id="addId" method="post" action="resources/user/order">
 <fieldset>
  <legend>Personal details</legend>
   <div>
    <label>First Name
     <input id="name" name="name" type="text" placeholder="First name only" required autofocus>
    </label>
   </div>
   <div>
    <label>Security code
     <input id="security" name="security" type="number" required title="The last three digits on the back of your card.">
    </label>
   </div>
   <div>
    <label>Country
     <input id="country" name="country" list="country-names" type="text" required>
     <datalist id="country-names">
      <option label="England" value="England"></option>
      <option label="Northern Ireland" value="Northern Ireland"></option>
      <option label="Ireland" value="Ireland"></option>
      <option label="Scotland" value="Scotland"></option>
      <option label="Wales" value="Wales"></option>
     </datalist>
    </label>
   </div>
   <fieldset>
    <legend>Card type</legend>
    <div class="card">                    
    <input id="visa" name="card" value="VISA" type="radio">
    <label for="visa">VISA</label>
    <input id="mastercard" name="card" value="Mastercard" type="radio">
    <label for="mastercard">Mastercard</label>
    <input id="amex" name="card" value="AMEX" type="radio">
    <label for="amex">AMEX</label>
   </div>
  </fieldset>
  <fieldset>
   <legend>Subscribe for</legend>
   <div class="order">                    
    <input id="newsletter" name="order" value="Newsletter" type="checkbox">
    <label for="newsletter">Newsletter</label>
    <input id="news" name="order" value="News" type="checkbox">
    <label for="news">News</label>
    <input id="promotions" name="order" value="Promotions" type="checkbox">
    <label for="promotions">Promotions</label>
   </div>
  </fieldset>
 </fieldset>
 <fieldset>
  <div>
   <button type=submit>Place Order</button>
  </div>
 </fieldset>
</form>
The @FormParam obtains the submitted values by indicating the values of each name attibute:
import java.util.Arrays;
import javax.ws.rs.FormParam;
import javax.ws.rs.Produces;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

@Path("user")
public class OrderResource {

    @POST
    @Path("/order")
    @Produces("text/html") // default: */*
    public Response orderAction(
            @FormParam("name") String name,
            @FormParam("security") int sn,
            @FormParam("country") String country,
            @FormParam("card") String card,
            @FormParam("order") String[] order) {

        return Response.status(200)
           .entity("<h1>Thank you :</h1>" + name
                 + "Your subscription overview: "
                 + "<h2>Security: </h2>" + sn
                 + "<h2>Country: </h2>" + country
                 + "<h2>card: </h2>" + card
                 + "<h2>Order: </h2>" + Arrays.toString(order))
          .build();
    }
}
The response is redirected to the same URL and it looks like figure below:
The complete application is available here. In the next post we will process date/time values.

luni, 12 octombrie 2015

JAX-RS Access HTTP Cookie in Resource

In this post, you can see how to access cookie parameters from a JAX-RS resource

Let's suppose that we have an application named, JaxrsCookieParameters_EE7, and a cookie as: hellofrom = Leonard. Via javax.ws.rs.CookieParam we can easily access this cookie in a JAX-RS resource as below:
import javax.ws.rs.CookieParam;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("hello")
public class HelloResource {

    @GET
    @Produces("text/plain") // default: */*
    public String hello(@CookieParam(value="hellofrom") String from) {
        return "Hello, " + from+"!";
    }
}
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("webresources")
public class ApplicationConfig extends Application {
}
The output will be as in figure below (for testing I just added the cookie manually in Google Chrome). The test URL is: http://localhost:8080/JaxrsCookieParameters_EE7/webresources/hello


Note Do not forget that cookies implies several limitations (use of semi-colons ;, and commas ,)! Is important to read the corresponding RFC.

The complete application is available here.

vineri, 9 octombrie 2015

JAX-RS extract the URI path parameters from the request URI

In this post, you can see how to extract the URI path parameters from the request URI in a JAX-RS application

Let's suppose that we have an application named, JaxrsPathParameters_EE7, and the following JAX-RS resource:
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/users/{username: [a-zA-Z][a-zA-Z_0-9]*}")
public class HelloUsersResource {

 @GET
 @Path("/admin/{id: \\d+}")
 @Produces("text/plain")
 public String helloAdmin() {
  return "Hello, Admin!";
 }
   
 @GET
 @Path("/user")
 @Produces("text/plain")
 public String helloUser() {
  return "Hello, User!";
 }
}
You already know how to work with this resource from the JAX-RS working with URI path templates example.
Further, let's suppose that you need to extract the URI parameters (in this case, username and id). This is very easy to accomplish via javax.ws.rs.PathParam annotation in the method parameter, as below:
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path("/users/{username: [a-zA-Z][a-zA-Z_0-9]*}")
public class HelloUsersResource {

 @GET
 @Path("/admin/{id: \\d+}")
 @Produces("text/plain")
 public String helloAdmin(@PathParam("username") String admin, @PathParam("id") String id) {
  return "Hello, " + admin + " (" + id + ")!";
 }

 @GET
 @Path("/user")
 @Produces("text/plain")
 public String helloUser(@PathParam("username") String user) {
  return "Hello, " + user + "!";
 }
}
Now, check out two examples:

http://localhost:8080/JaxrsPathParameters_EE7/webresources/users/foo/admin/007
Produces: Hello, foo (007)!

http://localhost:8080/JaxrsPathParameters_EE7/webresources/users/buzz/user
Produces: Hello, buzz!

  • If the URI path template variable cannot be cast to the specified type, the JAX-RS runtime returns an HTTP 400 ("Bad Request") error to the client.
  • If the @PathParam annotation cannot be cast to the specified type, the JAX-RS runtime returns an HTTP 404 ("Not Found") error to the client.

The complete application is available here.

marți, 6 octombrie 2015

JAX-RS consume a RESTful web service from a Servlet (including asynchronous)

In this post, you can see a simple example of consuming a RESTful web service from a Servlet (including asynchronous calls).

JavaEE 7 Client API for JAX-RS API is useful to access the RESTful web services. Basic steps:
  • Get the instance of javax.ws.rs.client.Client class (entry point for invoking RESTful web services).
  • Create an instance of javax.ws.rs.client.WebTarget using the instance of Client class (used to invoke a RESTful web service at some location or URI).
  • Populate the target with the required data (e.g. MIME type, post data, query parameters), and create a request of appropriate HTTP method type which would be an instance of javax.ws.rs.client.Invocation.
  • Obtain the response from the desired RESTful web service via javax.ws.rs.client.Invocation object.
Let's suppose that we have the following JAX-RS resource:
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("helloworld")
public class HelloWorldResource {

    @GET
    @Produces("text/plain") // default: */*
    public String helloWorld() {
        return "Hello, World!";
    }
}
Configured as:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("webresources")
public class ApplicationConfig extends Application {
}
If the application is named JaxrsSimpleServletClient_EE7, then the resource is available at:

http://localhost:8080/JaxrsSimpleServletClient_EE7/webresources/helloworld

From a Servlet we can access this resource like below:
@WebServlet("/ClientServlet")
public class ClientServlet extends HttpServlet {

    // for simple demo, URL is hard-coded
    private final String jaxrsResource = "http://localhost:8080/JaxrsSimpleServletClient_EE7/webresources/helloworld/";

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // get the instance of client which will be entry point to invoking services
        Client jaxrsClient = ClientBuilder.newClient();

        // targeting the JAX-RS serivce we want to invoke by capturing it in WebTarget instance
        WebTarget webTarget = jaxrsClient.target(jaxrsResource);

        // build the request (e.g. a GET request)
        Invocation invocation = webTarget.request("text/plain").buildGet();

        // invoke the request
        Response jaxrsResponse = invocation.invoke();

        // respond to client (user)
        String hello = jaxrsResponse.readEntity(String.class);

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("<h3>" + hello + "</h3>");
    }

    @Override
    public String getServletInfo() {
        return "Client Server";
    }

}
If you need to perform asynchronous request then add client support for making asynchronous calls to the server by using the AsyncContext class:
@WebServlet(urlPatterns={"/ClientServlet"}, asyncSupported=true)

Complete example is available here.

Read also:
Consume a RESTful web service from JSF

sâmbătă, 3 octombrie 2015

JAX-RS configure application examples

In this post, you can see how to configure a JAX-RS application

Let's suppose that we have an application named, JaxrsConfigureApplication_EE7, and the following two resources:
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("helloworld")
public class HelloWorldResource {

 @GET
 @Produces("text/plain") // default: */*
 public String helloWorld() {
  return "Hello, World!";
 }
}

import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("byeworld")
public class ByeWorldResource {

 @GET
 @Produces("text/plain") // default: */*
 public String byeWorld() {
  return "Bye, World!";
 }
}
Basically, by configuring a JAX-RS application means to set the base URI from which an application's resources respond to requests. This can be accomplished in two ways:

·         using the @ApplicationPath annotation in a subclass of javax.ws.rs.core.Application packaged within the WAR

For example, if your base URI will be /webresources (or, webresources) then simply add the following class:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("webresources")
public class ApplicationConfig extends Application {
}
In the preceding example, the base URI is set to /webresources, which means that all resources defined within the application are relative to /webresources. Check out the below URLs:

// this URL will invoke HelloWorldResource#helloWorld()
http://localhost:8080/JaxrsConfigureApplication_EE7/webresources/helloworld

// this URL will invoke ByeWorldResource#byeWorld()
http://localhost:8080/JaxrsConfigureApplication_EE7/webresources/byeworld

So, by default, all the resources in an archive will be processed for resources. We can easily alter this behavior by overriding the getClasses() method to manually register the resource classes in the application with the JAX-RS runtime. For example, we can register the HelloWorldResource in HelloApplicationConfig, as below:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("helloresources")
public class HelloApplicationConfig extends Application {

 @Override
 public Set<Class<?>> getClasses() {
  final Set<Class<?>> classes = new HashSet<>();
  classes.add(HelloWorldResource.class);
  // add more classes
  return classes;
 }
}
And, we can register the ByeWorldResource in ByeApplicationConfig, as below:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("byeresources")
public class ByeApplicationConfig extends Application {

 @Override
 public Set<Class<?>> getClasses() {
  final Set<Class<?>> classes = new HashSet<>();
  classes.add(ByeWorldResource.class);
  return classes;
 }
}
Now, the URLs will become:

// this URL will invoke HelloWorldResource#helloWorld()
http://localhost:8080/JaxrsConfigureApplication_EE7/helloresources/helloworld

// this URL will invoke ByeWorldResource#byeWorld()
http://localhost:8080/JaxrsConfigureApplication_EE7/byeresources/byeworld

The following URLs will not work!

http://localhost:8080/JaxrsConfigureApplication_EE7/helloresources/byeworld
http://localhost:8080/JaxrsConfigureApplication_EE7/byeresources/helloworld

The complete application is available here.

·         using the servlet-mapping tag within the WAR's web.xml deployment descriptor

Let's suppose that we have an application named, JaxrsConfigureApplicationWebXml_EE7, and the same two resources, HelloWorldResource and ByeWorldResource.

This time we will configure the application via the <servlet-mapping> tag in the web.xml deployment descriptor, using the Application class name as the servlet:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

 <servlet-mapping>
  <servlet-name>javax.ws.rs.core.Application</servlet-name>
  <url-pattern>/webresources/*</url-pattern>
 </servlet-mapping>
</web-app>
Check out the following valid URLs:

// this URL will invoke HelloWorldResource#helloWorld()
http://localhost:8080/JaxrsConfigureApplicationWebXml_EE7/webresources/helloworld

// this URL will invoke ByeWorldResource#byeWorld()
http://localhost:8080/JaxrsConfigureApplicationWebXml_EE7/webresources/byeworld

This setting will also override the path set by @ApplicationPath when using an Application subclass.  For example let's suppose that we have the following Application subclass:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("webresources")
public class ApplicationConfig extends Application {
}
And, in web.xml we have:
...
<servlet-mapping>
 <servlet-name>ee7.jaxrs.ApplicationConfig</servlet-name>
 <url-pattern>/greetings/*</url-pattern>      
</servlet-mapping>
...
Now, the following URLs will work:

// this URL will invoke HelloWorldResource#helloWorld()
http://localhost:8080/JaxrsConfigureApplicationWebXml_EE7/greetings/helloworld

// this URL will invoke ByeWorldResource#byeWorld()
http://localhost:8080/JaxrsConfigureApplicationWebXml_EE7/greetings/byeworld

While the following two will not work:

http://localhost:8080/JaxrsConfigureApplicationWebXml_EE7/webresources/helloworld
http://localhost:8080/JaxrsConfigureApplicationWebXml_EE7/webresources/byeworld

The complete application is available here.