diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45e762d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.metadata +/target +/.settings +.project +.classpath diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..596715c --- /dev/null +++ b/pom.xml @@ -0,0 +1,101 @@ + + 4.0.0 + eu.lestard + noteWebApp + 0.0.1-SNAPSHOT + war + + + UTF-8 + + + + + + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + org.apache.maven.plugins + maven-war-plugin + + false + + + + org.apache.tomcat.maven + tomcat7-maven-plugin + + + + + + + org.apache.myfaces.core + myfaces-api + 2.1.2 + + + org.apache.myfaces.core + myfaces-impl + 2.1.2 + + + + org.jboss.weld + weld-core + 1.1.0-01-glassfish + + + org.jboss.weld + weld-api + 1.1.0-01-glassfish + + + org.jboss.weld.servlet + weld-servlet + 1.0.1-Final + + + + + junit + junit + 4.9 + test + + + org.mockito + mockito-all + 1.9.0-rc1 + test + + + org.mockito + mockito-core + 1.9.0-rc1 + + + + nl.jqno.equalsverifier + equalsverifier + 1.0.2 + test + + + + + + + equalsverifier-repository + http://equalsverifier.googlecode.com/svn/maven/ + + + + + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..8a26695 --- /dev/null +++ b/readme.md @@ -0,0 +1,13 @@ +# JSF-CDI Beispiel-Applikation +Diese Applikation ist wurde für den Vortrag bei der [Java User Group Görlitz](http://juggr.github.io) zum +Thema ["Einführung in JavaServer Faces 2 und Contexts and Dependency Injection"](http://juggr.github.io/2011/11/30/jsf-cdi.html) am 30. November 2011 von Manuel Maukys +entwickelt. + +Die Anwendung benutzt Maven als Build-Tool. Mit `mvn clean install` wird die Anwendung compiliert und die Tests ausgeführt. + +Mit `mvn tomcat7:run` wird ein Embedded Tomcat gestartet und die Anwendung deployed. Sie kann anschließend +unter `http://localhost:8080/noteWebApp/` ausprobiert werden. + + + + diff --git a/src/main/java/eu/lestard/notes/entity/Note.java b/src/main/java/eu/lestard/notes/entity/Note.java new file mode 100644 index 0000000..e0a383c --- /dev/null +++ b/src/main/java/eu/lestard/notes/entity/Note.java @@ -0,0 +1,76 @@ +package eu.lestard.notes.entity; + +/** + * Entity class for notes. + * + * @author manuel + * + */ +public class Note { + + private String name; + private String content; + + public String getName() { + return this.name; + } + + /** + * Sets the name for this note instance. The name must not be empty or null. + * @param name the name of the note. + * + * @throws IllegalArgumentException if the name is null or empty. + */ + public void setName(String name) { + if(name == null){ + throw new IllegalArgumentException("Argument name must not be null"); + } + + if(name.length() == 0){ + throw new IllegalArgumentException("Argument name must not be empty"); + } + + this.name = name; + } + public String getContent() { + return this.content; + } + public void setContent(String content) { + this.content = content; + } + + @Override + public boolean equals(Object other){ + if(other == null){ + return false; + } + + if(this == other){ + return true; + } + + if(!(other instanceof Note)){ + return false; + } + + if(!this.getClass().equals(other.getClass())){ + return false; + } + + Note that = (Note)other; + + if(this.getName() != that.getName()){ + return false; + } + + return true; + } + + @Override + public int hashCode(){ + if(this.getName() != null){ + return this.getName().hashCode(); + } + return 1; + } +} diff --git a/src/main/java/eu/lestard/notes/entity/NullNote.java b/src/main/java/eu/lestard/notes/entity/NullNote.java new file mode 100644 index 0000000..8a1fa0f --- /dev/null +++ b/src/main/java/eu/lestard/notes/entity/NullNote.java @@ -0,0 +1,47 @@ +package eu.lestard.notes.entity; + +/** + * Null-Object class for the note entity. + * + * @author manuel + * + */ +public class NullNote extends Note { + + private static Note instance; + + private NullNote() { + } + + /** + * Singleton factory method. + * + * @return + */ + public static Note getInstance() { + if (instance == null) { + instance = new NullNote(); + } + + return instance; + } + + @Override + public String getName() { + return ""; + } + + @Override + public void setName(final String name) { + }; + + @Override + public String getContent() { + return ""; + } + + @Override + public void setContent(final String content) { + }; + +} diff --git a/src/main/java/eu/lestard/notes/service/NoteService.java b/src/main/java/eu/lestard/notes/service/NoteService.java new file mode 100644 index 0000000..3473ca7 --- /dev/null +++ b/src/main/java/eu/lestard/notes/service/NoteService.java @@ -0,0 +1,50 @@ +package eu.lestard.notes.service; + +import java.util.List; + +import eu.lestard.notes.entity.Note; + +/** + * Service class for all actions on notes. + * + * @author manuel + * + */ +public interface NoteService { + + /** + * Adds a note to the system. If the given note is an instance of NullNote, + * the note is not saved. + * + * If there is already a note with the given name (Note.name) + * the note old note is replaced with the new one. + * + * @param note + * the instance that should be added. + * + * @throws IllegalArgumentException + * if the note is null + */ + void addNote(final Note note); + + /** + * + * @param name + * the name of the note that should be found. + * @return the note instance with the given name or an instance of + * NullNote if there is no note saved with the given + * name. + * + * @throws IllegalArgumentException + * if the given name is null or empty ( + * name.length() == 0) + */ + Note findByName(final String name); + + /** + * + * @return an unmodifiable List of all saved notes. + */ + List findAll(); + +} diff --git a/src/main/java/eu/lestard/notes/service/NoteServiceImpl.java b/src/main/java/eu/lestard/notes/service/NoteServiceImpl.java new file mode 100644 index 0000000..ac216d0 --- /dev/null +++ b/src/main/java/eu/lestard/notes/service/NoteServiceImpl.java @@ -0,0 +1,62 @@ +package eu.lestard.notes.service; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.enterprise.context.SessionScoped; + +import eu.lestard.notes.entity.Note; +import eu.lestard.notes.entity.NullNote; + +@SessionScoped +public class NoteServiceImpl implements NoteService, Serializable { + + private static final long serialVersionUID = 3122100380644982038L; + + private final Map notes = new HashMap(); + + @Override + public void addNote(final Note note) { + if (note == null) { + throw new IllegalArgumentException("Argument note must not be null"); + } + + if (!(note instanceof NullNote)) { + notes.put(note.getName(), note); + } + + } + + @Override + public Note findByName(final String name) { + if (name == null) { + throw new IllegalArgumentException("Argument name must not be null"); + } + + if (name.length() == 0) { + throw new IllegalArgumentException( + "Argument name must not be empty"); + } + + Note note = notes.get(name); + + if (note == null) { + note = NullNote.getInstance(); + } + + return note; + } + + @Override + public List findAll() { + + List noteList = new ArrayList(notes.values()); + + return Collections.unmodifiableList(noteList); + } + +} diff --git a/src/main/java/eu/lestard/notes/view/NotesBackingBean.java b/src/main/java/eu/lestard/notes/view/NotesBackingBean.java new file mode 100644 index 0000000..4b6919e --- /dev/null +++ b/src/main/java/eu/lestard/notes/view/NotesBackingBean.java @@ -0,0 +1,57 @@ +package eu.lestard.notes.view; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +import javax.enterprise.context.SessionScoped; +import javax.inject.Named; + +import eu.lestard.notes.entity.Note; + +/** + * Backing bean that holds the data needed by the view. + * + * @author manuel + * + */ +@Named +@SessionScoped +public class NotesBackingBean implements Serializable { + + private static final long serialVersionUID = -7065449337339482947L; + + private List notes; + + private String name; + private String content; + + public NotesBackingBean() { + notes = Collections.emptyList(); + } + + public List getNotes() { + return Collections.unmodifiableList(notes); + } + + public void setNotes(final List notes) { + this.notes = notes; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getContent() { + return content; + } + + public void setContent(final String content) { + this.content = content; + } + +} diff --git a/src/main/java/eu/lestard/notes/view/NotesController.java b/src/main/java/eu/lestard/notes/view/NotesController.java new file mode 100644 index 0000000..fd36c0f --- /dev/null +++ b/src/main/java/eu/lestard/notes/view/NotesController.java @@ -0,0 +1,66 @@ +package eu.lestard.notes.view; + +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; + +import eu.lestard.notes.entity.Note; +import eu.lestard.notes.service.NoteService; + +/** + * Controller class to save new notes and synchronize the view with the values + * of the NoteService + * + * @author manuel + * + */ +@Named +public class NotesController { + + private final NotesBackingBean backingBean; + + private final NoteService noteService; + + @Inject + public NotesController(final NotesBackingBean backingBean, + final NoteService noteService) { + if (backingBean == null) { + throw new IllegalArgumentException( + "Argument NotesBackingBean was null"); + } + + if (noteService == null) { + throw new IllegalArgumentException("Argument NoteService was null"); + } + this.backingBean = backingBean; + this.noteService = noteService; + } + + @PostConstruct + @SuppressWarnings("unused") + private void postConstruct() { + synchronizeNotes(); + } + + public void addNote() { + String name = backingBean.getName(); + String content = backingBean.getContent(); + + Note note = new Note(); + note.setName(name); + note.setContent(content); + + noteService.addNote(note); + + synchronizeNotes(); + } + + private void synchronizeNotes() { + List notes = noteService.findAll(); + + backingBean.setNotes(notes); + } + +} diff --git a/src/main/webapp/WEB-INF/beans.xml b/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..8ba38bb --- /dev/null +++ b/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/faces-config.xml b/src/main/webapp/WEB-INF/faces-config.xml new file mode 100644 index 0000000..933b2ea --- /dev/null +++ b/src/main/webapp/WEB-INF/faces-config.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d7bae37 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,32 @@ + + + noteWebApp + + index.xhtml + + + + + + + javax.faces.PROJECT_STAGE + Development + + + + Faces Servlet + javax.faces.webapp.FacesServlet + 1 + + + Faces Servlet + *.xhtml + + + org.jboss.weld.environment.servlet.Listener + + + \ No newline at end of file diff --git a/src/main/webapp/index.xhtml b/src/main/webapp/index.xhtml new file mode 100644 index 0000000..148534b --- /dev/null +++ b/src/main/webapp/index.xhtml @@ -0,0 +1,55 @@ + + + + + + Notes + + +

