All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.alexfalappa.nbspringboot.Utils Maven / Gradle / Ivy

/*
 * Copyright 2016 Alessandro Falappa.
 *
 * 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 com.github.alexfalappa.nbspringboot;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import javax.swing.AbstractButton;
import javax.swing.DefaultButtonModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.UIManager;

import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.Sources;
import org.netbeans.spi.editor.completion.CompletionResultSet;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.util.Lookup;
import org.openide.util.NbPreferences;
import org.openide.util.Utilities;
import org.openide.windows.TopComponent;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
import org.springframework.boot.configurationmetadata.Deprecation;
import org.springframework.boot.configurationmetadata.ValueHint;

import com.github.alexfalappa.nbspringboot.cfgprops.completion.items.FileObjectCompletionItem;
import com.github.alexfalappa.nbspringboot.cfgprops.completion.items.ValueCompletionItem;
import com.github.alexfalappa.nbspringboot.projects.customizer.BootPanel;
import com.github.alexfalappa.nbspringboot.projects.service.api.HintSupport;

import static com.github.alexfalappa.nbspringboot.PrefConstants.PREF_VM_OPTS;
import static com.github.alexfalappa.nbspringboot.PrefConstants.PREF_VM_OPTS_LAUNCH;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFileAttributes;
import static java.util.logging.Level.WARNING;
import static java.util.regex.Pattern.compile;
import org.openide.util.Exceptions;

/**
 * Utility methods used in the plugin.
 *
 * @author Alessandro Falappa
 */
public final class Utils {

    private static final Logger logger = Logger.getLogger(Utils.class.getName());
    private static final Pattern PATTERN_JAVATYPE = compile("(\\w+\\.)+(\\w+)");
    private static final String PREFIX_CLASSPATH = "classpath:/";
    private static final String PREFIX_FILE = "file://";
    private static final Set resourcePrefixes = new HashSet<>();

    // prevent instantiation
    private Utils() {
    }

    static {
        resourcePrefixes.add(PREFIX_CLASSPATH);
        resourcePrefixes.add(PREFIX_FILE);
        resourcePrefixes.add("http://");
        resourcePrefixes.add("https://");
    }

    /**
     * Simplistic escape of angled brackets in the given string.
     *
     * @param text the string to escape
     * @return escaped string
     */
    public static String simpleHtmlEscape(String text) {
        return text.replace("<", "<").replace(">", ">");
    }

