001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.processor.idempotent.jpa;
018    
019    import java.util.List;
020    import javax.persistence.EntityManagerFactory;
021    import javax.persistence.Persistence;
022    
023    import org.apache.camel.spi.IdempotentRepository;
024    import org.springframework.orm.jpa.JpaTemplate;
025    import org.springframework.orm.jpa.JpaTransactionManager;
026    import org.springframework.transaction.TransactionDefinition;
027    import org.springframework.transaction.TransactionStatus;
028    import org.springframework.transaction.support.TransactionCallback;
029    import org.springframework.transaction.support.TransactionTemplate;
030    
031    /**
032     * @version $Revision: 782534 $
033     */
034    public class JpaMessageIdRepository implements IdempotentRepository<String> {
035        protected static final String QUERY_STRING = "select x from " + MessageProcessed.class.getName() + " x where x.processorName = ?1 and x.messageId = ?2";
036        private JpaTemplate jpaTemplate;
037        private String processorName;
038        private TransactionTemplate transactionTemplate;
039    
040        public JpaMessageIdRepository(JpaTemplate template, String processorName) {
041            this(template, createTransactionTemplate(template), processorName);
042        }
043    
044        public JpaMessageIdRepository(JpaTemplate template, TransactionTemplate transactionTemplate, String processorName) {
045            this.jpaTemplate = template;
046            this.processorName = processorName;
047            this.transactionTemplate = transactionTemplate;
048        }
049    
050        public static JpaMessageIdRepository jpaMessageIdRepository(String persistenceUnit, String processorName) {
051            EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnit);
052            return jpaMessageIdRepository(new JpaTemplate(entityManagerFactory), processorName);
053        }
054    
055        public static JpaMessageIdRepository jpaMessageIdRepository(JpaTemplate jpaTemplate, String processorName) {
056            return new JpaMessageIdRepository(jpaTemplate, processorName);
057        }
058    
059        private static TransactionTemplate createTransactionTemplate(JpaTemplate jpaTemplate) {
060            TransactionTemplate transactionTemplate = new TransactionTemplate();
061            transactionTemplate.setTransactionManager(new JpaTransactionManager(jpaTemplate.getEntityManagerFactory()));
062            transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
063            return transactionTemplate;
064        }
065    
066        public boolean add(final String messageId) {
067            // Run this in single transaction.
068            Boolean rc = (Boolean)transactionTemplate.execute(new TransactionCallback() {
069                public Object doInTransaction(TransactionStatus arg0) {
070                    List list = jpaTemplate.find(QUERY_STRING, processorName, messageId);
071                    if (list.isEmpty()) {
072                        MessageProcessed processed = new MessageProcessed();
073                        processed.setProcessorName(processorName);
074                        processed.setMessageId(messageId);
075                        jpaTemplate.persist(processed);
076                        jpaTemplate.flush();
077                        return Boolean.TRUE;
078                    } else {
079                        return Boolean.FALSE;
080                    }
081                }
082            });
083            return rc.booleanValue();
084        }
085    
086        public boolean contains(final String messageId) {
087            // Run this in single transaction.
088            Boolean rc = (Boolean)transactionTemplate.execute(new TransactionCallback() {
089                public Object doInTransaction(TransactionStatus arg0) {
090                    List list = jpaTemplate.find(QUERY_STRING, processorName, messageId);
091                    if (list.isEmpty()) {
092                        return Boolean.FALSE;
093                    } else {
094                        return Boolean.TRUE;
095                    }
096                }
097            });
098            return rc.booleanValue();
099        }
100    
101        public boolean remove(final String messageId) {
102            Boolean rc = (Boolean)transactionTemplate.execute(new TransactionCallback() {
103                public Object doInTransaction(TransactionStatus arg0) {
104                    List list = jpaTemplate.find(QUERY_STRING, processorName, messageId);
105                    if (list.isEmpty()) {
106                        return Boolean.FALSE;
107                    } else {
108                        MessageProcessed processoed = (MessageProcessed) list.get(0);
109                        jpaTemplate.remove(processoed);
110                        jpaTemplate.flush();
111                        return Boolean.TRUE;
112                    }
113                }
114            });
115            return rc.booleanValue();
116        }
117    
118        public boolean confirm(String s) {
119            // noop
120            return true;
121        }
122    
123    }