diff --git a/src/main/java/META-INF/persistence.xml b/src/main/java/META-INF/persistence.xml new file mode 100644 index 0000000000..077d0e17dc --- /dev/null +++ b/src/main/java/META-INF/persistence.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<persistence xmlns="http://java.sun.com/xml/ns/persistence" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/persistence + http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" + version="2.0"> + + <!-- NOTE THAT THERE ARE TWO PERSISTENCE UNITS, one default and one test used for either running or unit-tests --> + + <!-- A JPA Persistence Unit --> + <persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL"> + <provider>org.hibernate.ejb.HibernatePersistence</provider> + <class>se.su.dsv.scipro.data.dataobjects.Username</class> + <class>se.su.dsv.scipro.data.dataobjects.User</class> + <class>se.su.dsv.scipro.data.dataobjects.LazyDeletableDomainObject</class> + <class>se.su.dsv.scipro.data.dataobjects.Event</class> + <class>se.su.dsv.scipro.data.dataobjects.DomainObject</class> + + <!-- JPA entities must be registered here --> + + <properties> + + <!-- 2nd level cache --> + <property name="hibernate.cache.provider_class" value="org.hibernate.cache.SingletonEhCacheProvider" /> + <property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" /> + <property name="hibernate.cache.use_query_cache" value="true" /> + <property name="hibernate.cache.use_second_level_cache" value="true" /> + <property name="hibernate.generate_statistics" value="false" /> + + <!-- Local mysql test database --> + <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" /> + <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property> + <property name="hibernate.connection.url" value="jdbc:mysql://localhost/scipro"></property> + <property name="hibernate.connection.username" value="root"></property> + <property name="hibernate.connection.password" value="martin"></property> + <property name="hibernate.c3p0.idle_test_period" value="3600"></property> + + </properties> + </persistence-unit> + + <!-- A JPA Persistence Unit used for tests --> + <persistence-unit name="testPersistenceUnit" transaction-type="RESOURCE_LOCAL"> + + <!-- This list of persisted Entitys IS NOT updated by eclipes JPA facet, + if some tests are failing, then copy paste exact list from the above persistence unit --> + + <provider>org.hibernate.ejb.HibernatePersistence</provider> + <class>se.su.dsv.scipro.data.dataobjects.Username</class> + <class>se.su.dsv.scipro.data.dataobjects.User</class> + <class>se.su.dsv.scipro.data.dataobjects.LazyDeletableDomainObject</class> + <class>se.su.dsv.scipro.data.dataobjects.Event</class> + <class>se.su.dsv.scipro.data.dataobjects.DomainObject</class> + + <!-- JPA entities must be registered here --> + + <properties> + + <!-- 2nd level cache --> + <property name="hibernate.cache.provider_class" value="org.hibernate.cache.SingletonEhCacheProvider" /> + <property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" /> + <property name="hibernate.cache.use_query_cache" value="false" /> + <property name="hibernate.cache.use_second_level_cache" value="false" /> + <property name="hibernate.generate_statistics" value="false" /> + + <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> + <property name="hibernate.hbm2ddl.auto" value="create" /> + <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"></property> + <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:test"></property> + <property name="hibernate.show_sql" value="true" /> + + </properties> + </persistence-unit> + + +</persistence> diff --git a/src/main/java/se/su/dsv/scipro/DataInitialiser.java b/src/main/java/se/su/dsv/scipro/DataInitialiser.java new file mode 100644 index 0000000000..2d93617221 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/DataInitialiser.java @@ -0,0 +1,32 @@ +package se.su.dsv.scipro; + +import se.su.dsv.scipro.data.dao.interfaces.EventDao; +import se.su.dsv.scipro.data.dataobjects.Event; + +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +public class DataInitialiser { + + private static String[] dummyTitles = {"Wicket Event", "Party", "Breakfast At Tiffany's", "Holiday"}; + private static String[] dummyLocations = {"London", "Paris", "Pub", "New York"}; + + public void setEventDao(EventDao eventDao) { + this.eventDao = eventDao; + } + + private EventDao eventDao; + + public void dataInit() + { + for(int i = 0; i < 10; i++) + { + Event event = new Event(); + event.setTitle(dummyTitles[(int)(Math.random() * dummyTitles.length)]); + event.setLocation(dummyLocations[(int)(Math.random() * dummyLocations.length)]); + //eventDao.save(event); + } + } + +} diff --git a/src/main/java/se/su/dsv/scipro/HomePage.html b/src/main/java/se/su/dsv/scipro/HomePage.html new file mode 100644 index 0000000000..4d1cc20b04 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/HomePage.html @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"> + <head> + <title>LegUp: Wicket Spring JPA 2.0</title> + </head> + <body> + <div> + <strong><a href="http://jweekend.com/dev/LegUp">LegUp</a>: <a href="http://wicket.apache.org/">Wicket</a> <a href="http://www.springsource.org/">Spring</a> JPA 2.0</strong> + <br/><br/> + <a wicket:id="event">Event Page</a> + </div> + </body> +</html> + diff --git a/src/main/java/se/su/dsv/scipro/HomePage.java b/src/main/java/se/su/dsv/scipro/HomePage.java new file mode 100644 index 0000000000..708cc3f888 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/HomePage.java @@ -0,0 +1,30 @@ +package se.su.dsv.scipro; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; + +import se.su.dsv.scipro.pages.EventPage; + +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +public class HomePage extends WebPage { + + private static final long serialVersionUID = 1L; + + /** + * Constructor that is invoked when page is invoked without a em. + * + * @param parameters + * Page parameters + */ + public HomePage(final PageParameters parameters) { + + // Add the simplest type of label + add(new BookmarkablePageLink<Void>("event", EventPage.class)); + + + } +} diff --git a/src/main/java/se/su/dsv/scipro/SciProApplication.java b/src/main/java/se/su/dsv/scipro/SciProApplication.java new file mode 100644 index 0000000000..ebfb846d3f --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/SciProApplication.java @@ -0,0 +1,90 @@ +package se.su.dsv.scipro; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.wicket.Page; +import org.apache.wicket.Request; +import org.apache.wicket.Response; +import org.apache.wicket.Session; +import org.apache.wicket.protocol.http.WebApplication; +import org.apache.wicket.spring.injection.annot.SpringComponentInjector; + +import se.su.dsv.scipro.loginlogout.pages.LoginPage; +import se.su.dsv.scipro.loginlogout.pages.LogoutPage; +import se.su.dsv.scipro.pages.EventPage; + +/** + * Application object for your web application. If you want to run this application without deploying, run the Start class. + * + * @see wicket.myproject.Start#main(String[]) + * + * @author Martin Peters - mpeters@dsv.su.se + * + */ +public class SciProApplication extends WebApplication { + + /* + * These strings points to the location of the kerberos configuration files + */ + private final String jaasPath = "/WEB-INF/classes/jaas.conf"; + private final String krb5Path = "/WEB-INF/classes/kerb5.conf"; + + + /** + * Constructor + */ + public SciProApplication() + { + } + + protected SpringComponentInjector getSpringInjector() + { + return new SpringComponentInjector(this); + } + + @Override + protected void init() { + super.init(); + + setKerberosConfigs(); + + mountBookmarkablePage("event", EventPage.class); + mountBookmarkablePage("login", LoginPage.class); + mountBookmarkablePage("logout", LogoutPage.class); + + addComponentInstantiationListener(getSpringInjector()); + + } + + @SuppressWarnings("unchecked") + protected void setKerberosConfigs(){ + javax.servlet.ServletContext context = getServletContext(); + Logger logger = Logger.getRootLogger(); + java.util.Set<String> resources = context.getResourcePaths("/WEB-INF/classes/"); + + if(!resources.contains(jaasPath) || !resources.contains(krb5Path)){ + logger.log(Level.FATAL, "Path to authentication config files not correct. " + + "Users will not be able to log in!"); + } else { + String jaasRealPath = context.getRealPath(jaasPath); + String krb5RealPath = context.getRealPath(krb5Path); + logger.log(Level.INFO, "Setting location of jaas.conf to " + jaasRealPath); + logger.log(Level.INFO, "Setting location of kerb5.conf to " + krb5RealPath); + System.setProperty("java.security.auth.login.config", jaasRealPath); + System.setProperty("java.security.krb5.conf", krb5RealPath); + } + } + + /* (non-Javadoc) + * @see org.apache.wicket.Application#getHomePage() + */ + @Override + public Class<? extends Page> getHomePage() { + return HomePage.class; + } + + @Override + public Session newSession(Request request, Response response) { + return new SciProSession(request); + } +} diff --git a/src/main/java/se/su/dsv/scipro/SciProSession.java b/src/main/java/se/su/dsv/scipro/SciProSession.java new file mode 100644 index 0000000000..e62744d6d1 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/SciProSession.java @@ -0,0 +1,162 @@ +package se.su.dsv.scipro; + +import java.util.Locale; + +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginException; +import javax.servlet.http.Cookie; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.wicket.Request; +import org.apache.wicket.Session; +import org.apache.wicket.injection.web.InjectorHolder; +import org.apache.wicket.protocol.http.WebRequest; +import org.apache.wicket.protocol.http.WebSession; +import org.apache.wicket.spring.injection.annot.SpringBean; + +import se.su.dsv.scipro.auth.Authenticator; +import se.su.dsv.scipro.data.dao.interfaces.UserDao; +import se.su.dsv.scipro.data.dataobjects.User; + + + +public class SciProSession extends WebSession { + + private static final long serialVersionUID = -2655601050866343391L; + + private boolean loggedIn = false; + + @SpringBean + private UserDao userDao; + + //private List<Role> roles = new ArrayList<Role>(); + private User user = null; + + private String loggedInIdentity = null; + + + protected SciProSession(Request request) { + super(request); + InjectorHolder.getInjector().inject(this); + + Cookie cookie = ((WebRequest)request).getCookie("languagePreference"); + if(cookie != null){ + if(cookie.getValue().equals("en")) + this.setLocale(Locale.ENGLISH); + else if(cookie.getValue().equals("sv")) + this.setLocale(new Locale("sv","SE")); + } + } + + + public static SciProSession get() { + return (SciProSession) Session.get(); + } + + + protected void setUser(User user) { + this.user = user; + } + + public User getUser() { + return user; + } + + + protected void setLoggedInIdentity(String loggedInIdentity) { + this.loggedInIdentity = loggedInIdentity; + } + + + public String getLoggedInIdentity() { + return loggedInIdentity; + } + + + public boolean login(final String username, final String password){ + final boolean loginSuccess = authenticate(username, password); + if(loginSuccess){ + loggedIn = true; + } + return loginSuccess; + } + + + public void logout() + { + loggedIn = false; + } + + public final boolean isLoggedIn() { + return loggedIn; + } + + private boolean authenticate(String username, final String password) throws NullPointerException { + Authenticator auth = new Authenticator(); + /* + * An administrator can log in as a different user in the system by using 'adminusername::otherusername' for login + */ + String[] tmp = username.split("::"); + String loggedInAsUsername = null; + if(tmp.length > 0){ + username = tmp[0]; + if(tmp.length > 1) + loggedInAsUsername = tmp[1]; + } + + try { + auth.authenticate(username, password); + this.user = userDao.getUserByUsername(username); + if( user == null) + throw new NullPointerException("No user with this username found in the database, despite successful authentication"); + + setLoggedInIdentity(username+"@"+"dsv.su.se"); + if(user.getEmailAddress() == null || user.getEmailAddress().trim().equals("")){ + user.setEmailAddress(getLoggedInIdentity()); + user = userDao.save(user); + } + /* + * Here we switch the logged in user to be that of the person chosen be the logged in admin + */ + /* + if(userDao.isAdmin(user) && loggedInAsUsername != null){ + this.user = userDao.getUserByUserName(loggedInAsUsername); + if( user == null) + throw new NullPointerException("No user with this username found in the database, despite successful authentication"); + + } + if(userDao.isAuthor(user)){ + rolesString = rolesString +"AUTHOR,"; + roles.add(new AuthorRole()); + } + if(userDao.isSupervisor(user)){ + rolesString = rolesString +"SUPERVISOR,"; + roles.add(new SupervisorRole()); + } + if(userDao.isAdmin(user)){ + rolesString = rolesString +"ADMIN,"; + roles.add(new AdminRole()); + } + if(roles.isEmpty()){ + roles.add(new DefaultRole()); + } + */ + Logger logger = Logger.getLogger("Application"); + logger.log(Level.INFO, "User: "+getLoggedInIdentity()+ " logged in as: "+user.getFirstName()+" "+user.getLastName()+" "+user.getUserNames()); + return true; + } catch (FailedLoginException e) { + //e.printStackTrace(); + } catch (LoginException e) { + //e.printStackTrace(); + } + return false; + } + + @Override + public String toString(){ + return loggedInIdentity;//+" Roles: "+rolesString; + } + + +} diff --git a/src/main/java/se/su/dsv/scipro/auth/Authenticator.java b/src/main/java/se/su/dsv/scipro/auth/Authenticator.java new file mode 100644 index 0000000000..be49ade48a --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/auth/Authenticator.java @@ -0,0 +1,66 @@ +package se.su.dsv.scipro.auth; + +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +/** + * Class that handles authentication + * + * @author Dan Kjellman <dan-kjel@dsv.su.se> + */ +public class Authenticator { + + /** + * Method for authenticating users against underlying login module + * + * @param username the username + * @param password the password + * @return the authenticated username on success + * @throws LoginException if something unexpected happend + * @throws FailedLoginException if the username and password did not match + */ + public String authenticate(String username, String password) + throws LoginException, FailedLoginException { + + LoginContext lc = null; + + try { + //Create the callbackhandler and set username and password properties + LoginCallbackHandler loginCallback = new LoginCallbackHandler(); + loginCallback.setUsername(username); + loginCallback.setPassword(password); + + //Create LoginContext + lc = new LoginContext("ThesisJaasUser", loginCallback); + + //Catch exceptions if + } catch (LoginException le){ + Logger logger = Logger.getRootLogger(); + logger.log(Level.ERROR, "System error, Failed to create logincontext:" + le.getMessage()); + throw le; + } catch (SecurityException se){ + throw new LoginException("System error, Failed to create logincontext:" + se.getMessage()); + } catch (Exception e) { + throw new LoginException("System error:" + e.getMessage()); + } + + //try to authenticate + try { + lc.login(); + //return username on success + return username; + + //Catch LoginException if username and password did not match + } catch (LoginException le) { + throw new FailedLoginException("Autentication failed: " + le.getMessage()); + //Catch all other Exceptions if something unexpected happend + } catch (Exception e) { + throw new LoginException("System error, Failed to authenticate:" + e.getMessage()); + } + } + +} diff --git a/src/main/java/se/su/dsv/scipro/auth/LoginCallbackHandler.java b/src/main/java/se/su/dsv/scipro/auth/LoginCallbackHandler.java new file mode 100644 index 0000000000..2ba3547580 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/auth/LoginCallbackHandler.java @@ -0,0 +1,84 @@ +package se.su.dsv.scipro.auth; + +import java.io.IOException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +/** + * A Callbackhandler + * @author Dan Kjellman <dan-kjel@dsv.su.se> + */ +public class LoginCallbackHandler implements javax.security.auth.callback.CallbackHandler { + + private String password; + private String username; + + /** + * Constructor + */ + public LoginCallbackHandler(){} + + /** + * Get the username + * @return String username + */ + public String getUsername(){ + return username; + } + + /** + * Set the username + * + * @param username the username + */ + public void setUsername(String username){ + //If null set empty string, authentication will fail + if(username == null){ + this.username = ""; + } + this.username = username; + } + + /** + * Get the password + * @return String password + */ + public String getPassword(){ + return password; + } + + /** + * Set the password + * @param password + */ + public void setPassword(String password){ + //If null set empty string, authentication will fail + if(password == null){ + this.password = ""; + } + this.password = password; + } + + /** + * Handle the callbacks + */ + public void handle(Callback[] cb) throws IOException, + UnsupportedCallbackException { + + for(int i = 0; i<cb.length; i++){ + Callback c = cb[i]; + + if(c instanceof NameCallback){ + ((NameCallback)c).setName(getUsername()); + } else if (c instanceof PasswordCallback){ + ((PasswordCallback)c).setPassword(getPassword().toCharArray()); + } else { + throw new UnsupportedCallbackException(c, "Unsupported callback"); + } + } + + + } +} diff --git a/src/main/java/se/su/dsv/scipro/basepages/BasePage.html b/src/main/java/se/su/dsv/scipro/basepages/BasePage.html new file mode 100644 index 0000000000..832a82502e --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/basepages/BasePage.html @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta http-equiv="Content-type" content="text/html;charset=UTF-8" /> + <title>SciPro 0.1 Beta</title> + + <link href="styles/blueprint/screen.css" rel="stylesheet" media="screen,projection" /> + <link href="styles/blueprint/print.css" rel="stylesheet" media="print" /> + <link href="styles/blueprint/plugins/tabsplugin/screen.css" rel="stylesheet" media="screen,projection" /> + <!--[if lt IE 8]> + <link rel="stylesheet" href="styles/blueprint/ie.css" type="text/css" media="screen, projection" /> + <![endif]--> + <link href="styles/global.css" rel="stylesheet" media="screen,projection" /> + +</head> +<body> + <div> + <wicket:child/> + </div> +</body> +</html> \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/basepages/BasePage.java b/src/main/java/se/su/dsv/scipro/basepages/BasePage.java new file mode 100644 index 0000000000..30a6926997 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/basepages/BasePage.java @@ -0,0 +1,36 @@ +package se.su.dsv.scipro.basepages; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.CSSPackageResource; +import org.apache.wicket.markup.html.WebPage; + +public abstract class BasePage extends WebPage { + + public BasePage(){ + super(); + } + + public BasePage(PageParameters pp){ + super(pp); + } + + public static String ADMIN_CSS = "admin"; + public static String SUPERVISOR_CSS = "supervisor"; + public static String AUTHOR_CSS = "author"; + public static String GLOBAL_CSS = "global"; + public static String POPUP_CSS = "popup"; + public static String CSS_SUFFIX = ".css"; + + protected void setCss(String css){ + String languageCode = ""; + if(getLocale().getLanguage().equalsIgnoreCase("sv")) + languageCode = "sv"; + else + languageCode = "en"; + + add(CSSPackageResource.getHeaderContribution("styles/" + languageCode + CSS_SUFFIX)); + //add(CSSPackageResource.getHeaderContribution("styles/" + GLOBAL_CSS + CSS_SUFFIX)); + add(CSSPackageResource.getHeaderContribution("styles/" + css + CSS_SUFFIX)); + } + +} \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/basepages/BasePage.properties b/src/main/java/se/su/dsv/scipro/basepages/BasePage.properties new file mode 100644 index 0000000000..f309a22322 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/basepages/BasePage.properties @@ -0,0 +1,5 @@ + +submit: Submit + +palette.available: Available +palette.selected: Selected \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/basepages/BasePage_sv.properties b/src/main/java/se/su/dsv/scipro/basepages/BasePage_sv.properties new file mode 100644 index 0000000000..501c4c95f2 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/basepages/BasePage_sv.properties @@ -0,0 +1,5 @@ + +submit: Skicka + +palette.available: Valbara +palette.selected: Valda \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/data/dao/interfaces/Dao.java b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/Dao.java new file mode 100644 index 0000000000..9d42ea02f1 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/Dao.java @@ -0,0 +1,23 @@ +package se.su.dsv.scipro.data.dao.interfaces; + +import java.io.Serializable; +import java.util.List; + +import se.su.dsv.scipro.data.dataobjects.DomainObject; +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +public interface Dao<T extends DomainObject> +{ + public void delete(T o); + + public T load(Serializable id); + + public T save(T o); + + public List<T> findAll(); + + public int countAll(); +} + diff --git a/src/main/java/se/su/dsv/scipro/data/dao/interfaces/EventDao.java b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/EventDao.java new file mode 100644 index 0000000000..e724e2d89e --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/EventDao.java @@ -0,0 +1,10 @@ +package se.su.dsv.scipro.data.dao.interfaces; + +import se.su.dsv.scipro.data.dataobjects.Event; +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +public interface EventDao extends Dao<Event> { + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dao/interfaces/LazyDeletable.java b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/LazyDeletable.java new file mode 100644 index 0000000000..15a3d51bea --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/LazyDeletable.java @@ -0,0 +1,15 @@ +package se.su.dsv.scipro.data.dao.interfaces; + +/** + * + * @author Martin Peters - mpeters@dsv.su.se + * + * Classes implementing this interface MUST have a member of type boolean with the name 'deleted'. + */ +public interface LazyDeletable { + + public boolean isDeleted(); + + public void setDeleted(boolean deleted); + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dao/interfaces/LazyDeleteDao.java b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/LazyDeleteDao.java new file mode 100644 index 0000000000..962fce00cc --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/LazyDeleteDao.java @@ -0,0 +1,24 @@ +package se.su.dsv.scipro.data.dao.interfaces; + +import java.util.List; + +import se.su.dsv.scipro.data.dataobjects.DomainObject; + +/** + * + * @author Martin Peters - mpeters@dsv.su.se + * + * @param <T> + */ +public interface LazyDeleteDao<T extends DomainObject & LazyDeletable> extends Dao<T> { + + public T lazyDelete(T o); + + public int countAllLazyDeleted(); + + public List<T> findAllLazyDeleted(); + + public List<T> findAllLazyDeleted(final int first, final int count); + +} + diff --git a/src/main/java/se/su/dsv/scipro/data/dao/interfaces/UserDao.java b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/UserDao.java new file mode 100644 index 0000000000..04e9615110 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/UserDao.java @@ -0,0 +1,14 @@ +package se.su.dsv.scipro.data.dao.interfaces; + +import se.su.dsv.scipro.data.dataobjects.User; + +public interface UserDao extends LazyDeleteDao<User> { + + public User getUserByIdentifier(final Long identifier); + + public User getUserByUsername(final String userName); + + public User getUserByEmail(final String emailAddress); + + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dao/interfaces/UsernameDao.java b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/UsernameDao.java new file mode 100644 index 0000000000..30d3c0d831 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/interfaces/UsernameDao.java @@ -0,0 +1,12 @@ +package se.su.dsv.scipro.data.dao.interfaces; + +import java.util.List; + +import se.su.dsv.scipro.data.dataobjects.User; +import se.su.dsv.scipro.data.dataobjects.Username; + +public interface UsernameDao extends Dao<Username>{ + + public List<Username> getUsernamesByUser(final User user); + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dao/jpa/AbstractDaoJPAImpl.java b/src/main/java/se/su/dsv/scipro/data/dao/jpa/AbstractDaoJPAImpl.java new file mode 100644 index 0000000000..6e8b48a848 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/jpa/AbstractDaoJPAImpl.java @@ -0,0 +1,118 @@ +package se.su.dsv.scipro.data.dao.jpa; + +import java.io.Serializable; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; + +import org.hibernate.ejb.QueryHints; +import org.springframework.orm.jpa.JpaCallback; +import org.springframework.orm.jpa.support.JpaDaoSupport; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.data.dao.interfaces.Dao; +import se.su.dsv.scipro.data.dataobjects.DomainObject; + +/** + * + * @author Martin Peters - mpeters@dsv.su.se + * + * @param <T> + */ +public abstract class AbstractDaoJPAImpl<T extends DomainObject> extends JpaDaoSupport implements Dao<T> { + + protected Class<T> domainClass; + protected String domainClassString; + + public Class<T> getDomainClass(){ + return domainClass; + } + + public String getDomainClassString(){ + return domainClassString; + } + + + public AbstractDaoJPAImpl(Class<T> domainClass) { + this.domainClass = domainClass; + domainClassString = domainClass.getCanonicalName(); + } + + @Transactional + public void delete(T object) + { + getJpaTemplate().remove(object); + } + @Transactional + public T load(Serializable id) + { + return (T) getJpaTemplate().find(domainClass, id); + } + @Transactional + public T reLoad(T object){ + if(object != null) + return load(object.getId()); + else + return null; + } + + @Transactional + public T save(T object) + { + return getJpaTemplate().merge(object); + } + + @Transactional + public int countAll() { + return getJpaTemplate().execute(new JpaCallback<Integer>() { + + public Integer doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<Long> query = em.createQuery("SELECT COUNT (x) FROM "+domainClassString+" x", Long.class); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return (query.getSingleResult()).intValue(); + } + }); + + } + + @Transactional + public List<T> findAll() { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<T> query = em.createQuery("SELECT x FROM "+domainClassString+" x", domainClass); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + + @Transactional + public List<T> findAll(final int first, final int count) { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<T> query = em.createQuery("SELECT x FROM "+domainClassString+" x", domainClass); + query.setFirstResult(first); + query.setMaxResults(count); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + @Transactional + public List<T> findAll(final int first, final int count, final String orderBy) { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + String queryString = "SELECT x FROM "+domainClassString+" x ORDER BY x."+orderBy; + TypedQuery<T> query = em.createQuery(queryString, domainClass); + query.setFirstResult(first); + query.setMaxResults(count); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + +} + diff --git a/src/main/java/se/su/dsv/scipro/data/dao/jpa/EventDaoJPAImp.java b/src/main/java/se/su/dsv/scipro/data/dao/jpa/EventDaoJPAImp.java new file mode 100644 index 0000000000..ef9b4b756c --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/jpa/EventDaoJPAImp.java @@ -0,0 +1,46 @@ +package se.su.dsv.scipro.data.dao.jpa; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; + +import org.springframework.orm.jpa.JpaCallback; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.data.dao.interfaces.EventDao; +import se.su.dsv.scipro.data.dataobjects.Event; + +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +public class EventDaoJPAImp extends AbstractDaoJPAImpl<Event> implements EventDao { + + public EventDaoJPAImp() { + super(Event.class); + } + + @Transactional + public List<Event> findAll() { + return getJpaTemplate().execute(new JpaCallback<List<Event>>() { + public List<Event> doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<Event> query = em.createQuery("select e from Event e", Event.class); + return query.getResultList(); + } + }); + } + + @Transactional + public int countAll() { + return getJpaTemplate().execute(new JpaCallback<Integer>() { + + public Integer doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<Long> query = em.createQuery("select count (e) from Event e", Long.class); + return (query.getSingleResult()).intValue(); + } + }); + + } +} diff --git a/src/main/java/se/su/dsv/scipro/data/dao/jpa/LazyDeleteAbstractDaoJPAImpl.java b/src/main/java/se/su/dsv/scipro/data/dao/jpa/LazyDeleteAbstractDaoJPAImpl.java new file mode 100644 index 0000000000..42e9cd0155 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/jpa/LazyDeleteAbstractDaoJPAImpl.java @@ -0,0 +1,128 @@ +package se.su.dsv.scipro.data.dao.jpa; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; + +import org.hibernate.ejb.QueryHints; +import org.springframework.orm.jpa.JpaCallback; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.data.dao.interfaces.LazyDeletable; +import se.su.dsv.scipro.data.dao.interfaces.LazyDeleteDao; +import se.su.dsv.scipro.data.dataobjects.DomainObject; + +/** + * + * @author Martin Peters - mpeters@dsv.su.se + * + * @param <T> + */ +public abstract class LazyDeleteAbstractDaoJPAImpl<T extends DomainObject & LazyDeletable> extends AbstractDaoJPAImpl<T> implements LazyDeleteDao<T> { + + public LazyDeleteAbstractDaoJPAImpl(Class<T> domainClass) { + super(domainClass); + } + + @Transactional + public T lazyDelete(T o){ + o.setDeleted(true); + return save(o); + } + + @Override + @Transactional + public int countAll() { + return getJpaTemplate().execute(new JpaCallback<Integer>() { + + public Integer doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<Long> query = em.createQuery("SELECT COUNT (x) FROM "+domainClassString+" x WHERE x.deleted = false", Long.class); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return (query.getSingleResult()).intValue(); + } + }); + + } + + @Transactional + public int countAllLazyDeleted() { + return getJpaTemplate().execute(new JpaCallback<Integer>() { + + public Integer doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<Long> query = em.createQuery("SELECT COUNT (x) FROM "+domainClassString+" x WHERE x.deleted = true", Long.class); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return (query.getSingleResult()).intValue(); + } + }); + + } + + @Override + @Transactional + public List<T> findAll() { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<T> query = em.createQuery("SELECT x FROM "+domainClassString+" x WHERE x.deleted = false", domainClass); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + + @Transactional + public List<T> findAllLazyDeleted() { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<T> query = em.createQuery("SELECT x FROM "+domainClassString+" x WHERE x.deleted = true", domainClass); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + + @Override + @Transactional + public List<T> findAll(final int first, final int count) { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<T> query = em.createQuery("SELECT x FROM "+domainClassString+" x WHERE x.deleted = false", domainClass); + query.setFirstResult(first); + query.setMaxResults(count); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + + @Transactional + public List<T> findAllLazyDeleted(final int first, final int count) { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + TypedQuery<T> query = em.createQuery("SELECT x FROM "+domainClassString+" x WHERE x.deleted = true", domainClass); + query.setFirstResult(first); + query.setMaxResults(count); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + + @Override + @Transactional + public List<T> findAll(final int first, final int count, final String orderBy) { + return getJpaTemplate().execute(new JpaCallback<List<T>>() { + public List<T> doInJpa(EntityManager em) throws PersistenceException { + String queryString = "SELECT x FROM "+domainClassString+" x WHERE x.deleted = false ORDER BY x."+orderBy; + TypedQuery<T> query = em.createQuery(queryString, domainClass); + query.setFirstResult(first); + query.setMaxResults(count); + query.setHint(QueryHints.HINT_CACHEABLE, "true"); + return query.getResultList(); + } + }); + } + +} + diff --git a/src/main/java/se/su/dsv/scipro/data/dao/jpa/UserDaoJPAImp.java b/src/main/java/se/su/dsv/scipro/data/dao/jpa/UserDaoJPAImp.java new file mode 100644 index 0000000000..f980054707 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/jpa/UserDaoJPAImp.java @@ -0,0 +1,70 @@ +package se.su.dsv.scipro.data.dao.jpa; + +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; + +import org.springframework.orm.jpa.JpaCallback; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.data.dao.interfaces.UserDao; +import se.su.dsv.scipro.data.dataobjects.User; + + +public class UserDaoJPAImp extends LazyDeleteAbstractDaoJPAImpl<User> implements + UserDao { + + public UserDaoJPAImp() { + super(User.class); + } + + @Transactional + public User getUserByIdentifier(final Long identifier){ + return getJpaTemplate().execute(new JpaCallback<User>() { + public User doInJpa(EntityManager em) + throws PersistenceException { + TypedQuery<User> query = em.createQuery("select u FROM User u WHERE u.identifier = :identifier", User.class); + query.setParameter("identifier", identifier); + try{ + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + }); + } + + @Transactional + public User getUserByEmail(final String emailAddress){ + return getJpaTemplate().execute(new JpaCallback<User>() { + public User doInJpa(EntityManager em) + throws PersistenceException { + TypedQuery<User> query = em.createQuery("select u FROM User u WHERE u.emailAddress = :email", User.class); + query.setParameter("email", emailAddress); + try{ + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + }); + } + + @Transactional + public User getUserByUsername(final String username){ + return getJpaTemplate().execute(new JpaCallback<User>() { + public User doInJpa(EntityManager em) + throws PersistenceException { + TypedQuery<User> query = em.createQuery("select u FROM User u, Username un WHERE un.username = :username and un.user = u", User.class); + query.setParameter("username", username); + try{ + return query.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + }); + } + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dao/jpa/UserNameDaoJPAImp.java b/src/main/java/se/su/dsv/scipro/data/dao/jpa/UserNameDaoJPAImp.java new file mode 100644 index 0000000000..e60db624df --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dao/jpa/UserNameDaoJPAImp.java @@ -0,0 +1,43 @@ +package se.su.dsv.scipro.data.dao.jpa; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; + +import org.springframework.orm.jpa.JpaCallback; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.data.dao.interfaces.UsernameDao; +import se.su.dsv.scipro.data.dataobjects.User; +import se.su.dsv.scipro.data.dataobjects.Username; + +public class UserNameDaoJPAImp extends AbstractDaoJPAImpl<Username> implements UsernameDao{ + + public UserNameDaoJPAImp() { + super(Username.class); + } + + @Transactional + public List<Username> getUsernamesByUser(final User user) { + return getJpaTemplate().execute(new JpaCallback<List<Username>>() { + public List<Username> doInJpa(EntityManager em) + throws PersistenceException { + TypedQuery<Username> query = em.createQuery("select un FROM User u, Username un WHERE u = :user and un.user = u", Username.class); + query.setParameter("user", user); + try{ + return query.getResultList(); + } catch (NoResultException e) { + return new ArrayList<Username>(1); + } + } + }); + } + + + + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dataobjects/DomainObject.java b/src/main/java/se/su/dsv/scipro/data/dataobjects/DomainObject.java new file mode 100644 index 0000000000..f3427ced1a --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dataobjects/DomainObject.java @@ -0,0 +1,18 @@ +package se.su.dsv.scipro.data.dataobjects; + +import javax.persistence.MappedSuperclass; + +import org.apache.wicket.IClusterable; +/** + * + * @author Martin Peters - mpeters@dsv.su.se + * + */ +@MappedSuperclass +public abstract class DomainObject implements IClusterable{ + + private static final long serialVersionUID = 1L; + + abstract public Long getId(); + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dataobjects/Event.java b/src/main/java/se/su/dsv/scipro/data/dataobjects/Event.java new file mode 100644 index 0000000000..6511e31ae3 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dataobjects/Event.java @@ -0,0 +1,92 @@ +package se.su.dsv.scipro.data.dataobjects; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +@Entity +@Table(name="Event") +public class Event extends DomainObject { + + private static final long serialVersionUID = 2959377496669050427L; + + @Id + @GeneratedValue + private Long id; + + private String title; + private String location; + + public Event() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + + ((location == null) ? 0 : location.hashCode()); + result = prime * result + ((title == null) ? 0 : title.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Event other = (Event) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (location == null) { + if (other.location != null) + return false; + } else if (!location.equals(other.location)) + return false; + if (title == null) { + if (other.title != null) + return false; + } else if (!title.equals(other.title)) + return false; + return true; + } + + @Override + public String toString() { + return String.format("Event [id=%s, location=%s, title=%s]", id, location, title); + } +} \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/data/dataobjects/LazyDeletableDomainObject.java b/src/main/java/se/su/dsv/scipro/data/dataobjects/LazyDeletableDomainObject.java new file mode 100644 index 0000000000..0456c64610 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dataobjects/LazyDeletableDomainObject.java @@ -0,0 +1,36 @@ +package se.su.dsv.scipro.data.dataobjects; + +import javax.persistence.MappedSuperclass; + +import se.su.dsv.scipro.data.dao.interfaces.LazyDeletable; +/** + * + * @author Martin Peters - mpeters@dsv.su.se + * + */ +@MappedSuperclass +public abstract class LazyDeletableDomainObject extends DomainObject implements LazyDeletable{ + + private static final long serialVersionUID = 1L; + + private boolean deleted = false; + + /** + * @param set the object to be lazily deleted or not, does not take effect until after the object being saved. + */ + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + /** + * @return if the object is lazily deleted or not + */ + public boolean isDeleted() { + return deleted; + } + + + + + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dataobjects/User.java b/src/main/java/se/su/dsv/scipro/data/dataobjects/User.java new file mode 100644 index 0000000000..1b1dea043b --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dataobjects/User.java @@ -0,0 +1,122 @@ +package se.su.dsv.scipro.data.dataobjects; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +/** + * @author Martin Peters - mpeters@dsv.su.se + * + */ +@Entity +@Table(name="User") +@Cacheable(true) +@Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) //Hibernate specific +public class User extends LazyDeletableDomainObject { + + private static final long serialVersionUID = 8116476815877870372L; + + @Id + @GeneratedValue + private Long id; + + @Column(unique=true) + private Long identifier; + + private String firstName; + private String lastName; + @Column(unique=true) + private String emailAddress; + + @OneToMany(mappedBy="user") + private Set<Username> usernames = new HashSet<Username>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public void setIdentifier(Long identifier) { + this.identifier = identifier; + } + + public Long getIdentifier() { + return identifier; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getFirstName() { + return firstName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getLastName() { + return lastName; + } + + public void setEmailAddress(String email) { + this.emailAddress = email; + } + + public String getEmailAddress() { + return emailAddress; + } + + + public void setUserNames(Set<Username> usernames) { + this.usernames = usernames; + } + + public Set<Username> getUserNames() { + return usernames; + } + + @Override + public int hashCode() { + final int weight = 31; + int result = 17; + + result = weight * result + ((id == null) ? 0 : (int) (id ^ (id >>> 32))); + + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (this.getClass() != obj.getClass()) + return false; + + User other = (User) obj; + + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + + return true; + } + +} diff --git a/src/main/java/se/su/dsv/scipro/data/dataobjects/Username.java b/src/main/java/se/su/dsv/scipro/data/dataobjects/Username.java new file mode 100644 index 0000000000..88a58f31e5 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/data/dataobjects/Username.java @@ -0,0 +1,122 @@ +package se.su.dsv.scipro.data.dataobjects; + +import javax.persistence.Basic; +import javax.persistence.Cacheable; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +/** + * @author Martin Peters - mpeters@dsv.su.se + * + */ +@Entity +@Cacheable(true) +@Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) //Hibernate specific +@Table(name="Username", uniqueConstraints={@UniqueConstraint(columnNames={"username","realm"})}) +public class Username extends DomainObject { + + private static final long serialVersionUID = -2043481766263425696L; + + @Id + @GeneratedValue + private Long id; + + @Basic(optional=false) + private String username; + + @Basic(optional=false) + private String realm; + + @ManyToOne(optional=false) + private User user; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUserName() { + return username; + } + + public void setUserName(String userName) { + this.username = userName; + } + + /** + * @param realm the realm to set + */ + public void setRealm(String realm) { + this.realm = realm; + } + + /** + * @return the realm + */ + public String getRealm() { + return realm; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + @Override + public String toString(){ + return username; + } + + @Override + public int hashCode() { + final int weight = 31; + int result = 17; + + result = weight * result + ((id == null) ? 0 : (int) (id ^ (id >>> 32))); + result = weight * result + ((username == null) ? 0 : username.hashCode()); + result = weight * result + ((realm == null) ? 0 : realm.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (this == obj) + return true; + if (this.getClass() != obj.getClass()) + return false; + + Username other = (Username) obj; + + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (username == null) { + if (other.username != null) + return false; + } else if (!username.equals(other.username)) + return false; + if (realm == null) { + if (other.realm != null) + return false; + } else if (!realm.equals(other.realm)) + return false; + return true; + } +} diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/pages/LoginPage.html b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LoginPage.html new file mode 100644 index 0000000000..a9c462ed27 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LoginPage.html @@ -0,0 +1,14 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" +> +<body> +<wicket:extend> + <div id="loginheader" class="thesis-admin-span-12"> + <h1>SciPro</h1> + </div> + <div wicket:id="signInPanel"></div> +</wicket:extend> +</body> +</html> diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/pages/LoginPage.java b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LoginPage.java new file mode 100644 index 0000000000..8a19ab198c --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LoginPage.java @@ -0,0 +1,30 @@ +package se.su.dsv.scipro.loginlogout.pages; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.RestartResponseException; + +import se.su.dsv.scipro.HomePage; +import se.su.dsv.scipro.SciProSession; +import se.su.dsv.scipro.basepages.BasePage; +import se.su.dsv.scipro.loginlogout.panels.LoginPanel; + +/** + * Page for logging users into the system + * @param pp the page parameters + * @author Martin Peters - mpeters@dsv.su.se + */ +public class LoginPage extends BasePage { + + public LoginPage(final PageParameters pp) throws Exception { + + //Redirect to HomePage if user is authenticated + if(SciProSession.get().isLoggedIn()){ + getRequestCycle().setRedirect(true); + throw new RestartResponseException(HomePage.class); + } + + add(new LoginPanel("signInPanel", true)); + + } + +} diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/pages/LogoutPage.html b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LogoutPage.html new file mode 100644 index 0000000000..05424e260d --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LogoutPage.html @@ -0,0 +1,13 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" +> +<body> +<wicket:extend> + <div> + <span wicket:id="message">Message here</span><a wicket:id="loginLink"><span wicket:id="linkText">Link text here</span></a> + </div> +</wicket:extend> +</body> +</html> diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/pages/LogoutPage.java b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LogoutPage.java new file mode 100644 index 0000000000..b34466e233 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/pages/LogoutPage.java @@ -0,0 +1,23 @@ +package se.su.dsv.scipro.loginlogout.pages; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; + +import se.su.dsv.scipro.SciProSession; +import se.su.dsv.scipro.basepages.BasePage; + +public class LogoutPage extends BasePage { + + public LogoutPage(final PageParameters parameters){ + SciProSession session = SciProSession.get(); + + session.invalidate(); + + add(new Label("message", "You are now logged out. Log back in ")); + BookmarkablePageLink<Void> bml = new BookmarkablePageLink<Void>("loginLink", LoginPage.class); + bml.add(new Label("linkText", "here")); + add(bml); + + } +} diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.html b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.html new file mode 100644 index 0000000000..f3c8cd848c --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.html @@ -0,0 +1,58 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" +> +<body> + <wicket:panel> + + + <div style="margin-top: 25px;"> </div> + <span wicket:id="feedback"/> + <p class="thesis-admin-prepend-2"><wicket:message key="loginExplanation"/></p> + <form wicket:id="signInForm"> + <table class="no-bgcolor-table"> + <tr> + <td class="largetext rightaligned"><wicket:message key="username"/>:</td> + <td> + <input wicket:id="username" type="text" class="thesis-admin-title" value="foo@goo.moo" size="30"/> + </td> + </tr> + <tr> + <td class="largetext rightaligned"><wicket:message key="password"/>:</td> + <td> + <input wicket:id="password" type="password" class="thesis-admin-title" value="password" size="30"/> + </td> + </tr> + <tr wicket:id="rememberMeRow"> + <td></td> + <td> <input wicket:id="rememberMe" type="checkbox" /> <wicket:message key="rememberMe"/> </td> + </tr> + <tr> + <td></td> + <td> + <input type="submit" name="submit" wicket:message="value:login"/> + <input type="reset" wicket:message="value:reset"/> + </td> + </tr> + </table> + </form> + </wicket:panel> +</body> +</html> \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.java b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.java new file mode 100644 index 0000000000..25bbbb21ef --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.java @@ -0,0 +1,248 @@ +package se.su.dsv.scipro.loginlogout.panels; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.form.CheckBox; +import org.apache.wicket.markup.html.form.PasswordTextField; +import org.apache.wicket.markup.html.form.StatelessForm; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.panel.FeedbackPanel; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.util.value.ValueMap; + +import se.su.dsv.scipro.SciProSession; + + +/** + * Reusable user sign in panel with username and password as well as support for cookie persistence + * of the both. When the SignInPanel's form is submitted, the method signIn(String, String) is + * called, passing the username and password submitted. The signIn() method should authenticate the + * user's session. The default implementation calls AuthenticatedWebSession.get().signIn(). + * + * @author Jonathan Locke + * @author Juergen Donnerstag + * @author Eelco Hillenius + */ +public class LoginPanel extends Panel +{ + private static final long serialVersionUID = 1L; + + /** True if the panel should display a remember-me checkbox */ + private boolean includeRememberMe = true; + + /** Field for password. */ + private PasswordTextField password; + + /** True if the user should be remembered via form persistence (cookies) */ + private boolean rememberMe = true; + + /** Field for user name. */ + private TextField<String> username; + + /** + * Sign in form. + */ + public final class SignInForm extends StatelessForm<Void> + { + private static final long serialVersionUID = 1L; + + /** El-cheapo model for form. */ + private final ValueMap properties = new ValueMap(); + + /** + * Constructor. + * + * @param id + * id of the form component + */ + public SignInForm(final String id) + { + super(id); + + // Attach textfield components that edit properties map + // in lieu of a formal beans model + add(username = new TextField<String>("username", new PropertyModel<String>(properties, + "username"))); + add(password = new PasswordTextField("password", new PropertyModel<String>(properties, + "password"))); + + username.setType(String.class); + password.setType(String.class); + + // MarkupContainer row for remember me checkbox + final WebMarkupContainer rememberMeRow = new WebMarkupContainer("rememberMeRow"); + add(rememberMeRow); + + // Add rememberMe checkbox + rememberMeRow.add(new CheckBox("rememberMe", new PropertyModel<Boolean>( + LoginPanel.this, "rememberMe"))); + + // Make form values persistent + setPersistent(rememberMe); + + // Show remember me checkbox? + rememberMeRow.setVisible(includeRememberMe); + } + + /** + * @see org.apache.wicket.markup.html.form.Form#onSubmit() + */ + @Override + public final void onSubmit() + { + try{ + if (signIn(getUsername(), getPassword())) + { + onSignInSucceeded(); + } + else + { + onSignInFailed(); + } + } catch(NullPointerException npe){ + error("User authentication successful but user was not found in database! Please contact thesissupport@dsv.su.se or try a different username."); + } + } + } + + /** + * @see org.apache.wicket.Component#Component(String) + */ + public LoginPanel(final String id) + { + this(id, true); + } + + /** + * @param id + * See Component constructor + * @param includeRememberMe + * True if form should include a remember-me checkbox + * @see org.apache.wicket.Component#Component(String) + */ + public LoginPanel(final String id, final boolean includeRememberMe) + { + super(id); + + this.includeRememberMe = includeRememberMe; + + // Create feedback panel and add to page + final FeedbackPanel feedback = new FeedbackPanel("feedback"); + add(feedback); + + // Add sign-in form to page, passing feedback panel as + // validation error handler + add(new SignInForm("signInForm")); + } + + /** + * Removes persisted form data for the signin panel (forget me) + */ + public final void forgetMe() + { + // Remove persisted user data. Search for child component + // of type SignInForm and remove its related persistence values. + getPage().removePersistedFormData(LoginPanel.SignInForm.class, true); + } + + /** + * Convenience method to access the password. + * + * @return The password + */ + public String getPassword() + { + return password.getInput(); + } + + /** + * Get model object of the rememberMe checkbox + * + * @return True if user should be remembered in the future + */ + public boolean getRememberMe() + { + return rememberMe; + } + + /** + * Convenience method to access the username. + * + * @return The user name + */ + public String getUsername() + { + return username.getDefaultModelObjectAsString(); + } + + /** + * Convenience method set persistence for username and password. + * + * @param enable + * Whether the fields should be persistent + */ + public void setPersistent(final boolean enable) + { + username.setPersistent(enable); + } + + /** + * Set model object for rememberMe checkbox + * + * @param rememberMe + */ + public void setRememberMe(final boolean rememberMe) + { + this.rememberMe = rememberMe; + setPersistent(rememberMe); + } + + /** + * Sign in user if possible. + * + * @param username + * The username + * @param password + * The password + * @return True if signin was successful + */ + public boolean signIn(String username, String password) throws NullPointerException + { + return SciProSession.get().login(username, password); + } + + protected void onSignInFailed() + { + // Try the component based localizer first. If not found try the + // application localizer. Else use the default + error(getLocalizer().getString("loginFailed", this, "Login failed")); + } + + protected void onSignInSucceeded() + { + // If login has been called because the user was not yet + // logged in, than continue to the original destination, + // otherwise to the Home page + if (!continueToOriginalDestination()) + { + setResponsePage(getApplication().getHomePage()); + } + } +} diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.properties b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.properties new file mode 100644 index 0000000000..6cd4dcd38e --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel.properties @@ -0,0 +1,7 @@ +loginFailed: Login failed +username: Username +password: Password +rememberMe: Remember Me +login: Login +reset: Reset +loginExplanation: Log in with your kerberos credentials \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel_sv.properties b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel_sv.properties new file mode 100644 index 0000000000..b2452c30fb --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/loginlogout/panels/LoginPanel_sv.properties @@ -0,0 +1,8 @@ +loginFailed: Inloggning misslyckades +signInForm.password= l�senord +username: Anv�ndarnamn +password: L�senord +rememberMe: Kom ih�g mig +login: Logga in +reset: Rensa +loginExplanation: Logga in med ditt kerberoskonto \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/pages/EventPage.html b/src/main/java/se/su/dsv/scipro/pages/EventPage.html new file mode 100644 index 0000000000..b8b68116fc --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/pages/EventPage.html @@ -0,0 +1,25 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" +> +<head> + <meta http-equiv="Content-type" content="text/html;charset=UTF-8" /> + <title>LegUp: Wicket Spring JPA 2.0</title> +</head> +<body> + <strong><a href="http://jweekend.com/dev/LegUp">LegUp</a>: <a href="http://wicket.apache.org/">Wicket</a> <a href="http://www.springsource.org/">Spring</a> JPA 2.0</strong> + <h1>Event Page</h1> + <form wicket:id="eventForm"> + <fieldset> + <label>Title</label><input wicket:id="title" type="text" /><br/> + <label>Location</label><input wicket:id="location" type="text"/><br/> + <a wicket:id="submit">Save</a> + </fieldset> + </form> + <ul wicket:id="listContainer"> + <li wicket:id="list"><span wicket:id="eventName" /> @ <span wicket:id="eventLocation"/> + </li> + </ul> +</body> +</html> \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/pages/EventPage.java b/src/main/java/se/su/dsv/scipro/pages/EventPage.java new file mode 100644 index 0000000000..4baad11662 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/pages/EventPage.java @@ -0,0 +1,71 @@ +package se.su.dsv.scipro.pages; + +import java.util.List; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; + +import se.su.dsv.scipro.data.dao.interfaces.EventDao; +import se.su.dsv.scipro.data.dataobjects.Event; +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +public class EventPage extends WebPage { + + @SpringBean + private EventDao eventDao; + + public EventPage(final PageParameters pp) + { + Form<Event> eventForm = new Form<Event>("eventForm", new CompoundPropertyModel<Event>(new Event())); + eventForm.add(new TextField<String>("title").setRequired(true)); + eventForm.add(new TextField<String>("location").setRequired(true)); + + final WebMarkupContainer wmc = new WebMarkupContainer("listContainer"); + + wmc.add(new ListView<Event>("list", new PropertyModel<List<Event>>(this, "eventDao.findAll")){ + + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(ListItem<Event> item) { + Event event = item.getModelObject(); + item.add(new Label("eventName", event.getTitle())); + item.add(new Label("eventLocation", event.getLocation())); + } + + }); + wmc.setOutputMarkupId(true); + add(wmc); + + eventForm.add(new AjaxSubmitLink("submit"){ + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit(AjaxRequestTarget target, Form<?> form) { + Event event = (Event) form.getModelObject(); + Event newEvent = new Event(); + newEvent.setLocation(event.getLocation()); + newEvent.setTitle(event.getTitle()); + eventDao.save(newEvent); + target.addComponent(wmc); + } + }); + + + add(eventForm); + + } +} diff --git a/src/main/resources/applicationContext.xml b/src/main/resources/applicationContext.xml new file mode 100644 index 0000000000..5c0bf76c56 --- /dev/null +++ b/src/main/resources/applicationContext.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" + default-autowire="byName"> + + <bean id="entityManagerFactory" + class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> + <property name="persistenceUnitName" value="defaultPersistenceUnit" /> + </bean> + + <!-- + enable the configuration of transactional behavior based on + annotations + --> + <tx:annotation-driven transaction-manager="transactionManager" /> + + <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> + <property name="entityManagerFactory" ref="entityManagerFactory" /> + </bean> + + + <bean id="eventDao" class="se.su.dsv.scipro.data.dao.jpa.EventDaoJPAImp"> + <property name="entityManagerFactory" ref="entityManagerFactory" /> + </bean> + + <bean id="userDao" class="se.su.dsv.scipro.data.dao.jpa.UserDaoJPAImp"> + <property name="entityManagerFactory" ref="entityManagerFactory" /> + </bean> + + <bean class="se.su.dsv.scipro.DataInitialiser" init-method="dataInit"> + <property name="eventDao" ref="eventDao"></property> + </bean> + + +</beans> diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml new file mode 100644 index 0000000000..c0224ff966 --- /dev/null +++ b/src/main/resources/ehcache.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="ehcache.xsd" > + + <diskStore path="java.io.tmpdir"/> + + <cache + name="org.hibernate.cache.StandardQueryCache" + maxElementsInMemory="500" + eternal="false" + timeToLiveSeconds="600" + overflowToDisk="true"/> + + <defaultCache + maxElementsInMemory="10000" + eternal="false" + timeToIdleSeconds="360" + timeToLiveSeconds="600" + overflowToDisk="true" + diskPersistent="false" + diskExpiryThreadIntervalSeconds="120" + memoryStoreEvictionPolicy="LRU"/> + + + <cache name="se.su.dsv.scipro.data.dataobjects.Username" maxElementsInMemory="1000"/> + <cache name="se.su.dsv.scipro.data.dataobjects.User" maxElementsInMemory="1000"/> + + + +</ehcache> \ No newline at end of file diff --git a/src/main/resources/jaas.conf b/src/main/resources/jaas.conf new file mode 100644 index 0000000000..2ba0863931 --- /dev/null +++ b/src/main/resources/jaas.conf @@ -0,0 +1,3 @@ +ThesisJaasUser { + com.sun.security.auth.module.Krb5LoginModule required; +}; \ No newline at end of file diff --git a/src/main/resources/kerb5.conf b/src/main/resources/kerb5.conf new file mode 100644 index 0000000000..7d50259c36 --- /dev/null +++ b/src/main/resources/kerb5.conf @@ -0,0 +1,7 @@ +[libdefaults] + default_realm = DSV.SU.SE + default_tkt_enctypes = des3-cbc-sha1 +[realms] + DSV.SU.SE = { + kdc = kerberos.dsv.su.se +} diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000000..9dc92245ad --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,12 @@ +log4j.appender.Stdout=org.apache.log4j.ConsoleAppender +log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.Stdout.layout.conversionPattern=%-5p - %-26.26c{1} - %m\n + +log4j.rootLogger=INFO,Stdout + +log4j.logger.wicket=INFO +log4j.logger.wicket.protocol.http.HttpSessionStore=INFO +log4j.logger.wicket.version=INFO +log4j.logger.wicket.RequestCycle=INFO + + diff --git a/src/main/webapp/META-INF/MANIFEST.MF b/src/main/webapp/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..5e9495128c --- /dev/null +++ b/src/main/webapp/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..82211d5c26 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" + version="2.4"> + + <display-name>SciPro</display-name> + + <!-- Open session in view --> + <filter> + <filter-name>osiv</filter-name> + <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> + </filter> + + <filter-mapping> + <filter-name>osiv</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <filter> + <filter-name>wicket.WicketWarp</filter-name> + <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> + <init-param> + <param-name>applicationClassName</param-name> + <param-value>se.su.dsv.scipro.SciProApplication</param-value> + </init-param> + </filter> + + <filter-mapping> + <filter-name>wicket.WicketWarp</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <!-- Session timeout set to 8 hours --> + <session-config> + <session-timeout>480</session-timeout> + </session-config> + + <!-- Use deployment for production, development for development --> + <context-param> + <param-name>configuration</param-name> + <param-value>development</param-value> + <!-- param-value>deployment</param-value--> + </context-param> + + + <context-param> + <param-name>contextConfigLocation</param-name> + <param-value>classpath:applicationContext.xml</param-value> + </context-param> + <listener> + <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> + </listener> + + +</web-app> diff --git a/src/test/java/se/su/dsv/scipro/Start.java b/src/test/java/se/su/dsv/scipro/Start.java new file mode 100644 index 0000000000..d07bc3f53e --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/Start.java @@ -0,0 +1,43 @@ +package se.su.dsv.scipro; + +import org.mortbay.jetty.Connector; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.bio.SocketConnector; +import org.mortbay.jetty.webapp.WebAppContext; + +public class Start { + + public static void main(String[] args) throws Exception { + Server server = new Server(); + SocketConnector connector = new SocketConnector(); + connector.setPort(8080); + server.setConnectors(new Connector[] { connector }); + + WebAppContext bb = new WebAppContext(); + bb.setServer(server); + bb.setContextPath("/"); + bb.setWar("src/main/webapp"); + + + // START JMX SERVER + // MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + // MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer); + // server.getContainer().addEventListener(mBeanContainer); + // mBeanContainer.start(); + + server.addHandler(bb); + + try { + System.out.println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP"); + server.start(); + while (System.in.available() == 0) { + Thread.sleep(5000); + } + server.stop(); + server.join(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(100); + } + } +} diff --git a/src/test/java/se/su/dsv/scipro/dao/jpa/TestEventDaoJPA-context.xml b/src/test/java/se/su/dsv/scipro/dao/jpa/TestEventDaoJPA-context.xml new file mode 100644 index 0000000000..7719d0cbaa --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/dao/jpa/TestEventDaoJPA-context.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" + default-autowire="byName"> + + <bean id="entityManagerFactory" + class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> + <property name="persistenceUnitName" value="testPersistenceUnit" /> + </bean> + + <!-- + enable the configuration of transactional behavior based on + annotations + --> + <tx:annotation-driven transaction-manager="transactionManager" /> + + <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> + <property name="entityManagerFactory" ref="entityManagerFactory" /> + </bean> + + + <bean id="eventDao" class="se.su.dsv.scipro.data.dao.jpa.EventDaoJPAImp"> + <property name="entityManagerFactory" ref="entityManagerFactory" /> + </bean> + + +</beans> diff --git a/src/test/java/se/su/dsv/scipro/dao/jpa/TestEventDaoJPA.java b/src/test/java/se/su/dsv/scipro/dao/jpa/TestEventDaoJPA.java new file mode 100644 index 0000000000..0ed09f8cc4 --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/dao/jpa/TestEventDaoJPA.java @@ -0,0 +1,93 @@ +package se.su.dsv.scipro.dao.jpa; + + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.data.dao.interfaces.EventDao; +import se.su.dsv.scipro.data.dataobjects.Event; + +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class TestEventDaoJPA { + + @Autowired + private EventDao eventDao; + + protected Event event; + + @Before + public void startTransaction() + { + event = new Event(); + event.setLocation("new Location"); + event.setTitle("new Title"); + event = eventDao.save(event); + } + + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.EventDaoJPAImp#findAll()}. + */ + @Test + @Transactional + @Rollback + public void testFindAll() { + List<Event> events = new ArrayList<Event>(); + events.add(event); + Assert.assertEquals(events, eventDao.findAll()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.EventDaoJPAImp#countAll()}. + */ + @Test @Transactional + @Rollback + public void testCountAll() { + Assert.assertEquals(1, eventDao.countAll()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.AbstractDaoJPAImpl#delete(? extends se.su.dsv.scipro.data.dataobjects.DomainObject)}. + */ + @Test @Transactional + @Rollback + public void testDelete() { + eventDao.delete(event); + Assert.assertEquals(0, eventDao.countAll()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.AbstractDaoJPAImpl#load(java.io.Serializable)}. + */ + @Test @Transactional + @Rollback + public void testLoad() { + Event event2 = eventDao.load(event.getId()); + Assert.assertEquals(event, event2); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.AbstractDaoJPAImpl#save(se.su.dsv.scipro.data.dataobjects.DomainObject)}. + */ + @Test @Transactional + @Rollback + public void testSave() { + //if we have got this far then save works + } + +} diff --git a/src/test/java/se/su/dsv/scipro/dao/jpa/TestUserDaoJPA-context.xml b/src/test/java/se/su/dsv/scipro/dao/jpa/TestUserDaoJPA-context.xml new file mode 100644 index 0000000000..85cae8b053 --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/dao/jpa/TestUserDaoJPA-context.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" + default-autowire="byName"> + + <bean id="entityManagerFactory" + class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> + <property name="persistenceUnitName" value="testPersistenceUnit" /> + </bean> + + <!-- + enable the configuration of transactional behavior based on + annotations + --> + <tx:annotation-driven transaction-manager="transactionManager" /> + + <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> + <property name="entityManagerFactory" ref="entityManagerFactory" /> + </bean> + + + <bean id="userDao" class="se.su.dsv.scipro.data.dao.jpa.UserDaoJPAImp"> + <property name="entityManagerFactory" ref="entityManagerFactory" /> + </bean> + + +</beans> diff --git a/src/test/java/se/su/dsv/scipro/dao/jpa/TestUserDaoJPA.java b/src/test/java/se/su/dsv/scipro/dao/jpa/TestUserDaoJPA.java new file mode 100644 index 0000000000..8f7c3414a8 --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/dao/jpa/TestUserDaoJPA.java @@ -0,0 +1,137 @@ +package se.su.dsv.scipro.dao.jpa; + + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +import se.su.dsv.scipro.data.dao.interfaces.UserDao; +import se.su.dsv.scipro.data.dataobjects.User; + +/** + * + * @author Martin Peters - mpeters@dsv.su.se + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class TestUserDaoJPA { + + @Autowired + private UserDao userDao; + + protected User user; + + protected User deletedUser; + + @Before + public void startTransaction() + { + user = new User(); + user.setEmailAddress("test@dsv.su.se"); + user.setIdentifier(new Long(666)); + user.setFirstName("Test"); + user.setLastName("Person"); + user = userDao.save(user); + + deletedUser = new User(); + deletedUser.setEmailAddress("testdeleted@dsv.su.se"); + deletedUser.setIdentifier(new Long(777)); + deletedUser.setFirstName("Test"); + deletedUser.setLastName("Person"); + deletedUser.setDeleted(true); + deletedUser = userDao.save(deletedUser); + + } + + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.UserDaoJPAImp#findAll()}. + */ + @Test + @Transactional + @Rollback + public void testFindAll() { + List<User> users = new ArrayList<User>(); + users.add(user); + Assert.assertEquals(users, userDao.findAll()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.UserDaoJPAImp#countAll()}. + */ + @Test @Transactional + @Rollback + public void testCountAll() { + Assert.assertEquals(1, userDao.countAll()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.AbstractDaoJPAImpl#delete(? extends se.su.dsv.scipro.data.dataobjects.DomainObject)}. + */ + @Test @Transactional + @Rollback + public void testDelete() { + userDao.delete(user); + Assert.assertEquals(0, userDao.countAll()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.AbstractDaoJPAImpl#load(java.io.Serializable)}. + */ + @Test @Transactional + @Rollback + public void testLazyDelete() { + user = userDao.lazyDelete(user); + Assert.assertEquals(0, userDao.countAll()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.LazyDeleteAbstractDaoJPAImpl#lazyDelete(? extends se.su.dsv.scipro.data.dataobjects.LazyDeletableDomainObject)}. + */ + @Test @Transactional + @Rollback + public void testLoad() { + User user2 = userDao.load(user.getId()); + Assert.assertEquals(user, user2); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.AbstractDaoJPAImpl#save(se.su.dsv.scipro.data.dataobjects.DomainObject)}. + */ + @Test @Transactional + @Rollback + public void testSave() { + //if we have got this far then save works + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.LazyDeleteAbstractDaoJPAImpl#countAllLazyDeleted())}. + */ + @Test @Transactional + @Rollback + public void testCountAllLazyDeleted() { + Assert.assertEquals(1, userDao.countAllLazyDeleted()); + } + + /** + * Test method for {@link se.su.dsv.scipro.data.dao.jpa.LazyDeleteAbstractDaoJPAImpl#findAllLazyDeleted())}. + */ + @Test @Transactional + @Rollback + public void testFindAllLazyDeleted() { + List<User> users = new ArrayList<User>(); + users.add(deletedUser); + Assert.assertEquals(users, userDao.findAllLazyDeleted()); + } + +} diff --git a/src/test/java/se/su/dsv/scipro/wicket/TestWicketPages.java b/src/test/java/se/su/dsv/scipro/wicket/TestWicketPages.java new file mode 100644 index 0000000000..b302c39ef2 --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/wicket/TestWicketPages.java @@ -0,0 +1,66 @@ +package se.su.dsv.scipro.wicket; + +import org.apache.wicket.spring.injection.annot.SpringComponentInjector; +import org.apache.wicket.spring.test.ApplicationContextMock; +import org.apache.wicket.util.tester.WicketTester; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import se.su.dsv.scipro.HomePage; +import se.su.dsv.scipro.SciProApplication; +import se.su.dsv.scipro.data.dao.interfaces.EventDao; +import se.su.dsv.scipro.data.dao.interfaces.UserDao; +import se.su.dsv.scipro.loginlogout.pages.LoginPage; +import se.su.dsv.scipro.pages.EventPage; + +/** + * @author Richard Wilkinson - richard.wilkinson@jweekend.com + * + */ +public class TestWicketPages { + + protected WicketTester tester; + + @Before + public void setup() + { + final ApplicationContextMock acm = new ApplicationContextMock(); + + EventDao eventDao = Mockito.mock(EventDao.class); + UserDao userDao = Mockito.mock(UserDao.class); + + acm.putBean("eventDao", eventDao); + acm.putBean("userDao", userDao); + + tester = new WicketTester(new SciProApplication(){ + /* (non-Javadoc) + * @see se.su.dsv.scipro.WicketApplication#getGuiceInjector() + */ + @Override + protected SpringComponentInjector getSpringInjector() { + return new SpringComponentInjector(this, acm, true); + } + }); + } + + @Test + public void testStartPage() + { + tester.startPage(HomePage.class); + } + + @Test + public void testEventPage() + { + tester.startPage(EventPage.class); + } + + @Test + public void testLoginPage() + { + tester.startPage(LoginPage.class); + } + + +}