Bug 29526 - Cannot undeploy and deploy war file with on the same context
Summary: Cannot undeploy and deploy war file with on the same context
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 5
Classification: Unclassified
Component: Webapps:Manager (show other bugs)
Version: 5.0.24
Hardware: All All
: P3 critical with 4 votes (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-06-11 14:30 UTC by Pavel Sivolobtchik
Modified: 2005-10-11 06:56 UTC (History)
3 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Pavel Sivolobtchik 2004-06-11 14:30:05 UTC
1)Start tomcat
2)Go to Manager.
3)deploy a war file.
4)undeploy it.
5)try to  deploy it again and you get message
"FAIL - War file "proxy.war" already exists on server".

It used to work fine in tomcat 5.0.19.
It not fixed in the version 5.0.26-beta.
Comment 1 Remy Maucherat 2004-06-11 14:44:38 UTC
This works for me. Please don't reopen the report.
Comment 2 Remy Maucherat 2004-06-11 15:03:27 UTC
Hmm, actually, I tested again, and it now doesn't work anymore.
I did countless changes already to fix this issue, and now I'm really really
sick of it and tired of mickey mouse OS. As a result, I'm not going to fix this
issue. I recommend either using Linux, investigating this issue more (and submit
a patch), or convince another developer to look into it.
Comment 3 Dave 2004-06-21 13:56:49 UTC
Remy,
I am also encountering this bug with my application. When undeploying it 
leaves a single jar that cannot be deleted. I've tracked it down to a single 
class within this jar that is causing the problem. Here is the code, can you 
think of any reason this class may be causing a problem?:

package com.company;

// ----------------------------------------------------------------------------
-
// StringEncrypter.java
// ----------------------------------------------------------------------------
-

// CIPHER / GENERATORS
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.KeyGenerator;

// KEY SPECIFICATIONS
import java.security.spec.KeySpec;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEParameterSpec;

// EXCEPTIONS
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.io.UnsupportedEncodingException;
import java.io.IOException;


/**
 * ----------------------------------------------------------------------------
-
 * The following example implements a class for encrypting and decrypting
 * strings using several Cipher algorithms. The class is created with a key and
 * can be used repeatedly to encrypt and decrypt strings using that key.
 * Some of the more popular algorithms are:
 *      Blowfish
 *      DES
 *      DESede
 *      PBEWithMD5AndDES
 *      PBEWithMD5AndTripleDES
 *      TripleDES
 * ----------------------------------------------------------------------------
-
 */

public class Encrypter {

    Cipher ecipher;
    Cipher dcipher;


    /**
     * Constructor used to create this object.  Responsible for setting
     * and initializing this object's encrypter and decrypter Chipher instances
     * given a Secret Key and algorithm.
     * @param key        Secret Key used to initialize both the encrypter and
     *                   decrypter instances.
     * @param algorithm  Which algorithm to use for creating the encrypter and
     *                   decrypter instances.
     */
    Encrypter(SecretKey key, String algorithm) {
        try {
            ecipher = Cipher.getInstance(algorithm);
            dcipher = Cipher.getInstance(algorithm);
            ecipher.init(Cipher.ENCRYPT_MODE, key);
            dcipher.init(Cipher.DECRYPT_MODE, key);
        } catch (Exception e) {
        }
    }


