Package aQute.bnd.osgi
Class Jar
- java.lang.Object
-
- aQute.bnd.osgi.Jar
-
- All Implemented Interfaces:
java.io.Closeable,java.lang.AutoCloseable
public class Jar extends java.lang.Object implements java.io.Closeable
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static classJar.Compression
-
Field Summary
Fields Modifier and Type Field Description private java.lang.String[]algorithmsprivate static java.util.regex.PatternBSNprivate static intBUFFER_SIZEprivate booleancalculateFileDigestprivate booleanclosedprivate Jar.Compressioncompressionprivate static java.util.regex.PatternDEFAULT_DO_NOT_COPYprivate static java.lang.StringDEFAULT_MANIFEST_NAMEprivate java.util.NavigableMap<java.lang.String,java.util.Map<java.lang.String,Resource>>directoriesprivate booleandoNotTouchManifeststatic java.lang.Object[]EMPTY_ARRAYprivate static byte[]EOLUnfortunately we have to write our own manifest :-( because of a stupid bug in the manifest code.private intfileLengthprivate longlastModifiedprivate java.lang.StringlastModifiedReasonprivate java.util.Optional<java.util.jar.Manifest>manifestprivate booleanmanifestFirstprivate java.lang.StringmanifestNameprivate java.util.Optional<ModuleAttribute>moduleAttributeprivate java.lang.Stringnameprivate booleannomanifestprivate static java.util.function.Predicate<java.lang.String>pomXmlFilterprivate booleanreproducibleprivate java.util.NavigableMap<java.lang.String,Resource>resourcesprivate static byte[]SEPARATORprivate SHA256sha256private static java.util.regex.PatternSIGNER_FILES_Pprivate java.io.Filesourceprivate static longZIP_ENTRY_CONSTANT_TIMENote that setting the January 1st 1980 (or even worse, "0", as time) won't work due to Java 8 doing some interesting time processing: It checks if this date is before January 1st 1980 and if it is it starts setting some extra fields in the zip.private java.util.zip.ZipFilezipFile
-
Constructor Summary
Constructors Constructor Description Jar(java.io.File f)Jar(java.lang.String name)Jar(java.lang.String string, java.io.File file)Jar(java.lang.String name, java.io.File dirOrFile, java.util.regex.Pattern doNotCopy)Jar(java.lang.String name, java.io.InputStream in)Jar(java.lang.String name, java.io.InputStream in, long lastModified)Jar(java.lang.String name, java.lang.String path)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description booleanaddAll(Jar src)booleanaddAll(Jar sub, Instruction filter)Add all the resources in the given jar that match the given filter.booleanaddAll(Jar sub, Instruction filter, java.lang.String destination)Add all the resources in the given jar that match the given filter.booleanaddDirectory(java.util.Map<java.lang.String,Resource> directory, boolean overwrite)private static voidattributes(java.util.jar.Attributes value, java.io.OutputStream out)Output an Attributes map.(package private) java.lang.StringautomaticModuleName()private JarbuildFromDirectory(java.nio.file.Path baseDir, java.util.regex.Pattern doNotCopy)private JarbuildFromInputStream(java.io.InputStream in)private JarbuildFromResource(Resource resource)private JarbuildFromZip(java.io.File file)voidcalcChecksums(java.lang.String[] algorithms)Calculate the checksums and set them in the manifest.(package private) voidcheck()private static java.lang.Stringclean(java.lang.String s)private static java.util.jar.Manifestclean(java.util.jar.Manifest org)voidclose()voidcopy(Jar srce, java.lang.String path, boolean overwrite)private voidcopyResource(java.io.File dir, java.lang.String path, Resource resource)(package private) voidcreateDirectories(java.util.Set<java.lang.String> directories, java.util.zip.ZipOutputStream zip, java.lang.String name)voiddoChecksums(java.io.OutputStream out)private voiddoManifest(java.util.zip.ZipOutputStream jout, java.util.Set<java.lang.String> directories, java.lang.String manifestName)voidensureManifest()Make sure we have a manifestbooleanexists(java.lang.String path)voidexpand(java.io.File dir)Expand the JAR file to a directory.static JarfromResource(java.lang.String name, Resource resource)java.lang.StringgetBsn()Get the jar bsn from theConstants.BUNDLE_SYMBOLICNAMEmanifest header.java.net.URIgetDataURI(java.lang.String path, java.lang.String mime, int max)Return a data uri from the JAR.java.util.Map<java.lang.String,java.util.Map<java.lang.String,Resource>>getDirectories()java.util.Map<java.lang.String,Resource>getDirectory(java.lang.String path)intgetLength()Get the length of the last written file or -1 if unavailable.java.util.jar.ManifestgetManifest()java.lang.StringgetModuleName()java.lang.StringgetModuleVersion()java.lang.StringgetName()private static java.lang.StringgetName(java.io.File f)Make the JAR file name the project name if we get a src or bin directory.java.util.List<java.lang.String>getPackages()private java.lang.StringgetParent(java.lang.String path)java.util.stream.Stream<Resource>getPomXmlResources()ResourcegetResource(java.lang.String path)java.util.stream.Stream<java.lang.String>getResourceNames(java.util.function.Predicate<java.lang.String> matches)java.util.Map<java.lang.String,Resource>getResources()static java.util.stream.Stream<Resource>getResources(Resource jarResource, java.util.function.Predicate<java.lang.String> filter)java.util.stream.Stream<Resource>getResources(java.util.function.Predicate<java.lang.String> matches)java.util.Optional<byte[]>getSHA256()Get the SHA256 digest of the last write operation whensetCalculateFileDigest(boolean)was on.java.io.FilegetSource()byte[]getTimelessDigest()java.lang.StringgetVersion()Get the jar version from theConstants.BUNDLE_VERSIONmanifest header.Jar.CompressionhasCompression()booleanhasDirectory(java.lang.String path)booleanisEmpty()booleanisManifestFirst()Answer if the manifest was the first entrybooleanisReproducible()longlastModified()(package private) java.lang.StringlastModifiedReason()(package private) java.util.Optional<java.util.jar.Manifest>manifest()(package private) java.util.Optional<ModuleAttribute>moduleAttribute()static voidoutputManifest(java.util.jar.Manifest manifest, java.io.OutputStream out)Main function to output a manifest properly in UTF-8.private java.lang.StringpadString(java.lang.String s, int length, char pad)private voidputEntry(java.util.zip.ZipOutputStream jout, java.util.zip.ZipEntry entry, Resource r)booleanputResource(java.lang.String path, Resource resource)booleanputResource(java.lang.String path, Resource resource, boolean overwrite)Resourceremove(java.lang.String path)voidremovePrefix(java.lang.String prefixLow)voidremoveSubDirs(java.lang.String dir)booleanrename(java.lang.String oldPath, java.lang.String newPath)JarsetCalculateFileDigest(boolean onOrOff)Make this jar calculate the SHA256 when it is saved as a file.voidsetCompression(Jar.Compression compression)voidsetDigestAlgorithms(java.lang.String[] algorithms)voidsetDoNotTouchManifest()Make sure nobody touches the manifest! If the bundle is signed, we do not want anybody to touch the manifest after the digests have been calculated.voidsetManifest(java.io.File file)voidsetManifest(java.util.jar.Manifest manifest)voidsetManifestName(java.lang.String manifestName)voidsetName(java.lang.String name)voidsetReproducible(boolean reproducible)voidstripSignatures()java.lang.StringtoString()voidupdateModified(long time, java.lang.String reason)voidwrite(java.io.File file)voidwrite(java.io.OutputStream to)private static intwrite(java.io.OutputStream out, int width, byte[] bytes)Write the bytes but ensure that the line length does not exceed 72 characters.private static intwrite(java.io.OutputStream out, int width, java.lang.String s)Convert a string to bytes with UTF-8 and then output in max 72 bytesvoidwrite(java.lang.String file)private static voidwriteEntry(java.io.OutputStream out, java.lang.String name, java.lang.String value)Write out an entry, handling proper unicode and line length constraintsvoidwriteFolder(java.io.File dir)voidwriteManifest(java.io.OutputStream out)Cleanup the manifest for writing.static voidwriteManifest(java.util.jar.Manifest manifest, java.io.OutputStream out)private voidwriteResource(java.util.zip.ZipOutputStream jout, java.util.Set<java.lang.String> directories, java.lang.String path, Resource resource)
-
-
-
Field Detail
-
BUFFER_SIZE
private static final int BUFFER_SIZE
- See Also:
- Constant Field Values
-
ZIP_ENTRY_CONSTANT_TIME
private static final long ZIP_ENTRY_CONSTANT_TIME
Note that setting the January 1st 1980 (or even worse, "0", as time) won't work due to Java 8 doing some interesting time processing: It checks if this date is before January 1st 1980 and if it is it starts setting some extra fields in the zip. Java 7 does not do that - but in the zip not the milliseconds are saved but values for each of the date fields - but no time zone. And 1980 is the first year which can be saved. If you use January 1st 1980 then it is treated as a special flag in Java 8. Moreover, only even seconds can be stored in the zip file. Java 8 uses the upper half of some other long to store the remaining millis while Java 7 doesn't do that. So make sure that your seconds are even. Moreover, parsing happens via `new Date(millis)` inZipUtils#javaToDosTime() so we must use default timezone and locale. The date is 1980 February 1st CET.
-
DEFAULT_MANIFEST_NAME
private static final java.lang.String DEFAULT_MANIFEST_NAME
- See Also:
- Constant Field Values
-
DEFAULT_DO_NOT_COPY
private static final java.util.regex.Pattern DEFAULT_DO_NOT_COPY
-
EMPTY_ARRAY
public static final java.lang.Object[] EMPTY_ARRAY
-
resources
private final java.util.NavigableMap<java.lang.String,Resource> resources
-
directories
private final java.util.NavigableMap<java.lang.String,java.util.Map<java.lang.String,Resource>> directories
-
manifest
private java.util.Optional<java.util.jar.Manifest> manifest
-
moduleAttribute
private java.util.Optional<ModuleAttribute> moduleAttribute
-
manifestFirst
private boolean manifestFirst
-
manifestName
private java.lang.String manifestName
-
name
private java.lang.String name
-
source
private java.io.File source
-
zipFile
private java.util.zip.ZipFile zipFile
-
lastModified
private long lastModified
-
lastModifiedReason
private java.lang.String lastModifiedReason
-
doNotTouchManifest
private boolean doNotTouchManifest
-
nomanifest
private boolean nomanifest
-
reproducible
private boolean reproducible
-
compression
private Jar.Compression compression
-
closed
private boolean closed
-
algorithms
private java.lang.String[] algorithms
-
sha256
private SHA256 sha256
-
calculateFileDigest
private boolean calculateFileDigest
-
fileLength
private int fileLength
-
EOL
private static final byte[] EOL
Unfortunately we have to write our own manifest :-( because of a stupid bug in the manifest code. It tries to handle UTF-8 but the way it does it it makes the bytes platform dependent. So the following code outputs the manifest. A Manifest consists of'Manifest-Version: 1.0\r\n' main-attributes * \r\n name-section main-attributes ::= attributes attributes ::= key ': ' value '\r\n' name-section ::= 'Name: ' name '\r\n' attributes
Lines in the manifest should not exceed 72 bytes (! this is where the manifest screwed up as well when 16 bit unicodes were used).As a bonus, we can now sort the manifest!
-
SEPARATOR
private static final byte[] SEPARATOR
-
BSN
private static final java.util.regex.Pattern BSN
-
SIGNER_FILES_P
private static final java.util.regex.Pattern SIGNER_FILES_P
-
pomXmlFilter
private static final java.util.function.Predicate<java.lang.String> pomXmlFilter
-
-
Constructor Detail
-
Jar
public Jar(java.lang.String name)
-
Jar
public Jar(java.lang.String name, java.io.File dirOrFile, java.util.regex.Pattern doNotCopy) throws java.io.IOException- Throws:
java.io.IOException
-
Jar
public Jar(java.lang.String name, java.io.InputStream in, long lastModified) throws java.io.IOException- Throws:
java.io.IOException
-
Jar
public Jar(java.lang.String name, java.lang.String path) throws java.io.IOException- Throws:
java.io.IOException
-
Jar
public Jar(java.io.File f) throws java.io.IOException- Throws:
java.io.IOException
-
Jar
public Jar(java.lang.String name, java.io.InputStream in) throws java.io.IOException- Throws:
java.io.IOException
-
Jar
public Jar(java.lang.String string, java.io.File file) throws java.io.IOException- Throws:
java.io.IOException
-
-
Method Detail
-
fromResource
public static Jar fromResource(java.lang.String name, Resource resource) throws java.lang.Exception
- Throws:
java.lang.Exception
-
getResources
public static java.util.stream.Stream<Resource> getResources(Resource jarResource, java.util.function.Predicate<java.lang.String> filter) throws java.lang.Exception
- Throws:
java.lang.Exception
-
getName
private static java.lang.String getName(java.io.File f)
Make the JAR file name the project name if we get a src or bin directory.- Parameters:
f-
-
buildFromDirectory
private Jar buildFromDirectory(java.nio.file.Path baseDir, java.util.regex.Pattern doNotCopy) throws java.io.IOException
- Throws:
java.io.IOException
-
buildFromZip
private Jar buildFromZip(java.io.File file) throws java.io.IOException
- Throws:
java.io.IOException
-
buildFromResource
private Jar buildFromResource(Resource resource) throws java.lang.Exception
- Throws:
java.lang.Exception
-
buildFromInputStream
private Jar buildFromInputStream(java.io.InputStream in) throws java.io.IOException
- Throws:
java.io.IOException
-
setName
public void setName(java.lang.String name)
-
toString
public java.lang.String toString()
- Overrides:
toStringin classjava.lang.Object
-
putResource
public boolean putResource(java.lang.String path, Resource resource)
-
putResource
public boolean putResource(java.lang.String path, Resource resource, boolean overwrite)
-
getResource
public Resource getResource(java.lang.String path)
-
getResourceNames
public java.util.stream.Stream<java.lang.String> getResourceNames(java.util.function.Predicate<java.lang.String> matches)
-
getResources
public java.util.stream.Stream<Resource> getResources(java.util.function.Predicate<java.lang.String> matches)
-
getParent
private java.lang.String getParent(java.lang.String path)
-
getDirectories
public java.util.Map<java.lang.String,java.util.Map<java.lang.String,Resource>> getDirectories()
-
getDirectory
public java.util.Map<java.lang.String,Resource> getDirectory(java.lang.String path)
-
getResources
public java.util.Map<java.lang.String,Resource> getResources()
-
addDirectory
public boolean addDirectory(java.util.Map<java.lang.String,Resource> directory, boolean overwrite)
-
getManifest
public java.util.jar.Manifest getManifest() throws java.lang.Exception- Throws:
java.lang.Exception
-
manifest
java.util.Optional<java.util.jar.Manifest> manifest()
-
moduleAttribute
java.util.Optional<ModuleAttribute> moduleAttribute() throws java.lang.Exception
- Throws:
java.lang.Exception
-
getModuleName
public java.lang.String getModuleName() throws java.lang.Exception- Throws:
java.lang.Exception
-
automaticModuleName
java.lang.String automaticModuleName()
-
getModuleVersion
public java.lang.String getModuleVersion() throws java.lang.Exception- Throws:
java.lang.Exception
-
exists
public boolean exists(java.lang.String path)
-
isEmpty
public boolean isEmpty()
-
setManifest
public void setManifest(java.util.jar.Manifest manifest)
-
setManifest
public void setManifest(java.io.File file) throws java.io.IOException- Throws:
java.io.IOException
-
setManifestName
public void setManifestName(java.lang.String manifestName)
-
write
public void write(java.io.File file) throws java.lang.Exception- Throws:
java.lang.Exception
-
write
public void write(java.lang.String file) throws java.lang.Exception- Throws:
java.lang.Exception
-
write
public void write(java.io.OutputStream to) throws java.lang.Exception- Throws:
java.lang.Exception
-
writeFolder
public void writeFolder(java.io.File dir) throws java.lang.Exception- Throws:
java.lang.Exception
-
copyResource
private void copyResource(java.io.File dir, java.lang.String path, Resource resource) throws java.lang.Exception- Throws:
java.lang.Exception
-
doChecksums
public void doChecksums(java.io.OutputStream out) throws java.lang.Exception- Throws:
java.lang.Exception
-
padString
private java.lang.String padString(java.lang.String s, int length, char pad)
-
doManifest
private void doManifest(java.util.zip.ZipOutputStream jout, java.util.Set<java.lang.String> directories, java.lang.String manifestName) throws java.lang.Exception- Throws:
java.lang.Exception
-
putEntry
private void putEntry(java.util.zip.ZipOutputStream jout, java.util.zip.ZipEntry entry, Resource r) throws java.lang.Exception- Throws:
java.lang.Exception
-
writeManifest
public void writeManifest(java.io.OutputStream out) throws java.lang.ExceptionCleanup the manifest for writing. Cleaning up consists of adding a space after any \n to prevent the manifest to see this newline as a delimiter.- Parameters:
out- Output- Throws:
java.io.IOExceptionjava.lang.Exception
-
writeManifest
public static void writeManifest(java.util.jar.Manifest manifest, java.io.OutputStream out) throws java.io.IOException- Throws:
java.io.IOException
-
outputManifest
public static void outputManifest(java.util.jar.Manifest manifest, java.io.OutputStream out) throws java.io.IOExceptionMain function to output a manifest properly in UTF-8.- Parameters:
manifest- The manifest to outputout- The output stream- Throws:
java.io.IOException- when something fails
-
writeEntry
private static void writeEntry(java.io.OutputStream out, java.lang.String name, java.lang.String value) throws java.io.IOExceptionWrite out an entry, handling proper unicode and line length constraints- Throws:
java.io.IOException
-
write
private static int write(java.io.OutputStream out, int width, java.lang.String s) throws java.io.IOExceptionConvert a string to bytes with UTF-8 and then output in max 72 bytes- Parameters:
out- the output stringwidth- the current widths- the string to output- Returns:
- the new width
- Throws:
java.io.IOException- when something fails
-
write
private static int write(java.io.OutputStream out, int width, byte[] bytes) throws java.io.IOExceptionWrite the bytes but ensure that the line length does not exceed 72 characters. If it is more than 70 characters, we just put a cr/lf + space.- Parameters:
out- The output streamwidth- The nr of characters output in a line before this method startedbytes- the bytes to output- Returns:
- the nr of characters in the last line
- Throws:
java.io.IOException- if something fails
-
attributes
private static void attributes(java.util.jar.Attributes value, java.io.OutputStream out) throws java.io.IOExceptionOutput an Attributes map. We will sort this map before outputing.- Parameters:
value- the attributesout- the output stream- Throws:
java.io.IOException- when something fails
-
clean
private static java.util.jar.Manifest clean(java.util.jar.Manifest org)
-
clean
private static java.lang.String clean(java.lang.String s)
-
writeResource
private void writeResource(java.util.zip.ZipOutputStream jout, java.util.Set<java.lang.String> directories, java.lang.String path, Resource resource) throws java.lang.Exception- Throws:
java.lang.Exception
-
createDirectories
void createDirectories(java.util.Set<java.lang.String> directories, java.util.zip.ZipOutputStream zip, java.lang.String name) throws java.io.IOException- Throws:
java.io.IOException
-
getName
public java.lang.String getName()
-
addAll
public boolean addAll(Jar sub, Instruction filter)
Add all the resources in the given jar that match the given filter.- Parameters:
sub- the jarfilter- a pattern that should match the resoures in sub to be added
-
addAll
public boolean addAll(Jar sub, Instruction filter, java.lang.String destination)
Add all the resources in the given jar that match the given filter.- Parameters:
sub- the jarfilter- a pattern that should match the resoures in sub to be added
-
close
public void close()
- Specified by:
closein interfacejava.lang.AutoCloseable- Specified by:
closein interfacejava.io.Closeable
-
lastModified
public long lastModified()
-
lastModifiedReason
java.lang.String lastModifiedReason()
-
updateModified
public void updateModified(long time, java.lang.String reason)
-
hasDirectory
public boolean hasDirectory(java.lang.String path)
-
getPackages
public java.util.List<java.lang.String> getPackages()
-
getSource
public java.io.File getSource()
-
addAll
public boolean addAll(Jar src)
-
rename
public boolean rename(java.lang.String oldPath, java.lang.String newPath)
-
remove
public Resource remove(java.lang.String path)
-
setDoNotTouchManifest
public void setDoNotTouchManifest()
Make sure nobody touches the manifest! If the bundle is signed, we do not want anybody to touch the manifest after the digests have been calculated.
-
calcChecksums
public void calcChecksums(java.lang.String[] algorithms) throws java.lang.ExceptionCalculate the checksums and set them in the manifest.- Throws:
java.lang.Exception
-
getBsn
public java.lang.String getBsn() throws java.lang.ExceptionGet the jar bsn from theConstants.BUNDLE_SYMBOLICNAMEmanifest header.- Returns:
- null when the jar has no manifest, when the manifest has no
Constants.BUNDLE_SYMBOLICNAMEheader, or when the value of the header is not a valid bsn according toBSN. - Throws:
java.lang.Exception- when the jar is closed or when the manifest could not be retrieved.
-
getVersion
public java.lang.String getVersion() throws java.lang.ExceptionGet the jar version from theConstants.BUNDLE_VERSIONmanifest header.- Returns:
- null when the jar has no manifest or when the manifest has no
Constants.BUNDLE_VERSIONheader - Throws:
java.lang.Exception- when the jar is closed or when the manifest could not be retrieved.
-
expand
public void expand(java.io.File dir) throws java.lang.ExceptionExpand the JAR file to a directory.- Parameters:
dir- the dst directory, is not required to exist- Throws:
java.lang.Exception- if anything does not work as expected.
-
ensureManifest
public void ensureManifest() throws java.lang.ExceptionMake sure we have a manifest- Throws:
java.lang.Exception
-
isManifestFirst
public boolean isManifestFirst()
Answer if the manifest was the first entry
-
isReproducible
public boolean isReproducible()
-
setReproducible
public void setReproducible(boolean reproducible)
-
copy
public void copy(Jar srce, java.lang.String path, boolean overwrite)
-
setCompression
public void setCompression(Jar.Compression compression)
-
hasCompression
public Jar.Compression hasCompression()
-
check
void check()
-
getDataURI
public java.net.URI getDataURI(java.lang.String path, java.lang.String mime, int max) throws java.lang.ExceptionReturn a data uri from the JAR. The data must be less than 32k- Parameters:
path- the path in the jarmime- the mime type- Returns:
- a URI or null if conversion could not take place
- Throws:
java.lang.Exception
-
setDigestAlgorithms
public void setDigestAlgorithms(java.lang.String[] algorithms)
-
getTimelessDigest
public byte[] getTimelessDigest() throws java.lang.Exception- Throws:
java.lang.Exception
-
stripSignatures
public void stripSignatures()
-
removePrefix
public void removePrefix(java.lang.String prefixLow)
-
removeSubDirs
public void removeSubDirs(java.lang.String dir)
-
getPomXmlResources
public java.util.stream.Stream<Resource> getPomXmlResources()
-
setCalculateFileDigest
public Jar setCalculateFileDigest(boolean onOrOff)
Make this jar calculate the SHA256 when it is saved as a file. When this JAR is written, the digest is always cleared. If this flag is on, it will be calculated and set when the file is successfully saved.- Parameters:
onOrOff- state of calculating the digest when writing this jar. true is on, otherwise off
-
getSHA256
public java.util.Optional<byte[]> getSHA256()
Get the SHA256 digest of the last write operation whensetCalculateFileDigest(boolean)was on.- Returns:
- the SHA 256 digest or empty
-
getLength
public int getLength()
Get the length of the last written file or -1 if unavailable. The length is only calculated when the checksum calculation was on during the write.- Returns:
- the length of the last written file or -1 if unavailable.
-
-