update jar file with java code

O

Octal

I just need to update an existing big Jar file with a small text file.
I want to do this from a servlet so client gets a unique Jar. I'd like
to have it as Java code( it tried running a script file from the
servlet but that got me into deeper problems). The documentation on
manipulating Jar files I've found online is not very good and such
mehtods aren't well documented in general. If someone can show me some
sample code on how I can update a Jar file or give me a good link on
that, I would be really thankful.
 
T

Thomas Hawtin

Octal said:
I just need to update an existing big Jar file with a small text file.
I want to do this from a servlet so client gets a unique Jar. I'd like
to have it as Java code( it tried running a script file from the
servlet but that got me into deeper problems). The documentation on
manipulating Jar files I've found online is not very good and such
mehtods aren't well documented in general. If someone can show me some
sample code on how I can update a Jar file or give me a good link on
that, I would be really thankful.

If you need more than what is provided by the Java library, ANT has code
for manipulating jar files.

Since 1.3 jars have differed slightly from zips in that they can have an
index at the front as well as at the back. From 1.5 pack files are
available, which are more compact but also more expensive to create and
unpack.

Tom Hawtin
 
M

Mark Space

Octal said:
I just need to update an existing big Jar file with a small text file.
I want to do this from a servlet so client gets a unique Jar. I'd like
to have it as Java code( it tried running a script file from the
servlet but that got me into deeper problems). The documentation on
manipulating Jar files I've found online is not very good and such
mehtods aren't well documented in general. If someone can show me some
sample code on how I can update a Jar file or give me a good link on
that, I would be really thankful.

I have checked recently but I'm pretty sure that JAR files are just ZIP
files, and I think Java has a pretty decent interface/object for
manipulating zip files. Just open the jar as a zip, remove the file you
don't want, and add the one you do want. It's that easy.
 
I

IchBin

Octal said:
I just need to update an existing big Jar file with a small text file.
I want to do this from a servlet so client gets a unique Jar. I'd like
to have it as Java code( it tried running a script file from the
servlet but that got me into deeper problems). The documentation on
manipulating Jar files I've found online is not very good and such
mehtods aren't well documented in general. If someone can show me some
sample code on how I can update a Jar file or give me a good link on
that, I would be really thankful.
Not sure if this will help.. This may get you started. I have not worked
with the java.util.zip classes yet. I maybe wrong but you can not update
a zip file. You have to extract and build a new one and add new files
items. Again I am sure someone can correct me. The book from
Manning:'Java Swing 2nd Edition 2003' code wise, talks a lot about zip
files. Here are two examples (Compress and ZipJarManager)

/*
* Copyright (c) 2004 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 3nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose,
* including teaching and use in open-source projects.
* You may distribute it non-commercially as long as you retain this
notice.
* For a commercial use license, or to purchase the book,
* please visit http://www.davidflanagan.com/javaexamples3.
*/

import java.io.*;
import java.util.zip.*;

