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.kernel.impl;
017
018import org.fcrepo.kernel.TxSession;
019
020import static java.lang.reflect.Proxy.newProxyInstance;
021
022import java.lang.reflect.InvocationHandler;
023import java.lang.reflect.InvocationTargetException;
024import java.lang.reflect.Method;
025
026import javax.jcr.Session;
027
028/**
029 * A dynamic proxy that wraps JCR sessions. It is aware of fcrepo transactions,
030 * and turns mutating methods (e.g. logout, session) into no-ops. Those no-op'ed
031 * methods should be called from the Transaction level instead.
032 *
033 * @author awoods
034 */
035public class TxAwareSession implements InvocationHandler {
036
037    private final String txId;
038
039    private final Session session;
040
041    /**
042     * @param session a JCR session
043     * @param txID the transaction identifier
044     */
045    public TxAwareSession(final Session session, final String txID) {
046        this.session = session;
047        this.txId = txID;
048    }
049
050    /**
051     * Wrap a JCR session with this dynamic proxy
052     *
053     * @param session a JCR session
054     * @param txId the transaction identifier
055     * @return a wrapped JCR session
056     */
057    public static Session newInstance(final Session session, final String txId) {
058        return (Session) newProxyInstance(session.getClass().getClassLoader(),
059                new Class[] {TxSession.class},
060                new TxAwareSession(session, txId));
061    }
062
063    @Override
064    public Object invoke(final Object proxy, final Method method,
065            final Object[] args) throws Throwable {
066        final String name = method.getName();
067        if (name.equals("logout") || name.equals("save")) {
068            return null;
069        } else if (name.equals("getTxId")) {
070            return txId;
071        } else {
072            final Object invocationResult;
073            try {
074                invocationResult = method.invoke(session, args);
075            } catch (final InvocationTargetException e) {
076                throw e.getCause();
077            }
078            if (name.equals("impersonate")) {
079                return newInstance((Session) invocationResult, txId);
080            }
081            return invocationResult;
082        }
083    }
084}