/**
* Copyright 2014 Jason Sorensen (sorensenj@smert.net)
*
* 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 net.smert.frameworkgl.examples;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListModel;
/**
*
* @author Jason Sorensen <sorensenj@smert.net>
*/
public class JFrameMainModel {
private final static Logger log = Logger.getLogger(JFrameMainModel.class.getName());
private final CustomClassLoader customClassLoader;
private final String exampleDirectory;
private final String rootDirectoryPrefix;
public JFrameMainModel(String exampleDirectory, String rootDirectoryPrefix) {
customClassLoader = new CustomClassLoader();
this.exampleDirectory = exampleDirectory;
this.rootDirectoryPrefix = rootDirectoryPrefix;
}
private boolean checkMainMethodExists(String clazzName) {
boolean result = false;
try {
Class clazz = customClassLoader.loadClass(clazzName);
Method mainMethod = clazz.getMethod("main", String[].class);
mainMethod.setAccessible(true);
int mods = mainMethod.getModifiers();
Class returnType = mainMethod.getReturnType();
// Is method a public static void?
if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && (returnType == void.class)) {
result = true;
}
} catch (ClassNotFoundException e) {
log.log(Level.SEVERE, "Unable to find class", e);
} catch (NoSuchMethodException e) {
// Do nothing. Not all classes have a main method.
} catch (SecurityException e) {
log.log(Level.SEVERE, "There was a problem accessing the method", e);
}
return result;
}
private void filterFileAndCheck(String filename, String fullPath, String separator, List<String> mainClasses) {
if (!filename.contains("$") && filename.endsWith(".class") && !filename.startsWith("Main")) {
String clazzName = getClassNameFromPath(fullPath, separator);
if ((clazzName.length() != 0) && checkMainMethodExists(clazzName)) {
mainClasses.add(clazzName);
}
}
}
private String getClassNameFromPath(String fullPath, String separator) {
String clazzName = "";
String directory = (rootDirectoryPrefix + exampleDirectory).replace("/", separator);
int index = fullPath.indexOf(directory);
if (index != -1) {
clazzName = fullPath.substring(index).replaceFirst(".class$", "").replace(separator, ".");
}
return clazzName;
}
private int getDirectoryDepth(String fullPathThisClass) {
int depth = 0;
fullPathThisClass = fullPathThisClass.replace("\\", "/");
int index = fullPathThisClass.indexOf(rootDirectoryPrefix);
if (index != -1) {
String rootPathToClass = fullPathThisClass.substring(index);
depth = rootPathToClass.length() - rootPathToClass.replace("/", "").length();
}
return depth;
}
private List<String> getMainClasses() {
List<String> mainClasses = new ArrayList();
URL classLocation = JFrameMainModel.class.getResource(JFrameMainModel.class.getSimpleName() + ".class");
String protocol = classLocation.getProtocol();
switch (protocol) {
case "file":
getMainClassesFromFile(mainClasses, classLocation);
break;
case "jar":
getMainClassesFromJar(mainClasses);
break;
default:
throw new RuntimeException("Unknown protocol for current class: " + protocol);
}
return mainClasses;
}
private void getMainClassesFromFile(List<String> mainClasses, URL classLocation) {
try {
Path path = Paths.get(classLocation.toURI());
String rootPath = getRootPath(path.toString());
listFilesInDirectory(rootPath, mainClasses);
} catch (URISyntaxException e) {
log.log(Level.SEVERE, "Invalid URI syntax", e);
System.exit(-1);
}
}
private void getMainClassesFromJar(List<String> mainClasses) {
CodeSource src = JFrameMainModel.class.getProtectionDomain().getCodeSource();
if (src != null) {
URL jar = src.getLocation();
try {
try (ZipInputStream zip = new ZipInputStream(jar.openStream())) {
while (true) {
ZipEntry e = zip.getNextEntry();
if (e == null) {
break;
}
String fullPath = e.getName();
Path path = Paths.get(fullPath);
String filename = path.getFileName().toString();
filterFileAndCheck(filename, fullPath, "/", mainClasses);
}
}
} catch (IOException e) {
log.log(Level.SEVERE, "Unable to open ZipInputStream", e);
System.exit(-1);
}
}
}
private String getRootPath(String fullPathThisClass) {
int depth = getDirectoryDepth(fullPathThisClass);
Path currentPath = Paths.get(fullPathThisClass);
while (depth > 0) {
Path parent = currentPath.getParent();
currentPath = parent;
depth--;
}
return currentPath.toString();
}
private void listFilesInDirectory(String directoryPath, List<String> mainClasses) {
File directory = new File(directoryPath);
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
listFilesInDirectory(file.getPath(), mainClasses);
} else {
filterFileAndCheck(file.getName(), file.getAbsolutePath(), File.separator, mainClasses);
}
}
}
public AbstractListModel getListModelWithMainClasses() {
DefaultListModel listModelMainClasses = new DefaultListModel();
List<String> mainClasses = getMainClasses();
for (String clazz : mainClasses) {
listModelMainClasses.addElement(clazz);
}
return listModelMainClasses;
}
public void runDemo(String mainClass, String[] args) {
try {
Class clazz = customClassLoader.loadClass(mainClass, false);
Method mainMethod = clazz.getMethod("main", String[].class);
mainMethod.invoke(null, (Object) args);
} catch (Throwable e) {
log.log(Level.SEVERE, null, e);
System.exit(-1);
}
}
}