/**
* This class defines two static methods for gzipping files and zipping
* directories. It also defines a demonstration program as a nested class.
**/
public class Compress {
/** Gzip the contents of the from file and save in the to file. */
public static void gzipFile(String from, String to) throws
IOException {
// Create stream to read from the from file
FileInputStream in = new FileInputStream(from);
// Create stream to compress data and write it to the to file.
GZIPOutputStream out = new GZIPOutputStream(new
FileOutputStream(to));
// Copy bytes from one stream to the other
byte[] buffer = new byte[4096];
int bytes_read;
while((bytes_read = in.read(buffer)) != -1)
out.write(buffer, 0, bytes_read);
// And close the streams
in.close();
out.close();
}

/** Zip the contents of the directory, and save it in the zipfile */
public static void zipDirectory(String dir, String zipfile)
throws IOException, IllegalArgumentException {
// Check that the directory is a directory, and get its contents
File d = new File(dir);
if (!d.isDirectory())
throw new IllegalArgumentException("Compress: not a
directory: " +
dir);
String[] entries = d.list();
byte[] buffer = new byte[4096]; // Create a buffer for copying
int bytes_read;

// Create a stream to compress data and write it to the zipfile
ZipOutputStream out =
new ZipOutputStream(new FileOutputStream(zipfile));

// Loop through all entries in the directory
for(int i = 0; i < entries.length; i++) {
File f = new File(d, entries);
if (f.isDirectory()) continue; // Don't zip
sub-directories
FileInputStream in = new FileInputStream(f); // Stream to
read file
ZipEntry entry = new ZipEntry(f.getPath()); // Make a ZipEntry
out.putNextEntry(entry); // Store entry
while((bytes_read = in.read(buffer)) != -1) // Copy bytes
out.write(buffer, 0, bytes_read);
in.close(); // Close input
stream
}
// When we're done with the whole loop, close the output stream
out.close();
}

/**
* This nested class is a test program that demonstrates the use of the
* static methods defined above.
**/
public static class Test {
/**
* Compress a specified file or directory. If no destination name is
* specified, append .gz to a file name or .zip to a directory name
**/
public static void main(String args[]) throws IOException {
if ((args.length != 1)&& (args.length != 2)) { // check
arguments
System.err.println("Usage: java Compress$Test <from>
[<to>]");
System.exit(0);
}
String from = args[0], to;
File f = new File(from);
boolean directory = f.isDirectory(); // Is it a file or
directory?
if (args.length == 2) to = args[1];
else { // If destination not
specified
if (directory) to = from + ".zip"; // use a .zip suffix
else to = from + ".gz"; // or a .gz suffix
}

if ((new File(to)).exists()) { // Make sure not to overwrite
System.err.println("Compress: won't overwrite existing
file: "+
to);
System.exit(0);
}

// Finally, call one of the methods defined above to do the
work.
if (directory) Compress.zipDirectory(from, to);
else Compress.gzipFile(from, to);
}
}
}


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;

public class ZipJarManager extends JFrame {
public static int BUFFER_SIZE = 10240;

protected File m_currentDir;

protected SimpleFilter m_zipFilter;

protected SimpleFilter m_jarFilter;

protected ZipFileView m_view;

protected JButton m_btCreate;

protected JButton m_btExtract;

protected JLabel m_status;

public ZipJarManager() {
super("ZIP/JAR Manager");
setSize(300, 150);
JPanel p = new JPanel(new GridLayout(3, 1, 10, 10));
p.setBorder(new EmptyBorder(10, 10, 10, 10));
m_btCreate = new JButton("Create New Archive");
ActionListener lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
m_btCreate.setEnabled(false);
m_btExtract.setEnabled(false);
createArchive();
m_btCreate.setEnabled(true);
m_btExtract.setEnabled(true);
}
};
m_btCreate.addActionListener(lst);
m_btCreate.setMnemonic('c');
p.add(m_btCreate);
m_btExtract = new JButton("Extract From Archive");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
m_btCreate.setEnabled(false);
m_btExtract.setEnabled(false);
extractArchive();
m_btCreate.setEnabled(true);
m_btExtract.setEnabled(true);
}
};
m_btExtract.addActionListener(lst);
m_btExtract.setMnemonic('e');
p.add(m_btExtract);
m_status = new JLabel();
m_status.setBorder(new BevelBorder(BevelBorder.LOWERED, Color.white,
Color.gray));
p.add(m_status);

getContentPane().add(p, BorderLayout.CENTER);
m_zipFilter = new SimpleFilter("zip", "ZIP Files");
m_jarFilter = new SimpleFilter("jar", "JAR Files");
m_view = new ZipFileView();
try {
m_currentDir = (new File(".")).getCanonicalFile();
} catch (IOException ex) {
}
}

public void setStatus(String str) {
m_status.setText(str);
m_status.repaint();
}

protected void createArchive() {
// Show chooser to select archive
JFileChooser archiveChooser = new JFileChooser();
archiveChooser.addChoosableFileFilter(m_zipFilter);
archiveChooser.addChoosableFileFilter(m_jarFilter);
archiveChooser.setFileView(m_view);
archiveChooser.setMultiSelectionEnabled(false);
archiveChooser.setFileFilter(m_jarFilter);
javax.swing.filechooser.FileFilter ft =
archiveChooser.getAcceptAllFileFilter();
archiveChooser.removeChoosableFileFilter(ft);
archiveChooser.setCurrentDirectory(m_currentDir);
archiveChooser.setDialogType(JFileChooser.SAVE_DIALOG);
archiveChooser.setDialogTitle("New Archive");
if (archiveChooser.showDialog(this, "Create") !=
JFileChooser.APPROVE_OPTION)
return;
m_currentDir = archiveChooser.getCurrentDirectory();
final File archiveFile = archiveChooser.getSelectedFile();
if (!isArchiveFile(archiveFile))
return;
// Show chooser to select entries
JFileChooser entriesChooser = new JFileChooser();
entriesChooser.setCurrentDirectory(m_currentDir);
entriesChooser.setDialogType(JFileChooser.OPEN_DIALOG);
entriesChooser.setDialogTitle("Select Content For "
+ archiveFile.getName());
entriesChooser.setMultiSelectionEnabled(true);
entriesChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
if (entriesChooser.showDialog(this, "Add") !=
JFileChooser.APPROVE_OPTION)
return;
m_currentDir = entriesChooser.getCurrentDirectory();
final File[] selected = entriesChooser.getSelectedFiles();
String name = archiveFile.getName().toLowerCase();

if (name.endsWith(".zip")) {
Thread runner = new Thread() {
public void run() {
createZipArchive(archiveFile, selected);
}
};
runner.start();
}
else if (name.endsWith(".jar")) {
Thread runner = new Thread() {
public void run() {
createJarArchive(archiveFile, selected);
}
};
runner.start();
}
else {
setStatus("No JAR or ZIP file has been selected");
}
}

protected void extractArchive() {
// Show dialog to select archive and entries
ExtractChooser extractChooser = new ExtractChooser();
extractChooser.addChoosableFileFilter(m_zipFilter);
extractChooser.addChoosableFileFilter(m_jarFilter);
extractChooser.setFileView(m_view);
extractChooser.setMultiSelectionEnabled(false);
extractChooser.setFileFilter(m_jarFilter);
javax.swing.filechooser.FileFilter ft =
extractChooser.getAcceptAllFileFilter();
extractChooser.removeChoosableFileFilter(ft);
extractChooser.setCurrentDirectory(m_currentDir);
extractChooser.setDialogType(JFileChooser.OPEN_DIALOG);
extractChooser.setDialogTitle("Open Archive");
extractChooser.setMultiSelectionEnabled(false);
extractChooser.setPreferredSize(new Dimension(470,450));
if (extractChooser.showDialog(this, "Extract") !=
JFileChooser.APPROVE_OPTION)
return;
m_currentDir = extractChooser.getCurrentDirectory();
final File archiveFile = extractChooser.getSelectedFile();
if (!archiveFile.exists() || !isArchiveFile(archiveFile))
return;
final String[] entries = extractChooser.getSelectedEntries();
if (entries.length == 0) {
setStatus("No entries have been selected for extraction");
return;
}
// Show dialog to select output directory

JFileChooser dirChooser = new JFileChooser();
dirChooser.setCurrentDirectory(m_currentDir);
dirChooser.setDialogType(JFileChooser.OPEN_DIALOG);
dirChooser.setDialogTitle("Select Destination Directory For " +
archiveFile.getName());
dirChooser.setMultiSelectionEnabled(false);
dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (dirChooser.showDialog(this, "Select") !=
JFileChooser.APPROVE_OPTION)
return;
m_currentDir = dirChooser.getCurrentDirectory();
final File outputDir = dirChooser.getSelectedFile();
Thread runner = new Thread() {
public void run() {
extractFromArchive(archiveFile, entries, outputDir);
}
};
runner.start();
}

protected void createZipArchive(File archiveFile, File[] selected) {
try {
byte buffer[] = new byte[BUFFER_SIZE];
// Open archive file
FileOutputStream stream =
new FileOutputStream(archiveFile);
ZipOutputStream out = new ZipOutputStream(stream);
for (int k=0; k<selected.length; k++) {
if (selected[k]==null || !selected[k].exists() ||
selected[k].isDirectory())
continue;// Just in case...
setStatus("Adding "+selected[k].getName());
// Add archive entry
ZipEntry zipAdd = new ZipEntry(selected[k].getName());
zipAdd.setTime(selected[k].lastModified());
out.putNextEntry(zipAdd);
// Read input & write to output
FileInputStream in = new FileInputStream(selected[k]);
while (true) {
int nRead = in.read(buffer, 0, buffer.length);
if (nRead <= 0)
break;
out.write(buffer, 0, nRead);
}
in.close();
}
out.close();
stream.close();
setStatus("ZIP archive was created successfully");
}
catch (Exception e) {
e.printStackTrace();
setStatus("Error: "+e.getMessage());
return;
}
}

