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