Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

#232 Added logging when exploring libraries (jars or folders) #234

Merged
merged 5 commits into from
Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Gluon and/or its affiliates.
* Copyright (c) 2017, 2020, Gluon and/or its affiliates.
* Copyright (c) 2012, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
Expand Down Expand Up @@ -34,6 +34,8 @@

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
Expand All @@ -47,13 +49,15 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import com.oracle.javafx.scenebuilder.kit.alert.ImportingGluonControlsAlert;
import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.AbstractModalDialog;
import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
import com.oracle.javafx.scenebuilder.kit.i18n.I18N;
import com.oracle.javafx.scenebuilder.kit.library.BuiltinLibrary;
import com.oracle.javafx.scenebuilder.kit.library.user.UserLibrary;
import com.oracle.javafx.scenebuilder.kit.library.util.FolderExplorer;
import com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer;
Expand Down Expand Up @@ -89,10 +93,12 @@
*/
public class ImportWindowController extends AbstractModalDialog {

private static final Logger LOGGER = Logger.getLogger(ImportWindowController.class.getSimpleName());

public enum PrefSize {

DEFAULT, TWO_HUNDRED_BY_ONE_HUNDRED, TWO_HUNDRED_BY_TWO_HUNDRED
};
}

final List<File> importFiles;
private final LibraryPanelController libPanelController;
Expand Down Expand Up @@ -462,7 +468,13 @@ protected List<JarReport> call() throws Exception {

boolean importingGluonControls = false;
for (JarReport jarReport : jarReportList) {
Path file = jarReport.getJar();
String jarName = file.getName(file.getNameCount() - 1).toString();
StringBuilder sb = new StringBuilder(
I18N.getString("log.info.explore." + (Files.isDirectory(file) ? "folder" : "jar") + ".results", jarName))
.append("\n");
for (JarReportEntry e : jarReport.getEntries()) {
sb.append("> ").append(e.toString()).append("\n");
if ((e.getStatus() == JarReportEntry.Status.OK) && e.isNode()) {
boolean checked = true;
final String canonicalName = e.getKlass().getCanonicalName();
Expand All @@ -483,8 +495,17 @@ protected List<JarReport> call() throws Exception {
updateOKButtonTitle(numOfComponentToImport);
updateSelectionToggleText(numOfComponentToImport);
});
} else {
if (e.getException() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.getException().printStackTrace(pw);
sb.append(">> " + sw.toString());
}
}
}
LOGGER.info(sb.toString());

if (jarReport.hasGluonControls()) {
importingGluonControls = true;
}
Expand Down Expand Up @@ -534,7 +555,7 @@ void unsetProcessing() {

importList.getSelectionModel().selectedItemProperty().addListener((ChangeListener<ImportRow>) (ov, t, t1) -> {
previewGroup.getChildren().clear();
final String fxmlText = JarExplorer.makeFxmlText(t1.getJarReportEntry().getKlass());
final String fxmlText = BuiltinLibrary.makeFxmlText(t1.getJarReportEntry().getKlass());
try {
FXOMDocument fxomDoc = new FXOMDocument(fxmlText, null, importClassLoader, null);
zeNode = (Node) fxomDoc.getSceneGraphRoot();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Gluon and/or its affiliates.
* Copyright (c) 2016, 2020, Gluon and/or its affiliates.
* Copyright (c) 2012, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
Expand Down Expand Up @@ -97,7 +97,32 @@ public static String getFX8Qualifier() {
public static String getEmptyQualifier() {
return EMPTY_QUALIFIER;
}


/**
* Creates the FXML content to import a given class as follows:
* <pre>{@code
* <?xml version="1.0" encoding="UTF-8"?> //NOI18N
* <?import a.b.C?>
* <C/>
* }</pre>
*
* @param componentClass the class
* @return a String with the FXML content
*/
public static String makeFxmlText(Class<?> componentClass) {
final StringBuilder sb = new StringBuilder();

sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); //NOI18N
sb.append("<?import "); //NOI18N
sb.append(componentClass.getCanonicalName());
sb.append("?>"); //NOI18N
sb.append("<"); //NOI18N
sb.append(componentClass.getSimpleName());
sb.append("/>\n"); //NOI18N

return sb.toString();
}

/*
* Library
*/
Expand Down Expand Up @@ -382,30 +407,7 @@ private void addItem(String name, String fxmlText, String section, String iconNa
}


private static String makeFxmlText(Class<?> componentClass) {
final StringBuilder sb = new StringBuilder();

/*
* <?xml version="1.0" encoding="UTF-8"?> //NOI18N
*
* <?import a.b.C?>
*
* <C/>
*/

sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); //NOI18N

sb.append("<?import "); //NOI18N
sb.append(componentClass.getCanonicalName());
sb.append("?>"); //NOI18N
sb.append("<"); //NOI18N
sb.append(componentClass.getSimpleName());
sb.append("/>\n"); //NOI18N

return sb.toString();
}

private static String makeRegionFxmlText(Class<? extends Region> componentClass,
private static String makeRegionFxmlText(Class<? extends Region> componentClass,
double pw, double ph) {
final StringBuilder sb = new StringBuilder();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Gluon and/or its affiliates.
* Copyright (c) 2017, 2020, Gluon and/or its affiliates.
* Copyright (c) 2012, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
Expand Down Expand Up @@ -48,6 +48,7 @@
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
Expand All @@ -71,11 +72,17 @@
*
*/
class LibraryFolderWatcher implements Runnable {


private static final Logger LOGGER = Logger.getLogger(LibraryFolderWatcher.class.getSimpleName());

private final UserLibrary library;

private enum FILE_TYPE {FXML, JAR, FOLDER_MARKER};

private enum FILE_TYPE {FXML, JAR, FOLDER_MARKER}

private static final List<String> JAVAFX_MODULES = Arrays.asList(
"javafx-base", "javafx-graphics", "javafx-controls",
"javafx-fxml", "javafx-media", "javafx-web", "javafx-swing");

public LibraryFolderWatcher(UserLibrary library) {
this.library = library;
}
Expand Down Expand Up @@ -347,20 +354,39 @@ private void exploreAndUpdateLibrary(Collection<Path> jarsOrFolders) throws IOEx
final List<JarReport> jarOrFolderReports = new ArrayList<>();
// boolean shouldShowImportGluonJarAlert = false;
for (Path currentJarOrFolder : jarsOrFolders) {
String jarName = currentJarOrFolder.getName(currentJarOrFolder.getNameCount() - 1).toString();
if (JAVAFX_MODULES.stream().anyMatch(jarName::startsWith)) {
continue;
}

JarReport jarReport;
String resultText = "";
if (LibraryUtil.isJarPath(currentJarOrFolder)) {
Logger.getLogger(this.getClass().getSimpleName()).info(I18N.getString("log.info.explore.jar", currentJarOrFolder));
LOGGER.info(I18N.getString("log.info.explore.jar", currentJarOrFolder));
final JarExplorer explorer = new JarExplorer(currentJarOrFolder);
JarReport jarReport = explorer.explore(classLoader);
jarOrFolderReports.add(jarReport);
jarReport = explorer.explore(classLoader);
resultText = I18N.getString("log.info.explore.jar.results", jarName);
}
else if (Files.isDirectory(currentJarOrFolder)) {
Logger.getLogger(this.getClass().getSimpleName()).info(I18N.getString("log.info.explore.folder", currentJarOrFolder));
LOGGER.info(I18N.getString("log.info.explore.folder", currentJarOrFolder));
final FolderExplorer explorer = new FolderExplorer(currentJarOrFolder);
JarReport jarReport = explorer.explore(classLoader);
jarOrFolderReports.add(jarReport);
jarReport = explorer.explore(classLoader);
resultText = I18N.getString("log.info.explore.folder.results", jarName);
} else {
continue;
}

jarOrFolderReports.add(jarReport);

StringBuilder sb = new StringBuilder(resultText).append("\n");
if (jarReport.getEntries().isEmpty()) {
sb.append("> ").append(I18N.getString("log.info.explore.no.results"));
} else {
jarReport.getEntries().forEach(entry -> sb.append("> ").append(entry.toString()).append("\n"));
}
LOGGER.info(sb.toString());

Logger.getLogger(this.getClass().getSimpleName()).info(I18N.getString("log.info.explore.end", currentJarOrFolder));
LOGGER.info(I18N.getString("log.info.explore.end", currentJarOrFolder));

// if (jarReport.hasGluonControls()) {
// // We check if the jar has already been imported to avoid showing the import gluon jar
Expand Down Expand Up @@ -412,7 +438,7 @@ private Collection<LibraryItem> makeLibraryItems(JarReport jarOrFolderReport) th
if (!excludedItems.contains(canonicalName) &&
!artifactsFilter.contains(canonicalName)) {
final String name = e.getKlass().getSimpleName();
final String fxmlText = JarExplorer.makeFxmlText(e.getKlass());
final String fxmlText = BuiltinLibrary.makeFxmlText(e.getKlass());
result.add(new LibraryItem(name, UserLibrary.TAG_USER_DEFINED, fxmlText, iconURL, library));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2020, Gluon and/or its affiliates.
* Copyright (c) 2012, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
* This file is available and licensed under the following license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* - Neither the name of Oracle Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.javafx.scenebuilder.kit.library.util;

import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform;
import com.oracle.javafx.scenebuilder.kit.library.BuiltinLibrary;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;

abstract class ExplorerBase {

static Object instantiateWithFXMLLoader(Class<?> klass, ClassLoader classLoader) throws IOException {
Object result;

final String fxmlText = BuiltinLibrary.makeFxmlText(klass);
final byte[] fxmlBytes = fxmlText.getBytes(Charset.forName("UTF-8")); //NOI18N

final FXMLLoader fxmlLoader = new FXMLLoader();
try {
fxmlLoader.setClassLoader(classLoader);
result = fxmlLoader.load(new ByteArrayInputStream(fxmlBytes));
} catch(IOException x) {
throw x;
} catch(RuntimeException|Error x) {
throw new IOException(x);
}

return result;
}

String makeClassName(String entryName, String separator) {
final String result;

if (! entryName.endsWith(".class")) { //NOI18N
result = null;
} else if (entryName.contains("$")) { //NOI18N
// We skip inner classes for now
result = null;
} else {
final int endIndex = entryName.length()-6; // ".class" -> 6 //NOI18N
result = entryName.substring(0, endIndex).replace(separator, "."); //NOI18N
}

return result;
}

JarReportEntry exploreEntry(String entryName, ClassLoader classLoader, String className) {
JarReportEntry.Status status;
Throwable entryException;
Class<?> entryClass = null;

// Filtering out what starts with com.javafx. is bound to DTL-6378.
if (className == null || className.startsWith("java.") //NOI18N
|| className.startsWith("javax.") || className.startsWith("javafx.") //NOI18N
|| className.startsWith("com.oracle.javafx.scenebuilder.") //NOI18N
|| className.startsWith("com.javafx.")
|| className.startsWith("module-info")
|| className.startsWith(EditorPlatform.GLUON_PACKAGE)) { //NOI18N
status = JarReportEntry.Status.IGNORED;
entryClass = null;
entryException = null;
} else {
try {
// Some reading explaining why using Class.forName is not appropriate:
// http://blog.osgi.org/2011/05/what-you-should-know-about-class.html
// http://blog.bjhargrave.com/2007/09/classforname-caches-defined-class-in.html
// http://stackoverflow.com/questions/8100376/class-forname-vs-classloader-loadclass-which-to-use-for-dynamic-loading
entryClass = classLoader.loadClass(className); // Note: static intializers of entryClass are not run, this doesn't seem to be an issue

if (Modifier.isAbstract(entryClass.getModifiers())
|| !Node.class.isAssignableFrom(entryClass)) {
status = JarReportEntry.Status.IGNORED;
entryClass = null;
entryException = null;
} else {
instantiateWithFXMLLoader(entryClass, classLoader);
status = JarReportEntry.Status.OK;
entryException = null;
}
} catch (RuntimeException | IOException x) {
status = JarReportEntry.Status.CANNOT_INSTANTIATE;
entryException = x;
} catch (Error | ClassNotFoundException x) {
status = JarReportEntry.Status.CANNOT_LOAD;
entryClass = null;
entryException = x;
}
}

return new JarReportEntry(entryName, status, entryException, entryClass, className);
}
}
Loading