Tuesday, September 17, 2013

JSF/CDI Tip of the Day: How to create a @Producer for JSF

I was using this code as a utility class to get the current HttpServletRequest object. I added the @Named annotation to expose it via Expression Language (EL). However, it should be noted that the #{request} is an implicit object already. You can see from the output below that they do produce the same output.
1
2
3
4
<div>
    #{request.getSession(false).id}
    #{httpServletRequest.getSession(false).id}
</div>

ServletRequestProducer.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.bluelotussoftware.bean;
 
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
 
/**
 * A producer class that returns the current {@link HttpServletRequest} object
 * from the {@link FacesContext#getExternalContext()}. This {@link Named}
 * producer can be used directly in Expression Language (EL) as {@literal #{httpServletRequest}}.
 *
 * @author John Yeary
 * @version 1.0
 */
public class ServletRequestProducer {
 
    @Produces
    @Named
    public HttpServletRequest getHttpServletRequest() {
        HttpServletRequest httpServletRequest = null;
        Object object = FacesContext.getCurrentInstance().getExternalContext().getRequest();
        if (object instanceof HttpServletRequest) {
            httpServletRequest = (HttpServletRequest) object;
        }
        return httpServletRequest;
    }
}

JSF 2.x Tip of the Day: Resetting the Current UIViewRoot

I needed to clear the UIViewRoot for something I was working on. In the process, I created a simple method that replaces the current view with a new view using the same view ID. I figured I would publish this little gem before I deleted the proof of concept I was working on.

I also thought I should include an example where I am using it to navigate to another page.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   public void replaceCurrentView() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        Application application = facesContext.getApplication();
        ViewHandler viewHandler = application.getViewHandler();
        // Use the same view ID as the old view.
        UIViewRoot uivr = viewHandler.createView(facesContext, facesContext.getViewRoot().getViewId());
        facesContext.setViewRoot(uivr);
//        facesContext.renderResponse();
    }
 
public String navigate() {
        replaceCurrentView();
        FacesContext.getCurrentInstance().getApplication().getStateManager().saveView(FacesContext.getCurrentInstance());
        return "nextpage";
    }

Wednesday, September 11, 2013

JAX-RS 1.x Tip of the Day: Using POST with JAX-RS

http://commons.wikimedia.org
I was looking over some more unpublished code, and found a simple gem that demonstrates how to use a HTTP POST with JAX-RS and a @Singleton.

The code was originally developed with JAX-RS 1.0, but I went back and retrofitted it to work on JAX-RS 1.1. The code has a @Singleton that manages the "Widgets" that are created using the HTTP POST. It is a simple and fun example of what you can do with JAX-RS.

It is a simple application that creates "Widget" objects and returns JSON with the widget data.

The code for the project can be found here: jersey-post-example

Note: This example application needs to be run on GlassFish 3.1.2+ because of an issue with Guava GlassFish 4.

JSON Response


WidgetSingleton.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.bluelotussoftware.jersey.cdi;
 
import com.bluelotussoftware.jersey.misc.Widget;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Named;
import javax.inject.Singleton;
 
/**
 *
 * @author John Yeary
 */
@Named
@Singleton
public class WidgetSingleton implements Serializable {
 
    private static final long serialVersionUID = 939286339566082006L;
    private static final List<widget> widgets = new ArrayList<widget>();
 
    public WidgetSingleton() {
    }
 
    public List<widget> getWidgets() {
        return Collections.unmodifiableList(widgets);
    }
 
    public boolean add(Widget widget) {
        return widgets.add(widget);
    }
 
    public boolean remove(Widget widget) {
        return widgets.remove(widget);
    }
}

ExampleResource.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.bluelotussoftware.jersey.cdi.resources;
 
import com.bluelotussoftware.jersey.cdi.WidgetSingleton;
import com.bluelotussoftware.jersey.misc.Widget;
import java.io.Serializable;
import java.util.List;
import java.util.ListIterator;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.apache.commons.codec.binary.Hex;
 
/**
 * REST Web Service
 *
 * @author John Yeary
 */
@Path("example")
@RequestScoped
public class ExampleResource implements Serializable {
 
