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.rrt.jpa;
020    
021    import java.util.Collection;
022    import java.util.HashMap;
023    import java.util.List;
024    import java.util.Map;
025    
026    import javax.persistence.EntityManager;
027    import javax.persistence.EntityManagerFactory;
028    import javax.persistence.EntityTransaction;
029    import javax.persistence.PersistenceException;
030    import javax.persistence.PersistenceUnit;
031    
032    import org.apache.james.rrt.api.RecipientRewriteTableException;
033    import org.apache.james.rrt.jpa.model.JPARecipientRewrite;
034    import org.apache.james.rrt.lib.AbstractRecipientRewriteTable;
035    import org.apache.james.rrt.lib.RecipientRewriteTableUtil;
036    
037    /**
038     * Class responsible to implement the Virtual User Table in database with JPA
039     * access.
040     */
041    public class JPARecipientRewriteTable extends AbstractRecipientRewriteTable {
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        /**
059         * @throws RecipientRewriteTableException
060         * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#addMappingInternal(String, String, String)
061         */
062        protected void addMappingInternal(String user, String domain, String mapping) throws RecipientRewriteTableException {
063            String fixedUser = getFixedUser(user);
064            String fixedDomain = getFixedDomain(domain);
065            Collection<String> map = getUserDomainMappings(fixedUser, fixedDomain);
066            if (map != null && map.size() != 0) {
067                map.add(mapping);
068                doUpdateMapping(fixedUser, fixedDomain, RecipientRewriteTableUtil.CollectionToMapping(map));
069            } else {
070                doAddMapping(fixedUser, fixedDomain, mapping);
071            }
072        }
073    
074        /**
075         * @throws RecipientRewriteTableException
076         * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#mapAddressInternal(java.lang.String,
077         *      java.lang.String)
078         */
079        protected String mapAddressInternal(String user, String domain) throws RecipientRewriteTableException {
080            EntityManager entityManager = entityManagerFactory.createEntityManager();
081            final EntityTransaction transaction = entityManager.getTransaction();
082            try {
083                transaction.begin();
084                List<JPARecipientRewrite> virtualUsers = entityManager.createNamedQuery("selectMappings").setParameter("user", user).setParameter("domain", domain).getResultList();
085                transaction.commit();
086                if (virtualUsers.size() > 0) {
087                    return virtualUsers.get(0).getTargetAddress();
088                }
089            } catch (PersistenceException e) {
090                getLogger().debug("Failed to find mapping for  user=" + user + " and domain=" + domain, e);
091                if (transaction.isActive()) {
092                    transaction.rollback();
093                }
094                throw new RecipientRewriteTableException("Error while retrieve mappings", e);
095            } finally {
096                entityManager.close();
097            }
098            return null;
099        }
100    
101        /**
102         * @throws RecipientRewriteTableException
103         * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#mapAddress(java.lang.String, java.lang.String)
104         */
105        protected Collection<String> getUserDomainMappingsInternal(String user, String domain) throws RecipientRewriteTableException {
106            EntityManager entityManager = entityManagerFactory.createEntityManager();
107            final EntityTransaction transaction = entityManager.getTransaction();
108            try {
109                transaction.begin();
110                List<JPARecipientRewrite> virtualUsers = entityManager.createNamedQuery("selectUserDomainMapping").setParameter("user", user).setParameter("domain", domain).getResultList();
111                transaction.commit();
112                if (virtualUsers.size() > 0) {
113                    return RecipientRewriteTableUtil.mappingToCollection(virtualUsers.get(0).getTargetAddress());
114                }
115            } catch (PersistenceException e) {
116                getLogger().debug("Failed to get user domain mappings", e);
117                if (transaction.isActive()) {
118                    transaction.rollback();
119                }
120                throw new RecipientRewriteTableException("Error while retrieve mappings", e);
121    
122            } finally {
123                entityManager.close();
124            }
125            return null;
126        }
127    
128        /**
129         * @throws RecipientRewriteTableException
130         * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#getAllMappingsInternal()
131         */
132        protected Map<String, Collection<String>> getAllMappingsInternal() throws RecipientRewriteTableException {
133            EntityManager entityManager = entityManagerFactory.createEntityManager();
134            final EntityTransaction transaction = entityManager.getTransaction();
135            Map<String, Collection<String>> mapping = new HashMap<String, Collection<String>>();
136            try {
137                transaction.begin();
138                List<JPARecipientRewrite> virtualUsers = entityManager.createNamedQuery("selectAllMappings").getResultList();
139                transaction.commit();
140                for (JPARecipientRewrite virtualUser : virtualUsers) {
141                    mapping.put(virtualUser.getUser() + "@" + virtualUser.getDomain(), RecipientRewriteTableUtil.mappingToCollection(virtualUser.getTargetAddress()));
142                }
143                if (mapping.size() > 0)
144                    return mapping;
145            } catch (PersistenceException e) {
146                getLogger().debug("Failed to get all mappings", e);
147                if (transaction.isActive()) {
148                    transaction.rollback();
149                }
150                throw new RecipientRewriteTableException("Error while retrieve mappings", e);
151    
152            } finally {
153                entityManager.close();
154            }
155            return null;
156        }
157    
158        /**
159         * @throws RecipientRewriteTableException
160         * @see org.apache.james.rrt.lib.AbstractRecipientRewriteTable#removeMappingInternal(String, String, String)
161         */
162        protected void removeMappingInternal(String user, String domain, String mapping) throws RecipientRewriteTableException {
163            String fixedUser = getFixedUser(user);
164            String fixedDomain = getFixedDomain(domain);
165            Collection<String> map = getUserDomainMappings(fixedUser, fixedDomain);
166            if (map != null && map.size() > 1) {
167                map.remove(mapping);
168                doUpdateMapping(fixedUser, fixedDomain, RecipientRewriteTableUtil.CollectionToMapping(map));
169            } else {
170                doRemoveMapping(fixedUser, fixedDomain, mapping);
171            }
172        }
173    
174        /**
175         * Update the mapping for the given user and domain
176         * 
177         * @param user the user
178         * @param domain the domain
179         * @param mapping the mapping
180         * @return true if update was successfully
181         * @throws RecipientRewriteTableException
182         */
183        private boolean doUpdateMapping(String user, String domain, String mapping) throws RecipientRewriteTableException {
184            EntityManager entityManager = entityManagerFactory.createEntityManager();
185            final EntityTransaction transaction = entityManager.getTransaction();
186            try {
187                transaction.begin();
188                int updated = entityManager.createNamedQuery("updateMapping").setParameter("targetAddress", mapping).setParameter("user", user).setParameter("domain", domain).executeUpdate();
189                transaction.commit();
190                if (updated > 0) {
191                    return true;
192                }
193            } catch (PersistenceException e) {
194                getLogger().debug("Failed to update mapping", e);
195                if (transaction.isActive()) {
196                    transaction.rollback();
197                }
198                throw new RecipientRewriteTableException("Unable to update mapping", e);
199            } finally {
200                entityManager.close();
201            }
202            return false;
203        }
204    
205        /**
206         * Remove a mapping for the given user and domain
207         * 
208         * @param user the user
209         * @param domain the domain
210         * @param mapping the mapping
211         * @throws RecipientRewriteTableException
212         */
213        private void doRemoveMapping(String user, String domain, String mapping) throws RecipientRewriteTableException {
214            EntityManager entityManager = entityManagerFactory.createEntityManager();
215            final EntityTransaction transaction = entityManager.getTransaction();
216            try {
217                transaction.begin();
218                int deleted = entityManager.createNamedQuery("deleteMapping").setParameter("user", user).setParameter("domain", domain).setParameter("targetAddress", mapping).executeUpdate();
219                transaction.commit();
220    
221            } catch (PersistenceException e) {
222                getLogger().debug("Failed to remove mapping", e);
223                if (transaction.isActive()) {
224                    transaction.rollback();
225                }
226                throw new RecipientRewriteTableException("Unable to remove mapping", e);
227    
228            } finally {
229                entityManager.close();
230            }
231        }
232    
233        /**
234         * Add mapping for given user and domain
235         * 
236         * @param user the user
237         * @param domain the domain
238         * @param mapping the mapping
239         * @throws RecipientRewriteTableException
240         */
241        private void doAddMapping(String user, String domain, String mapping) throws RecipientRewriteTableException {
242            EntityManager entityManager = entityManagerFactory.createEntityManager();
243            final EntityTransaction transaction = entityManager.getTransaction();
244            try {
245                transaction.begin();
246                JPARecipientRewrite jpaRecipientRewrite = new JPARecipientRewrite(user, domain, mapping);
247                entityManager.persist(jpaRecipientRewrite);
248                transaction.commit();
249            } catch (PersistenceException e) {
250                getLogger().debug("Failed to save virtual user", e);
251                if (transaction.isActive()) {
252                    transaction.rollback();
253                }
254                throw new RecipientRewriteTableException("Unable to add mapping", e);
255            } finally {
256                entityManager.close();
257            }
258        }
259    
260    }