blob: 6fbdad8bd5db5f593c6e5b1025c971a351cccdaf [file]
/**
*
* 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 commonj.sdo.impl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import commonj.sdo.helper.CopyHelper;
import commonj.sdo.helper.DataFactory;
import commonj.sdo.helper.DataHelper;
import commonj.sdo.helper.EqualityHelper;
import commonj.sdo.helper.TypeHelper;
import commonj.sdo.helper.XMLHelper;
import commonj.sdo.helper.XSDHelper;
/**
* A HelperProvider obtains specific default helpers and other
* implementation-specific objects used by a Java implementation of SDO.
*
* @version $Rev$ $Date$
*/
public abstract class HelperProvider {
/**
* The default HelperProvider INSTANCE. This is located using the ClassLoader used
* to load the HelperProvider class itself and if no default implementation is available
* this field will be set to null.
*/
public static final HelperProvider INSTANCE;
/**
* The name of the resource that is used for service location.
*/
public static final String SERVICE_RESOURCE_NAME = "META-INF/services/commonj.sdo.impl.HelperProvider";
/**
* The name of the system property that will be checked for an implementation name.
*/
public static final String PROPERTY_NAME = "commonj.sdo.impl.HelperProvider";
static {
// initialize the default instance using this class's classloader
// set to null if none could be located (implies no default implementation)
HelperProvider provider;
try {
provider = getInstance(HelperProvider.class.getClassLoader());
} catch (NoHelperProviderException e) {
provider = null;
}
INSTANCE = provider;
}
/**
* Locate and instantiate a HelperProvider.
* <p/>
* Attempt to locate a HelperProvider using first the Thread's current context classloader and then,
* if that is not set, not readable, or does not provide an implementation, using the classloader
* used to load the HelperProvider class itself.
* <p/>
* A new instance is returned for each sucessful invocation.
*
* @return an implementation of HelperProvider
* @throws NoHelperProviderException if no provider implementation was defined or it could not be instantiated
*/
public static HelperProvider getInstance() throws NoHelperProviderException {
String implName = getImplementationName();
ClassLoader cl = getContextClassLoader();
if (cl != null) {
HelperProvider provider = loadImplementation(cl, implName);
if (provider != null) {
return provider;
}
}
cl = HelperProvider.class.getClassLoader();
HelperProvider provider = loadImplementation(cl, implName);
if (provider != null) {
return provider;
}
throw new NoHelperProviderException(implName);
}
/**
* Locate and instantiate a HelperProvider using the supplied ClassLoader.
* <p/>
* The name of the implementation to use is determined by the value of the "commonj.sdo.impl.HelperProvider"
* system property. If this is not set or this code does not have permission to read it then the name
* will be retrieved from the META-INF/services/commonj.sdo.impl.HelperProvider resource as returned
* by the supplied classloader as described in the
* <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">JAR file specification</a>.
* <p/>
* A new instance is returned for each sucessful invocation.
*
* @param cl the classloader to use to locate and instantiate the implementation
* @return the specified implementation of HelperProvider
* @throws NoHelperProviderException if no provider implementation was defined or it could not be instantiated
*/
public static HelperProvider getInstance(ClassLoader cl) throws NoHelperProviderException {
String implName = getImplementationName();
HelperProvider provider = loadImplementation(cl, implName);
if (provider == null) {
throw new NoHelperProviderException(implName);
}
return provider;
}
private static ClassLoader getContextClassLoader() {
try {
return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return Thread.currentThread().getContextClassLoader();
}
});
} catch (SecurityException e) {
return null;
}
}
private static HelperProvider loadImplementation(ClassLoader cl, String implName) throws NoHelperProviderException {
// if no name is requested, locate using the supplied classloader
if (implName == null) {
implName = getImplementationName(cl);
}
// no implementation to try, return null
if (implName == null) {
return null;
}
// try an instantiate the implementation
try {
return (HelperProvider) cl.loadClass(implName).newInstance();
} catch (InstantiationException e) {
throw new NoHelperProviderException(implName, e);
} catch (IllegalAccessException e) {
throw new NoHelperProviderException(implName, e);
} catch (ClassNotFoundException e) {
throw new NoHelperProviderException(implName, e);
}
}
private static String getImplementationName() {
try {
return (String)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return System.getProperty(PROPERTY_NAME);
}
});
} catch (SecurityException e) {
return null;
}
}
private static String getImplementationName(ClassLoader cl) {
InputStream is = cl.getResourceAsStream(SERVICE_RESOURCE_NAME);
if (is == null) {
return null;
}
InputStreamReader in;
try {
in = new InputStreamReader(is, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new AssertionError("UTF-8 encoding not available");
}
try {
BufferedReader reader = new BufferedReader(in, 128);
try {
String line;
while ((line = reader.readLine()) != null) {
int i = line.indexOf('#');
if (i != -1) {
line = line.substring(0, i);
}
line = line.trim();
if (line.length() > 0) {
return line;
}
}
return null;
} finally {
reader.close();
}
} catch (IOException e) {
throw new NoHelperProviderException(e);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// implementation specific methods for users that don't want to use the default implementation
/**
* Returns a CopyHelper obtained from this implementation.
*
* @return a CopyHelper obtained from this implementation
*/
public abstract CopyHelper copyHelper();
/**
* Returns a DataFactory obtained from this implementation.
*
* @return a DataFactory obtained from this implementation
*/
public abstract DataFactory dataFactory();
/**
* Returns a DataHelper obtained from this implementation.
*
* @return a DataHelper obtained from this implementation
*/
public abstract DataHelper dataHelper();
/**
* Returns a EqualityHelper obtained from this implementation.
*
* @return a EqualityHelper obtained from this implementation
*/
public abstract EqualityHelper equalityHelper();
/**
* Returns a TypeHelper obtained from this implementation.
*
* @return a TypeHelper obtained from this implementation
*/
public abstract TypeHelper typeHelper();
/**
* Returns a XMLHelper obtained from this implementation.
*
* @return a XMLHelper obtained from this implementation
*/
public abstract XMLHelper xmlHelper();
/**
* Returns a XSDHelper obtained from this implementation.
*
* @return a XSDHelper obtained from this implementation
*/
public abstract XSDHelper xsdHelper();
/**
* Create a Resolvable using this implementation
*
* @return a Resolvable created using this implementation
*/
public abstract ExternalizableDelegator.Resolvable resolvable();
/**
* Create a Resolvable using this implementation
*
* @param target the object to be resolved
* @return a Resolvable created using this implementation
*/
public abstract ExternalizableDelegator.Resolvable resolvable(Object target);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// static helper methods required by the specification
/**
* Returns a CopyHelper obtained from the default HelperProvider.
*
* @return a CopyHelper obtained from the default HelperProvider
*/
public static CopyHelper getCopyHelper() {
return INSTANCE.copyHelper();
}
/**
* Returns a DataFactory obtained from the default HelperProvider.
*
* @return a DataFactory obtained from the default HelperProvider
*/
public static DataFactory getDataFactory() {
return INSTANCE.dataFactory();
}
/**
* Returns a DataHelper obtained from the default HelperProvider.
*
* @return a DataHelper obtained from the default HelperProvider
*/
public static DataHelper getDataHelper() {
return INSTANCE.dataHelper();
}
/**
* Returns a EqualityHelper obtained from the default HelperProvider.
*
* @return a EqualityHelper obtained from the default HelperProvider
*/
public static EqualityHelper getEqualityHelper() {
return INSTANCE.equalityHelper();
}
/**
* Returns a TypeHelper obtained from the default HelperProvider.
*
* @return a TypeHelper obtained from the default HelperProvider
*/
public static TypeHelper getTypeHelper() {
return INSTANCE.typeHelper();
}
/**
* Returns a XMLHelper obtained from the default HelperProvider.
*
* @return a XMLHelper obtained from the default HelperProvider
*/
public static XMLHelper getXMLHelper() {
return INSTANCE.xmlHelper();
}
/**
* Returns a XSDHelper obtained from the default HelperProvider.
*
* @return a XSDHelper obtained from the default HelperProvider
*/
public static XSDHelper getXSDHelper() {
return INSTANCE.xsdHelper();
}
/**
* Create a Resolvable using the default HelperProvider
*
* @return a Resolvable created using the default HelperProvider
*/
public static ExternalizableDelegator.Resolvable createResolvable() {
return INSTANCE.resolvable();
}
/**
* Create a Resolvable using the default HelperProvider
*
* @param target the object to be resolved
* @return a Resolvable created using the default HelperProvider
*/
public static ExternalizableDelegator.Resolvable createResolvable(Object target) {
return INSTANCE.resolvable(target);
}
}