Your Notes:

+ + + + + + + + + + + + + + + + + + + + + +
+ \ No newline at end of file diff --git a/src/main/webapp/resources/components/notes/note.xhtml b/src/main/webapp/resources/components/notes/note.xhtml new file mode 100644 index 0000000..b6aedc2 --- /dev/null +++ b/src/main/webapp/resources/components/notes/note.xhtml @@ -0,0 +1,25 @@ + + + + + + + + + +
+

+ +

+

+ +

+
+
+ + \ No newline at end of file diff --git a/src/test/java/eu/lestard/notes/entity/NoteTest.java b/src/test/java/eu/lestard/notes/entity/NoteTest.java new file mode 100644 index 0000000..0e30a9a --- /dev/null +++ b/src/test/java/eu/lestard/notes/entity/NoteTest.java @@ -0,0 +1,32 @@ +package eu.lestard.notes.entity; + +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; + +import org.junit.Test; + +public class NoteTest { + + + @Test(expected=IllegalArgumentException.class) + public void testSetNameFailEmpty(){ + Note note = new Note(); + + note.setName(""); + } + + @Test(expected=IllegalArgumentException.class) + public void testSetNameFailNull(){ + Note note = new Note(); + + note.setName(null); + } + + + @Test + public void testEqualsAndHashcode(){ + EqualsVerifier.forClass(Note.class) + .suppress(Warning.NONFINAL_FIELDS).usingGetClass().verify(); + } + +} diff --git a/src/test/java/eu/lestard/notes/service/NotesServiceTest.java b/src/test/java/eu/lestard/notes/service/NotesServiceTest.java new file mode 100644 index 0000000..559181e --- /dev/null +++ b/src/test/java/eu/lestard/notes/service/NotesServiceTest.java @@ -0,0 +1,114 @@ +package eu.lestard.notes.service; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import eu.lestard.notes.entity.Note; +import eu.lestard.notes.entity.NullNote; + +public class NotesServiceTest { + + private static final String NOTE_NAME2 = "myNote2"; + private static final String NOTE_CONTENT = "This is my Content"; + private static final String NOTE_NAME = "myNote1"; + + @Test + public void testAddNoteAndFindByName() { + NoteService noteService = new NoteServiceImpl(); + + Note note = new Note(); + + note.setName(NOTE_NAME); + note.setContent(NOTE_CONTENT); + noteService.addNote(note); + + Note note2 = noteService.findByName(NOTE_NAME); + + assertEquals(NOTE_NAME, note2.getName()); + assertEquals(NOTE_CONTENT, note2.getContent()); + } + + @Test + public void testFindByNameFailNoEntry(){ + NoteService noteService = new NoteServiceImpl(); + + Note emptyNote = noteService.findByName(NOTE_NAME); + + assertNotNull(emptyNote); + + assertTrue(emptyNote instanceof NullNote); + } + + + @Test(expected=IllegalArgumentException.class) + public void testFindByNameFailNull(){ + NoteService noteService = new NoteServiceImpl(); + + noteService.findByName(null); + } + + @Test(expected=IllegalArgumentException.class) + public void testFindByNameFailEmpty(){ + NoteService noteService = new NoteServiceImpl(); + + noteService.findByName(""); + } + + + @Test(expected=IllegalArgumentException.class) + public void testAddNoteFailNull(){ + NoteService noteService = new NoteServiceImpl(); + noteService.addNote(null); + } + + @Test + public void testAddNoteNullObject(){ + NoteService noteService = new NoteServiceImpl(); + + Note note = NullNote.getInstance(); + noteService.addNote(note); + + + List notes = noteService.findAll(); + + assertTrue(notes.isEmpty()); + } + + + @Test + public void testGetAll(){ + NoteService noteService = new NoteServiceImpl(); + + Note note = new Note(); + note.setName(NOTE_NAME); + note.setContent(NOTE_CONTENT); + noteService.addNote(note); + + Note note2 = new Note(); + note2.setName(NOTE_NAME2); + note2.setContent(NOTE_CONTENT); + noteService.addNote(note2); + + List notes = noteService.findAll(); + assertEquals(2,notes.size()); + assertTrue(notes.contains(note)); + assertTrue(notes.contains(note2)); + } + + @Test + public void testGetAllWithNoNotesSaved(){ + NoteService noteService = new NoteServiceImpl(); + + List notes = noteService.findAll(); + + assertNotNull(notes); + + assertTrue(notes.isEmpty()); + + } +} diff --git a/src/test/java/eu/lestard/notes/view/NotesControllerTest.java b/src/test/java/eu/lestard/notes/view/NotesControllerTest.java new file mode 100644 index 0000000..b48d0db --- /dev/null +++ b/src/test/java/eu/lestard/notes/view/NotesControllerTest.java @@ -0,0 +1,64 @@ +package eu.lestard.notes.view; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import eu.lestard.notes.entity.Note; +import eu.lestard.notes.service.NoteService; + +public class NotesControllerTest { + + + private static final String MY_NOTE_NAME = "My Note 1"; + + private static final String MY_NOTE_CONTENT = "My note content...."; + + private NoteService noteService; + + private NotesBackingBean backingBean; + + + @Test + public void testAddNote(){ + + this.backingBean = new NotesBackingBean(); + + + this.noteService = Mockito.mock(NoteService.class); + NotesController controller = new NotesController(this.backingBean,this.noteService); + + this.backingBean.setName(MY_NOTE_NAME); + this.backingBean.setContent(MY_NOTE_CONTENT); + + List notes = this.backingBean.getNotes(); + assertTrue(notes.isEmpty()); + + // We need to setup the NoteService + List notesInService = new ArrayList(); + Note tempNote = new Note(); + tempNote.setName(MY_NOTE_NAME); + tempNote.setContent(MY_NOTE_CONTENT); + notesInService.add(tempNote); + Mockito.when(this.noteService.findAll()).thenReturn(notesInService); + + controller.addNote(); + + Mockito.verify(this.noteService, Mockito.times(1)).addNote(Mockito.any(Note.class)); + + notes = this.backingBean.getNotes(); + assertEquals(1, notes.size()); + + Note note = notes.get(0); + assertEquals(MY_NOTE_NAME,note.getName()); + assertEquals(MY_NOTE_CONTENT, note.getContent()); + + } + +}