You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicemix.apache.org by gn...@apache.org on 2009/08/26 13:19:20 UTC

svn commit: r807962 [2/2] - in /servicemix/sandbox/karaf/nmr: assembly/src/main/descriptors/ assembly/src/main/filtered-resources/ assembly/src/main/filtered-resources/etc/ jbi/osgi/ jbi/osgi/src/main/java/org/apache/servicemix/jbi/osgi/ jbi/osgi/src/m...

Added: servicemix/sandbox/karaf/nmr/transaction/src/main/java/org/apache/servicemix/transaction/TransactionManagerService.java
URL: http://svn.apache.org/viewvc/servicemix/sandbox/karaf/nmr/transaction/src/main/java/org/apache/servicemix/transaction/TransactionManagerService.java?rev=807962&view=auto
==============================================================================
--- servicemix/sandbox/karaf/nmr/transaction/src/main/java/org/apache/servicemix/transaction/TransactionManagerService.java (added)
+++ servicemix/sandbox/karaf/nmr/transaction/src/main/java/org/apache/servicemix/transaction/TransactionManagerService.java Wed Aug 26 11:19:19 2009
@@ -0,0 +1,220 @@
+/*
+ * 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.servicemix.transaction;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Properties;
+import java.io.File;
+import java.io.IOException;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
+import javax.transaction.UserTransaction;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
+import org.apache.geronimo.transaction.manager.TransactionLog;
+import org.apache.geronimo.transaction.manager.XidFactory;
+import org.apache.geronimo.transaction.manager.XidFactoryImpl;
+import org.apache.geronimo.transaction.manager.RecoverableTransactionManager;
+import org.apache.geronimo.transaction.log.HOWLLog;
+import org.apache.geronimo.transaction.log.UnrecoverableLog;
+import org.objectweb.howl.log.LogConfigurationException;
+
+/**
+ */
+public class TransactionManagerService {
+
+    public static final String TRANSACTION_TIMEOUT = "felix.transaction.timeout";
+    public static final String RECOVERABLE = "felix.transaction.recoverable";
+    public static final String HOWL_BUFFER_CLASS_NAME = "felix.transaction.howl.bufferClassName";
+    public static final String HOWL_BUFFER_SIZE = "felix.transaction.howl.bufferSize";
+    public static final String HOWL_CHECKSUM_ENABLED = "felix.transaction.howl.checksumEnabled";
+    public static final String HOWL_ADLER32_CHECKSUM = "felix.transaction.howl.adler32Checksum";
+    public static final String HOWL_FLUSH_SLEEP_TIME = "felix.transaction.howl.flushSleepTime";
+    public static final String HOWL_LOG_FILE_EXT = "felix.transaction.howl.logFileExt";
+    public static final String HOWL_LOG_FILE_NAME = "felix.transaction.howl.logFileName";
+    public static final String HOWL_MAX_BLOCKS_PER_FILE = "felix.transaction.howl.maxBlocksPerFile";
+    public static final String HOWL_MAX_LOG_FILES = "felix.transaction.howl.maxLogFiles";
+    public static final String HOWL_MAX_BUFFERS = "felix.transaction.howl.maxBuffers";
+    public static final String HOWL_MIN_BUFFERS = "felix.transaction.howl.minBuffers";
+    public static final String HOWL_THREADS_WAITING_FORCE_THRESHOLD = "felix.transaction.howl.threadsWaitingForceThreshold";
+    public static final String HOWL_LOG_FILE_DIR = "felix.transaction.howl.logFileDir";
+
+    public static final int DEFAULT_TRANSACTION_TIMEOUT = 600; // 600 seconds -> 10 minutes
+    public static final boolean DEFAULT_RECOVERABLE = false;   // not recoverable by default
+
+    private static final String PLATFORM_TRANSACTION_MANAGER_CLASS = "org.springframework.transaction.PlatformTransactionManager";
+
+    private final String pid;
+    private final Dictionary properties;
+    private final BundleContext bundleContext;
+    private boolean useSpring;
+    private GeronimoTransactionManager transactionManager;
+    private TransactionLog transactionLog;
+    private ServiceRegistration serviceRegistration;
+
+    public TransactionManagerService(String pid, Dictionary properties, BundleContext bundleContext) throws ConfigurationException {
+        this.pid = pid;
+        this.properties = properties;
+        this.bundleContext = bundleContext;
+        // Transaction timeout
+        int transactionTimeout = getInt(TRANSACTION_TIMEOUT, DEFAULT_TRANSACTION_TIMEOUT);
+        if (transactionTimeout <= 0) {
+            throw new ConfigurationException(TRANSACTION_TIMEOUT, "Property " + TRANSACTION_TIMEOUT + " must be > 0");
+        }
+        // XID factory
+        XidFactory xidFactory = new XidFactoryImpl(pid.getBytes());
+        // Transaction log
+        if (getBool(RECOVERABLE, DEFAULT_RECOVERABLE)) {
+            String bufferClassName = getString(HOWL_BUFFER_CLASS_NAME, "org.objectweb.howl.log.BlockLogBuffer");
+            int bufferSizeKBytes = getInt(HOWL_BUFFER_SIZE, 32);
+            if (bufferSizeKBytes < 1 || bufferSizeKBytes > 32) {
+                throw new ConfigurationException(HOWL_BUFFER_SIZE, "bufferSize must be between 1 and 32");
+            }
+            boolean checksumEnabled = getBool(HOWL_CHECKSUM_ENABLED, true);
+            boolean adler32Checksum = getBool(HOWL_ADLER32_CHECKSUM, true);
+            int flushSleepTimeMilliseconds = getInt(HOWL_FLUSH_SLEEP_TIME, 50);
+            String logFileExt = getString(HOWL_LOG_FILE_EXT, "log");
+            String logFileName = getString(HOWL_LOG_FILE_NAME, "transaction");
+            int maxBlocksPerFile = getInt(HOWL_MAX_BLOCKS_PER_FILE, -1);
+            int maxLogFiles = getInt(HOWL_MAX_LOG_FILES, 2);
+            int minBuffers = getInt(HOWL_MIN_BUFFERS, 4);
+            if (minBuffers < 0) {
+                throw new ConfigurationException(HOWL_MIN_BUFFERS, "minBuffers must be > 0");
+            }
+            int maxBuffers = getInt(HOWL_MAX_BUFFERS, 0);
+            if (maxBuffers > 0 && minBuffers < maxBuffers) {
+                throw new ConfigurationException(HOWL_MAX_BUFFERS, "minBuffers must be <= maxBuffers");
+            }
+            int threadsWaitingForceThreshold = getInt(HOWL_THREADS_WAITING_FORCE_THRESHOLD, -1);
+            String logFileDir = getString(HOWL_LOG_FILE_DIR, null);
+            if (logFileDir == null || logFileDir.length() == 0 || !new File(logFileDir).isAbsolute()) {
+                throw new ConfigurationException(HOWL_LOG_FILE_DIR, "Property should be set to an absolute directory");
+            }
+            try {
+                transactionLog = new HOWLLog(bufferClassName,
+                                             bufferSizeKBytes,
+                                             checksumEnabled,
+                                             adler32Checksum,
+                                             flushSleepTimeMilliseconds,
+                                             logFileDir,
+                                             logFileExt,
+                                             logFileName,
+                                             maxBlocksPerFile,
+                                             maxBuffers,
+                                             maxLogFiles,
+                                             minBuffers,
+                                             threadsWaitingForceThreshold,
+                                             xidFactory != null ? xidFactory : new XidFactoryImpl(),
+                                             null);
+            } catch (LogConfigurationException e) {
+                // This should not really happen as we've checked properties earlier
+                throw new ConfigurationException(null, null, e);
+            } catch (IOException e) {
+                // This should not really happen as we've checked properties earlier
+                throw new ConfigurationException(null, null, e);
+            }
+        } else {
+            transactionLog =  new UnrecoverableLog();
+        }
+        // Create transaction manager
+        try {
+            try {
+                transactionManager = new SpringTransactionManagerCreator().create(transactionTimeout, xidFactory, transactionLog);
+                useSpring = true;
+            } catch (NoClassDefFoundError e) {
+                transactionManager = new GeronimoTransactionManager(transactionTimeout, xidFactory, transactionLog);
+            }
+        } catch (XAException e) {
+            throw new RuntimeException("Error recovering transaction log", e);
+        }
+    }
+
+    public void start() throws Exception {
+        if (transactionLog instanceof HOWLLog) {
+            ((HOWLLog) transactionLog).doStart();
+        }
+        List<String> clazzes = new ArrayList<String>();
+        clazzes.add(TransactionManager.class.getName());
+        clazzes.add(TransactionSynchronizationRegistry.class.getName());
+        clazzes.add(UserTransaction.class.getName());
+        clazzes.add(RecoverableTransactionManager.class.getName());
+        if (useSpring) {
+            clazzes.add(PLATFORM_TRANSACTION_MANAGER_CLASS);
+        }
+        serviceRegistration = bundleContext.registerService(clazzes.toArray(new String[clazzes.size()]), transactionManager, new Properties());
+    }
+
+    public void close() throws Exception {
+        if (serviceRegistration != null) {
+            serviceRegistration.unregister();
+        }
+        if (transactionLog instanceof HOWLLog) {
+            ((HOWLLog) transactionLog).doStop();
+        }
+    }
+
+    private String getString(String property, String dflt) throws ConfigurationException {
+        String value = (String) properties.get(property);
+        if (value != null) {
+            return value;
+        }
+        return dflt;
+    }
+
+    private int getInt(String property, int dflt) throws ConfigurationException {
+        String value = (String) properties.get(property);
+        if (value != null) {
+            try {
+                return Integer.parseInt(value);
+            } catch (Exception e) {
+                throw new ConfigurationException(property, "Error parsing " + property + "(" + value + ") property as an integer", e);
+            }
+        }
+        return dflt;
+    }
+
+    private boolean getBool(String property, boolean dflt) throws ConfigurationException {
+        String value = (String) properties.get(property);
+        if (value != null) {
+            try {
+                return Boolean.parseBoolean(value);
+            } catch (Exception e) {
+                throw new ConfigurationException(property, "Error parsing " + property + "(" + value + ") property as a boolean", e);
+            }
+        }
+        return dflt;
+    }
+
+    /**
+     * We use an inner static class to decouple this class from the spring-tx classes
+     * in order to not have NoClassDefFoundError if those are not present.
+     */
+    public static class SpringTransactionManagerCreator {
+
+        public GeronimoTransactionManager create(int defaultTransactionTimeoutSeconds, XidFactory xidFactory, TransactionLog transactionLog) throws XAException {
+            return new GeronimoPlatformTransactionManager(defaultTransactionTimeoutSeconds, xidFactory, transactionLog);
+        }
+
+    }
+}