protected void createJarArchive(File archiveFile, File[] selected) {
try {
byte buffer[] = new byte[BUFFER_SIZE];
// Open archive file
FileOutputStream stream = new FileOutputStream(archiveFile);
JarOutputStream out = new JarOutputStream(stream, new Manifest());
for (int k = 0; k < selected.length; k++) {
if (selected[k] == null || !selected[k].exists()
|| selected[k].isDirectory())
continue;// Just in case...
setStatus("Adding " + selected[k].getName());
// Add archive entry
JarEntry jarAdd = new JarEntry(selected[k].getName());
jarAdd.setTime(selected[k].lastModified());
out.putNextEntry(jarAdd);
// Write file to archive
FileInputStream in = new FileInputStream(selected[k]);
while (true) {
int nRead = in.read(buffer, 0, buffer.length);
if (nRead <= 0)
break;
out.write(buffer, 0, nRead);
}
in.close();
}
out.close();
stream.close();
setStatus("JAR archive was created successfully");
} catch (Exception ex) {
ex.printStackTrace();
setStatus("Error: " + ex.getMessage());
}
}

protected void extractFromArchive(File archiveFile,
String[] entries, File outputDir) {
try {
byte buffer[] = new byte[BUFFER_SIZE];
// Open the archive file
FileInputStream stream =
new FileInputStream(archiveFile);
ZipInputStream in = new ZipInputStream(stream);
// Find archive entry
while (true) {
ZipEntry zipExtract = in.getNextEntry();
if (zipExtract == null)
break;
boolean bFound = false;
for (int k=0; k<entries.length; k++) {
if (zipExtract.getName().equals(entries[k])) {
bFound = true;
break;
}
}
if (!bFound) {
in.closeEntry();
continue;
}
setStatus("Extracting "+zipExtract.getName());
// Create output file and check required directory
File outFile = new File(outputDir,
zipExtract.getName());
File parent = outFile.getParentFile();
if (parent != null && !parent.exists())
parent.mkdirs();
// Extract unzipped file
FileOutputStream out =
new FileOutputStream(outFile);
while (true) {
int nRead = in.read(buffer,
0, buffer.length);
if (nRead <= 0)
break;
out.write(buffer, 0, nRead);
}
out.close();
in.closeEntry();
}
in.close();
stream.close();
setStatus("Files were extracted successfully");
}
catch (Exception ex) {
ex.printStackTrace();
setStatus("Error: "+ex.getMessage());
}
}

public static boolean isArchiveFile(File f) {
String name = f.getName().toLowerCase();
return (name.endsWith(".zip") || name.endsWith(".jar"));
}

