com.alee.utils.jar.JarStructure Maven / Gradle / Ivy
The newest version!
/*
* This file is part of WebLookAndFeel library.
*
* WebLookAndFeel library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* WebLookAndFeel library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WebLookAndFeel library. If not, see .
*/
package com.alee.utils.jar;
import com.alee.api.annotations.NotNull;
import com.alee.api.annotations.Nullable;
import com.alee.utils.FileUtils;
import com.alee.utils.ReflectUtils;
import com.alee.utils.UtilityException;
import com.alee.utils.file.FileDownloadListener;
import javax.swing.*;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.security.CodeSource;
import java.util.List;
import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* This class represents single JAR file structure.
* It might be really useful to navigate through JAR
*
* @author Mikle Garin
*/
public class JarStructure
{
/**
* Location of JAR file which structure is represented by this object.
* Since local copy of file is always required to create this structure this field always points at existing local JAR file.
*/
@NotNull
protected final String jarLocation;
/**
* Root {@link JarEntry}.
* Represents JAR structure itself using nested {@link JarEntry}.
*/
@NotNull
protected final JarEntry root;
/**
* Constructs new {@link JarStructure}.
*
* @param jarClass any class within the JAR
*/
public JarStructure ( @NotNull final Class jarClass )
{
this ( jarClass, null, null, null );
}
/**
* Constructs new {@link JarStructure}.
*
* @param jarClass any class within the JAR
* @param allowedExtensions list of extension filters
* @param allowedPackages list of allowed packages
*/
public JarStructure ( @NotNull final Class jarClass, @Nullable final List allowedExtensions,
@Nullable final List allowedPackages )
{
this ( jarClass, allowedExtensions, allowedPackages, null );
}
/**
* Constructs new {@link JarStructure}.
*
* @param jarClass any class within the JAR
* @param allowedExtensions list of extension filters
* @param allowedPackages list of allowed packages
* @param listener {@link FileDownloadListener} for JAR file
*/
public JarStructure ( @NotNull final Class jarClass, @Nullable final List allowedExtensions,
@Nullable final List allowedPackages, @Nullable final FileDownloadListener listener )
{
try
{
final CodeSource src = jarClass.getProtectionDomain ().getCodeSource ();
if ( src != null )
{
// Source url
final URL jarUrl = src.getLocation ();
final URI uri = jarUrl.toURI ();
// Source file
final File jarFile;
final String scheme = uri.getScheme ();
if ( scheme != null && scheme.equalsIgnoreCase ( "file" ) )
{
// Local jar-file
jarFile = new File ( uri );
}
else
{
// Remote jar-file
jarFile = FileUtils.downloadFile (
jarUrl.toString (),
File.createTempFile ( jarUrl.getFile (), ".tmp" ),
listener
);
}
// Creating JAR structure
this.jarLocation = jarFile.getAbsolutePath ();
// Updating root element
this.root = new JarEntry ( this, JarEntryType.JAR, jarFile.getName () );
// Reading all entries and parsing them into structure
final ZipInputStream zip = new ZipInputStream ( jarUrl.openStream () );
ZipEntry zipEntry;
while ( ( zipEntry = zip.getNextEntry () ) != null )
{
final String entryName = zipEntry.getName ();
if ( isAllowedPackage ( entryName, allowedPackages ) &&
( zipEntry.isDirectory () || isAllowedExtension ( entryName, allowedExtensions ) ) )
{
final String[] path = entryName.split ( "/" );
JarEntry currentLevel = this.root;
for ( int i = 0; i < path.length; i++ )
{
if ( i < path.length - 1 )
{
JarEntry child = currentLevel.findChildByName ( path[ i ] );
if ( child == null )
{
child = new JarEntry ( this, currentLevel, zipEntry, JarEntryType.PACKAGE, path[ i ] );
currentLevel.addChild ( child );
}
currentLevel = child;
}
else
{
final JarEntryType type;
final String ext = FileUtils.getFileExtPart ( path[ i ], false );
if ( ext.equals ( "java" ) )
{
type = JarEntryType.JAVA;
}
else if ( ext.equals ( "class" ) )
{
type = JarEntryType.CLASS;
}
else if ( !ext.isEmpty () )
{
type = JarEntryType.FILE;
}
else
{
type = JarEntryType.PACKAGE;
}
currentLevel.addChild ( new JarEntry ( this, currentLevel, zipEntry, type, path[ i ] ) );
}
}
}
}
zip.close ();
}
else
{
throw new UtilityException ( "Unable to retrieve JAR file location" );
}
}
catch ( final Exception e )
{
throw new UtilityException ( "Unable to read JAR file", e );
}
}
/**
* Returns whether JAR entry with the specified name is allowed by the packages list or not.
*
* @param entryName JAR entry name
* @param allowedPackages list of allowed packages
* @return true if JAR entry with the specified name is allowed by the packages list, false otherwise
*/
private boolean isAllowedPackage ( @NotNull final String entryName, @Nullable final List allowedPackages )
{
boolean allowed;
if ( allowedPackages != null && allowedPackages.size () != 0 )
{
allowed = false;
for ( final String packageStart : allowedPackages )
{
if ( entryName.startsWith ( packageStart ) )
{
allowed = true;
break;
}
}
}
else
{
allowed = true;
}
return allowed;
}
/**
* Returns whether JAR entry with the specified name is allowed by the extensions list or not.
*
* @param entryName JAR entry name
* @param allowedExtensions list of allowed extensions
* @return true if JAR entry with the specified name is allowed by the extensions list, false otherwise
*/
private boolean isAllowedExtension ( @NotNull final String entryName, @Nullable final List allowedExtensions )
{
return allowedExtensions == null || allowedExtensions.size () == 0 || allowedExtensions.contains (
FileUtils.getFileExtPart ( entryName, true ).toLowerCase ( Locale.ROOT )
);
}
/**
* Returns JAR file location.
*
* @return JAR file location
*/
@NotNull
public String getJarLocation ()
{
return jarLocation;
}
/**
* Returns root {@link JarEntry} of {@link JarEntryType#JAR} representing JAR itself.
*
* @return root {@link JarEntry} of {@link JarEntryType#JAR} representing JAR itself
*/
@NotNull
public JarEntry getRoot ()
{
return root;
}
/**
* Returns copy of children {@link JarEntry}s of the root {@link JarEntry}.
*
* @return copy of children {@link JarEntry}s of the root {@link JarEntry}
*/
@NotNull
public List getChildEntries ()
{
return root.getChildren ();
}
/**
* Returns child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found.
*
* @param name child {@link JarEntry} name
* @return child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found
*/
@NotNull
public JarEntry getChildByName ( @Nullable final String name )
{
return root.getChildByName ( name );
}
/**
* Returns child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found.
*
* @param name child {@link JarEntry} name
* @param recursively whether should look for the child recursively in all children
* @return child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found
*/
@NotNull
public JarEntry getChildByName ( @Nullable final String name, final boolean recursively )
{
return root.getChildByName ( name, recursively );
}
/**
* Returns child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found.
*
* @param name child {@link JarEntry} name
* @return child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found
*/
@Nullable
public JarEntry findChildByName ( @Nullable final String name )
{
return root.findChildByName ( name );
}
/**
* Returns child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found.
*
* @param name child {@link JarEntry} name
* @param recursively whether should look for the child recursively in all children
* @return child {@link JarEntry} with the specfiied name or {@code null} if it cannot be found
*/
@Nullable
public JarEntry findChildByName ( @Nullable final String name, final boolean recursively )
{
return root.findChildByName ( name, recursively );
}
/**
* Returns {@link JarEntry} for the specified {@link Class} or {@code null} if it cannot be found.
*
* @param forClass {@link Class} to find {@link JarEntry} for
* @return {@link JarEntry} for the specified {@link Class} or {@code null} if it cannot be found
*/
@Nullable
public JarEntry getClassEntry ( @NotNull final Class> forClass )
{
final String[] packages = ReflectUtils.getClassPackages ( forClass );
final String classFileName = ReflectUtils.getJavaClassName ( forClass );
int currentPackage = 0;
JarEntry classEntry = getRoot ();
while ( classEntry != null )
{
if ( currentPackage < packages.length )
{
classEntry = classEntry.findChildByName ( packages[ currentPackage ] );
}
else
{
classEntry = classEntry.findChildByName ( classFileName );
break;
}
currentPackage++;
}
return classEntry;
}
/**
* Returns {@link JarEntry} for the specified {@link Package} or {@code null} if it cannot be found.
*
* @param forPackage {@link Package} to find {@link JarEntry} for
* @return {@link JarEntry} for the specified {@link Package} or {@code null} if it cannot be found
*/
@Nullable
public JarEntry getPackageEntry ( @NotNull final Package forPackage )
{
return getPackageEntry ( forPackage.getName () );
}
/**
* Returns {@link JarEntry} for the specified {@link Package} name or {@code null} if it cannot be found.
*
* @param forPackage {@link Package} name to find {@link JarEntry} for
* @return {@link JarEntry} for the specified {@link Package} name or {@code null} if it cannot be found
*/
@Nullable
public JarEntry getPackageEntry ( @NotNull final String forPackage )
{
final String[] packages = ReflectUtils.getPackages ( forPackage );
JarEntry packageEntry = getRoot ();
for ( final String currentPackage : packages )
{
if ( packageEntry != null )
{
packageEntry = packageEntry.findChildByName ( currentPackage );
}
else
{
break;
}
}
return packageEntry;
}
/**
* Sets {@link Icon} for the {@link JarEntry} representing specified {@link Class}.
*
* @param forClass {@link Class} to find {@link JarEntry} for
* @param icon {@link Icon}
*/
public void setClassIcon ( @NotNull final Class> forClass, @NotNull final Icon icon )
{
final JarEntry classEntry = getClassEntry ( forClass );
if ( classEntry != null )
{
classEntry.setIcon ( icon );
}
}
/**
* Sets {@link Icon} for the {@link JarEntry} representing specified {@link Package}.
*
* @param forPackage {@link Package} to find {@link JarEntry} for
* @param icon {@link Icon}
*/
public void setPackageIcon ( @NotNull final Package forPackage, @NotNull final Icon icon )
{
setPackageIcon ( forPackage.getName (), icon );
}
/**
* Sets {@link Icon} for the {@link JarEntry} representing specified {@link Package} name.
*
* @param forPackage {@link Package} name to find {@link JarEntry} for
* @param icon {@link Icon}
*/
public void setPackageIcon ( @NotNull final String forPackage, @NotNull final Icon icon )
{
final JarEntry packageEntry = getPackageEntry ( forPackage );
if ( packageEntry != null )
{
packageEntry.setIcon ( icon );
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy