You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2010/08/05 21:32:40 UTC
svn commit: r982743 [2/3] - in /myfaces/core/trunk/impl: ./
src/main/java/org/apache/myfaces/commons/
src/main/java/org/apache/myfaces/commons/discovery/
src/main/java/org/apache/myfaces/commons/discovery/jdk/
src/main/java/org/apache/myfaces/commons/d...
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInDictionary.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInDictionary.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInDictionary.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInDictionary.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,117 @@
+/*
+ * 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.myfaces.commons.discovery.resource.names;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.myfaces.commons.discovery.ResourceNameDiscover;
+import org.apache.myfaces.commons.discovery.ResourceNameIterator;
+
+
+/**
+ * Recover resources from a Dictionary. This covers Properties as well,
+ * since <code>Properties extends Hashtable extends Dictionary</code>.
+ *
+ * The recovered value is expected to be either a <code>String</code>
+ * or a <code>String[]</code>.
+ *
+ * @author Richard A. Sitze
+ */
+public class DiscoverNamesInDictionary
+ extends ResourceNameDiscoverImpl
+ implements ResourceNameDiscover
+{
+ private static Logger log = Logger.getLogger(DiscoverNamesInDictionary.class.getName());
+ public static void setLog(Logger _log) {
+ log = _log;
+ }
+
+ private Dictionary dictionary;
+
+ /** Construct a new resource discoverer
+ */
+ public DiscoverNamesInDictionary() {
+ setDictionary(new Hashtable());
+ }
+
+ /** Construct a new resource discoverer
+ */
+ public DiscoverNamesInDictionary(Dictionary dictionary) {
+ setDictionary(dictionary);
+ }
+
+ protected Dictionary getDictionary() {
+ return dictionary;
+ }
+
+ /**
+ * Specify set of class loaders to be used in searching.
+ */
+ public void setDictionary(Dictionary table) {
+ this.dictionary = table;
+ }
+
+ public void addResource(String resourceName, String resource) {
+ dictionary.put(resourceName, resource);
+ }
+
+ public void addResource(String resourceName, String[] resources) {
+ dictionary.put(resourceName, resources);
+ }
+
+ /**
+ * @return Enumeration of ResourceInfo
+ */
+ public ResourceNameIterator findResourceNames(final String resourceName) {
+ if (log.isLoggable(Level.FINE))
+ log.fine("find: resourceName='" + resourceName + "'");
+
+ Object baseResource = dictionary.get(resourceName);
+
+ final String[] resources;
+ if (baseResource instanceof String) {
+ resources = new String[] { (String)baseResource };
+ } else if (baseResource instanceof String[]) {
+ resources = (String[])baseResource;
+ } else {
+ resources = null;
+ }
+
+ return new ResourceNameIterator() {
+ private int idx = 0;
+
+ public boolean hasNext() {
+ if (resources != null) {
+ while (idx < resources.length && resources[idx] == null) {
+ idx++;
+ }
+ return idx < resources.length;
+ }
+ return false;
+ }
+
+ public String nextResourceName() {
+ return hasNext() ? resources[idx++] : null;
+ }
+ };
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInFile.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInFile.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInFile.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInFile.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,259 @@
+/*
+ * 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.myfaces.commons.discovery.resource.names;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.myfaces.commons.discovery.Resource;
+import org.apache.myfaces.commons.discovery.ResourceDiscover;
+import org.apache.myfaces.commons.discovery.ResourceIterator;
+import org.apache.myfaces.commons.discovery.ResourceNameDiscover;
+import org.apache.myfaces.commons.discovery.ResourceNameIterator;
+import org.apache.myfaces.commons.discovery.resource.ClassLoaders;
+import org.apache.myfaces.commons.discovery.resource.DiscoverResources;
+
+
+
+/**
+ * Discover ALL files of a given name, and return resource names
+ * contained within the set of files:
+ * <ul>
+ * <li>one resource name per line,</li>
+ * <li>whitespace ignored,</li>
+ * <li>comments begin with '#'</li>
+ * </ul>
+ *
+ * Default discoverer is DiscoverClassLoaderResources,
+ * but it can be set to any other.
+ *
+ * @author Richard A. Sitze
+ * @author Costin Manolache
+ * @author James Strachan
+ */
+public class DiscoverNamesInFile
+ extends ResourceNameDiscoverImpl
+ implements ResourceNameDiscover
+{
+ private static Logger log = Logger.getLogger(DiscoverNamesInFile.class.getName());
+ public static void setLog(Logger _log) {
+ log = _log;
+ }
+
+ private ResourceDiscover _discoverResources;
+
+ private final String _prefix;
+ private final String _suffix;
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverNamesInFile() {
+ _discoverResources = new DiscoverResources();
+ _prefix = null;
+ _suffix = null;
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverNamesInFile(String prefix, String suffix) {
+ _discoverResources = new DiscoverResources();
+ _prefix = prefix;
+ _suffix = suffix;
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverNamesInFile(ClassLoaders loaders) {
+ _discoverResources = new DiscoverResources(loaders);
+ _prefix = null;
+ _suffix = null;
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverNamesInFile(ClassLoaders loaders, String prefix, String suffix) {
+ _discoverResources = new DiscoverResources(loaders);
+ _prefix = prefix;
+ _suffix = suffix;
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverNamesInFile(ResourceDiscover discoverer) {
+ _discoverResources = discoverer;
+ _prefix = null;
+ _suffix = null;
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverNamesInFile(ResourceDiscover discoverer, String prefix, String suffix) {
+ _discoverResources = discoverer;
+ _prefix = prefix;
+ _suffix = suffix;
+ }
+
+ /**
+ * Specify set of class loaders to be used in searching.
+ */
+ public void setDiscoverer(ResourceDiscover discover) {
+ _discoverResources = discover;
+ }
+
+ /**
+ * To be used by downstream elements..
+ */
+ public ResourceDiscover getDiscover() {
+ return _discoverResources;
+ }
+
+ /**
+ * @return Enumeration of ServiceInfo
+ */
+ public ResourceNameIterator findResourceNames(final String serviceName) {
+ String fileName;
+ if (_prefix != null && _prefix.length() > 0) {
+ fileName = _prefix + serviceName;
+ } else {
+ fileName = serviceName;
+ }
+
+ if (_suffix != null && _suffix.length() > 0) {
+ fileName = fileName + _suffix;
+ }
+
+ if (log.isLoggable(Level.FINE)) {
+ if (_prefix != null && _suffix != null) {
+ log.fine("find: serviceName='" + serviceName + "' as '" + fileName + "'");
+ } else {
+ log.fine("find: serviceName = '" + fileName + "'");
+ }
+ }
+
+
+ final ResourceIterator files =
+ getDiscover().findResources(fileName);
+
+ return new ResourceNameIterator() {
+ private int idx = 0;
+ private Vector classNames = null;
+ private String resource = null;
+
+ public boolean hasNext() {
+ if (resource == null) {
+ resource = getNextClassName();
+ }
+ return resource != null;
+ }
+
+ public String nextResourceName() {
+ String element = resource;
+ resource = null;
+ return element;
+ }
+
+ private String getNextClassName() {
+ if (classNames == null || idx >= classNames.size()) {
+ classNames = getNextClassNames();
+ idx = 0;
+ if (classNames == null) {
+ return null;
+ }
+ }
+
+ String className = (String)classNames.get(idx++);
+
+ if (log.isLoggable(Level.FINE))
+ log.fine("getNextClassResource: next class='" + className + "'");
+
+ return className;
+ }
+
+ private Vector getNextClassNames() {
+ while (files.hasNext()) {
+ Vector results = readServices(files.nextResource());
+ if (results != null && results.size() > 0) {
+ return results;
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Read everything, no defering here..
+ * Ensure that files are closed before we leave.
+ */
+ private Vector readServices(final Resource info) {
+ Vector results = new Vector();
+
+ InputStream is = info.getResourceAsStream();
+
+ if( is != null ) {
+ try {
+ try {
+ // This code is needed by EBCDIC and other
+ // strange systems. It's a fix for bugs
+ // reported in xerces
+ BufferedReader rd;
+ try {
+ rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ } catch (java.io.UnsupportedEncodingException e) {
+ rd = new BufferedReader(new InputStreamReader(is));
+ }
+
+ try {
+ String serviceImplName;
+ while( (serviceImplName = rd.readLine()) != null) {
+ int idx = serviceImplName.indexOf('#');
+ if (idx >= 0) {
+ serviceImplName = serviceImplName.substring(0, idx);
+ }
+ serviceImplName = serviceImplName.trim();
+
+ if (serviceImplName.length() != 0) {
+ results.add(serviceImplName);
+ }
+ }
+ } finally {
+ rd.close();
+ }
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ return results;
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInManagedProperties.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInManagedProperties.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInManagedProperties.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInManagedProperties.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,99 @@
+/*
+ * 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.myfaces.commons.discovery.resource.names;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.myfaces.commons.discovery.ResourceNameDiscover;
+import org.apache.myfaces.commons.discovery.ResourceNameIterator;
+import org.apache.myfaces.commons.discovery.tools.ManagedProperties;
+
+
+/**
+ * Recover resource name from Managed Properties.
+ * @see org.apache.myfaces.commons.discovery.tools.ManagedProperties
+ *
+ * @author Richard A. Sitze
+ */
+public class DiscoverNamesInManagedProperties
+ extends ResourceNameDiscoverImpl
+ implements ResourceNameDiscover
+{
+ private static Logger log = Logger.getLogger(DiscoverNamesInManagedProperties.class.getName());
+ public static void setLog(Logger _log) {
+ log = _log;
+ }
+
+
+ private final String _prefix;
+ private final String _suffix;
+
+ /** Construct a new resource discoverer
+ */
+ public DiscoverNamesInManagedProperties() {
+ _prefix = null;
+ _suffix = null;
+ }
+
+ /** Construct a new resource discoverer
+ */
+ public DiscoverNamesInManagedProperties(String prefix, String suffix) {
+ _prefix = prefix;
+ _suffix = suffix;
+ }
+
+ /**
+ * @return Enumeration of ResourceInfo
+ */
+ public ResourceNameIterator findResourceNames(final String resourceName) {
+ String name;
+ if (_prefix != null && _prefix.length() > 0) {
+ name = _prefix + resourceName;
+ } else {
+ name = resourceName;
+ }
+
+ if (_suffix != null && _suffix.length() > 0) {
+ name = name + _suffix;
+ }
+
+ if (log.isLoggable(Level.FINE)) {
+ if (_prefix != null && _suffix != null) {
+ log.fine("find: resourceName='" + resourceName + "' as '" + name + "'");
+ } else {
+ log.fine("find: resourceName = '" + name + "'");
+ }
+ }
+
+ final String newResourcName = name;
+ return new ResourceNameIterator() {
+ private String resource = ManagedProperties.getProperty(newResourcName);
+ public boolean hasNext() {
+ return resource != null;
+ }
+
+ public String nextResourceName() {
+ String element = resource;
+ resource = null;
+ return element;
+ }
+ };
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInSystemProperties.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInSystemProperties.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInSystemProperties.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverNamesInSystemProperties.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,68 @@
+/*
+ * 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.myfaces.commons.discovery.resource.names;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.myfaces.commons.discovery.ResourceNameDiscover;
+import org.apache.myfaces.commons.discovery.ResourceNameIterator;
+
+
+/**
+ * Recover resource name from System Properties.
+ *
+ * @author Richard A. Sitze
+ */
+public class DiscoverNamesInSystemProperties
+ extends ResourceNameDiscoverImpl
+ implements ResourceNameDiscover
+{
+ private static Logger log = Logger.getLogger(DiscoverNamesInSystemProperties.class.getName());
+ public static void setLog(Logger _log) {
+ log = _log;
+ }
+
+ /** Construct a new resource discoverer
+ */
+ public DiscoverNamesInSystemProperties() {
+ }
+
+ /**
+ * @return Enumeration of ResourceInfo
+ */
+ public ResourceNameIterator findResourceNames(final String resourceName) {
+ if (log.isLoggable(Level.FINE))
+ log.fine("find: resourceName='" + resourceName + "'");
+
+ return new ResourceNameIterator() {
+ private String resource = System.getProperty(resourceName);
+
+ public boolean hasNext() {
+ return resource != null;
+ }
+
+ public String nextResourceName() {
+ String element = resource;
+ resource = null;
+ return element;
+ }
+ };
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverServiceNames.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverServiceNames.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverServiceNames.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/DiscoverServiceNames.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,81 @@
+/*
+ * 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.myfaces.commons.discovery.resource.names;
+
+import org.apache.myfaces.commons.discovery.ResourceDiscover;
+import org.apache.myfaces.commons.discovery.ResourceNameDiscover;
+import org.apache.myfaces.commons.discovery.resource.ClassLoaders;
+
+
+/**
+ * Provide JDK 1.3 style service discovery...
+ *
+ * The caller will first configure the discoverer by creating a
+ * root Discoverer for the files.
+ *
+ * @author Richard A. Sitze
+ * @author Craig R. McClanahan
+ * @author Costin Manolache
+ * @author James Strachan
+ */
+public class DiscoverServiceNames
+ extends DiscoverNamesInFile
+ implements ResourceNameDiscover
+{
+ protected static final String SERVICE_HOME = "META-INF/services/";
+
+ /** Construct a new service discoverer
+ */
+ public DiscoverServiceNames() {
+ super(SERVICE_HOME, null);
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverServiceNames(String prefix, String suffix) {
+ super((prefix == null) ? SERVICE_HOME : SERVICE_HOME + prefix, suffix);
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverServiceNames(ClassLoaders loaders) {
+ super(loaders, SERVICE_HOME, null);
+ }
+
+ /**
+ * Construct a new resource discoverer
+ */
+ public DiscoverServiceNames(ClassLoaders loaders, String prefix, String suffix) {
+ super(loaders, (prefix == null) ? SERVICE_HOME : SERVICE_HOME + prefix, suffix);
+ }
+
+ /** Construct a new service discoverer
+ */
+ public DiscoverServiceNames(ResourceDiscover discoverer) {
+ super(discoverer, SERVICE_HOME, null);
+ }
+
+ /** Construct a new service discoverer
+ */
+ public DiscoverServiceNames(ResourceDiscover discoverer, String prefix, String suffix) {
+ super(discoverer, (prefix == null) ? SERVICE_HOME : SERVICE_HOME + prefix, suffix);
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/NameDiscoverers.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/NameDiscoverers.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/NameDiscoverers.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/NameDiscoverers.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,112 @@
+/*
+ * 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.myfaces.commons.discovery.resource.names;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.myfaces.commons.discovery.ResourceNameDiscover;
+import org.apache.myfaces.commons.discovery.ResourceNameIterator;
+
+
+/**
+ * Holder for multiple ResourceNameDiscover instances.
+ * The result is the union of the results from each
+ * (not a chained sequence, where results feed the next in line.
+ *
+ * @author Richard A. Sitze
+ */
+public class NameDiscoverers
+ extends ResourceNameDiscoverImpl
+ implements ResourceNameDiscover
+{
+ private static Logger log = Logger.getLogger(NameDiscoverers.class.getName());
+ public static void setLog(Logger _log) {
+ log = _log;
+ }
+
+ private Vector discoverers = new Vector();
+
+ /**
+ * Construct a new resource name discoverer
+ */
+ public NameDiscoverers() {
+ }
+
+ /**
+ * Specify an additional class loader to be used in searching.
+ * The order of loaders determines the order of the result.
+ * It is recommended to add the most specific loaders first.
+ */
+ public void addResourceNameDiscover(ResourceNameDiscover discover) {
+ if (discover != null) {
+ discoverers.addElement(discover);
+ }
+ }
+
+ protected ResourceNameDiscover getResourceNameDiscover(int idx) {
+ return (ResourceNameDiscover)discoverers.get(idx);
+ }
+
+ protected int size() {
+ return discoverers.size();
+ }
+
+ /**
+ * Set of results of all discoverers.
+ *
+ * @return ResourceIterator
+ */
+ public ResourceNameIterator findResourceNames(final String resourceName) {
+ if (log.isLoggable(Level.FINE))
+ log.fine("find: resourceName='" + resourceName + "'");
+
+ return new ResourceNameIterator() {
+ private int idx = 0;
+ private ResourceNameIterator iterator = null;
+
+ public boolean hasNext() {
+ if (iterator == null || !iterator.hasNext()) {
+ iterator = getNextIterator();
+ if (iterator == null) {
+ return false;
+ }
+ }
+ return iterator.hasNext();
+ }
+
+ public String nextResourceName() {
+ return iterator.nextResourceName();
+ }
+
+ private ResourceNameIterator getNextIterator() {
+ while (idx < size()) {
+ ResourceNameIterator iter =
+ getResourceNameDiscover(idx++).findResourceNames(resourceName);
+
+ if (iter.hasNext()) {
+ return iter;
+ }
+ }
+ return null;
+ }
+ };
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/ResourceNameDiscoverImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/ResourceNameDiscoverImpl.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/ResourceNameDiscoverImpl.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/resource/names/ResourceNameDiscoverImpl.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,74 @@
+/*
+ * 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.myfaces.commons.discovery.resource.names;
+
+import org.apache.myfaces.commons.discovery.ResourceNameDiscover;
+import org.apache.myfaces.commons.discovery.ResourceNameIterator;
+
+
+/**
+ * Helper class for methods implementing the ResourceNameDiscover interface.
+ *
+ * @author Richard A. Sitze
+ */
+public abstract class ResourceNameDiscoverImpl implements ResourceNameDiscover
+{
+ /**
+ * Locate names of resources that are bound to <code>resourceName</code>.
+ *
+ * @return ResourceNameIterator
+ */
+ public abstract ResourceNameIterator findResourceNames(String resourceName);
+
+ /**
+ * Locate names of resources that are bound to <code>resourceName</code>.
+ *
+ * @return ResourceNameIterator
+ */
+ public ResourceNameIterator findResourceNames(final ResourceNameIterator inputNames) {
+ return new ResourceNameIterator() {
+ private ResourceNameIterator resourceNames = null;
+ private String resourceName = null;
+
+ public boolean hasNext() {
+ if (resourceName == null) {
+ resourceName = getNextResourceName();
+ }
+ return resourceName != null;
+ }
+
+ public String nextResourceName() {
+ String name = resourceName;
+ resourceName = null;
+ return name;
+ }
+
+ private String getNextResourceName() {
+ while (inputNames.hasNext() && (resourceNames == null || !resourceNames.hasNext())) {
+ resourceNames =
+ findResourceNames(inputNames.nextResourceName());
+ }
+
+ return (resourceNames != null && resourceNames.hasNext())
+ ? resourceNames.nextResourceName()
+ : null;
+ }
+ };
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/ClassUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/ClassUtils.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/ClassUtils.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/ClassUtils.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,140 @@
+/*
+ * 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.myfaces.commons.discovery.tools;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.myfaces.commons.discovery.DiscoveryException;
+
+
+/**
+ * @author Richard A. Sitze
+ */
+public class ClassUtils {
+ private static Logger log = Logger.getLogger(ClassUtils.class.getName());
+ public static void setLog(Logger _log) {
+ log = _log;
+ }
+
+ /**
+ * Get package name.
+ * Not all class loaders 'keep' package information,
+ * in which case Class.getPackage() returns null.
+ * This means that calling Class.getPackage().getName()
+ * is unreliable at best.
+ */
+ public static String getPackageName(Class clazz) {
+ Package clazzPackage = clazz.getPackage();
+ String packageName;
+ if (clazzPackage != null) {
+ packageName = clazzPackage.getName();
+ } else {
+ String clazzName = clazz.getName();
+ packageName = clazzName.substring(0, clazzName.lastIndexOf('.'));
+ }
+ return packageName;
+ }
+
+ /**
+ * @return Method 'public static returnType methodName(paramTypes)',
+ * if found to be <strong>directly</strong> implemented by clazz.
+ */
+ public static Method findPublicStaticMethod(Class clazz,
+ Class returnType,
+ String methodName,
+ Class[] paramTypes) {
+ boolean problem = false;
+ Method method = null;
+
+ // verify '<methodName>(<paramTypes>)' is directly in class.
+ try {
+ method = clazz.getDeclaredMethod(methodName, paramTypes);
+ } catch(NoSuchMethodException e) {
+ problem = true;
+ log.log(Level.FINE, "Class " + clazz.getName() + ": missing method '" + methodName + "(...)", e);
+ }
+
+ // verify 'public static <returnType>'
+ if (!problem &&
+ !(Modifier.isPublic(method.getModifiers()) &&
+ Modifier.isStatic(method.getModifiers()) &&
+ method.getReturnType() == returnType)) {
+ if (log.isLoggable(Level.FINE)) {
+ if (!Modifier.isPublic(method.getModifiers())) {
+ log.fine(methodName + "() is not public");
+ }
+ if (!Modifier.isStatic(method.getModifiers())) {
+ log.fine(methodName + "() is not static");
+ }
+ if (method.getReturnType() != returnType) {
+ log.fine("Method returns: " + method.getReturnType().getName() + "@@" + method.getReturnType().getClassLoader());
+ log.fine("Should return: " + returnType.getName() + "@@" + returnType.getClassLoader());
+ }
+ }
+ problem = true;
+ method = null;
+ }
+
+ return method;
+ }
+
+ /**
+ * Instantiate a new
+ */
+ public static Object newInstance(Class impl, Class paramClasses[], Object params[])
+ throws DiscoveryException,
+ InstantiationException,
+ IllegalAccessException,
+ NoSuchMethodException,
+ InvocationTargetException
+ {
+ if (paramClasses == null || params == null) {
+ return impl.newInstance();
+ } else {
+ Constructor constructor = impl.getConstructor(paramClasses);
+ return constructor.newInstance(params);
+ }
+ }
+
+ /**
+ * Throws exception if <code>impl</code> does not
+ * implement or extend the SPI.
+ */
+ public static void verifyAncestory(Class spi, Class impl)
+ throws DiscoveryException
+ {
+ if (spi == null) {
+ throw new DiscoveryException("No interface defined!");
+ }
+
+ if (impl == null) {
+ throw new DiscoveryException("No implementation defined for " + spi.getName());
+ }
+
+ if (!spi.isAssignableFrom(impl)) {
+ throw new DiscoveryException("Class " + impl.getName() +
+ " does not implement " + spi.getName());
+ }
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DefaultClassHolder.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DefaultClassHolder.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DefaultClassHolder.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DefaultClassHolder.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,81 @@
+/*
+ * 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.myfaces.commons.discovery.tools;
+
+import org.apache.myfaces.commons.discovery.ResourceClass;
+import org.apache.myfaces.commons.discovery.ResourceClassIterator;
+import org.apache.myfaces.commons.discovery.resource.ClassLoaders;
+import org.apache.myfaces.commons.discovery.resource.classes.DiscoverClasses;
+
+
+/**
+ * Holder for a default class.
+ *
+ * Class may be specified by name (String) or class (Class).
+ * Using the holder complicates the users job, but minimized # of API's.
+ *
+ * @author Richard A. Sitze
+ */
+public class DefaultClassHolder {
+ private Class defaultClass;
+ private final String defaultName;
+
+ public DefaultClassHolder(Class defaultClass) {
+ this.defaultClass = defaultClass;
+ this.defaultName = defaultClass.getName();
+ }
+
+ public DefaultClassHolder(String defaultName) {
+ this.defaultClass = null;
+ this.defaultName = defaultName;
+ }
+
+ /**
+ * @param spi non-null SPI
+ * @param loaders Used only if class needs to be loaded.
+ *
+ * @return Default Class. Load the class if necessary,
+ * and verify that it implements the SPI.
+ * (this forces the check, no way out..).
+ */
+ public Class getDefaultClass(SPInterface spi, ClassLoaders loaders) {
+ if (defaultClass == null) {
+ DiscoverClasses classDiscovery = new DiscoverClasses(loaders);
+ ResourceClassIterator classes = classDiscovery.findResourceClasses(getDefaultName());
+ if (classes.hasNext()) {
+ ResourceClass info = classes.nextResourceClass();
+ try {
+ defaultClass = info.loadClass();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ if (defaultClass != null) {
+ spi.verifyAncestory(defaultClass);
+ }
+
+ return defaultClass;
+ }
+
+ public String getDefaultName() {
+ return defaultName;
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverClass.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverClass.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverClass.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverClass.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,613 @@
+/*
+ * 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.myfaces.commons.discovery.tools;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.myfaces.commons.discovery.DiscoveryException;
+import org.apache.myfaces.commons.discovery.ResourceClass;
+import org.apache.myfaces.commons.discovery.ResourceClassIterator;
+import org.apache.myfaces.commons.discovery.ResourceNameIterator;
+import org.apache.myfaces.commons.discovery.resource.ClassLoaders;
+import org.apache.myfaces.commons.discovery.resource.classes.DiscoverClasses;
+import org.apache.myfaces.commons.discovery.resource.names.DiscoverServiceNames;
+
+
+/**
+ * <p>Discover class that implements a given service interface,
+ * with discovery and configuration features similar to that employed
+ * by standard Java APIs such as JAXP.
+ * </p>
+ *
+ * <p>In the context of this package, a service interface is defined by a
+ * Service Provider Interface (SPI). The SPI is expressed as a Java interface,
+ * abstract class, or (base) class that defines an expected programming
+ * interface.
+ * </p>
+ *
+ * <p>DiscoverClass provides the <code>find</code> methods for locating a
+ * class that implements a service interface (SPI). Each form of
+ * <code>find</code> varies slightly, but they all perform the same basic
+ * function.
+ *
+ * The <code>DiscoverClass.find</code> methods proceed as follows:
+ * </p>
+ * <ul>
+ * <p><li>
+ * Get the name of an implementation class. The name is the first
+ * non-null value obtained from the following resources:
+ * <ul>
+ * <li>
+ * The value of the (scoped) system property whose name is the same as
+ * the SPI's fully qualified class name (as given by SPI.class.getName()).
+ * The <code>ScopedProperties</code> class provides a way to bind
+ * properties by classloader, in a secure hierarchy similar in concept
+ * to the way classloader find class and resource files.
+ * See <code>ScopedProperties</code> for more details.
+ * <p>If the ScopedProperties are not set by users, then behaviour
+ * is equivalent to <code>System.getProperty()</code>.
+ * </p>
+ * </li>
+ * <p><li>
+ * The value of a <code>Properties properties</code> property, if provided
+ * as a parameter, whose name is the same as the SPI's fully qualifed class
+ * name (as given by SPI.class.getName()).
+ * </li></p>
+ * <p><li>
+ * The value obtained using the JDK1.3+ 'Service Provider' specification
+ * (http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html) to locate a
+ * service named <code>SPI.class.getName()</code>. This is implemented
+ * internally, so there is not a dependency on JDK 1.3+.
+ * </li></p>
+ * </ul>
+ * </li></p>
+ * <p><li>
+ * If the name of the implementation class is non-null, load that class.
+ * The class loaded is the first class loaded by the following sequence
+ * of class loaders:
+ * <ul>
+ * <li>Thread Context Class Loader</li>
+ * <li>DiscoverSingleton's Caller's Class Loader</li>
+ * <li>SPI's Class Loader</li>
+ * <li>DiscoverSingleton's (this class or wrapper) Class Loader</li>
+ * <li>System Class Loader</li>
+ * </ul>
+ * An exception is thrown if the class cannot be loaded.
+ * </li></p>
+ * <p><li>
+ * If the name of the implementation class is null, AND the default
+ * implementation class name (<code>defaultImpl</code>) is null,
+ * then an exception is thrown.
+ * </li></p>
+ * <p><li>
+ * If the name of the implementation class is null, AND the default
+ * implementation class (<code>defaultImpl</code>) is non-null,
+ * then load the default implementation class. The class loaded is the
+ * first class loaded by the following sequence of class loaders:
+ * <ul>
+ * <li>SPI's Class Loader</li>
+ * <li>DiscoverSingleton's (this class or wrapper) Class Loader</li>
+ * <li>System Class Loader</li>
+ * </ul>
+ * <p>
+ * This limits the scope in which the default class loader can be found
+ * to the SPI, DiscoverSingleton, and System class loaders. The assumption here
+ * is that the default implementation is closely associated with the SPI
+ * or system, and is not defined in the user's application space.
+ * </p>
+ * <p>
+ * An exception is thrown if the class cannot be loaded.
+ * </p>
+ * </li></p>
+ * <p><li>
+ * Verify that the loaded class implements the SPI: an exception is thrown
+ * if the loaded class does not implement the SPI.
+ * </li></p>
+ * </ul>
+ * </p>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is modelled
+ * after the SAXParserFactory and DocumentBuilderFactory implementations
+ * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
+ * </p>
+ *
+ * @author Richard A. Sitze
+ * @author Craig R. McClanahan
+ * @author Costin Manolache
+ * @version $Revision: 480374 $ $Date: 2006-11-28 22:33:25 -0500 (Mar, 28 Nov 2006) $
+ */
+public class DiscoverClass {
+ /**
+ * Readable placeholder for a null value.
+ */
+ public static final DefaultClassHolder nullDefaultImpl = null;
+
+ /**
+ * Readable placeholder for a null value.
+ */
+ public static final PropertiesHolder nullProperties = null;
+
+
+ private ClassLoaders classLoaders = null;
+
+
+ /**
+ * Create a class instance with dynamic environment
+ * (thread context class loader is determined on each call).
+ *
+ * Dynamically construct class loaders on each call.
+ */
+ public DiscoverClass() {
+ this(null);
+ }
+
+ /**
+ * Create a class instance with dynamic environment
+ * (thread context class loader is determined on each call).
+ *
+ * Cache static list of class loaders for each call.
+ */
+ public DiscoverClass(ClassLoaders classLoaders) {
+ this.classLoaders = classLoaders;
+ }
+
+
+ public ClassLoaders getClassLoaders(Class spiClass) {
+ return classLoaders;
+ }
+
+
+ /**
+ * Find class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @return Class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded, or if
+ * the resulting class does not implement (or extend) the SPI.
+ */
+ public Class find(Class spiClass)
+ throws DiscoveryException
+ {
+ return find(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ nullProperties,
+ nullDefaultImpl);
+ }
+
+ /**
+ * Find class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation.
+ *
+ * @return Class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded, or if
+ * the resulting class does not implement (or extend) the SPI.
+ */
+ public Class find(Class spiClass, Properties properties)
+ throws DiscoveryException
+ {
+ return find(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ new PropertiesHolder(properties),
+ nullDefaultImpl);
+ }
+
+ /**
+ * Find class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param defaultImpl Default implementation name.
+ *
+ * @return Class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded, or if
+ * the resulting class does not implement (or extend) the SPI.
+ */
+ public Class find(Class spiClass, String defaultImpl)
+ throws DiscoveryException
+ {
+ return find(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ nullProperties,
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Find class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,.
+ *
+ * @param defaultImpl Default implementation class.
+ *
+ * @return Class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded, or if
+ * the resulting class does not implement (or extend) the SPI.
+ */
+ public Class find(Class spiClass, Properties properties, String defaultImpl)
+ throws DiscoveryException
+ {
+ return find(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ new PropertiesHolder(properties),
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Find class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param propertiesFileName Used to determine name of SPI implementation,.
+ *
+ * @param defaultImpl Default implementation class.
+ *
+ * @return Class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded, or if
+ * the resulting class does not implement (or extend) the SPI.
+ */
+ public Class find(Class spiClass, String propertiesFileName, String defaultImpl)
+ throws DiscoveryException
+ {
+ return find(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ new PropertiesHolder(propertiesFileName),
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Find class implementing SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,.
+ *
+ * @param defaultImpl Default implementation class.
+ *
+ * @return Class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded, or if
+ * the resulting class does not implement (or extend) the SPI.
+ */
+ public static Class find(ClassLoaders loaders,
+ SPInterface spi,
+ PropertiesHolder properties,
+ DefaultClassHolder defaultImpl)
+ throws DiscoveryException
+ {
+ if (loaders == null) {
+ loaders = ClassLoaders.getLibLoaders(spi.getSPClass(),
+ DiscoverClass.class,
+ true);
+ }
+
+ Properties props = (properties == null)
+ ? null
+ : properties.getProperties(spi, loaders);
+
+ String[] classNames = discoverClassNames(spi, props);
+
+ if (classNames.length > 0) {
+ DiscoverClasses classDiscovery = new DiscoverClasses(loaders);
+
+ ResourceClassIterator classes =
+ classDiscovery.findResourceClasses(classNames[0]);
+
+ // If it's set as a property.. it had better be there!
+ if (classes.hasNext()) {
+ ResourceClass info = classes.nextResourceClass();
+ try {
+ return info.loadClass();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ } else {
+ ResourceNameIterator classIter =
+ (new DiscoverServiceNames(loaders)).findResourceNames(spi.getSPName());
+
+ ResourceClassIterator classes =
+ (new DiscoverClasses(loaders)).findResourceClasses(classIter);
+
+
+ if (!classes.hasNext() && defaultImpl != null) {
+ return defaultImpl.getDefaultClass(spi, loaders);
+ }
+
+ // Services we iterate through until we find one that loads..
+ while (classes.hasNext()) {
+ ResourceClass info = classes.nextResourceClass();
+ try {
+ return info.loadClass();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ throw new DiscoveryException("No implementation defined for " + spi.getSPName());
+ // return null;
+ }
+
+ /**
+ * Create new instance of class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public Object newInstance(Class spiClass)
+ throws DiscoveryException,
+ InstantiationException,
+ IllegalAccessException,
+ NoSuchMethodException,
+ InvocationTargetException
+ {
+ return newInstance(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ nullProperties,
+ nullDefaultImpl);
+ }
+
+ /**
+ * Create new instance of class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public Object newInstance(Class spiClass, Properties properties)
+ throws DiscoveryException,
+ InstantiationException,
+ IllegalAccessException,
+ NoSuchMethodException,
+ InvocationTargetException
+ {
+ return newInstance(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ new PropertiesHolder(properties),
+ nullDefaultImpl);
+ }
+
+ /**
+ * Create new instance of class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public Object newInstance(Class spiClass, String defaultImpl)
+ throws DiscoveryException,
+ InstantiationException,
+ IllegalAccessException,
+ NoSuchMethodException,
+ InvocationTargetException
+ {
+ return newInstance(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ nullProperties,
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Create new instance of class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public Object newInstance(Class spiClass, Properties properties, String defaultImpl)
+ throws DiscoveryException,
+ InstantiationException,
+ IllegalAccessException,
+ NoSuchMethodException,
+ InvocationTargetException
+ {
+ return newInstance(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ new PropertiesHolder(properties),
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Create new instance of class implementing SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param propertiesFileName Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public Object newInstance(Class spiClass, String propertiesFileName, String defaultImpl)
+ throws DiscoveryException,
+ InstantiationException,
+ IllegalAccessException,
+ NoSuchMethodException,
+ InvocationTargetException
+ {
+ return newInstance(getClassLoaders(spiClass),
+ new SPInterface(spiClass),
+ new PropertiesHolder(propertiesFileName),
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Create new instance of class implementing SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object newInstance(ClassLoaders loaders,
+ SPInterface spi,
+ PropertiesHolder properties,
+ DefaultClassHolder defaultImpl)
+ throws DiscoveryException,
+ InstantiationException,
+ IllegalAccessException,
+ NoSuchMethodException,
+ InvocationTargetException
+ {
+ return spi.newInstance(find(loaders, spi, properties, defaultImpl));
+ }
+
+ /**
+ * <p>Discover names of SPI implementation Classes from properties.
+ * The names are the non-null values, in order, obtained from the following
+ * resources:
+ * <ul>
+ * <li>ManagedProperty.getProperty(SPI.class.getName());</li>
+ * <li>properties.getProperty(SPI.class.getName());</li>
+ * </ul>
+ *
+ * @param properties Properties that may define the implementation
+ * class name(s).
+ *
+ * @return String[] Name of classes implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found.
+ */
+ public static String[] discoverClassNames(SPInterface spi,
+ Properties properties)
+ {
+ Vector names = new Vector();
+
+ String spiName = spi.getSPName();
+ String propertyName = spi.getPropertyName();
+
+ boolean includeAltProperty = !spiName.equals(propertyName);
+
+ // Try the (managed) system property spiName
+ String className = getManagedProperty(spiName);
+ if (className != null) names.addElement(className);
+
+ if (includeAltProperty) {
+ // Try the (managed) system property propertyName
+ className = getManagedProperty(propertyName);
+ if (className != null) names.addElement(className);
+ }
+
+ if (properties != null) {
+ // Try the properties parameter spiName
+ className = properties.getProperty(spiName);
+ if (className != null) names.addElement(className);
+
+ if (includeAltProperty) {
+ // Try the properties parameter propertyName
+ className = properties.getProperty(propertyName);
+ if (className != null) names.addElement(className);
+ }
+ }
+
+ String[] results = new String[names.size()];
+ names.copyInto(results);
+
+ return results;
+ }
+
+
+ /**
+ * Load the class whose name is given by the value of a (Managed)
+ * System Property.
+ *
+ * @see ManagedProperties
+ *
+ * @param propertName the name of the system property whose value is
+ * the name of the class to load.
+ */
+ public static String getManagedProperty(String propertyName) {
+ String value;
+ try {
+ value = ManagedProperties.getProperty(propertyName);
+ } catch (SecurityException e) {
+ value = null;
+ }
+ return value;
+ }
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverSingleton.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverSingleton.java?rev=982743&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverSingleton.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/commons/discovery/tools/DiscoverSingleton.java Thu Aug 5 19:32:38 2010
@@ -0,0 +1,488 @@
+/*
+ * 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.myfaces.commons.discovery.tools;
+
+import java.util.HashMap;
+import java.util.Properties;
+
+import org.apache.myfaces.commons.discovery.DiscoveryException;
+import org.apache.myfaces.commons.discovery.jdk.JDKHooks;
+import org.apache.myfaces.commons.discovery.resource.ClassLoaders;
+
+
+/**
+ * <p>Discover singleton service providers.
+ * This
+ * </p>
+ *
+ * <p>DiscoverSingleton instances are cached by the Discovery service,
+ * keyed by a combination of
+ * <ul>
+ * <li>thread context class loader,</li>
+ * <li>groupContext, and</li>
+ * <li>SPI.</li>
+ * </ul>
+ * This DOES allow multiple instances of a given <i>singleton</i> class
+ * to exist for different class loaders and different group contexts.
+ * </p>
+ *
+ * <p>In the context of this package, a service interface is defined by a
+ * Service Provider Interface (SPI). The SPI is expressed as a Java interface,
+ * abstract class, or (base) class that defines an expected programming
+ * interface.
+ * </p>
+ *
+ * <p>DiscoverSingleton provides the <code>find</code> methods for locating and
+ * instantiating a singleton instance of an implementation of a service (SPI).
+ * Each form of <code>find</code> varies slightly, but they all perform the
+ * same basic function.
+ *
+ * The simplest <code>find</code> methods are intended for direct use by
+ * components looking for a service. If you are not sure which finder(s)
+ * to use, you can narrow your search to one of these:
+ * <ul>
+ * <li>static Object find(Class spi);</li>
+ * <li>static Object find(Class spi, Properties properties);</li>
+ * <li>static Object find(Class spi, String defaultImpl);</li>
+ * <li>static Object find(Class spi,
+ * Properties properties, String defaultImpl);</li>
+ * <li>static Object find(Class spi,
+ * String propertiesFileName, String defaultImpl);</li>
+ * <li>static Object find(String groupContext, Class spi,
+ * Properties properties, String defaultImpl);</li>
+ * <li>static Object find(String groupContext, Class spi,
+ * String propertiesFileName, String defaultImpl);</li>
+ * </ul>
+ *
+ * The <code>DiscoverSingleton.find</code> methods proceed as follows:
+ * </p>
+ * <ul>
+ * <p><li>
+ * Examine an internal cache to determine if the desired service was
+ * previously identified and instantiated. If found in cache, return it.
+ * </li></p>
+ * <p><li>
+ * Get the name of an implementation class. The name is the first
+ * non-null value obtained from the following resources:
+ * <ul>
+ * <li>
+ * The value of the (scoped) system property whose name is the same as
+ * the SPI's fully qualified class name (as given by SPI.class.getName()).
+ * The <code>ScopedProperties</code> class provides a way to bind
+ * properties by classloader, in a secure hierarchy similar in concept
+ * to the way classloader find class and resource files.
+ * See <code>ScopedProperties</code> for more details.
+ * <p>If the ScopedProperties are not set by users, then behaviour
+ * is equivalent to <code>System.getProperty()</code>.
+ * </p>
+ * </li>
+ * <p><li>
+ * The value of a <code>Properties properties</code> property, if provided
+ * as a parameter, whose name is the same as the SPI's fully qualifed class
+ * name (as given by SPI.class.getName()).
+ * </li></p>
+ * <p><li>
+ * The value obtained using the JDK1.3+ 'Service Provider' specification
+ * (http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html) to locate a
+ * service named <code>SPI.class.getName()</code>. This is implemented
+ * internally, so there is not a dependency on JDK 1.3+.
+ * </li></p>
+ * </ul>
+ * </li></p>
+ * <p><li>
+ * If the name of the implementation class is non-null, load that class.
+ * The class loaded is the first class loaded by the following sequence
+ * of class loaders:
+ * <ul>
+ * <li>Thread Context Class Loader</li>
+ * <li>DiscoverSingleton's Caller's Class Loader</li>
+ * <li>SPI's Class Loader</li>
+ * <li>DiscoverSingleton's (this class or wrapper) Class Loader</li>
+ * <li>System Class Loader</li>
+ * </ul>
+ * An exception is thrown if the class cannot be loaded.
+ * </li></p>
+ * <p><li>
+ * If the name of the implementation class is null, AND the default
+ * implementation class (<code>defaultImpl</code>) is null,
+ * then an exception is thrown.
+ * </li></p>
+ * <p><li>
+ * If the name of the implementation class is null, AND the default
+ * implementation class (<code>defaultImpl</code>) is non-null,
+ * then load the default implementation class. The class loaded is the
+ * first class loaded by the following sequence of class loaders:
+ * <ul>
+ * <li>SPI's Class Loader</li>
+ * <li>DiscoverSingleton's (this class or wrapper) Class Loader</li>
+ * <li>System Class Loader</li>
+ * </ul>
+ * <p>
+ * This limits the scope in which the default class loader can be found
+ * to the SPI, DiscoverSingleton, and System class loaders. The assumption
+ * here is that the default implementation is closely associated with the SPI
+ * or system, and is not defined in the user's application space.
+ * </p>
+ * <p>
+ * An exception is thrown if the class cannot be loaded.
+ * </p>
+ * </li></p>
+ * <p><li>
+ * Verify that the loaded class implements the SPI: an exception is thrown
+ * if the loaded class does not implement the SPI.
+ * </li></p>
+ * <p><li>
+ * Create an instance of the class.
+ * </li></p>
+ * </ul>
+ *
+ * <p>
+ * Variances for various forms of the <code>find</code>
+ * methods are discussed with each such method.
+ * Variances include the following concepts:
+ * <ul>
+ * <li><b>rootFinderClass</b> - a wrapper encapsulating a finder method
+ * (factory or other helper class). The root finder class is used to
+ * determine the 'real' caller, and hence the caller's class loader -
+ * thereby preserving knowledge that is relevant to finding the
+ * correct/expected implementation class.
+ * </li>
+ * <li><b>propertiesFileName</b> - <code>Properties</code> may be specified
+ * directly, or by property file name. A property file is loaded using the
+ * same sequence of class loaders used to load the SPI implementation:
+ * <ul>
+ * <li>Thread Context Class Loader</li>
+ * <li>DiscoverSingleton's Caller's Class Loader</li>
+ * <li>SPI's Class Loader</li>
+ * <li>DiscoverSingleton's (this class) Class Loader</li>
+ * <li>System Class Loader</li>
+ * </ul>
+ * </li>
+ * <li><b>groupContext</b> - differentiates service providers for different
+ * logical groups of service users, that might otherwise be forced to share
+ * a common service and, more importantly, a common configuration of that
+ * service.
+ * <p>The groupContext is used to qualify the name of the property file
+ * name: <code>groupContext + '.' + propertiesFileName</code>. If that
+ * file is not found, then the unqualified propertyFileName is used.
+ * </p>
+ * <p>In addition, groupContext is used to qualify the name of the system
+ * property used to find the service implementation by prepending the value
+ * of <code>groupContext</code> to the property name:
+ * <code>groupContext> + '.' + SPI.class.getName()</code>.
+ * Again, if a system property cannot be found by that name, then the
+ * unqualified property name is used.
+ * </p>
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is modelled
+ * after the SAXParserFactory and DocumentBuilderFactory implementations
+ * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
+ * </p>
+ *
+ * @author Richard A. Sitze
+ * @author Craig R. McClanahan
+ * @author Costin Manolache
+ * @version $Revision: 480374 $ $Date: 2006-11-28 22:33:25 -0500 (Mar, 28 Nov 2006) $
+ */
+public class DiscoverSingleton {
+ /********************** (RELATIVELY) SIMPLE FINDERS **********************
+ *
+ * These finders are suitable for direct use in components looking for a
+ * service. If you are not sure which finder(s) to use, you can narrow
+ * your search to one of these.
+ */
+
+ /**
+ * Find implementation of SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class spiClass)
+ throws DiscoveryException
+ {
+ return find(null,
+ new SPInterface(spiClass),
+ DiscoverClass.nullProperties,
+ DiscoverClass.nullDefaultImpl);
+ }
+
+ /**
+ * Find implementation of SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class spiClass, Properties properties)
+ throws DiscoveryException
+ {
+ return find(null,
+ new SPInterface(spiClass),
+ new PropertiesHolder(properties),
+ DiscoverClass.nullDefaultImpl);
+ }
+
+ /**
+ * Find implementation of SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class spiClass, String defaultImpl)
+ throws DiscoveryException
+ {
+ return find(null,
+ new SPInterface(spiClass),
+ DiscoverClass.nullProperties,
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Find implementation of SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class spiClass,
+ Properties properties,
+ String defaultImpl)
+ throws DiscoveryException
+ {
+ return find(null,
+ new SPInterface(spiClass),
+ new PropertiesHolder(properties),
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /**
+ * Find implementation of SPI.
+ *
+ * @param spiClass Service Provider Interface Class.
+ *
+ * @param propertiesFileName Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class spiClass,
+ String propertiesFileName,
+ String defaultImpl)
+ throws DiscoveryException
+ {
+ return find(null,
+ new SPInterface(spiClass),
+ new PropertiesHolder(propertiesFileName),
+ new DefaultClassHolder(defaultImpl));
+ }
+
+ /*************** FINDERS FOR USE IN FACTORY/HELPER METHODS ***************
+ */
+
+
+ /**
+ * Find implementation of SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImpl Default implementation.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(ClassLoaders loaders,
+ SPInterface spi,
+ PropertiesHolder properties,
+ DefaultClassHolder defaultImpl)
+ throws DiscoveryException
+ {
+ ClassLoader contextLoader = JDKHooks.getJDKHooks().getThreadContextClassLoader();
+
+ Object obj = get(contextLoader, spi.getSPName());
+
+ if (obj == null) {
+ try {
+ obj = DiscoverClass.newInstance(loaders, spi, properties, defaultImpl);
+
+ if (obj != null) {
+ put(contextLoader, spi.getSPName(), obj);
+ }
+ } catch (DiscoveryException de) {
+ throw de;
+ } catch (Exception e) {
+ throw new DiscoveryException("Unable to instantiate implementation class for " + spi.getSPName(), e);
+ }
+ }
+
+ return obj;
+ }
+
+ /********************** CACHE-MANAGEMENT SUPPORT **********************/
+
+ /**
+ * Release all internal references to previously created service
+ * instances associated with the current thread context class loader.
+ * The <code>release()</code> method is called for service instances that
+ * implement the <code>Service</code> interface.
+ *
+ * This is useful in environments like servlet containers,
+ * which implement application reloading by throwing away a ClassLoader.
+ * Dangling references to objects in that class loader would prevent
+ * garbage collection.
+ */
+ public static synchronized void release() {
+ EnvironmentCache.release();
+ }
+
+ /**
+ * Release any internal references to a previously created service
+ * instance associated with the current thread context class loader.
+ * If the SPI instance implements <code>Service</code>, then call
+ * <code>release()</code>.
+ */
+ public static synchronized void release(Class spiClass) {
+ HashMap spis = (HashMap)EnvironmentCache.get(JDKHooks.getJDKHooks().getThreadContextClassLoader());
+
+ if (spis != null) {
+ spis.remove(spiClass.getName());
+ }
+ }
+
+
+ /************************* SPI CACHE SUPPORT *************************
+ *
+ * Cache services by a 'key' unique to the requesting class/environment:
+ *
+ * When we 'release', it is expected that the caller of the 'release'
+ * have the same thread context class loader... as that will be used
+ * to identify all cached entries to be released.
+ *
+ * We will manage synchronization directly, so all caches are implemented
+ * as HashMap (unsynchronized).
+ *
+ * - ClassLoader::groupContext::SPI::Instance Cache
+ * Cache : HashMap
+ * Key : Thread Context Class Loader (<code>ClassLoader</code>).
+ * Value : groupContext::SPI Cache (<code>HashMap</code>).
+ *
+ * - groupContext::SPI::Instance Cache
+ * Cache : HashMap
+ * Key : groupContext (<code>String</code>).
+ * Value : SPI Cache (<code>HashMap</code>).
+ *
+ * - SPI::Instance Cache
+ * Cache : HashMap
+ * Key : SPI Class Name (<code>String</code>).
+ * Value : SPI Instance/Implementation (<code>Object</code>.
+ */
+
+ /**
+ * Implements first two levels of the cache (loader & groupContext).
+ * Allows null keys, important as default groupContext is null.
+ */
+ // FIXME: Why is this here? All the methods used are static.
+ //private static final EnvironmentCache root_cache = new EnvironmentCache();
+
+ /**
+ * Get service keyed by spi & classLoader.
+ */
+ private static synchronized Object get(ClassLoader classLoader,
+ String spiName)
+ {
+ HashMap spis = (HashMap)EnvironmentCache.get(classLoader);
+
+ return (spis != null)
+ ? spis.get(spiName)
+ : null;
+ }
+
+ /**
+ * Put service keyed by spi & classLoader.
+ */
+ private static synchronized void put(ClassLoader classLoader,
+ String spiName,
+ Object service)
+ {
+ if (service != null)
+ {
+ HashMap spis = (HashMap)EnvironmentCache.get(classLoader);
+
+ if (spis == null) {
+ spis = new HashMap(EnvironmentCache.smallHashSize);
+ EnvironmentCache.put(classLoader, spis);
+ }
+
+ spis.put(spiName, service);
+ }
+ }
+}