Package org.apache.felix.ipojo.transaction

Source Code of org.apache.felix.ipojo.transaction.TransactionHandler

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.felix.ipojo.transaction;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;

import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.PrimitiveHandler;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.parser.FieldMetadata;
import org.apache.felix.ipojo.parser.MethodMetadata;
import org.apache.felix.ipojo.parser.ParseUtils;
import org.apache.felix.ipojo.util.Callback;

public class TransactionHandler extends PrimitiveHandler implements Synchronization {

    public static final String NAMESPACE= "org.apache.felix.ipojo.transaction";

    public static final String NAME= "transaction";

    private static final String FIELD_ATTRIBUTE= "field";

    private static final String ONCOMMIT_ATTRIBUTE= "oncommit";

    private static final String ONROLLBACK_ATTRIBUTE= "onrollback";

    private static final String TRANSACTIONAL_ELEMENT = "transactional";

    private static final String METHOD_ATTRIBUTE = "method";

    private static final String TIMEOUT_ATTRIBUTE = "timeout";

    private static final String PROPAGATION_ATTRIBUTE = "propagation";

    private static final String EXCEPTIONONROLLBACK_ATTRIBUTE = "exceptiononrollback";

    private static final String NOROLLBACKFOR_ATTRIBUTE = "norollbackfor";

    public static final int DEFAULT_PROPAGATION = TransactionalMethod.REQUIRES;


    private TransactionManager m_transactionManager; // Service Dependency

    private List<TransactionalMethod> m_methods = new ArrayList<TransactionalMethod>();

    private Callback m_onRollback;

    private Callback m_onCommit;

    private List<Transaction> m_transactions = new ArrayList<Transaction>();


    public void configure(Element arg0, Dictionary arg1)
            throws ConfigurationException {
        Element[] elements = arg0.getElements(NAME, NAMESPACE);
        if (elements.length > 1) {
            throw new ConfigurationException("The handler " + NAMESPACE + ":" + NAME + " cannot be declared several times");
        }

        String field = elements[0].getAttribute(FIELD_ATTRIBUTE);
        if (field != null) {
            FieldMetadata meta = getPojoMetadata().getField(field);
            if (meta == null) {
                throw new ConfigurationException("The transaction field does not exist in the pojo class : " + field);
            }
            if (! meta.getFieldType().equals(Transaction.class.getName())) {
                throw new ConfigurationException("The transaction field type must be " + Transaction.class.getName());
            }
            // Register the interceptor
            getInstanceManager().register(meta, this);

        }

        String oncommit = elements[0].getAttribute(ONCOMMIT_ATTRIBUTE);
        if (oncommit != null) {
            m_onCommit = new Callback(oncommit, new String[] { Transaction.class.getName() }, false, getInstanceManager());
        }

        String onrollback = elements[0].getAttribute(ONROLLBACK_ATTRIBUTE);
        if (onrollback != null) {
            m_onRollback = new Callback(onrollback, new String[] { Transaction.class.getName() }, false, getInstanceManager());
        }


        Element[] sub = elements[0].getElements(TRANSACTIONAL_ELEMENT);
        if (sub == null  || sub.length == 0) {
            throw new ConfigurationException("The handler " + NAMESPACE + ":" + NAME + " must have " + TRANSACTIONAL_ELEMENT + " subelement");
        }

        for (int i = 0; i < sub.length; i++) {
            String method = sub[i].getAttribute(METHOD_ATTRIBUTE);
            String to = sub[i].getAttribute(TIMEOUT_ATTRIBUTE);
            String propa = sub[i].getAttribute(PROPAGATION_ATTRIBUTE);
            String nrbf = sub[i].getAttribute(NOROLLBACKFOR_ATTRIBUTE);
            String eorb = sub[i].getAttribute(EXCEPTIONONROLLBACK_ATTRIBUTE);

            if (method == null) {
                throw new ConfigurationException("A transactional element must specified the method attribute");
            }
            MethodMetadata meta = this.getPojoMetadata().getMethod(method);
            if (meta == null) {
                throw new ConfigurationException("A transactional method is not in the pojo class : " + method);
            }

            int timeout = 0;
            if (to != null) {
                timeout = new Integer(to).intValue();
            }

            int propagation = DEFAULT_PROPAGATION;
            if (propa != null) {
                propagation = parsePropagation(propa);
            }

            List<String> exceptions = new ArrayList<String>();
            if (nrbf != null) {
                exceptions = (List<String>) ParseUtils.parseArraysAsList(nrbf);
            }

            boolean exceptionOnRollback = false;
            if (eorb != null) {
                exceptionOnRollback = new Boolean(eorb).booleanValue();
            }

            TransactionalMethod tm = new TransactionalMethod(method, propagation, timeout, exceptions, exceptionOnRollback, this);
            m_methods.add(tm);
            this.getInstanceManager().register(meta, tm);
        }

    }