    private static final long serialVersionUID = -8883891023988941637L;
    @Inject
    WidgetSingleton ws;
    @Context
    private UriInfo uriInfo;
 
    public ExampleResource() {
    }
 
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public GenericEntity<List<widget>> get() {
        return new GenericEntity<List<widget>>(ws.getWidgets()) {
        };
    }
 
    @GET
    @Path("{index}")
    @Produces({MediaType.APPLICATION_JSON})
    public Widget get(@PathParam("index") int index) {
        return ws.getWidgets().get(index);
    }
 
    /**
     * PUT method for updating or creating an instance of ExampleResource
     *
     * @param widget representation for the resource
     * @return an HTTP response with content of the updated or created resource.
     */
    @PUT
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    public Response put(Widget widget) {
        ListIterator<widget> iterator = ws.getWidgets().listIterator();
        boolean found = false;
        for (Widget w : ws.getWidgets()) {
            if (w.getName() != null && w.getName().equals(widget.getName())) {
                found = true;
                ws.remove(w);
                ws.add(widget);
            }
        }
 
        // This is not idempotent!
        if (!found) {
            ws.add(widget);
            UriBuilder uriBuilder = UriBuilder.fromUri(uriInfo.getRequestUri());
            uriBuilder.path("{index}");
            String index = String.valueOf(ws.getWidgets().lastIndexOf(widget));
            return Response.created(uriBuilder.build(index)).entity(widget).build();
        }
 
        return Response.ok(widget).build();
    }
 
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces({MediaType.APPLICATION_JSON})
    public Response post(@FormParam("name") String name, @FormParam("value") String value) {
        Widget widget = new Widget(name, value);
        ws.add(widget);
        int index = ws.getWidgets().indexOf(widget);
        UriBuilder uriBuilder = UriBuilder.fromUri(uriInfo.getRequestUri());
        uriBuilder.path("{index}");
        EntityTag etag = new EntityTag(Hex.encodeHexString(widget.toString().getBytes()));
        return Response.created(uriBuilder.build(index)).
                tag(etag).
                entity(widget).
                type(MediaType.APPLICATION_JSON).
                build();
    }
}

Widget.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.bluelotussoftware.jersey.misc;
 
import java.io.Serializable;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
 
/**
 *
 * @author John Yeary
 */
public class Widget implements Serializable {
 
    private static final long serialVersionUID = 679964674798270082L;
    private String name;
    private String value;
 
    public Widget() {
    }
 
    public Widget(String name, String value) {
        this.name = name;
        this.value = value;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getValue() {
        return value;
    }
 
    public void setValue(String value) {
        this.value = value;
    }
 
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Widget other = (Widget) obj;
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        if ((this.value == null) ? (other.value != null) : !this.value.equals(other.value)) {
            return false;
        }
        return true;
    }
 
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + (this.name != null ? this.name.hashCode() : 0);
        hash = 79 * hash + (this.value != null ? this.value.hashCode() : 0);
        return hash;
    }
 
    @Override
    public String toString() {
        JSONObject jsono = new JSONObject(); // Quick way to return JSON.
        try {
            jsono.put("name", name);
            jsono.put("value", value);
 
        } catch (JSONException ignored) {
        }
        return jsono.toString();
    }
}

Monday, September 09, 2013

JSF 2.1 Tip of the Day: Creating a Custom Switch List

I found some code where I was tweaking on an example that Jim Driscoll wrote as a series of articles on Java.net.

I decided that I should publish it along with the references to the other articles.

JSF has a number of component frameworks available from groups like PrimeFaces and RichFaces. These are better choices than this code to accomplish the same thing.

However, you don't need all the additional code to do the same thing with plain old vanilla JSF. You will just need to write all the code.

The code for this project can be found here: switchlist-example

