blob: ce61464ad68aa5000cf39c0c5920bd85b58088e3 [file] [log] [blame]
/*
Derby - Class org.apache.derby.catalog.Java5SystemProcedures
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.derby.catalog;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.SQLException;
import org.apache.derby.iapi.sql.dictionary.OptionalTool;
import org.apache.derby.iapi.error.PublicAPI;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.services.context.Context;
import org.apache.derby.iapi.services.context.ContextService;
import org.apache.derby.iapi.services.loader.ClassFactory;
import org.apache.derby.iapi.services.loader.ClassFactoryContext;
/**
* <p>
* System procedures which run only on Java 5 or higher.
* </p>
*/
public class Java5SystemProcedures
{
///////////////////////////////////////////////////////////////////////////////////
//
// CONSTANTS
//
///////////////////////////////////////////////////////////////////////////////////
/** Offsets into arrays in OPTIONAL_TOOLS */
private static final int TOOL_NAME = 0;
private static final int TOOL_CLASS_NAME = TOOL_NAME + 1;
/** Generic name for all user-supplied tools: the first optional arg is the tool class name */
private static final String CUSTOM_TOOL_CLASS_NAME = "customTool";
///////////////////////////////////////////////////////////////////////////////////
//
// STATE
//
///////////////////////////////////////////////////////////////////////////////////
/** Mapping of tool names to their implementing classes for use by SYSCS_REGISTER_TOOL */
private static final String[][] OPTIONAL_TOOLS = new String[][]
{
{ "databaseMetaData", "org.apache.derby.impl.tools.optional.DBMDWrapper" },
{ "foreignViews", "org.apache.derby.impl.tools.optional.ForeignDBViews" },
{ "luceneSupport", "org.apache.derby.optional.lucene.LuceneSupport" },
{ "optimizerTracing", "org.apache.derby.impl.sql.compile.OptimizerTracer" },
{ "optimizerTracingViews", "org.apache.derby.impl.sql.compile.OptTraceViewer" },
{ "rawDBReader", "org.apache.derby.optional.dump.RawDBReader" },
{ "simpleJson", "org.apache.derby.optional.json.SimpleJsonTool" },
};
///////////////////////////////////////////////////////////////////////////////////
//
// PUBLIC BEHAVIOR
//
///////////////////////////////////////////////////////////////////////////////////
/**
* <p>
* Load or unload an optional tool package. If the tool name is the special
* CUSTOM_TOOL_CLASS_NAME tool, then the first optionalArg is the name
* of a user-supplied class which implements OptionalTool.
* </p>
*
* @param toolName Name of the tool package.
* @param register True if the package should be loaded, false otherwise.
* @param optionalArgs Tool-specific configuration parameters.
*/
public static void SYSCS_REGISTER_TOOL
(
String toolName,
boolean register,
String... optionalArgs
)
throws SQLException
{
try {
ClassFactoryContext cfc = (ClassFactoryContext) getContext( ClassFactoryContext.CONTEXT_ID );
ClassFactory classFactory = cfc.getClassFactory();
String toolClassName = findToolClassName( toolName, optionalArgs );
OptionalTool tool = null;
Class<?> toolClass;
try {
toolClass = classFactory.loadApplicationClass( toolClassName );
}
catch (ClassNotFoundException cnfe) { throw wrap( cnfe ); }
if (!OptionalTool.class.isAssignableFrom(toolClass)) {
throw badCustomTool(toolClassName);
}
try {
tool = (OptionalTool) toolClass.getConstructor().newInstance();
}
catch (InstantiationException ie) { throw wrap( ie ); }
catch (IllegalAccessException iae) { throw wrap( iae ); }
catch (NoSuchMethodException ie) { throw wrap( ie ); }
catch (java.lang.reflect.InvocationTargetException iae) { throw wrap( iae ); }
// Strip the custom tool class name from the optional args as necessary
if ( CUSTOM_TOOL_CLASS_NAME.equals( toolName ) )
{
optionalArgs = stripCustomClassName( optionalArgs );
}
if ( register ) { tool.loadTool( optionalArgs ); }
else { tool.unloadTool( optionalArgs ); }
}
catch (StandardException se) { throw PublicAPI.wrapStandardException( se ); }
}
/** Lookup the class name corresponding to the name of an optional tool */
private static String findToolClassName( String toolName, String... optionalArgs ) throws StandardException
{
//
// For a user-supplied tool, the first optional arg is the name of a user-supplied class
// which implements OptionalTool
//
if ( CUSTOM_TOOL_CLASS_NAME.equals( toolName ) )
{
if ( (optionalArgs == null) || (optionalArgs.length == 0) )
{
throw badTool( "null" );
}
else { return optionalArgs[ 0 ]; }
}
for ( String[] descriptor : OPTIONAL_TOOLS )
{
if ( descriptor[ TOOL_NAME ].equals( toolName ) ) { return descriptor[ TOOL_CLASS_NAME ]; }
}
throw badTool( toolName );
}
private static StandardException badTool( String toolName )
{
return StandardException.newException( SQLState.LANG_UNKNOWN_TOOL_NAME, toolName );
}
private static StandardException badCustomTool(String className) {
return StandardException.newException(
SQLState.LANG_UNKNOWN_CUSTOM_TOOL_NAME, className);
}
/**
* <p>
* For a custom tool, we strip the first arg from the list of optional args. By
* the time we get to this method, it has already been determined that there is
* at least one arg and it is the name of a class which implements OptionalTool.
* </p>
*/
private static String[] stripCustomClassName( String... optionalArgs )
{
int count = optionalArgs.length - 1;
String[] retval = new String[ count ];
for ( int i = 0; i < count; i++ ) { retval[ i ] = optionalArgs[ i + 1 ]; }
return retval;
}
///////////////////////////////////////////////////////////////////////////////////
//
// MINIONS
//
///////////////////////////////////////////////////////////////////////////////////
private static StandardException wrap( Throwable t ) { return StandardException.plainWrapException( t ); }
/**
* Privileged lookup of a Context. Must be private so that user code
* can't call this entry point.
*/
private static Context getContext( final String contextID )
{
if ( System.getSecurityManager() == null )
{
return ContextService.getContext( contextID );
}
else
{
return AccessController.doPrivileged
(
new PrivilegedAction<Context>()
{
public Context run()
{
return ContextService.getContext( contextID );
}
}
);
}
}
}