001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    package org.apache.james.domainlist.jpa;
020    
021    import java.util.ArrayList;
022    import java.util.List;
023    
024    import javax.annotation.PostConstruct;
025    import javax.persistence.EntityManager;
026    import javax.persistence.EntityManagerFactory;
027    import javax.persistence.EntityTransaction;
028    import javax.persistence.NoResultException;
029    import javax.persistence.PersistenceException;
030    import javax.persistence.PersistenceUnit;
031    
032    import org.apache.james.domainlist.api.DomainListException;
033    import org.apache.james.domainlist.jpa.model.JPADomain;
034    import org.apache.james.domainlist.lib.AbstractDomainList;
035    
036    /**
037     * JPA implementation of the DomainList.<br>
038     * This implementation is compatible with the JDBCDomainList, meaning same
039     * database schema can be reused.
040     */
041    public class JPADomainList extends AbstractDomainList {
042    
043        /**
044         * The entity manager to access the database.
045         */
046        private EntityManagerFactory entityManagerFactory;
047    
048        /**
049         * Set the entity manager to use.
050         * 
051         * @param entityManagerFactory
052         */
053        @PersistenceUnit
054        public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
055            this.entityManagerFactory = entityManagerFactory;
056        }
057    
058        @PostConstruct
059        public void init() {
060            createEntityManager().close();
061        }
062    
063        /**
064         * @see
065         * org.apache.james.domainlist.lib.AbstractDomainList#getDomainListInternal()
066         */
067        @SuppressWarnings("unchecked")
068        protected List<String> getDomainListInternal() throws DomainListException {
069            List<String> domains = new ArrayList<String>();
070            EntityManager entityManager = entityManagerFactory.createEntityManager();
071            final EntityTransaction transaction = entityManager.getTransaction();
072            try {
073                transaction.begin();
074                domains = entityManager.createNamedQuery("listDomainNames").getResultList();
075                transaction.commit();
076            } catch (PersistenceException e) {
077                getLogger().error("Failed to list domains", e);
078                if (transaction.isActive()) {
079                    transaction.rollback();
080                }
081                throw new DomainListException("Unable to retrieve domains", e);
082            } finally {
083                entityManager.close();
084            }
085            if (domains.size() == 0) {
086                return null;
087            } else {
088                return new ArrayList<String>(domains);
089            }
090        }
091    
092        /**
093         * @see org.apache.james.domainlist.api.DomainList#containsDomain(java.lang.String)
094         */
095        public boolean containsDomain(String domain) throws DomainListException {
096            EntityManager entityManager = entityManagerFactory.createEntityManager();
097            final EntityTransaction transaction = entityManager.getTransaction();
098            try {
099                transaction.begin();
100                JPADomain jpaDomain = (JPADomain) entityManager.createNamedQuery("findDomainByName").setParameter("name", domain).getSingleResult();
101                transaction.commit();
102                return (jpaDomain != null) ? true : false;
103            } catch (NoResultException e) {
104                getLogger().debug("No domain found", e);
105                transaction.commit();
106                return false;
107            } catch (PersistenceException e) {
108                getLogger().error("Failed to find domain", e);
109                if (transaction.isActive()) {
110                    transaction.rollback();
111                }
112                throw new DomainListException("Unable to retrieve domains", e);
113            } finally {
114                entityManager.close();
115            }
116        }
117    
118        /**
119         * @see
120         * org.apache.james.domainlist.api.DomainList#addDomain(java.lang.String)
121         */
122        public void addDomain(String domain) throws DomainListException {
123            String lowerCasedDomain = domain.toLowerCase();
124            if (containsDomain(lowerCasedDomain)) {
125                throw new DomainListException(lowerCasedDomain + " already exists.");
126            }
127            EntityManager entityManager = entityManagerFactory.createEntityManager();
128            final EntityTransaction transaction = entityManager.getTransaction();
129            try {
130                transaction.begin();
131                JPADomain jpaDomain = new JPADomain(lowerCasedDomain);
132                entityManager.persist(jpaDomain);
133                transaction.commit();
134            } catch (PersistenceException e) {
135                getLogger().error("Failed to save domain", e);
136                if (transaction.isActive()) {
137                    transaction.rollback();
138                }
139                throw new DomainListException("Unable to add domain " + domain, e);
140            } finally {
141                entityManager.close();
142            }
143        }
144    
145        /**
146         * @see
147         * org.apache.james.domainlist.api.DomainList#removeDomain(java.lang.String)
148         */
149        public void removeDomain(String domain) throws DomainListException {
150            EntityManager entityManager = entityManagerFactory.createEntityManager();
151            final EntityTransaction transaction = entityManager.getTransaction();
152            try {
153                transaction.begin();
154                entityManager.createNamedQuery("deleteDomainByName").setParameter("name", domain).executeUpdate();
155                transaction.commit();
156            } catch (PersistenceException e) {
157                getLogger().error("Failed to remove domain", e);
158                if (transaction.isActive()) {
159                    transaction.rollback();
160                }
161                throw new DomainListException("Unable to remove domain " + domain, e);
162    
163            } finally {
164                entityManager.close();
165            }
166        }
167    
168        /**
169         * Return a new {@link EntityManager} instance
170         * 
171         * @return manager
172         */
173        private EntityManager createEntityManager() {
174            return entityManagerFactory.createEntityManager();
175        }
176    
177    }