index.xhtml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      >
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Switchlist Example</title>
        <h:outputStylesheet library="css" name="switchlist.css"/>
    </h:head>
    <h:body>
        <h:form id="form1">
            <h:selectManyListbox id="list1" value="#{listHolder.list1}" styleClass="switchlist">
                <f:selectItems value="#{listHolder.items1}"/>
            </h:selectManyListbox>
            <h:panelGroup id="buttonGroup1" styleClass="switchlistButtons">
                <h:commandButton id="button1" value="→" actionListener="#{listHolder.move1to2}" styleClass="switchlistButton">
                    <f:ajax execute="form1:button1 form1:list1" render="form1:list1 form1:list2"/>
                </h:commandButton>
                <h:commandButton id="button2" value="←" actionListener="#{listHolder.move2to1}" styleClass="switchlistButton">
                    <f:ajax execute="form1:button2 form1:list2" render="form1:list1 form1:list2"/>
                </h:commandButton>
            </h:panelGroup>
            <h:selectManyListbox id="list2" value="#{listHolder.list2}" styleClass="switchlist">
                <f:selectItems value="#{listHolder.items2}"/>
            </h:selectManyListbox>
             
 
            <h:commandButton value="Reset" type="submit" actionListener="#{listHolder.resetLists()}">
                <f:ajax execute="@form" render="form1"/>
            </h:commandButton>
            <h:messages/>
        </h:form>
    </h:body>
</html>

ListHolder.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.bluelotussoftware.jsf;
 
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
 
/**
 *
 * @author Jim Driscoll
 * @author John Yeary
 * @version 2.0
 */
@ManagedBean
@ViewScoped
public class ListHolder implements Serializable {
 
    private static final long serialVersionUID = -933704272568697599L;
    private final Map<String, String> items1 = new LinkedHashMap<String, String>();
    private final Map<String, String> items2 = new LinkedHashMap<String, String>();
    private String[] list1 = null;
    private String[] list2 = null;
 
    public ListHolder() {
        resetLists();
    }
 
    public void move1to2(ActionEvent event) {
        if (list1 != null && list1.length > 0) {
            for (String item : list1) {
                items2.put(item, items1.remove(item));
            }
        }
    }
 
    public void move2to1(ActionEvent event) {
        if (list2 != null && list2.length > 0) {
            for (String item : list2) {
                items1.put(item, items2.remove(item));
            }
        }
    }
 
    public Map<String, String> getItems1() {
        return items1;
    }
 
    public Map<String, String> getItems2() {
        return items2;
    }
 
    public String[] getList1() {
        return list1;
    }
 
    public void setList1(String[] list1) {
        this.list1 = list1;
    }
 
    public String[] getList2() {
        return list2;
    }
 
    public void setList2(String[] list2) {
        this.list2 = list2;
    }
 
    public void resetLists() {
 
        items1.clear();
        items2.clear();
 
        items1.put("one", "one");
        items1.put("two", "two");
        items1.put("three", "three");
        items1.put("four", "four");
 
        items2.put("five", "five");
        items2.put("six", "six");
        items2.put("seven", "seven");
        items2.put("eight", "eight");
    }
}

References

ExecutorService and CountDownLatch Example

Image from Jeff Blogs
One of the most difficult concepts in teaching programming is threads. If you don't do a lot of thread programming, that knowledge has a quick way of being replaced in your mind.

Today, modern frameworks especially Java EE make thread programming even less apparent to the developer.

I had a very highly asynchronous application that was generating data based on examining data returned from a measurement sensor in a grain silo. The sensor was generating a lot of data especially as the silo was being filled, or emptied. I had a Java application that was generating real-time data that would start/stop various hardware based on how full, or empty the silo was. This application was also generating data charts. We have one big giant potential mess if the application does not work right. The Java Concurrency API came to the rescue. The charting data could be kicked off using CountDownLatch to ensure that we didn't start generating a new chart until the last chart was generated from the data. The sensor was generating more data than our application could chart in real-time.

In the last year, I have taught a couple of programming courses to our JUG, and invariably I need to cover Thread programming.

This is an example application that shows what happens if threads are left to their own devices. This example "works" sometimes, but usually the counter does not match up correctly with the other counters. You may need to run it a couple of times to "see" it break.

If you have a simple example that demonstrates this concept, please let me know. I am always looking for good ideas.

Here is the project code: ExecutorLatchExample

Executor.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.bluelotussoftware.example;
 
import java.util.concurrent.CountDownLatch;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
public class Executor {
 
    final static int MAX_COUNT = 10;
 