public static void main(String argv[]) {
ZipJarManager frame = new ZipJarManager();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

class SimpleFilter extends javax.swing.filechooser.FileFilter {
private String m_description = null;

private String m_extension = null;

public SimpleFilter(String extension, String description) {
m_description = description;
m_extension = "." + extension.toLowerCase();
}

public String getDescription() {
return m_description;
}

public boolean accept(File f) {
if (f == null)
return false;
if (f.isDirectory())
return true;
return f.getName().toLowerCase().endsWith(m_extension);
}
}

class ZipFileView extends javax.swing.filechooser.FileView {
protected static ImageIcon ZIP_ICON = new ImageIcon("archive.gif");

protected static ImageIcon JAR_ICON = new ImageIcon("archive.gif");

public String getName(File f) {
String name = f.getName();
return name.equals("") ? f.getPath() : name;
}

public String getDescription(File f) {
return getTypeDescription(f);
}

public String getTypeDescription(File f) {
String name = f.getName().toLowerCase();
if (name.endsWith(".zip"))
return "ZIP Archive File";
else if (name.endsWith(".jar"))
return "Java Archive File";
else
return "File";
}

public Icon getIcon(File f) {
String name = f.getName().toLowerCase();
if (name.endsWith(".zip"))
return ZIP_ICON;
else if (name.endsWith(".jar"))
return JAR_ICON;
else
return null;
}

public Boolean isTraversable(File f) {
return (f.isDirectory() ? Boolean.TRUE : Boolean.FALSE);
}
}

class TabListCellRenderer extends JLabel implements ListCellRenderer {
protected static Border m_noFocusBorder;

protected FontMetrics m_fm = null;

protected Insets m_insets = new Insets(0, 0, 0, 0);

protected int m_defaultTab = 50;

protected int[] m_tabs = null;

public TabListCellRenderer() {
super();
m_noFocusBorder = new EmptyBorder(1, 1, 1, 1);
setOpaque(true);
setBorder(m_noFocusBorder);
}

public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
setText(value.toString());
setBackground(isSelected ? list.getSelectionBackground() : list
.getBackground());
setForeground(isSelected ? list.getSelectionForeground() : list
.getForeground());
setFont(list.getFont());
setBorder((cellHasFocus) ? UIManager
.getBorder("List.focusCellHighlightBorder") : m_noFocusBorder);
return this;
}

public void setDefaultTab(int defaultTab) {
m_defaultTab = defaultTab;
}

public int getDefaultTab() {
return m_defaultTab;
}

public void setTabs(int[] tabs) {
m_tabs = tabs;
}

public int[] getTabs() {
return m_tabs;
}

public int getTab(int index) {
if (m_tabs == null)
return m_defaultTab * index;
int len = m_tabs.length;
if (index >= 0 && index < len)
return m_tabs[index];
return m_tabs[len - 1] + m_defaultTab * (index - len + 1);
}

public void paintComponent(Graphics g) {
super.paintComponent(g);
m_fm = g.getFontMetrics();
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight());
g.setColor(getForeground());
g.setFont(getFont());
m_insets = getInsets();
int x = m_insets.left;
int y = m_insets.top + m_fm.getAscent();
StringTokenizer st = new StringTokenizer(getText(), "\t");
while (st.hasMoreTokens()) {
String sNext = st.nextToken();
g.drawString(sNext, x, y);
x += m_fm.stringWidth(sNext);
if (!st.hasMoreTokens())
break;
int index = 0;
while (x >= getTab(index))
index++;
x = getTab(index);
}
}
}

