You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rd...@apache.org on 2008/11/12 20:34:18 UTC
svn commit: r713471 - in /james/server/trunk: ./ jpa-store/
jpa-store/src/main/java/org/apache/james/server/jpa/
jpa-store/src/test/java/org/ jpa-store/src/test/java/org/apache/
jpa-store/src/test/java/org/apache/james/ jpa-store/src/test/java/org/apac...
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;
+@Entity(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: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org