Hi Robert, shouldn't the equals(Object) and hashCode() method get overridden in JPAUser to check for the right properties ?
Cheers, Norman Maurer 2008/11/12 <[EMAIL PROTECTED]> > Author: rdonkin > Date: Wed Nov 12 11:34:18 2008 > New Revision: 713471 > > URL: http://svn.apache.org/viewvc?rev=713471&view=rev > Log: > Basic proof of concept implementation. More work needed. > > Added: > james/server/trunk/jpa-store/src/test/java/org/ > james/server/trunk/jpa-store/src/test/java/org/apache/ > james/server/trunk/jpa-store/src/test/java/org/apache/james/ > james/server/trunk/jpa-store/src/test/java/org/apache/james/server/ > james/server/trunk/jpa-store/src/test/java/org/apache/james/server/jpa/ > > > james/server/trunk/jpa-store/src/test/java/org/apache/james/server/jpa/JpaUsersRepositoryTest.java > Modified: > james/server/trunk/include.properties > james/server/trunk/jpa-store/build.xml > > > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUser.java > > > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUsersRepository.java > > Modified: james/server/trunk/include.properties > URL: > http://svn.apache.org/viewvc/james/server/trunk/include.properties?rev=713471&r1=713470&r2=713471&view=diff > > ============================================================================== > --- james/server/trunk/include.properties (original) > +++ james/server/trunk/include.properties Wed Nov 12 11:34:18 2008 > @@ -330,8 +330,8 @@ > > > # ------ JPA -------------------------- > -jta-spec.jar=${path.lib.geronimo.specs}/geronimo-jta_1.1_spec-1.1 > -jpa-spec.jar=${path.lib.geronimo.specs}/geronimo-jpa_3.0_spec-1.0 > +jta-spec.jar=${path.lib.geronimo.specs}/geronimo-jta_1.1_spec-1.1.jar > +jpa-spec.jar=${path.lib.geronimo.specs}/geronimo-jpa_3.0_spec-1.0.jar > > # ------ OpenJPA ---------------------- > serp.jar=${path.lib.serp}/serp-1.13.1.jar > > Modified: james/server/trunk/jpa-store/build.xml > URL: > http://svn.apache.org/viewvc/james/server/trunk/jpa-store/build.xml?rev=713471&r1=713470&r2=713471&view=diff > > ============================================================================== > --- james/server/trunk/jpa-store/build.xml (original) > +++ james/server/trunk/jpa-store/build.xml Wed Nov 12 11:34:18 2008 > @@ -1,6 +1,57 @@ > <?xml version="1.0" encoding="UTF-8"?> > +<!-- > + 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. > +--> > <project default="main" name="jpa-store"> > <description>Builds jpa-function module. This is an function > module.</description> > <property name="name.module" value="jpa-store" /> > <import file="../build-tools/function-build.xml" optional="no" /> > + > + <target > + name='build' > + description='Builds without cleaning' > + depends='check-environment, conditional-clean, set-classpath' > + unless='dont.build.module'> > + <echo>Building ${name.module}</echo> > + <CompileMainSource/> > + <path id='path.enhance.jpa'> > + <path refid='classpath.base'/> > + <path refid='classpath.openjpa.repo'/> > + </path> > + > + <taskdef > + name="openjpac" > + classname="org.apache.openjpa.ant.PCEnhancerTask" > + classpathref="path.enhance.jpa"/> > + > + <openjpac> > + <fileset dir="${dir.src.java}"> > + <include name="org/apache/james/jpa/**/*.java" /> > + </fileset> > + <classpath> > + <path refid='classpath.main'/> > + <path refid='classpath.openjpa.repo'/> > + <pathelement location="${dir.src.java}"/> > + <pathelement location="${dir.build.bin}"/> > + </classpath> > + <config > + log="TOOL=TRACE" > + > metaDataFactory="jpa(Types=org.apache.james.server.jpa.JPAUser)"/> > + </openjpac> > + </target> > </project> > > Modified: > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUser.java > URL: > http://svn.apache.org/viewvc/james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUser.java?rev=713471&r1=713470&r2=713471&view=diff > > ============================================================================== > --- > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUser.java > (original) > +++ > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUser.java > Wed Nov 12 11:34:18 2008 > @@ -19,22 +19,89 @@ > > package org.apache.james.server.jpa; > > +import javax.persistence.Basic; > +import javax.persistence.Entity; > +import javax.persistence.Id; > +import javax.persistence.Version; > + > +import org.apache.jackrabbit.util.Text; > import org.apache.james.api.user.User; > > [EMAIL PROTECTED](name="User") > public class JPAUser implements User { > > + /** > + * Static salt for hashing password. > + * Modifying this value will render all passwords unrecognizable. > + */ > + public static final String SALT = "JPAUsersRepository"; > + > + /** > + * Hashes salted password. > + * @param username not null > + * @param password not null > + * @return not null > + */ > + public static String hashPassword(String username, String password) { > + // Combine dynamic and static salt > + final String hashedSaltedPassword = Text.md5(Text.md5(username + > password) + SALT); > + return hashedSaltedPassword; > + } > > + /** Prevents concurrent modification */ > + @SuppressWarnings("unused") > + @Version > + private int version; > > + /** Key by user name */ > + @Id > + private String name; > + /** Hashed password */ > + @Basic > + private String password; > + > + protected JPAUser() {} > + > + public JPAUser(final String userName, String password) { > + super(); > + this.name = userName; > + this.password = hashPassword(userName, password); > + } > + > public String getUserName() { > - return null; > + return name; > + } > + > + /** > + * Gets salted, hashed password. > + * @return the hashedSaltedPassword > + */ > + public final String getHashedSaltedPassword() { > + return password; > } > > public boolean setPassword(String newPass) { > - return false; > + final boolean result; > + if (newPass == null) { > + result = false; > + } else { > + password = hashPassword(name, newPass); > + result = true; > + } > + return result; > } > > public boolean verifyPassword(String pass) { > - return false; > + final boolean result; > + if (pass == null) { > + result = password == null; > + } else if (password == null) { > + result = false; > + } else { > + result = password.equals(hashPassword(name, pass)); > + } > + return result; > } > - > + > + > } > > Modified: > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUsersRepository.java > URL: > http://svn.apache.org/viewvc/james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUsersRepository.java?rev=713471&r1=713470&r2=713471&view=diff > > ============================================================================== > --- > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUsersRepository.java > (original) > +++ > james/server/trunk/jpa-store/src/main/java/org/apache/james/server/jpa/JPAUsersRepository.java > Wed Nov 12 11:34:18 2008 > @@ -19,13 +19,80 @@ > > package org.apache.james.server.jpa; > > +import java.util.Collections; > import java.util.Iterator; > +import java.util.List; > > +import javax.persistence.EntityManager; > +import javax.persistence.EntityTransaction; > +import javax.persistence.PersistenceException; > + > +import org.apache.commons.logging.Log; > +import org.apache.commons.logging.LogFactory; > import org.apache.james.api.user.User; > import org.apache.james.api.user.UsersRepository; > > +/** > + * Proof-of-concept repository using JPA. > + * TODO: Support managed contexts. > + * TODO: Use factory and support pooled contexts > + */ > public class JPAUsersRepository implements UsersRepository { > > + private static final Log LOGGER = > LogFactory.getLog(JPAUsersRepository.class); > + > + private Log logger = LOGGER; > + > + private EntityManager entityManager; > + > + /** > + * Constructs repository with injection. > + * @param entityManager not null > + */ > + public JPAUsersRepository(EntityManager entityManager) { > + super(); > + this.entityManager = entityManager; > + } > + > + /** > + * Constructor for setting injection. > + */ > + public JPAUsersRepository() { > + this(null); > + } > + > + /** > + * Gets current logger. > + * @return the logger > + */ > + public final Log getLogger() { > + return logger; > + } > + > + /** > + * Setter injection for logging. > + * @param logger the logger to set > + */ > + public final void setLogger(Log logger) { > + this.logger = logger; > + } > + > + /** > + * Gets entity manager. > + * @return the entityManager > + */ > + public final EntityManager getEntityManager() { > + return entityManager; > + } > + > + /** > + * Sets entity manager. > + * @param entityManager the entityManager to set > + */ > + public final void setEntityManager(EntityManager entityManager) { > + this.entityManager = entityManager; > + } > + > /** > * Adds a user to the repository with the specified User object. > * > @@ -39,7 +106,7 @@ > * implementations of users object. > */ > public boolean addUser(User user) { > - return false; > + throw new UnsupportedOperationException(); > } > > /** > @@ -53,9 +120,9 @@ > * eventually modified by retrieving it later. > */ > public void addUser(String name, Object attributes) { > - > + throw new UnsupportedOperationException(); > } > - > + > /** > * Adds a user to the repository with the specified password > * > @@ -66,6 +133,19 @@ > * @since James 2.3.0 > */ > public boolean addUser(String username, String password) { > + final EntityTransaction transaction = > entityManager.getTransaction(); > + try { > + transaction.begin(); > + JPAUser user = new JPAUser(username, password); > + entityManager.persist(user); > + transaction.commit(); > + return true; > + } catch (PersistenceException e) { > + logger.debug("Failed to save user", e); > + if (transaction.isActive()) { > + transaction.rollback(); > + } > + } > return false; > } > > @@ -79,7 +159,19 @@ > * @since James 1.2.2 > */ > public User getUserByName(String name) { > - return new JPAUser(); > + return getJPAUserByName(name); > + } > + > + private JPAUser getJPAUserByName(String name) { > + try > + { > + return (JPAUser) entityManager.createQuery("SELECT user FROM > User user WHERE user.name=?1") > + .setParameter(1, name) > + .getSingleResult(); > + } catch (PersistenceException e) { > + logger.debug("Failed to find user", e); > + return null; > + } > } > > /** > @@ -94,7 +186,7 @@ > * implementations and the getUserByName will search according to this > property. > */ > public User getUserByNameCaseInsensitive(String name) { > - return new JPAUser(); > + throw new UnsupportedOperationException(); > } > > /** > @@ -115,6 +207,23 @@ > * @return true if successful. > */ > public boolean updateUser(User user) { > + final EntityTransaction transaction = > entityManager.getTransaction(); > + try { > + if (contains(user.getUserName())) { > + transaction.begin(); > + entityManager.merge(user); > + transaction.commit(); > + } else { > + logger.debug("User not found"); > + return false; > + } > + } catch (PersistenceException e) { > + logger.debug("Failed to update user", e); > + if (transaction.isActive()) { > + transaction.rollback(); > + } > + return false; > + } > return true; > } > > @@ -124,7 +233,18 @@ > * @param name the user to remove from the repository > */ > public void removeUser(String name) { > - > + final EntityTransaction transaction = > entityManager.getTransaction(); > + try { > + transaction.begin(); > + JPAUser user = getJPAUserByName(name); > + entityManager.remove(user); > + transaction.commit(); > + } catch (PersistenceException e) { > + logger.debug("Failed to save user", e); > + if (transaction.isActive()) { > + transaction.rollback(); > + } > + } > } > > /** > @@ -134,7 +254,15 @@ > * @return whether the user is in the repository > */ > public boolean contains(String name) { > - return false; > + try > + { > + return ((Long) entityManager.createQuery("SELECT COUNT(user) > FROM User user WHERE user.name=?1") > + .setParameter(1, name) > + .getSingleResult()).longValue() > 0; > + } catch (PersistenceException e) { > + logger.debug("Failed to find user", e); > + return false; > + } > } > > /** > @@ -148,7 +276,7 @@ > * implementations and the contains will search according to this > property. > */ > public boolean containsCaseInsensitive(String name) { > - return false; > + throw new UnsupportedOperationException(); > } > > /** > @@ -163,7 +291,17 @@ > * @since James 1.2.2 > */ > public boolean test(String name, String password) { > - return false; > + final JPAUser user = getJPAUserByName(name); > + final boolean result; > + if (user == null) > + { > + result = false; > + } > + else > + { > + result = user.verifyPassword(password); > + } > + return result; > } > > /** > @@ -172,7 +310,14 @@ > * @return the number of users in the repository > */ > public int countUsers() { > - return 0; > + try > + { > + return ((Long) entityManager.createQuery("SELECT COUNT(user) > FROM User user") > + .getSingleResult()).intValue(); > + } catch (PersistenceException e) { > + logger.debug("Failed to find user", e); > + return 0; > + } > } > > /** > @@ -181,8 +326,28 @@ > * @return Iterator over a collection of Strings, each being one user > in the repository. > */ > public Iterator list() { > - return null; > + try > + { > + final List results = entityManager.createQuery("SELECT user > FROM User user").getResultList(); > + return new Iterator() { > + private final Iterator it = results.iterator(); > + public boolean hasNext() { > + return it.hasNext(); > + } > + > + public Object next() { > + return ((JPAUser)it.next()).getUserName(); > + } > + > + public void remove() { > + throw new UnsupportedOperationException(); > + } > + }; > + } catch (PersistenceException e) { > + logger.debug("Failed to find user", e); > + return Collections.EMPTY_LIST.iterator(); > + } > } > - > + > > } > > Added: > james/server/trunk/jpa-store/src/test/java/org/apache/james/server/jpa/JpaUsersRepositoryTest.java > URL: > http://svn.apache.org/viewvc/james/server/trunk/jpa-store/src/test/java/org/apache/james/server/jpa/JpaUsersRepositoryTest.java?rev=713471&view=auto > > ============================================================================== > --- > james/server/trunk/jpa-store/src/test/java/org/apache/james/server/jpa/JpaUsersRepositoryTest.java > (added) > +++ > james/server/trunk/jpa-store/src/test/java/org/apache/james/server/jpa/JpaUsersRepositoryTest.java > Wed Nov 12 11:34:18 2008 > @@ -0,0 +1,85 @@ > +/**************************************************************** > + * 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. * > + ****************************************************************/ > + > +package org.apache.james.server.jpa; > + > +import java.util.HashMap; > + > +import javax.persistence.PersistenceException; > + > +import org.apache.james.api.user.UsersRepository; > +import org.apache.james.userrepository.MockUsersRepositoryTest; > +import org.apache.openjpa.persistence.OpenJPAEntityManager; > +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory; > +import org.apache.openjpa.persistence.OpenJPAEntityTransaction; > +import org.apache.openjpa.persistence.OpenJPAPersistence; > + > +public class JpaUsersRepositoryTest extends MockUsersRepositoryTest { > + > + private HashMap<String, String> properties; > + private OpenJPAEntityManagerFactory factory; > + private OpenJPAEntityManager manager; > + > + @Override > + protected void setUp() throws Exception { > + properties = new HashMap<String, String>(); > + properties.put("openjpa.ConnectionDriverName", "org.h2.Driver"); > + properties.put("openjpa.ConnectionURL", > "jdbc:h2:target/users/db"); > + properties.put("openjpa.Log", "JDBC=WARN, SQL=WARN, > Runtime=WARN"); > + properties.put("openjpa.ConnectionFactoryProperties", > "PrettyPrint=true, PrettyPrintLineLength=72"); > + properties.put("openjpa.jdbc.SynchronizeMappings", > "buildSchema(ForeignKeys=true)"); > + properties.put("openjpa.MetaDataFactory", > "jpa(Types=org.apache.james.server.jpa.JPAUser)"); > + super.setUp(); > + deleteAll(); > + } > + > + @Override > + protected void tearDown() throws Exception { > + deleteAll(); > + super.tearDown(); > + if (manager != null) > + { > + manager.close(); > + } > + if (factory != null) > + { > + factory.close(); > + } > + } > + > + private void deleteAll() { > + try > + { > + OpenJPAEntityManager manager = factory.createEntityManager(); > + final OpenJPAEntityTransaction transaction = > manager.getTransaction(); > + transaction.begin(); > + manager.createQuery("DELETE FROM User user").executeUpdate(); > + transaction.commit(); > + } catch (PersistenceException e) { > + e.printStackTrace(); > + } > + } > + > + protected UsersRepository getUsersRepository() throws Exception > + { > + factory = OpenJPAPersistence.getEntityManagerFactory(properties); > + manager = factory.createEntityManager(); > + return new JPAUsersRepository(manager); > + } > +} > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > >