001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.camel;
017
018import static org.slf4j.LoggerFactory.getLogger;
019
020import java.io.InputStream;
021import java.net.URI;
022
023import org.fcrepo.client.FcrepoClient;
024import org.fcrepo.client.FcrepoOperationFailedException;
025import org.fcrepo.client.FcrepoResponse;
026import org.slf4j.Logger;
027import org.springframework.transaction.CannotCreateTransactionException;
028import org.springframework.transaction.TransactionDefinition;
029import org.springframework.transaction.TransactionSystemException;
030import org.springframework.transaction.support.AbstractPlatformTransactionManager;
031import org.springframework.transaction.support.DefaultTransactionStatus;
032
033/**
034 * A Transaction Manager for interacting with fedora-based transactions
035 *
036 * @author Aaron Coburn
037 * @since Feb 16, 2015
038 */
039public class FcrepoTransactionManager extends AbstractPlatformTransactionManager {
040
041    private FcrepoClient client;
042
043    private String baseUrl;
044
045    private String authUsername;
046
047    private String authPassword;
048
049    private String authHost;
050
051    private static final Logger LOGGER = getLogger(FcrepoTransactionManager.class);
052
053    /**
054     * Create a FcrepoTransactionManager
055     */
056    public FcrepoTransactionManager() {
057        super();
058        setNestedTransactionAllowed(false);
059    }
060
061    /**
062     * Set the baseUrl for the transaction manager.
063     *
064     * @param baseUrl the fcrepo base url
065     */
066    public void setBaseUrl(final String baseUrl) {
067        this.baseUrl = baseUrl;
068    }
069
070    /**
071     * Get the base url for the transaction manager.
072     *
073     * @return the fcrepo base url
074     */
075    public String getBaseUrl() {
076        return baseUrl;
077    }
078
079    /**
080     * Set the authUsername for the transaction manager.
081     *
082     * @param authUsername the username for authentication
083     */
084    public void setAuthUsername(final String authUsername) {
085        this.authUsername = authUsername;
086    }
087
088    /**
089     * Get the authUsername for the transaction manager.
090     *
091     * @return the username for authentication
092     */
093    public String getAuthUsername() {
094        return authUsername;
095    }
096
097    /**
098     * Set the authPassword for the transaction manager.
099     *
100     * @param authPassword the password used for authentication
101     */
102    public void setAuthPassword(final String authPassword) {
103        this.authPassword = authPassword;
104    }
105
106    /**
107     * Get the authPassword for the transaction manager.
108     *
109     * @return the password used for authentication
110     */
111    public String getAuthPassword() {
112        return authPassword;
113    }
114
115    /**
116     * Set the authHost for the transaction manager.
117     *
118     * @param authHost the host realm used for authentication
119     */
120    public void setAuthHost(final String authHost) {
121        this.authHost = authHost;
122    }
123
124    /**
125     * Get the authHost for the transaction manager.
126     *
127     * @return the host realm used for authentication
128     */
129    public String getAuthHost() {
130        return authHost;
131    }
132
133    @Override
134    protected void doBegin(final Object transaction, final TransactionDefinition definition) {
135        final FcrepoResponse response;
136        final InputStream is = null;
137        final String contentType = null;
138        final FcrepoTransactionObject tx = (FcrepoTransactionObject)transaction;
139
140        if (tx.getSessionId() == null) {
141            try {
142                response = getClient().post(URI.create(baseUrl + FcrepoConstants.TRANSACTION), is, contentType);
143            } catch (FcrepoOperationFailedException ex) {
144                LOGGER.debug("HTTP Operation failed: ", ex);
145                throw new CannotCreateTransactionException("Could not create fcrepo transaction");
146            }
147
148            if (response != null && response.getLocation() != null) {
149                tx.setSessionId(response.getLocation().toString().substring(baseUrl.length() + 1));
150            } else {
151                throw new CannotCreateTransactionException("Invalid response while creating transaction");
152            }
153        }
154    }
155
156    @Override
157    protected void doCommit(final DefaultTransactionStatus status) {
158        final FcrepoTransactionObject tx = (FcrepoTransactionObject)status.getTransaction();
159        final InputStream is = null;
160        final String contentType = null;
161
162        try {
163            getClient().post(URI.create(baseUrl + "/" + tx.getSessionId() + FcrepoConstants.COMMIT), is, contentType);
164        } catch (FcrepoOperationFailedException ex) {
165            LOGGER.debug("Transaction commit failed: ", ex);
166            throw new TransactionSystemException("Could not commit fcrepo transaction");
167        } finally {
168            tx.setSessionId(null);
169        }
170    }
171
172    @Override
173    protected void doRollback(final DefaultTransactionStatus status) {
174        final FcrepoTransactionObject tx = (FcrepoTransactionObject)status.getTransaction();
175
176        try {
177            getClient().post(URI.create(baseUrl + "/" + tx.getSessionId() + FcrepoConstants.ROLLBACK), null, null);
178        } catch (FcrepoOperationFailedException ex) {
179            LOGGER.debug("Transaction rollback failed: ", ex);
180            throw new TransactionSystemException("Could not rollback fcrepo transaction");
181        } finally {
182            tx.setSessionId(null);
183        }
184    }
185
186    @Override
187    protected Object doGetTransaction() {
188        return new FcrepoTransactionObject();
189    }
190
191    private FcrepoClient getClient() {
192        final Boolean throwExceptionOnFailure = true;
193
194        if (client == null) {
195            client = new FcrepoClient(
196                    authUsername,
197                    authPassword,
198                    authHost,
199                    throwExceptionOnFailure);
200        }
201        return client;
202    }
203}