    public static void main(String[] args) throws InterruptedException {
 
        System.out.println("starting counter: " + StaticCounter.getCounter());
 
        for (int i = 0; i < MAX_COUNT; i++) {
 
            new Thread(new Runnable() {
                @Override
                public void run() {
                    StaticCounter.addToCounter(1);
                }
            }).start();
        }
 
        // This will return an inaccurate value most of the time. To get an accurate result use a countdown latch
        System.out.println("=====> final counter: " + StaticCounter.getCounter());
 
        CountDownLatch start = new CountDownLatch(1);
        CountDownLatch finished = new CountDownLatch(MAX_COUNT);
 
        for (int i = 0; i < MAX_COUNT; ++i) {
            new Thread(new Runner(start, finished)).start();
        }
        System.out.println("Starting the countdown...");
        start.countDown(); // Starting all threads... way cool!
        finished.await();  // Waiting for all threads to finish
        System.out.println("=====> final count on Runner: " + Runner.count);
    }
}

Runner.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.bluelotussoftware.example;
 
import java.util.concurrent.CountDownLatch;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
public class Runner implements Runnable {
 
    public static int count;
    private final CountDownLatch finished;
    private final CountDownLatch start;
 
    public Runner(CountDownLatch start, CountDownLatch finished) {
        this.start = start;
        this.finished = finished;
    }
 
    @Override
    public void run() {
        try {
            start.await();
            add(1);
            finished.countDown();
        } catch (InterruptedException ex) {
        } // return;
 
    }
 
    public static synchronized void add(int value) {
        count = count + value;
        System.out.println("runner count: " + count);
    }
}

StaticCounter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.bluelotussoftware.example;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
public class StaticCounter {
 
    private static int counter = 0;
 
    public StaticCounter() {
    }
 
    public static synchronized void addToCounter(final int number) {
        counter = counter + number;
        System.out.println("counter value: " + counter);
    }
 
    public static synchronized int getCounter() {
        return counter;
    }
}

Woodstock File Upload Example


Here is another example from my code proof of concept archives.

As many of you may know, I was a big proponent of using Project Woodstock (Visual JSF). I still believe that Visual JSF and NetBeans were a great combination. In this project, you will see a couple of example applications for doing file uploads. The project was built using NetBeans 6.7.1 with the Visual JSF libraries and runtime installed.

Using the older NetBeans IDE will allow you to see Visual JSF and why it was cool in addition to getting the correct libraries installed.
Visual JSF was the "killer" framework that got me interested in JSF. It is a JSF 1.2 based framework. If you have need for nice looking components and a really easy framework + IDE combination, it is a good choice.

The code for the project can be found here: WoodstockFileUploadExample

Here is the download page visually in the IDE.


Page1.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8"?>
    <jsp:directive.page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"/>
    <f:view>
        <webuijsf:page id="page1">
            <webuijsf:html id="html1">
                <webuijsf:head id="head1">
                    <webuijsf:link id="link1" url="/resources/stylesheet.css"/>
                </webuijsf:head>
                <webuijsf:body id="body1" style="-rave-layout: grid">
                    <webuijsf:form id="form1">
                        <webuijsf:upload binding="#{Page1.fileUpload1}" id="fileUpload1" style="left: 24px; top: 24px; position: absolute"/>
                        <webuijsf:button actionExpression="#{Page1.uploadFileButton_action}" binding="#{Page1.uploadFileButton}" id="uploadFileButton"
                            primary="true" style="left: 23px; top: 72px; position: absolute" text="Upload File"/>
                        <webuijsf:staticText binding="#{Page1.fileNameStaticText}" id="fileNameStaticText" style="left: 96px; top: 120px; position: absolute"/>
                        <webuijsf:staticText binding="#{Page1.fileTypeStaticText}" id="fileTypeStaticText" style="left: 96px; top: 144px; position: absolute"/>
                        <webuijsf:staticText binding="#{Page1.fileSizeStaticText}" id="fileSizeStaticText" style="left: 96px; top: 168px; position: absolute"/>
                        <webuijsf:label id="fileNameLabel" style="left: 24px; top: 120px; position: absolute" text="File Name:"/>
                        <webuijsf:label id="fileTypeLabel" style="left: 24px; top: 144px; position: absolute" text="File Type:"/>
                        <webuijsf:label id="fileSizeLabel" style="left: 24px; top: 168px; position: absolute" text="File Size:"/>
                        <webuijsf:image binding="#{Page1.image1}" id="image1" style="left: 24px; top: 192px; position: absolute"/>
                        <webuijsf:messageGroup id="messageGroup1" style="left: 24px; top: 264px; position: absolute"/>
                        <webuijsf:button actionExpression="#{Page1.button1_action}" id="button1" style="left: 95px; top: 72px; position: absolute" text="Back"/>
                    </webuijsf:form>
                </webuijsf:body>
            </webuijsf:html>
        </webuijsf:page>
    </f:view>
</jsp:root>

Page2.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
    <jsp:directive.page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"/>
    <f:view>
        <webuijsf:script>
            document.getElementById('form1:fileChooser1').setChooseButton('form1:fileChooseButton');
        </webuijsf:script>
        <webuijsf:page id="page1">
            <webuijsf:html id="html1">
                <webuijsf:head id="head1">
                    <webuijsf:link id="link1" url="/resources/stylesheet.css"/>
                </webuijsf:head>
                <webuijsf:body id="body1" style="-rave-layout: grid">
                    <webuijsf:form enctype="multipart/form-data" id="form1">
                        <webuijsf:fileChooser binding="#{Page2.fileChooser1}" id="fileChooser1" multiple="true" selected="#{Page2.selectedFiles}" style="left: 24px; top: 24px; position: absolute"/>
                        <webuijsf:button actionExpression="#{Page2.fileChooseButton_action}" actionListenerExpression="#{Page2.chooseFile}"
                            id="fileChooseButton" primary="true" style="left: 23px; top: 480px; position: absolute" text="Choose File"/>
                        <webuijsf:messageGroup id="messageGroup1" style="position: absolute; left: 24px; top: 528px"/>
                        <webuijsf:button actionExpression="#{Page2.button1_action}" id="button1" style="left: 119px; top: 480px; position: absolute" text="Back"/>
                    </webuijsf:form>
                </webuijsf:body>
            </webuijsf:html>
        </webuijsf:page>
    </f:view>
</jsp:root>
The code is really simple to create and use via NetBeans enjoy. This code will work on Java EE5, EE6, and EE7.

Sunday, September 08, 2013

Apache Commons IO File Monitoring Example

Here is another example from the archives of the mythical archana on File monitoring using Apache Commons I/O for file monitoring. I remember working on this to see if we could come up with a solution since we could not upgrade the application to Java SE 7. So this proof of concept was to try out a couple of different file monitoring options.

This example uses a FileAlterationListener to monitor file changes. It is simple to implement.

The code for the project can be found here: file-monitor

package com.bluelotussoftware.commons.io;
import java.io.File;
import java.util.Date;
import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationObserver;
/**
*
* @author John Yeary
* @version 1.0
*/
public class FileAlterationListenerImpl implements FileAlterationListener {
/**
* {@inheritDoc}
*/
@Override
public void onStart(final FileAlterationObserver observer) {
System.out.println("The WindowsFileListener has started on " + observer.getDirectory().getAbsolutePath());
}
/**
* {@inheritDoc}
*/
@Override
public void onDirectoryCreate(final File directory) {
System.out.println(directory.getAbsolutePath() + " was created.");
}
/**
* {@inheritDoc}
*/
@Override
public void onDirectoryChange(final File directory) {
System.out.println(directory.getAbsolutePath() + " wa modified");
}
/**
* {@inheritDoc}
*/
@Override
public void onDirectoryDelete(final File directory) {
System.out.println(directory.getAbsolutePath() + " was deleted.");
}
/**
* {@inheritDoc}
*/
@Override
public void onFileCreate(final File file) {
System.out.println(file.getAbsoluteFile() + " was created.");
System.out.println("----------> length: " + file.length());
System.out.println("----------> last modified: " + new Date(file.lastModified()));
System.out.println("----------> readable: " + file.canRead());
System.out.println("----------> writable: " + file.canWrite());
System.out.println("----------> executable: " + file.canExecute());
}
/**
* {@inheritDoc}
*/
@Override
public void onFileChange(final File file) {
System.out.println(file.getAbsoluteFile() + " was modified.");
System.out.println("----------> length: " + file.length());
System.out.println("----------> last modified: " + new Date(file.lastModified()));
System.out.println("----------> readable: " + file.canRead());
System.out.println("----------> writable: " + file.canWrite());
System.out.println("----------> executable: " + file.canExecute());
}
/**
* {@inheritDoc}
*/
@Override
public void onFileDelete(final File file) {
System.out.println(file.getAbsoluteFile() + " was deleted.");
}
/**
* {@inheritDoc}
*/
@Override
public void onStop(final FileAlterationObserver observer) {
System.out.println("The WindowsFileListener has stopped on " + observer.getDirectory().getAbsolutePath());
}
}
package com.bluelotussoftware.commons.io;
import java.io.File;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
/**
*
* @author John Yeary
* @version 1.0
*/
public class FileMonitor {
public static void main(String[] args) throws Exception {
// Change this to match the environment you want to watch.
final File directory = new File("/Users/jyeary/Desktop");
FileAlterationObserver fao = new FileAlterationObserver(directory);
fao.addListener(new FileAlterationListenerImpl());
final FileAlterationMonitor monitor = new FileAlterationMonitor();
monitor.addObserver(fao);
System.out.println("Starting monitor. CTRL+C to stop.");
monitor.start();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("Stopping monitor.");
monitor.stop();
} catch (Exception ignored) {
}
}
}));
}
}

Friday, September 06, 2013

Apache Commons File Upload Servlet Example

I was doing some code cleanup, and found this servlet that does file upload using Apache Commons Fileupload.

I have a couple of other articles and code that are better, but I thought I would publish this just as another example. I did a quick code search and it appears I was using some code example snippets from the Apache Commons fileupload site, some forum posts, and an article OnJava on the O'Reilly & Associates site: Using the Jakarta Commons, Part 1.

Simply put, the provenance of this code is questionable. If you contributed to it, please send me a link to your code and I will add your name to the authors list. I don't want to claim the code as my own since I am sure I got it from multiple F/OSS sources.

Here are some of the other articles which I am sure I know about:
Here is the servlet code: apache-commons-file-upload

ApacheCommonsFileUploadServlet.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.bluelotussoftware.apache.commons.fileupload.example;
 
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
 
/**
 *
 * @author Unknown
 * @author Vikram Goyal
 * @author John Yeary
 * @version 1.0
 */
public class ApacheCommonsFileUploadServlet extends HttpServlet {
 
    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/plain;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            // first check if the upload request coming in is a multipart request
            boolean isMultipart = FileUpload.isMultipartContent(request);
            log("content-length: " + request.getContentLength());
            log("method: " + request.getMethod());
            log("character encoding: " + request.getCharacterEncoding());
 
            if (isMultipart) {
                DiskFileUpload upload = new DiskFileUpload();
                List items = null;
 
                try {
                    // parse this request by the handler
                    // this gives us a list of items from the request
                    items = upload.parseRequest(request);
                    log("items: " + items.toString());
                } catch (FileUploadException ex) {
                    log("Failed to parse request", ex);
                }
                Iterator itr = items.iterator();
 
                while (itr.hasNext()) {
                    FileItem item = (FileItem) itr.next();
 
                    // check if the current item is a form field or an uploaded file
                    if (item.isFormField()) {
 
                        // get the name of the field
                        String fieldName = item.getFieldName();
 
                        // if it is name, we can set it in request to thank the user
                        if (fieldName.equals("name")) {
                            out.print("Thank You: " + item.getString());
                        }
 
                    } else {
 
                        // the item must be an uploaded file save it to disk. Note that there
                        // seems to be a bug in item.getName() as it returns the full path on
                        // the client's machine for the uploaded file name, instead of the file
                        // name only. To overcome that, I have used a workaround using
                        // fullFile.getName().
                        File fullFile = new File(item.getName());
                        File savedFile = new File(getServletContext().getRealPath("/"), fullFile.getName());
                        try {
                            item.write(savedFile);
                        } catch (Exception ex) {
                            log("Failed to save file", ex);
                        }
                    }
                }
 
            }
        } finally {
            out.close();
        }
    }
 
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
 
    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
 
    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}