    /**
     * Shortens a string representing a fully qualified Java type.
     * 

* Strips all package names from the type. Also acts on generic parameters. *

* For example {@code java.util.List} gets shortened to {@code List}. * * @param type a Java type string * @return the shortened type */ public static String shortenJavaType(String type) { return PATTERN_JAVATYPE.matcher(type).replaceAll("$2"); } /** * Builds an HTML formatted string with details on a Spring Boot configuration property extracted from its * {@code ItemMetadata}. * * @param cfgMeta the configuration property metadata object * @return the HTML formatted configuration property details */ public static String cfgPropDetailsHtml(ConfigurationMetadataProperty cfgMeta) { StringBuilder sb = new StringBuilder(); // deprecation (optional) Deprecation deprecation = cfgMeta.getDeprecation(); if (deprecation != null) { sb.append(""); if (isErrorDeprecated(cfgMeta)) { sb.append("REMOVED"); } else { sb.append("Deprecated"); } sb.append(""); // deprecation reason if present String reason = deprecation.getReason(); if (reason != null) { sb.append(": ").append(simpleHtmlEscape(reason)); } sb.append("
"); String replacement = deprecation.getReplacement(); if (replacement != null) { sb.append("Replaced by: ").append(replacement).append("
"); } } // description (optional) final String description = cfgMeta.getDescription(); if (description != null) { sb.append(description).append("
"); } // type sb.append("").append(simpleHtmlEscape(shortenJavaType(cfgMeta.getType()))).append(""); return sb.toString(); } public static String vmOptsFromPrefs() { StringBuilder sb = new StringBuilder(); if (NbPreferences.forModule(PrefConstants.class).getBoolean(PREF_VM_OPTS_LAUNCH, true)) { sb.append(BootPanel.VMOPTS_OPTIMIZE); } if (sb.length() > 0) { sb.append(' '); } sb.append(NbPreferences.forModule(PrefConstants.class).get(PREF_VM_OPTS, "")); return sb.toString(); } public static boolean isErrorDeprecated(ConfigurationMetadataProperty meta) { Deprecation depr = meta.getDeprecation(); return depr != null && depr.getLevel() != null && depr.getLevel().equals(Deprecation.Level.ERROR); } /** * Tries to retrieve the most appropriate {@link Project}. *

* Looks first in the global action context, then in the active {@link TopComponent} context. In each case tries first a * direct reference then via the owner of a file object and lastly via a data object. * * @return the active project or null if no active project found */ public static Project getActiveProject() { // lookup in global context Project prj = Utilities.actionsGlobalContext().lookup(Project.class); if (prj != null) { logger.log(Level.FINE, "Found project reference in actions global context"); return prj; } FileObject foobj = Utilities.actionsGlobalContext().lookup(FileObject.class); if (foobj != null) { prj = FileOwnerQuery.getOwner(foobj); if (prj != null) { logger.log(Level.FINE, "Found project reference via file object in actions global context"); return prj; } } DataObject dobj = Utilities.actionsGlobalContext().lookup(DataObject.class); if (dobj != null) { FileObject fo = dobj.getPrimaryFile(); prj = FileOwnerQuery.getOwner(fo); if (prj != null) { logger.log(Level.FINE, "Found project reference via data object in actions global context"); return prj; } } // lookup in active editor final TopComponent activeEditor = TopComponent.getRegistry().getActivated(); if (activeEditor != null) { final Lookup tcLookup = activeEditor.getLookup(); prj = tcLookup.lookup(Project.class); if (prj != null) { logger.log(Level.FINE, "Found project reference in lookup of active editor"); return prj; } foobj = tcLookup.lookup(FileObject.class); if (foobj != null) { prj = FileOwnerQuery.getOwner(foobj); if (prj != null) { logger.log(Level.FINE, "Found project reference in lookup of active editor via file object"); return prj; } } dobj = tcLookup.lookup(DataObject.class); if (dobj != null) { FileObject fo = dobj.getPrimaryFile(); prj = FileOwnerQuery.getOwner(fo); if (prj != null) { logger.log(Level.FINE, "Found project reference in lookup of active editor via data object"); return prj; } } } logger.log(Level.FINE, "Couldn't find active project reference"); return null; } /** * Retrieves the execute {@code ClassPath} object for the given project. * * @param proj the project * @return found ClassPath object or null */ public static ClassPath execClasspathForProj(Project proj) { Sources srcs = ProjectUtils.getSources(proj); SourceGroup[] srcGroups = srcs.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); if (srcGroups.length > 0) { return ClassPath.getClassPath(srcGroups[0].getRootFolder(), ClassPath.EXECUTE); } else { logger.log(WARNING, "No sources found for project: {0}", new Object[]{proj.toString()}); } return null; } public static FileObject resourcesFolderForProj(Project proj) { Sources srcs = ProjectUtils.getSources(proj); SourceGroup[] srcGroups = srcs.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_RESOURCES); if (srcGroups.length > 0) { // the first sourcegroup is src/main/resources (the second is src/test/resources) return srcGroups[0].getRootFolder(); } return proj.getProjectDirectory(); } public static void completeBoolean(String filter, Consumer consumer) { if ("true".contains(filter)) { consumer.accept(Utils.createHint("true")); } if ("false".contains(filter)) { consumer.accept(Utils.createHint("false")); } } public static void completeCharset(String filter, Consumer consumer) { HintSupport.getAllCharsets().stream() .filter(chrsName -> chrsName.toLowerCase().contains(filter.toLowerCase())) .forEachOrdered(chrsName -> { consumer.accept(Utils.createHint(chrsName)); }); } public static void completeLocale(String filter, Consumer consumer) { HintSupport.getAllLocales().stream() .filter(lclName -> lclName.toLowerCase().contains(filter.toLowerCase())) .forEachOrdered(lclName -> { consumer.accept(Utils.createHint(lclName)); }); } public static void completeMimetype(String filter, Consumer consumer) { HintSupport.MIMETYPES.stream() .filter(mime -> mime.toLowerCase().contains(filter.toLowerCase())) .forEachOrdered(mime -> { consumer.accept(Utils.createHint(mime)); }); } public static void completeEnum(ClassPath cp, String dataType, String filter, Consumer consumer) { try { Object[] enumvals = cp.getClassLoader(true).loadClass(dataType).getEnumConstants(); if (enumvals != null) { for (Object val : enumvals) { final String valName = val.toString().toLowerCase(); if (filter == null || valName.contains(filter)) { consumer.accept(createEnumHint(valName)); } } } } catch (ClassNotFoundException ex) { // enum not available in project classpath, no completion possible } } public static void completeSpringResource(FileObject resourcesFolder, String filter, CompletionResultSet completionResultSet, int dotOffset, int caretOffset) { if (filter.startsWith(PREFIX_CLASSPATH)) { String resFilter = filter.substring(PREFIX_CLASSPATH.length()); int startOffset = dotOffset + PREFIX_CLASSPATH.length(); String filePart = resFilter; FileObject foBase = resourcesFolder; if (resFilter.contains("/")) { final int slashIdx = resFilter.lastIndexOf('/'); final String basePart = resFilter.substring(0, slashIdx); filePart = resFilter.substring(slashIdx + 1); startOffset += slashIdx + 1; foBase = resourcesFolder.getFileObject(basePart); } for (FileObject fObj : foBase.getChildren()) { String fname = fObj.getNameExt(); if (fname.contains(filePart)) { completionResultSet.addItem(new FileObjectCompletionItem(fObj, startOffset, caretOffset)); } } } else if (filter.startsWith(PREFIX_FILE)) { String fileFilter = filter.substring(PREFIX_FILE.length()); int startOffset = dotOffset + PREFIX_FILE.length(); if (fileFilter.isEmpty()) { Iterable rootDirs = FileSystems.getDefault().getRootDirectories(); for (Path rootDir : rootDirs) { FileObject foRoot = FileUtil.toFileObject(rootDir.toFile()); // filter out CD/DVD drives letter on Windows if (foRoot != null) { completionResultSet.addItem(new FileObjectCompletionItem(foRoot, startOffset, caretOffset)); } } } else { Path pTest = Paths.get(fileFilter); startOffset += fileFilter.length(); String filePart = ""; if (!Files.exists(pTest)) { filePart = pTest.getFileName().toString(); pTest = pTest.getParent(); startOffset -= filePart.length(); } if (pTest != null) { try (DirectoryStream stream = Files.newDirectoryStream(pTest)) { for (Path p : stream) { if (Files.isReadable(p)) { String fname = p.toString().toLowerCase(); if (fname.contains(filePart)) { completionResultSet.addItem(new FileObjectCompletionItem(FileUtil.toFileObject(p.toFile()), startOffset, caretOffset)); } } } } catch (IOException ex) { Exceptions.printStackTrace(ex); } } } } else { for (String rp : resourcePrefixes) { if (rp.contains(filter)) { completionResultSet.addItem(new ValueCompletionItem(Utils.createHint(rp), dotOffset, caretOffset)); } } } } /** * Create a {@code ValueHint} object from the given value. *

* Created hint has no description. * * @param value the value to use * @return a ValueHint object */ public static ValueHint createHint(String value) { ValueHint vh = new ValueHint(); vh.setValue(value); return vh; } /** * Create a {@code ValueHint} object from the given java enumeration value. *

* Created hint has no description and has a Spring Boot property name canonical format. * * @param value the value to use * @return a ValueHint object */ public static ValueHint createEnumHint(String value) { ValueHint vh = new ValueHint(); vh.setValue(value.replaceAll("_", "-")); return vh; } /** * Create a {@code ValueHint} object from the given value and description. * * @param value the value to use * @param description the description to use * @return a ValueHint object */ public static ValueHint createHint(String value, String description) { ValueHint vh = new ValueHint(); vh.setValue(value); vh.setDescription(description); return vh; } /** * Converts an icon from the current LAF defaults into an ImageIcon by painting it. *

* Some ui-icons misbehave in that they unconditionally class-cast to the component type they are mostly painted on. * Consequently they blow up if we are trying to paint them anywhere else (f.i. in a renderer). This method tries to * instantiate a component of the type expected by the icon. *

* This method is an adaption of a cool trick by Darryl Burke/Rob Camick found at * http://tips4java.wordpress.com/2008/12/18/icon-table-cell-renderer/#comment-120 * * @param iconName the name of the icon in UIManager * @return an ImageIcon with the Icon image */ public static ImageIcon lafDefaultIcon(String iconName) { Icon ico = UIManager.getIcon(iconName); BufferedImage image = new BufferedImage(ico.getIconWidth(), ico.getIconHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = image.createGraphics(); try { // paint with a generic java.awt.Component ico.paintIcon(new JPanel(), g2, 0, 0); } catch (ClassCastException e) { try { // try to instantiate the needed java.awt.Component String className = e.getMessage(); className = className.substring(className.lastIndexOf(" ") + 1); Class clazz = Class.forName(className); JComponent standInComponent = getSubstitute(clazz); ico.paintIcon(standInComponent, g2, 0, 0); } catch (ClassNotFoundException | IllegalAccessException ex) { // fallback g2.drawRect(0, 0, 16, 16); g2.drawLine(0, 0, 16, 16); g2.drawLine(16, 0, 0, 16); } } g2.dispose(); return new ImageIcon(image); } private static JComponent getSubstitute(Class clazz) throws IllegalAccessException { JComponent standInComponent; try { standInComponent = (JComponent) clazz.newInstance(); } catch (InstantiationException e) { standInComponent = new AbstractButton() { }; ((AbstractButton) standInComponent).setModel(new DefaultButtonModel()); } return standInComponent; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy