/*
* Copyright 2002-2004 Greg Hinkle
*
* Licensed 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.mc4j.ems.connection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mc4j.ems.connection.settings.ConnectionSettings;
import org.mc4j.ems.connection.support.ConnectionProvider;
import org.mc4j.ems.connection.support.classloader.ClassLoaderFactory;
import org.mc4j.ems.connection.support.metadata.*;
import java.io.File;
import java.io.FilenameFilter;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Greg Hinkle (ghinkle@users.sourceforge.net), Apr 5, 2005
* @version $Revision: 1.2 $($Author: ghinkl $ / $Date: 2006/04/12 19:11:33 $)
*/
public class ConnectionFactory {
private static final String BROAD_SEARCH_PROPERTY = "mc4j.ems.fileSearchBroad";
private static final int DEFAULT_SEARCH_DEPTH = 6;
private static final String SEARCH_DEPTH_PROPERTY = "mc4j.ems.fileSearchDepth";
private boolean broadSearch = false;
private int searchDepth = DEFAULT_SEARCH_DEPTH;
private static Log log = LogFactory.getLog(ConnectionFactory.class);
public static final ConnectionTypeDescriptor[] CONNECTION_DESCRIPTORS =
new ConnectionTypeDescriptor[]{
new JBossConnectionTypeDescriptor(),
new Tomcat55ConnectionTypeDescriptor(),
new JDMKConnectionTypeDescriptor(),
new J2SE5ConnectionTypeDescriptor(),
new JSR160ConnectionTypeDescriptor(),
new GeronimoConnectionTypeDescriptor(),
new Mx4jConnectionTypeDescriptor(),
new Oc4jConnectionTypeDescriptor(),
new PramatiConnectionTypeDescriptor(),
new SJSASConnectionTypeDescriptor(),
new WeblogicConnectionTypeDescriptor(),
new Weblogic9ConnectionTypeDescriptor(),
new Weblogic9Jsr77ConnectionTypeDescriptor(),
new WebsphereConnectionTypeDescriptor(),
new WebsphereStudioConnectionTypeDescriptor()};
// TODO GH: Move to a SPI model allowing new types to be added later?
// TODO GH: Perhaps go to a more externalized descriptor based model?
public static List<ConnectionTypeDescriptor> getConnectionTypes() {
return Arrays.asList(CONNECTION_DESCRIPTORS);
}
public ConnectionFactory() {
if (System.getProperty(BROAD_SEARCH_PROPERTY) != null) {
broadSearch = Boolean.valueOf(System.getProperty(BROAD_SEARCH_PROPERTY));
}
if (System.getProperty(SEARCH_DEPTH_PROPERTY) != null) {
searchDepth = Integer.parseInt(System.getProperty(SEARCH_DEPTH_PROPERTY));
}
}
public EmsConnection connect(ConnectionSettings connectionSettings) {
log.info("Connecting to " + connectionSettings.toString());
String className = connectionSettings.getConnectionType().getConnectionNodeClassName();
try {
// TODO GH: Does this need to be configurable per connection?
ClassLoader loader = ClassLoaderFactory.getInstance().buildClassLoader(connectionSettings);
log.debug("Loading connection class from ClassLoader [" + loader + "] ConnectionProvider class [" + className + "]");
// TODO GH: Add intelligent classloader layer here that can either work
// directly against current classloader or build a non-delegating child
// to override with connection specific classes
Class clazz = Class.forName(className, false, loader);
ConnectionProvider connectionProvider =
(ConnectionProvider) clazz.newInstance();
connectionProvider.initialize(connectionSettings);
return connectionProvider.connect();
} catch (IllegalAccessException e) {
throw new ConnectionException("Could not access ConnectionClass", e);
} catch (InstantiationException e) {
throw new ConnectionException("Could not instantiate ConnectionClass", e);
} catch (ClassNotFoundException e) {
throw new ConnectionException("Could not find ConnectionClass " + className, e);
}
}
/**
* This will find server classes for a ConnectionSettings by using the supplied
* LibraryURI of the ConnectionSettings and searching for the ConnectClassPathEntries
* of the ConnectionType supplied with the settings.
* <p/>
* This method should only be called once. If the entries need to be reset, you should
* first clear the settings' classpath entries. This method appends class path entries
* to the existing list.
*
* @param connectionSettings the ConnectionSettings to update with recommeneded class
* path entries
*/
public void discoverServerClasses(ConnectionSettings connectionSettings) {
if (connectionSettings.getLibraryURI() != null) {
long start = System.currentTimeMillis();
String[] serverFiles = connectionSettings.getConnectionType().getConnectionClasspathEntries();
// No server file dependencies
if (serverFiles == null)
return;
File serverInstall = new File(connectionSettings.getLibraryURI());
if (!serverInstall.exists())
throw new LoadException("Supplied server installation does not exist " + connectionSettings.getLibraryURI());
List<File> foundFiles = new ArrayList<File>();
for (String serverFile : serverFiles) {
if (broadSearch && serverFile.indexOf('/') >= 0) {
serverFile = serverFile.substring(serverFile.lastIndexOf('/')+1);
}
log.debug("Searching for library " + serverFile);
File[] matchedFiles = null;
try {
if (serverFile.indexOf('/') >= 0) {
matchedFiles = findDeepFiles(serverInstall, serverFile);
} else {
File file = findFile(serverInstall, serverFile);
if (file != null)
matchedFiles = new File[]{file};
}
} catch (Exception e) {
log.info("Library dependency not found " + serverFile, e);
}
if (matchedFiles != null) {
for (File matchedFile : matchedFiles) {
if (matchedFile != null && !foundFiles.contains(matchedFile)) {
foundFiles.add(matchedFile);
log.debug("Library dependency resolved " + matchedFile.getAbsolutePath());
}
}
} else {
log.info("Connection library dependancy [" + serverFile+ "] not found in directory: " + serverInstall);
}
}
if (connectionSettings.getClassPathEntries() == null)
connectionSettings.setClassPathEntries(foundFiles);
else
connectionSettings.getClassPathEntries().addAll(foundFiles);
log.info("Discovered libraries in " + (System.currentTimeMillis() - start) + " ms");
}
}
private File findFile(File directory, String filename) {
return findFile(directory, filename, 1);
}
private File findFile(File directory, String filename, int depth) {
if (depth > searchDepth)
return null;
File[] children = directory.listFiles();
if (children == null)
return null;
for (File child : children) {
if (child.isDirectory()) {
File result = findFile(child, filename, depth + 1);
if (result != null)
return result;
} else {
if (filename.equalsIgnoreCase(child.getName()))
return child;
}
}
return null;
}
private File[] findDeepFiles(File directory, String filename) {
if (filename.startsWith("/"))
filename = filename.substring(1);
int in = filename.indexOf("/");
if (in < 0) {
if (filename.equals("*")) {
return directory.listFiles();
} else {
File match = getChild(directory, filename);
if (match == null)
return null;
else
return new File[]{match};
}
} else {
String dir = filename.substring(0, in);
String restOfName = filename.substring(in + 1, filename.length());
if (dir.equals("*")) {
File[] children = directory.listFiles(new DirectoryFilter());
if (children != null) {
for (File child : children) {
File[] childDir = findDeepFiles(child, restOfName);
if (childDir != null) {
return childDir;
}
}
}
log.debug("Could not find " + directory.getAbsolutePath() + " :: " + restOfName);
return null;
} else {
File childDir = getChild(directory, dir);
if (childDir == null) {
log.debug("Could not find " + directory.getAbsolutePath() + " :: " + restOfName);
return null;
} else {
return findDeepFiles(childDir, restOfName);
}
}
}
}
private static class DirectoryFilter implements FileFilter {
public boolean accept(File pathname) {
return pathname.isDirectory();
}
}
public File getChild(File directory, final String childName) {
if (directory == null)
return null;
if (!directory.exists())
return null;
File[] children = directory.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return childName.equals(name);
}
});
if (children.length == 1) {
return children[0];
} else {
//log.info("Connection library dependancy [" + childName + "] not found in directory: " + directory.getAbsolutePath());
return null;
}
}
}