Java EE Tip of the Day: @WebFilter Testing Using Arquillian, Warp, and Drone

Introduction

I was looking for a simple solution to test @WebFilter servlet filters. The tests that I had used a lot of mocks, but really just left me unsatisfied. It was not a real world production solution. How would they "really" behave in the actual server environment. I had been using Arquillian to do some testing of our CDI layer, and decided to try it on filters.

I looked at the API, and examples and found really nothing. I found one really "bogus" test example from core api tests that left me really wondering if I should bother. As many of you know though, I love a challenge. I tried a number of ideas including making the filter a JSR-316 @ManagedBean. I am not sure what glue I sniffed for that one (it didn't work...), and using @Inject (that didn't work either... more glue).

What I settled on was using Arquillian Warp and Drone to check the HttpServletRequest and HttpServletResponse after the filter processed it. There are a couple of annotations @BeforeServlet and @AfterServlet that helped me with checking my filters. There are no before and after filter annotations though. That would have made life easier.

Note: The thing to keep in mind with these annotations is that the filtering will have already occurred. You are looking at the post-filter results.

I also wanted to be able to demonstrate another really cool feature called ShrinkWrap, and its Java EE descriptor extensions. This allows you to programmatically create your web.xml file to provide additional flexibility like overriding annotations.

Problem Description

We want to be able to test a @WebFilter that modifies HttpServletRequest attributes, and HttpServletResponse headers. The filter should be tested in isolation, and in a real container to examine the real-world response. The tests should be able to be run on a variety of containers with no modification to the test code.

A Solution

Using MavenArquillianWarpDroneShrinkWrap, and GlassFish 3.1.2.2 embedded we can accomplish all aspects of the testing requirements. I used GlassFish since it is the Reference Implementation for Java EE 5, EE 6 and EE7, and it is a great application server. The container can be swapped out easily in maven with another profile. In the example code below, I used NetBeans 7.4 Beta to do the development.

The code for the project can be found on BitBucket here: maven-arqullian-filter-test

There are two types of examples included. One set of examples demonstrate simple integration tests that use annotations, and annotation override using web.xml. The second set of examples demonstrate dynamic web.xml generation, and overriding. Here are some code snippets from the project.

