Author: gnodet
Date: Thu Sep 23 16:35:41 2010
New Revision: 1000531
URL: http://svn.apache.org/viewvc?rev=1000531&view=rev
Log:
[SMX4-596] [utils] Provide a way to set a global RejectedExecutionHandler when
using the ExecutorFactory
Added:
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/FactoryFinder.java
Modified:
servicemix/utils/trunk/pom.xml
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/ExecutorFactoryImpl.java
Modified: servicemix/utils/trunk/pom.xml
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/pom.xml?rev=1000531&r1=1000530&r2=1000531&view=diff
==============================================================================
--- servicemix/utils/trunk/pom.xml (original)
+++ servicemix/utils/trunk/pom.xml Thu Sep 23 16:35:41 2010
@@ -93,7 +93,12 @@
<dependency>
<groupId>org.apache.servicemix.specs</groupId>
<artifactId>org.apache.servicemix.specs.jbi-api-1.0</artifactId>
- <version>1.1.0</version>
+ <version>1.5.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.specs</groupId>
+ <artifactId>org.apache.servicemix.specs.locator</artifactId>
+ <version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
@@ -222,6 +227,12 @@
<Import-Package>
*;resolution:=optional
</Import-Package>
+ <Private-Package>
+ org.apache.servicemix.specs.locator;-split-package:=merge-first
+ </Private-Package>
+ <Bundle-Activator>
+ org.apache.servicemix.specs.locator.Activator
+ </Bundle-Activator>
</instructions>
</configuration>
</plugin>
Modified:
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/ExecutorFactoryImpl.java
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/ExecutorFactoryImpl.java?rev=1000531&r1=1000530&r2=1000531&view=diff
==============================================================================
---
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/ExecutorFactoryImpl.java
(original)
+++
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/ExecutorFactoryImpl.java
Thu Sep 23 16:35:41 2010
@@ -93,7 +93,10 @@ public class ExecutorFactoryImpl impleme
queue = new ArrayBlockingQueue<Runnable>(config.getQueueSize());
}
ThreadFactory factory = new DefaultThreadFactory(id,
config.isThreadDaemon(), config.getThreadPriority());
- RejectedExecutionHandler handler = new
ThreadPoolExecutor.CallerRunsPolicy();
+
+ RejectedExecutionHandler handler = (RejectedExecutionHandler)
FactoryFinder.find(RejectedExecutionHandler.class.getName(),
+
ThreadPoolExecutor.CallerRunsPolicy.class.getName());
+
ThreadPoolExecutor service = new
ThreadPoolExecutor(config.getCorePoolSize(),
config.getMaximumPoolSize() < 0 ? Integer.MAX_VALUE :
config.getMaximumPoolSize(), config
.getKeepAliveTime(), TimeUnit.MILLISECONDS, queue,
factory, handler);
Added:
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/FactoryFinder.java
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/FactoryFinder.java?rev=1000531&view=auto
==============================================================================
---
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/FactoryFinder.java
(added)
+++
servicemix/utils/trunk/src/main/java/org/apache/servicemix/executors/impl/FactoryFinder.java
Thu Sep 23 16:35:41 2010
@@ -0,0 +1,280 @@
+/*
+ * 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.executors.impl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.PrivilegedAction;
+import java.util.Properties;
+
+/**
+ * This code is designed to implement the pluggability
+ * feature and is designed to both compile and run on JDK version 1.1 and
+ * later. The code also runs both as part of an unbundled jar file and
+ * when bundled as part of the JDK.
+ */
+class FactoryFinder {
+ /**
+ * Set to true for debugging.
+ */
+ private static final boolean debug = false;
+
+ private static void debugPrintln(String msg) {
+ if (debug) {
+ System.err.println("Factory Finder:" + msg);
+ }
+ }
+
+ /**
+ * Figure out which ClassLoader to use. For JDK 1.2 and later use
+ * the context ClassLoader.
+ *
+ * @return the <code>ClassLoader</code>
+ * @throws ConfigurationError if this class is unable to work with the
+ * host JDK
+ */
+ private static ClassLoader findClassLoader()
+ throws ConfigurationError {
+ // REVIEW This doPriv block may be unnecessary because this method is
private and
+ // the caller already has a doPriv. I added the doPriv in case
someone changes the
+ // visibility of this method to non-private.
+ ClassLoader cl = (ClassLoader)
+ doPrivileged( new PrivilegedAction() {
+ public Object run() {
+
+ Method m = null;
+
+ try {
+
+ m = Thread.class.getMethod("getContextClassLoader",
(Class []) null);
+ } catch (NoSuchMethodException e) {
+ // Assume that we are running JDK 1.1, use the current
ClassLoader
+ debugPrintln("assuming JDK 1.1");
+ return FactoryFinder.class.getClassLoader();
+ }
+
+ try {
+ return (ClassLoader) m.invoke(Thread.currentThread(),
(Object []) null);
+ } catch (IllegalAccessException e) {
+ // assert(false)
+ throw new ConfigurationError("Unexpected
IllegalAccessException",
+ e);
+ } catch (InvocationTargetException e) {
+ // assert(e.getTargetException() instanceof
SecurityException)
+ throw new ConfigurationError("Unexpected
InvocationTargetException",
+ e);
+ }
+ }
+ }
+ );
+ return cl;
+
+ }
+
+ /**
+ * Create an instance of a class using the specified
+ * <code>ClassLoader</code>, or if that fails from the
+ * <code>ClassLoader</code> that loaded this class.
+ *
+ * @param className the name of the class to instantiate
+ * @param classLoader a <code>ClassLoader</code> to load the class from
+ * @return a new <code>Object</code> that is an instance of the class of
+ * the given name from the given class loader
+ * @throws ConfigurationError if the class could not be found or
+ * instantiated
+ */
+ private static Object newInstance(String className,
+ ClassLoader classLoader)
+ throws ConfigurationError {
+
+ final ClassLoader iClassLoader = classLoader;
+ final String iClassName = className;
+
+ // REVIEW This doPriv block may be unnecessary because this method is
private and
+ // the caller already has a doPriv. I added the doPriv in case
someone changes the
+ // visibility of this method to non-private.
+ Object obj =
+ doPrivileged( new PrivilegedAction() {
+ public Object run() {
+ try {
+ if (iClassLoader != null) {
+ try {
+ return
iClassLoader.loadClass(iClassName).newInstance();
+ } catch (ClassNotFoundException x) {
+ // try again
+ }
+ }
+ return Class.forName(iClassName).newInstance();
+ } catch (ClassNotFoundException x) {
+ throw new ConfigurationError(
+ "Provider " + iClassName + " not found", x);
+ } catch (Exception x) {
+ throw new ConfigurationError(
+ "Provider " + iClassName + " could not be
instantiated: " + x,
+ x);
+ }
+ }
+ });
+ return obj;
+ }
+
+ /**
+ * Finds the implementation Class object in the specified order. Main
+ * entry point.
+ *
+ * @param factoryId Name of the factory to find, same as
+ * a property name
+ * @param fallbackClassName Implementation class name, if nothing else
+ * is found. Use null to mean no fallback.
+ * @return Class object of factory, never null
+ * @throws FactoryFinder.ConfigurationError
+ * Package private so this code can be shared.
+ */
+ static Object find(String factoryId, String fallbackClassName)
+ throws ConfigurationError {
+
+ final String iFactoryId = factoryId;
+ final String iFallbackClassName = fallbackClassName;
+
+ Object obj =
+ doPrivileged( new PrivilegedAction() {
+ public Object run() {
+ debugPrintln("debug is on");
+
+ ClassLoader classLoader = findClassLoader();
+
+ try {
+ // If we are deployed into an OSGi
environment, leverage it
+ Class spiClass =
org.apache.servicemix.specs.locator.OsgiLocator.locate(iFactoryId);
+ if (spiClass != null) {
+ return spiClass.newInstance();
+ }
+ } catch (Throwable e) {
+ }
+
+ // Use the system property first
+ try {
+ String systemProp =
+ System.getProperty(iFactoryId);
+ if (systemProp != null) {
+ debugPrintln("found system property " +
systemProp);
+ return newInstance(systemProp, classLoader);
+ }
+ } catch (SecurityException se) {
+ }
+
+ String serviceId = "META-INF/services/" + iFactoryId;
+ // try to find services in CLASSPATH
+ try {
+ InputStream is = null;
+ if (classLoader == null) {
+ is =
ClassLoader.getSystemResourceAsStream(serviceId);
+ } else {
+ is = classLoader.getResourceAsStream(serviceId);
+ }
+
+ if (is != null) {
+ debugPrintln("found " + serviceId);
+
+ // Read the service provider name in UTF-8 as
specified in
+ // the jar spec. Unfortunately this fails in
Microsoft
+ // VJ++, which does not implement the UTF-8
+ // encoding. Theoretically, we should simply let
it fail in
+ // that case, since the JVM is obviously broken if
it
+ // doesn't support such a basic standard. But
since there
+ // are still some users attempting to use VJ++ for
+ // development, we have dropped in a fallback
which makes a
+ // second attempt using the platform's default
encoding. In
+ // VJ++ this is apparently ASCII, which is a
subset of
+ // UTF-8... and since the strings we'll be reading
here are
+ // also primarily limited to the 7-bit ASCII range
(at
+ // least, in English versions), this should work
well
+ // enough to keep us on the air until we're ready
to
+ // officially decommit from VJ++. [Edited comment
from
+ // jkesselm]
+ BufferedReader rd;
+ try {
+ rd = new BufferedReader(new
InputStreamReader(is, "UTF-8"));
+ } catch (java.io.UnsupportedEncodingException e) {
+ rd = new BufferedReader(new
InputStreamReader(is));
+ }
+
+ String factoryClassName = rd.readLine();
+ rd.close();
+
+ if (factoryClassName != null &&
+ ! "".equals(factoryClassName)) {
+ debugPrintln("loaded from services: " +
factoryClassName);
+ return newInstance(factoryClassName,
classLoader);
+ }
+ }
+ } catch (Exception ex) {
+ if (debug) ex.printStackTrace();
+ }
+
+ if (iFallbackClassName == null) {
+ throw new ConfigurationError(
+ "Provider for " + iFactoryId + " cannot be
found", null);
+ }
+
+ debugPrintln("loaded from fallback value: " +
iFallbackClassName);
+ return newInstance(iFallbackClassName, classLoader);
+ }
+ });
+ return obj;
+ }
+
+ private static Object doPrivileged(PrivilegedAction action) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null) {
+ return(action.run());
+ } else {
+ return java.security.AccessController.doPrivileged(action);
+ }
+ }
+
+ static class ConfigurationError extends Error {
+ // fixme: should this be refactored to use the jdk1.4 exception
+ // wrapping?
+
+ private Exception exception;
+
+ /**
+ * Construct a new instance with the specified detail string and
+ * exception.
+ *
+ * @param msg the Message for this error
+ * @param x an Exception that caused this failure, or null
+ */
+ ConfigurationError(String msg, Exception x) {
+ super(msg);
+ this.exception = x;
+ }
+
+ Exception getException() {
+ return exception;
+ }
+ }
+}