    private int parsePropagation(String propa) throws ConfigurationException {
       if (propa.equalsIgnoreCase("requires")) {
           return TransactionalMethod.REQUIRES;

       } else if (propa.equalsIgnoreCase("mandatory")){
           return TransactionalMethod.MANDATORY;

       } else if (propa.equalsIgnoreCase("notsupported")) {
           return TransactionalMethod.NOT_SUPPORTED;

       } else if (propa.equalsIgnoreCase("supported")) {
           return TransactionalMethod.SUPPORTED;

       } else if (propa.equalsIgnoreCase("never")) {
           return TransactionalMethod.NEVER;

        } else if (propa.equalsIgnoreCase("requiresnew")) {
            return TransactionalMethod.REQUIRES_NEW;
        }

       throw new ConfigurationException("Unknown propgation policy : " + propa);
    }

    public void start() {
        // Set transaction managers.
        for (TransactionalMethod method : m_methods) {
            method.setTransactionManager(m_transactionManager);
        }
    }

    public void stop() {
        // Nothing to do.
    }

    public synchronized void bind(TransactionManager tm) {
        for (TransactionalMethod method : m_methods) {
            method.setTransactionManager(tm);
        }
    }

    public synchronized void unbind(TransactionManager tm) {
        for (TransactionalMethod method : m_methods) {
            method.setTransactionManager(null);
        }
    }

    public void transactionRolledback(Transaction t) {
       if (m_onRollback != null) {
            try {
                m_onRollback.call(new Object[] { t });
            } catch (NoSuchMethodException e1) {
                error("Cannot invoke the onRollback method, method not found",
                        e1);
            } catch (IllegalAccessException e1) {
                error(
                        "Cannot invoke the onRollback method,cannot access the method",
                        e1);
            } catch (InvocationTargetException e1) {
                error(
                        "Cannot invoke the onRollback method,the method thrown an exception",
                        e1.getTargetException());
            }
        }
    }

    public void transactionCommitted(Transaction t) {
        if (m_onRollback != null) {
            try {
                m_onCommit.call(new Object[] { t });
            } catch (NoSuchMethodException e1) {
                error("Cannot invoke the onCommit callback, method not found",
                        e1);
            } catch (IllegalAccessException e1) {
                error(
                        "Cannot invoke the onCommit callback,cannot access the method",
                        e1);
            } catch (InvocationTargetException e1) {
                error(
                        "Cannot invoke the onCommit callback,the method thrown an exception",
                        e1.getTargetException());
            }
        }

    }

    public void stateChanged(int newState) {
        if (newState == ComponentInstance.INVALID) {
            // rollback all owned transactions.
            for (int i = 0; i < m_methods.size(); i++) {
                m_methods.get(i).rollbackOwnedTransactions();
            }

            for (int i =0; i < m_transactions.size(); i++) {
                try {
                    m_transactions.get(i).setRollbackOnly();
                } catch (Exception e) {
                    error("Cannot set rollback only on a transaction : " + e.getMessage());
                }
            }
        }
    }

    public synchronized Object onGet(Object pojo, String fieldName, Object value) {
        try {
            if (m_transactionManager != null) {
                return m_transactionManager.getTransaction();
            } else {
                return null;
            }
        } catch (SystemException e) {
            error("Cannot get the current transaction, internal error", e);
            return null;
        }
    }

    public void afterCompletion(int arg0) {
        try {
            if (m_transactionManager.getTransaction() != null) {
                m_transactions .remove(m_transactionManager.getTransaction());
                if (arg0 == Status.STATUS_ROLLEDBACK) {
                    transactionRolledback(m_transactionManager.getTransaction());
                } else if (arg0 == Status.STATUS_COMMITTED) {
                    transactionCommitted(m_transactionManager.getTransaction());
                }
            }
        } catch (SystemException e) {
           error("Cannot remove the transaction from the transaction list : " + e.getMessage());
        }
    }

    public void beforeCompletion() {

    }

    public void addTransaction(Transaction transaction) {
        if (m_transactions.contains(transaction)) {
            return;
        }
        try {
            transaction.registerSynchronization(this);
            m_transactions.add(transaction);
        } catch (Exception e) {
           error("Cannot add the transaction to the transaction list : " + e.getMessage());
        }
    }

    public List<Transaction> getTransactions() {
        return m_transactions;
    }


}
TOP

Related Classes of org.apache.felix.ipojo.transaction.TransactionHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.