package com.bluelotussoftware.example.filter;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.warp.Activity;
import org.jboss.arquillian.warp.Inspection;
import org.jboss.arquillian.warp.Warp;
import org.jboss.arquillian.warp.WarpTest;
import org.jboss.arquillian.warp.servlet.AfterServlet;
import org.jboss.arquillian.warp.servlet.BeforeServlet;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
/**
* <p>
* Checks the {@link HeaderFilter} initialization parameter set the enabled to
* confirm that headers are added to the {@link HttpServletRequest}, and
* {@link HttpServletResponse}.</p>
* <p>
* This test class deployment represents the simplest test form for deployment
* of a {@literal Servlet 3.0} based Filter that takes advantage of
* annotations.</p>
*
* @author John Yeary
* @version 1.0
* @see HeaderFilterRegistrationIntegrationTest
*/
@RunWith(value = Arquillian.class)
@WarpTest
@RunAsClient
public class HeaderFilterIntegrationTest {
@ArquillianResource
private URL contextPath;
@Drone
private WebDriver webdriver;
/**
* Default constructor.
*/
public HeaderFilterIntegrationTest() {
}
/**
* Creates a {@link WebArchive} for auto-deployment in Arquillian.
*
* @return an Web ARchive (war) file representing the filter to be tested.
*/
@Deployment
public static WebArchive createDeployment() {
WebArchive war = ShrinkWrap.create(WebArchive.class)
.addClass(HeaderFilter.class);
System.out.println(war.toString(true));
return war;
}
/**
* Executes the doFilter() method of the filter and checks the expected
* results.
*/
@Test
public void testDoFilter() {
Warp.initiate(new Activity() {
@Override
public void perform() {
System.out.println("TEST URL: " + contextPath.toString());
webdriver.navigate().to(contextPath);
}
}).inspect(new Inspection() {
private static final long serialVersionUID = 1489207995240215531L;
@ArquillianResource
HttpServletRequest request;
@ArquillianResource
HttpServletResponse response;
@BeforeServlet
public void before() {
List attributeNames = Collections.list(request.getAttributeNames());
System.out.println("Attributes: " + Arrays.toString(attributeNames.toArray()));
String attribute = (String) request.getAttribute("X-ATTRIBUTE");
assertEquals("Experimental Attribute", attribute);
}
@AfterServlet
public void after() {
System.out.println("Headers: " + Arrays.toString(response.getHeaderNames().toArray()));
assertEquals("Experimental Header", response.getHeader("X-HEADER"));
}
});
}
}
package com.bluelotussoftware.example.filter;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.warp.Activity;
import org.jboss.arquillian.warp.Inspection;
import org.jboss.arquillian.warp.Warp;
import org.jboss.arquillian.warp.WarpTest;
import org.jboss.arquillian.warp.servlet.AfterServlet;
import org.jboss.arquillian.warp.servlet.BeforeServlet;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.descriptor.api.Descriptors;
import org.jboss.shrinkwrap.descriptor.api.webapp30.WebAppDescriptor;
import org.jboss.shrinkwrap.descriptor.api.webcommon30.WebAppVersionType;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
/**
* Checks the {@link HeaderFilter} initialization parameter set the disabled to
* confirm that headers are not added to the {@link HttpServletRequest}, or
* {@link HttpServletResponse}.
*
* @author John Yeary
* @version 1.0
* @see HeaderFilterDisabledIntegrationTest
*/
@RunWith(Arquillian.class)
@WarpTest
@RunAsClient
public class HeaderFilterRegistrationIntegrationDisabledTest {
public static final String URL_PATTERN = "/*";
public static final String PARAM_NAME = "enabled";
public static final String PARAM_VALUE = "false";
@ArquillianResource
private URL contextPath;
@Drone
private WebDriver webdriver;
/**
* Default constructor.
*/
public HeaderFilterRegistrationIntegrationDisabledTest() {
}
/**
* Creates a {@link WebArchive} for auto-deployment in Arquillian.
*
* @return an Web ARchive (war) file representing the filter to be tested.
*/
@Deployment
public static WebArchive createDeployment() {
WebArchive war = ShrinkWrap.create(WebArchive.class)
.addClass(HeaderFilter.class)
.setWebXML(generateWebXMLAsset());
System.out.println(war.toString(true));
return war;
}
/**
* This builder constructs a web.xml descriptor for a filter and converts it
* to a {@link StringAsset}.
*
* @return the web.xml represented as an {@link Asset}.
*/
private static Asset generateWebXMLAsset() {
WebAppDescriptor wad = Descriptors.create(WebAppDescriptor.class);
wad.version(WebAppVersionType._3_0)
.createFilter()
.filterName(HeaderFilter.class.getSimpleName())
.filterClass(HeaderFilter.class.getName())
.createInitParam()
.paramName(PARAM_NAME)
.paramValue(PARAM_VALUE)
.up()
.up()
.createFilterMapping()
.filterName(HeaderFilter.class.getSimpleName())
.urlPattern(URL_PATTERN)
.up();
System.out.println(wad.exportAsString());
return new StringAsset(wad.exportAsString());
}
/**
* Executes the doFilter() method of the filter and checks the expected
* results.
*/
@Test
public void testDoFilter() {
Warp.initiate(new Activity() {
@Override
public void perform() {
System.out.println("TEST URL: " + contextPath.toString());
webdriver.navigate().to(contextPath);
}
}).inspect(new Inspection() {
private static final long serialVersionUID = 1489207995240215531L;
@ArquillianResource
HttpServletRequest request;
@ArquillianResource
HttpServletResponse response;
@BeforeServlet
public void before() {
List attributeNames = Collections.list(request.getAttributeNames());
System.out.println("Attributes: " + Arrays.toString(attributeNames.toArray()));
assertNull(request.getAttribute("X-ATTRIBUTE"));
}
@AfterServlet
public void after() {
System.out.println("Headers: " + Arrays.toString(response.getHeaderNames().toArray()));
assertNull(response.getHeader("X-HEADER"));
}
});
}
}

Popular Posts