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.kernel.modeshape;
019
020import static com.google.common.reflect.Reflection.newProxy;
021
022import java.lang.reflect.InvocationTargetException;
023import java.lang.reflect.Method;
024
025import javax.jcr.Session;
026
027import org.fcrepo.kernel.api.TxSession;
028
029import com.google.common.reflect.AbstractInvocationHandler;
030
031/**
032 * A dynamic proxy that wraps JCR sessions. It is aware of fcrepo transactions,
033 * and turns mutating methods (e.g. logout, session) into no-ops. Those no-op'ed
034 * methods should be called from the Transaction level instead.
035 *
036 * @author awoods
037 */
038public class TxAwareSession extends AbstractInvocationHandler {
039
040    private final String txId;
041
042    private final Session session;
043
044    /**
045     * @param session a JCR session
046     * @param txID the transaction identifier
047     */
048    public TxAwareSession(final Session session, final String txID) {
049        this.session = session;
050        this.txId = txID;
051    }
052
053    /**
054     * Wrap a JCR session with this dynamic proxy
055     *
056     * @param session a JCR session
057     * @param txId the transaction identifier
058     * @return a wrapped JCR session
059     */
060    public static Session newInstance(final Session session, final String txId) {
061        return newProxy(TxSession.class, new TxAwareSession(session, txId));
062    }
063
064    @Override
065    protected Object handleInvocation(final Object proxy, final Method method, 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}