    /**
     * Constructor used to create this object.  Responsible for setting
     * and initializing this object's encrypter and decrypter Chipher instances
     * given a Pass Phrase and algorithm.
     * @param passPhrase Pass Phrase used to initialize both the encrypter and
     *                   decrypter instances.
     */
    Encrypter(String passPhrase) {

        // 8-bytes Salt
        byte[] salt = {
            (byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32,
            (byte)0x56, (byte)0x35, (byte)0xE3, (byte)0x03
        };

        // Iteration count
        int iterationCount = 20;

        try {

            KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, 
iterationCount);
            SecretKey key = SecretKeyFactory.getInstance
("PBEWithMD5AndDES").generateSecret(keySpec);

            ecipher = Cipher.getInstance(key.getAlgorithm());
            dcipher = Cipher.getInstance(key.getAlgorithm());

            // Prepare the parameters to the cipthers
            AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, 
iterationCount);

            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

        } catch (Exception e) {
        }
    }


    /**
     * Takes a single String as an argument and returns an Encrypted version
     * of that String.
     * @param str String to be encrypted
     * @return <code>String</code> Encrypted version of the provided String
     */
    public String encrypt(String str) {
        try {
            // Encode the string into bytes using utf-8
            byte[] utf8 = str.getBytes("UTF8");

            // Encrypt
            byte[] enc = ecipher.doFinal(utf8);

            // Encode bytes to base64 to get a string
            return new sun.misc.BASE64Encoder().encode(enc);

        } catch (Exception e) {
        }
    }


    public static Encrypter getEncrypter()
    {
        return new Encrypter("Any old phrase");
    }

    /**
     * Takes a encrypted String as an argument, decrypts and returns the 
     * decrypted String.
     * @param str Encrypted String to be decrypted
     * @return <code>String</code> Decrypted version of the provided String
     */
    public String decrypt(String str) {

        try {

            // Decode base64 to get bytes
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);

            // Decrypt
            byte[] utf8 = dcipher.doFinal(dec);

            // Decode using utf-8
            return new String(utf8, "UTF8");

        } catch (Exception e) {
        }
    }

Comment 4 Remy Maucherat 2004-06-28 16:20:54 UTC
This problem won't be resolved in 5.0.x. I'll redo the deployer in the next
release so that JARs are locked sometimes (as usual), but we don't care about it
(similar to JBoss). Until then, I don't recommend using Windows if you want hot
deployment to work reliably (at least not until M$ adds some option to allow
certain processes to avoid the file locking "feature" - I understand this is a
"useful" feature for the average desktop user, but for server side ...).
Comment 5 J.Pietschmann 2004-07-07 14:35:19 UTC
> tired of mickey mouse OS
The same happened to me on AIX 5 with /webapps on a NFS mounted drive, with
NFS lock files hanging around instead of the jars itself, thereby blocking
removal of the directory.
The really annoying part is that the Ant task claims success:

wardeploymanager:
   [deploy] OK - Anwendung mit Kontext Pfad /bre entfernt
   [deploy] OK - Anwendung mit Kontext Pfad /bre entfernt
   [deploy] OK - Anwendung mit Kontext Pfad /bre installiert

Isn't there a way to reliably detect that the webapp removal failed (for
whatever reason)?
Comment 6 Chris Reed 2004-07-24 19:57:09 UTC
Not using Windows isn't always an option...

The changes for 28272 uses the jar URL to see if the context.xml file exists 
inside the .war.  The jar URL connection class caches by default, and leaves a 
file descriptor open to the jar file.  By disabling caching, it doesn't and the 
jar file can be deleted.

--- ManagerServlet.java.orig	Thu Jun 17 21:02:56 2004
+++ ManagerServlet.java	Sat Jul 24 20:40:52 2004
@@ -27,6 +27,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.URL;
+import java.net.URLConnection;
 import java.net.MalformedURLException;
 import java.util.Iterator;
 import java.util.jar.JarEntry;
@@ -845,7 +846,9 @@
                         }
                         contextXml = new URL(contextWar +
                                              "META-INF/context.xml");
-                        stream = contextXml.openStream();
+                        URLConnection 
jarUrlConnection=contextXml.openConnection();
+                        jarUrlConnection.setUseCaches(false);
+                        stream = jarUrlConnection.getInputStream();;
                         // WAR contains META-INF/context.xml resource - install
                         deployer.install(new URL(contextWar));
                         return;
Comment 7 Frank Spies 2004-08-19 15:18:46 UTC
This does not work for me on my linux machine using Tomcat 5.0.19.
Comment 8 Yoav Shapira 2004-08-30 20:20:42 UTC
I've applied the patch for Tomcat 5.0(.29) -- thanks for submitting it.  For 
Tomcat 5.5, this is not applicable as significant changes have been made to 
relevant code (both the Manager and the Context).  When 5.5.0 is available, 
test out the "antiJARLocking" attribute and if a bug still exists, file an 
issue against 5.5.0.  Thanks.