class ExtractChooser extends JFileChooser {
protected JList m_zipEntries;

protected JDialog createDialog(Component parent)
throws HeadlessException {
JDialog dialog = super.createDialog(parent);
m_zipEntries = new JList();
m_zipEntries.setSelectionMode(
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
TabListCellRenderer renderer = new TabListCellRenderer();
renderer.setTabs(new int[] {240, 300, 360});
m_zipEntries.setCellRenderer(renderer);
JPanel p = new JPanel(new BorderLayout());
p.setBorder(new EmptyBorder(0,10,10,10));
p.add(new JLabel("Files to extract:"), BorderLayout.NORTH);
JScrollPane ps = new JScrollPane(m_zipEntries);
p.add(ps, BorderLayout.CENTER);
dialog.getContentPane().add(p, BorderLayout.SOUTH);
PropertyChangeListener lst = new PropertyChangeListener() {
SimpleDateFormat m_sdf = new SimpleDateFormat(
"MM/dd/yyyy hh:mm a");
DefaultListModel m_emptyModel = new DefaultListModel();
public void propertyChange(PropertyChangeEvent e) {
if (e.getPropertyName() ==
JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
m_zipEntries.setModel(m_emptyModel);
return;
}
else if (e.getPropertyName() ==
JFileChooser.SELECTED_FILE_CHANGED_PROPERTY) {
File f = getSelectedFile();
if (f == null) {
m_zipEntries.setModel(m_emptyModel);
return;
}
String name = f.getName().toLowerCase();
if (!name.endsWith(".zip") && !name.endsWith(".jar")) {
m_zipEntries.setModel(m_emptyModel);
return;
}
try {
ZipFile zipFile = new ZipFile(f.getPath());
DefaultListModel model = new DefaultListModel();
Enumeration en = zipFile.entries();
while (en.hasMoreElements()) {
ZipEntry zipEntr = (ZipEntry)en.
nextElement();
Date d = new Date(zipEntr.getTime());
String str = zipEntr.getName()+'\t'+
zipEntr.getSize()+'\t'+m_sdf.format(d);
model.addElement(str);
}
zipFile.close();
m_zipEntries.setModel(model);
m_zipEntries.setSelectionInterval(0,
model.getSize()-1);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
else {
m_zipEntries.setModel(m_emptyModel);
return;
}
}
};
addPropertyChangeListener(lst);
cancelSelection();
return dialog;
}

public String[] getSelectedEntries() {
Object[] selObj = m_zipEntries.getSelectedValues();
String[] entries = new String[selObj.length];
for (int k = 0; k < selObj.length; k++) {
String str = selObj[k].toString();
int index = str.indexOf('\t');
entries[k] = str.substring(0, index);
}
return entries;
}
}



Thanks in Advance...
IchBin, Pocono Lake, Pa, USA http://weconsultants.phpnet.us
__________________________________________________________________________

'If there is one, Knowledge is the "Fountain of Youth"'
-William E. Taylor, Regular Guy (1952-)
 
M

Mark Space

IchBin said:
Not sure if this will help.. This may get you started. I have not worked
with the java.util.zip classes yet. I maybe wrong but you can not update
a zip file. You have to extract and build a new one and add new files
items. Again I am sure someone can correct me. The book from

Well good answer there, IchBin. I haven't worked with the zip classes
either, I just assumed that there'd be a "add" method. But nope,
there's delete and read but no write. What a bummer. It looks like
someone at Sun got bored and wandered off before the API was done.
 
E

Eric Sosman

Mark said:
Well good answer there, IchBin. I haven't worked with the zip classes
either, I just assumed that there'd be a "add" method. But nope,
there's delete and read but no write. What a bummer. It looks like
someone at Sun got bored and wandered off before the API was done.

Does that matter for the O.P.'s purposes? Yes, he said
he wanted to "update an existing big jar" -- but in truth,
that doesn't seem to be what he needs at all! He's writing
a servlet to send a jar to a client, and he apparently wants
to "fingerprint" each jar with a client-specific entry. So
what he really needs, it seems to me, is a read-only jar on
the server that he can copy entry by entry from (probably) a
ZipInputStream to a ZipOutputStream. Along the way he can
synthesize and write his one extra "fingerprint" entry to the
ZipOutputStream. The jar that's sent to the client never gets
written to the server's storage, never needs to be updated on
the server -- it's just a transient, in-flight "fire and forget"
stream of output that happens to have the form of a zip file.

... or have I completely misunderstood the intent?
 
M

Mark Space

Eric said:
Does that matter for the O.P.'s purposes? Yes, he said
he wanted to "update an existing big jar" -- but in truth,
that doesn't seem to be what he needs at all! He's writing
a servlet to send a jar to a client, and he apparently wants
to "fingerprint" each jar with a client-specific entry. So
what he really needs, it seems to me, is a read-only jar on
the server that he can copy entry by entry from (probably) a
ZipInputStream to a ZipOutputStream. Along the way he can
synthesize and write his one extra "fingerprint" entry to the
ZipOutputStream. The jar that's sent to the client never gets

Hmm, if I remember the zip file formant, there's an index and file count
at the beginning of the zip file, so one has to complete all writes to
the archive before it's valid. But what you suggest might be possible,
with a little clever work from the OP.

But in general, the absence of a generic "add this to an existing
archive" seems defective to me. Maybe there's a good reason for it though.

I wonder if he could use two jar files. One big one with most of the
methods, which never gets changed, and one smaller one with just the
ticket and validation method. This might be easier on the server's CPU
and disk IO bandwidth.
 
C

Chris Uppal

Mark said:
Hmm, if I remember the zip file formant, there's an index and file count
at the beginning of the zip file,

The end.

But in general, the absence of a generic "add this to an existing
archive" seems defective to me. Maybe there's a good reason for it
though.

The only option for "modifying" ZIP files which doesn't amount to making a copy
of the file (with whatever desired changes applied as you do so), is to append
to an existing file. In that case you can overwrite the existing
table-of-contents with the appended file(s), and then recreate the table of
contents. In fact, you can also delete the last N files, but that's not a very
useful operation and in any case depends on being able to truncate a file to a
length other than zero (which is not, IIRC, available on all OSs).

I vaguely remember seeing something about an append operation being
added to the java.util.zip.*; but I can't now recall whether it was just
someone whining in the Bug Parade, or was something concrete planned for an
upcoming release.

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,619
Members
45,315
Latest member
VernellPos

Latest Threads

Top