You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2006/10/24 05:18:02 UTC

svn commit: r467222 [5/31] - in /tomcat/tc6.0.x/trunk/java: javax/annotation/ javax/annotation/security/ javax/ejb/ javax/el/ javax/mail/ javax/mail/internet/ javax/persistence/ javax/servlet/ javax/servlet/http/ javax/servlet/jsp/ javax/servlet/jsp/el...

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java?view=diff&rev=467222&r1=467221&r2=467222
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java Mon Oct 23 20:17:11 2006
@@ -1,747 +1,747 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.HashMap;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.catalina.Context;
-import org.apache.catalina.Engine;
-import org.apache.catalina.Host;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleException;
-import org.apache.catalina.ha.CatalinaCluster;
-import org.apache.catalina.ha.ClusterDeployer;
-import org.apache.catalina.ha.ClusterListener;
-import org.apache.catalina.ha.ClusterMessage;
-import org.apache.catalina.tribes.Member;
-import org.apache.tomcat.util.modeler.Registry;
-
-
-/**
- * <p>
- * A farm war deployer is a class that is able to deploy/undeploy web
- * applications in WAR form within the cluster.
- * </p>
- * Any host can act as the admin, and will have three directories
- * <ul>
- * <li>deployDir - the directory where we watch for changes</li>
- * <li>applicationDir - the directory where we install applications</li>
- * <li>tempDir - a temporaryDirectory to store binary data when downloading a
- * war from the cluster</li>
- * </ul>
- * Currently we only support deployment of WAR files since they are easier to
- * send across the wire.
- * 
- * @author Filip Hanik
- * @author Peter Rossbach
- * @version $Revision: 390639 $
- */
-public class FarmWarDeployer extends ClusterListener implements ClusterDeployer, FileChangeListener {
-    /*--Static Variables----------------------------------------*/
-    public static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
-            .getLog(FarmWarDeployer.class);
-    /**
-     * The descriptive information about this implementation.
-     */
-    private static final String info = "FarmWarDeployer/1.2";
-
-    /*--Instance Variables--------------------------------------*/
-    protected CatalinaCluster cluster = null;
-
-    protected boolean started = false; //default 5 seconds
-
-    protected HashMap fileFactories = new HashMap();
-
-    protected String deployDir;
-
-    protected String tempDir;
-
-    protected String watchDir;
-
-    protected boolean watchEnabled = false;
-
-    protected WarWatcher watcher = null;
-
-    /**
-     * Iteration count for background processing.
-     */
-    private int count = 0;
-
-    /**
-     * Frequency of the Farm watchDir check. Cluster wide deployment will be
-     * done once for the specified amount of backgrondProcess calls (ie, the
-     * lower the amount, the most often the checks will occur).
-     */
-    protected int processDeployFrequency = 2;
-
-    /**
-     * Path where context descriptors should be deployed.
-     */
-    protected File configBase = null;
-
-    /**
-     * The associated host.
-     */
-    protected Host host = null;
-
-    /**
-     * The host appBase.
-     */
-    protected File appBase = null;
-
-    /**
-     * MBean server.
-     */
-    protected MBeanServer mBeanServer = null;
-
-    /**
-     * The associated deployer ObjectName.
-     */
-    protected ObjectName oname = null;
-
-    /*--Constructor---------------------------------------------*/
-    public FarmWarDeployer() {
-    }
-
-    /**
-     * Return descriptive information about this deployer implementation and the
-     * corresponding version number, in the format
-     * <code>&lt;description&gt;/&lt;version&gt;</code>.
-     */
-    public String getInfo() {
-
-        return (info);
-
-    }
-
-    /*--Logic---------------------------------------------------*/
-    public void start() throws Exception {
-        if (started)
-            return;
-        getCluster().addClusterListener(this);
-        if (watchEnabled) {
-            watcher = new WarWatcher(this, new File(getWatchDir()));
-            if (log.isInfoEnabled())
-                log.info("Cluster deployment is watching " + getWatchDir()
-                         + " for changes.");
-        }
-    
-        // Check to correct engine and host setup
-        Object parent = getCluster().getContainer();
-        Engine engine = null;
-        if ( parent instanceof Host ) {
-            host = (Host) parent;
-            engine = (Engine) host.getParent();
-        }else {
-            engine = (Engine)parent;
-        }
-        try {
-            oname = new ObjectName(engine.getName() + ":type=Deployer,host="
-                    + host.getName());
-        } catch (Exception e) {
-            log.error("Can't construct MBean object name" + e);
-        }
-        configBase = new File(System.getProperty("catalina.base"), "conf");
-        if (engine != null) {
-            configBase = new File(configBase, engine.getName());
-        } else if (host != null) {
-            configBase = new File(configBase, host.getName());
-        }
-
-        // Retrieve the MBean server
-        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
-
-        started = true;
-        count = 0;
-        if (log.isInfoEnabled())
-            log.info("Cluster FarmWarDeployer started.");
-    }
-
-    /*
-     * stop cluster wide deployments
-     * 
-     * @see org.apache.catalina.ha.ClusterDeployer#stop()
-     */
-    public void stop() throws LifecycleException {
-        started = false;
-        getCluster().removeClusterListener(this);
-        count = 0;
-        if (watcher != null) {
-            watcher.clear();
-            watcher = null;
-
-        }
-        if (log.isInfoEnabled())
-            log.info("Cluster FarmWarDeployer stopped.");
-    }
-
-    public void cleanDeployDir() {
-        throw new java.lang.UnsupportedOperationException(
-                "Method cleanDeployDir() not yet implemented.");
-    }
-
-    /**
-     * Callback from the cluster, when a message is received, The cluster will
-     * broadcast it invoking the messageReceived on the receiver.
-     * 
-     * @param msg
-     *            ClusterMessage - the message received from the cluster
-     */
-    public void messageReceived(ClusterMessage msg) {
-        try {
-            if (msg instanceof FileMessage && msg != null) {
-                FileMessage fmsg = (FileMessage) msg;
-                if (log.isDebugEnabled())
-                    log.debug("receive cluster deployment [ path: "
-                            + fmsg.getContextPath() + " war:  "
-                            + fmsg.getFileName() + " ]");
-                FileMessageFactory factory = getFactory(fmsg);
-                // TODO correct second try after app is in service!
-                if (factory.writeMessage(fmsg)) {
-                    //last message received war file is completed
-                    String name = factory.getFile().getName();
-                    if (!name.endsWith(".war"))
-                        name = name + ".war";
-                    File deployable = new File(getDeployDir(), name);
-                    try {
-                        String path = fmsg.getContextPath();
-                        if (!isServiced(path)) {
-                            addServiced(path);
-                            try {
-                                remove(path);
-                                factory.getFile().renameTo(deployable);
-                                check(path);
-                            } finally {
-                                removeServiced(path);
-                            }
-                            if (log.isDebugEnabled())
-                                log.debug("deployment from " + path
-                                        + " finished.");
-                        } else
-                            log.error("Application " + path
-                                    + " in used. touch war file " + name
-                                    + " again!");
-                    } catch (Exception ex) {
-                        log.error(ex);
-                    } finally {
-                        removeFactory(fmsg);
-                    }
-                }
-            } else if (msg instanceof UndeployMessage && msg != null) {
-                try {
-                    UndeployMessage umsg = (UndeployMessage) msg;
-                    String path = umsg.getContextPath();
-                    if (log.isDebugEnabled())
-                        log.debug("receive cluster undeployment from " + path);
-                    if (!isServiced(path)) {
-                        addServiced(path);
-                        try {
-                            remove(path);
-                        } finally {
-                            removeServiced(path);
-                        }
-                        if (log.isDebugEnabled())
-                            log.debug("undeployment from " + path
-                                    + " finished.");
-                    } else
-                        log.error("Application "
-                            + path
-                            + " in used. Sorry not remove from backup cluster nodes!");
-                } catch (Exception ex) {
-                    log.error(ex);
-                }
-            }
-        } catch (java.io.IOException x) {
-            log.error("Unable to read farm deploy file message.", x);
-        }
-    }
-
-    /**
-     * create factory for all transported war files
-     * 
-     * @param msg
-     * @return Factory for all app message (war files)
-     * @throws java.io.FileNotFoundException
-     * @throws java.io.IOException
-     */
-    public synchronized FileMessageFactory getFactory(FileMessage msg)
-            throws java.io.FileNotFoundException, java.io.IOException {
-        File tmpFile = new File(msg.getFileName());
-        File writeToFile = new File(getTempDir(), tmpFile.getName());
-        FileMessageFactory factory = (FileMessageFactory) fileFactories.get(msg
-                .getFileName());
-        if (factory == null) {
-            factory = FileMessageFactory.getInstance(writeToFile, true);
-            fileFactories.put(msg.getFileName(), factory);
-        }
-        return factory;
-    }
-
-    /**
-     * Remove file (war) from messages)
-     * 
-     * @param msg
-     */
-    public void removeFactory(FileMessage msg) {
-        fileFactories.remove(msg.getFileName());
-    }
-
-    /**
-     * Before the cluster invokes messageReceived the cluster will ask the
-     * receiver to accept or decline the message, In the future, when messages
-     * get big, the accept method will only take a message header
-     * 
-     * @param msg
-     *            ClusterMessage
-     * @return boolean - returns true to indicate that messageReceived should be
-     *         invoked. If false is returned, the messageReceived method will
-     *         not be invoked.
-     */
-    public boolean accept(ClusterMessage msg) {
-        return (msg instanceof FileMessage) || (msg instanceof UndeployMessage);
-    }
-
-    /**
-     * Install a new web application, whose web application archive is at the
-     * specified URL, into this container and all the other members of the
-     * cluster with the specified context path. A context path of "" (the empty
-     * string) should be used for the root application for this container.
-     * Otherwise, the context path must start with a slash.
-     * <p>
-     * If this application is successfully installed locally, a ContainerEvent
-     * of type <code>INSTALL_EVENT</code> will be sent to all registered
-     * listeners, with the newly created <code>Context</code> as an argument.
-     * 
-     * @param contextPath
-     *            The context path to which this application should be installed
-     *            (must be unique)
-     * @param war
-     *            A URL of type "jar:" that points to a WAR file, or type
-     *            "file:" that points to an unpacked directory structure
-     *            containing the web application to be installed
-     * 
-     * @exception IllegalArgumentException
-     *                if the specified context path is malformed (it must be ""
-     *                or start with a slash)
-     * @exception IllegalStateException
-     *                if the specified context path is already attached to an
-     *                existing web application
-     * @exception IOException
-     *                if an input/output error was encountered during
-     *                installation
-     */
-    public void install(String contextPath, URL war) throws IOException {
-        Member[] members = getCluster().getMembers();
-        Member localMember = getCluster().getLocalMember();
-        FileMessageFactory factory = FileMessageFactory.getInstance(new File(
-                war.getFile()), false);
-        FileMessage msg = new FileMessage(localMember, war.getFile(),
-                contextPath);
-        if(log.isDebugEnabled())
-            log.debug("Send cluster war deployment [ path:"
-                    + contextPath + " war: " + war + " ] started.");
-        msg = factory.readMessage(msg);
-        while (msg != null) {
-            for (int i = 0; i < members.length; i++) {
-                if (log.isDebugEnabled())
-                    log.debug("Send cluster war fragment [ path: "
-                            + contextPath + " war: " + war + " to: " +  members[i] + " ]");
-                getCluster().send(msg, members[i]);
-            }
-            msg = factory.readMessage(msg);
-        }
-        if(log.isDebugEnabled())
-            log.debug("Send cluster war deployment [ path: "
-                    + contextPath + " war: " + war + " ] finished.");
-    }
-
-    /**
-     * Remove an existing web application, attached to the specified context
-     * path. If this application is successfully removed, a ContainerEvent of
-     * type <code>REMOVE_EVENT</code> will be sent to all registered
-     * listeners, with the removed <code>Context</code> as an argument.
-     * Deletes the web application war file and/or directory if they exist in
-     * the Host's appBase.
-     * 
-     * @param contextPath
-     *            The context path of the application to be removed
-     * @param undeploy
-     *            boolean flag to remove web application from server
-     * 
-     * @exception IllegalArgumentException
-     *                if the specified context path is malformed (it must be ""
-     *                or start with a slash)
-     * @exception IllegalArgumentException
-     *                if the specified context path does not identify a
-     *                currently installed web application
-     * @exception IOException
-     *                if an input/output error occurs during removal
-     */
-    public void remove(String contextPath, boolean undeploy) throws IOException {
-        if (log.isInfoEnabled())
-            log.info("Cluster wide remove of web app " + contextPath);
-        Member localMember = getCluster().getLocalMember();
-        UndeployMessage msg = new UndeployMessage(localMember, System
-                .currentTimeMillis(), "Undeploy:" + contextPath + ":"
-                + System.currentTimeMillis(), contextPath, undeploy);
-        if (log.isDebugEnabled())
-            log.debug("Send cluster wide undeployment from "
-                    + contextPath );
-        cluster.send(msg);
-        // remove locally
-        if (undeploy) {
-            try {
-                if (!isServiced(contextPath)) {
-                    addServiced(contextPath);
-                    try {
-                        remove(contextPath);
-                    } finally {
-                        removeServiced(contextPath);
-                    }
-                } else
-                    log.error("Local remove from " + contextPath
-                            + "failed, other manager has app in service!");
-
-            } catch (Exception ex) {
-                log.error("local remove from " + contextPath + " failed", ex);
-            }
-        }
-
-    }
-
-    /*
-     * Modifcation from watchDir war detected!
-     * 
-     * @see org.apache.catalina.ha.deploy.FileChangeListener#fileModified(java.io.File)
-     */
-    public void fileModified(File newWar) {
-        try {
-            File deployWar = new File(getDeployDir(), newWar.getName());
-            copy(newWar, deployWar);
-            String contextName = getContextName(deployWar);
-            if (log.isInfoEnabled())
-                log.info("Installing webapp[" + contextName + "] from "
-                        + deployWar.getAbsolutePath());
-            try {
-                remove(contextName, false);
-            } catch (Exception x) {
-                log.error("No removal", x);
-            }
-            install(contextName, deployWar.toURL());
-        } catch (Exception x) {
-            log.error("Unable to install WAR file", x);
-        }
-    }
-
-    /*
-     * War remvoe from watchDir
-     * 
-     * @see org.apache.catalina.ha.deploy.FileChangeListener#fileRemoved(java.io.File)
-     */
-    public void fileRemoved(File removeWar) {
-        try {
-            String contextName = getContextName(removeWar);
-            if (log.isInfoEnabled())
-                log.info("Removing webapp[" + contextName + "]");
-            remove(contextName, true);
-        } catch (Exception x) {
-            log.error("Unable to remove WAR file", x);
-        }
-    }
-
-    /**
-     * Create a context path from war
-     * @param war War filename
-     * @return '/filename' or if war name is ROOT.war context name is empty string '' 
-     */
-    protected String getContextName(File war) {
-        String contextName = "/"
-        + war.getName().substring(0,
-                war.getName().lastIndexOf(".war"));
-        if("/ROOT".equals(contextName))
-            contextName= "" ;
-        return contextName ;
-    }
-    
-    /**
-     * Given a context path, get the config file name.
-     */
-    protected String getConfigFile(String path) {
-        String basename = null;
-        if (path.equals("")) {
-            basename = "ROOT";
-        } else {
-            basename = path.substring(1).replace('/', '#');
-        }
-        return (basename);
-    }
-
-    /**
-     * Given a context path, get the config file name.
-     */
-    protected String getDocBase(String path) {
-        String basename = null;
-        if (path.equals("")) {
-            basename = "ROOT";
-        } else {
-            basename = path.substring(1);
-        }
-        return (basename);
-    }
-
-    /**
-     * Return a File object representing the "application root" directory for
-     * our associated Host.
-     */
-    protected File getAppBase() {
-
-        if (appBase != null) {
-            return appBase;
-        }
-
-        File file = new File(host.getAppBase());
-        if (!file.isAbsolute())
-            file = new File(System.getProperty("catalina.base"), host
-                    .getAppBase());
-        try {
-            appBase = file.getCanonicalFile();
-        } catch (IOException e) {
-            appBase = file;
-        }
-        return (appBase);
-
-    }
-
-    /**
-     * Invoke the remove method on the deployer.
-     */
-    protected void remove(String path) throws Exception {
-        // TODO Handle remove also work dir content !
-        // Stop the context first to be nicer
-        Context context = (Context) host.findChild(path);
-        if (context != null) {
-            if(log.isDebugEnabled())
-                log.debug("Undeploy local context " +path );
-            ((Lifecycle) context).stop();
-            File war = new File(getAppBase(), getDocBase(path) + ".war");
-            File dir = new File(getAppBase(), getDocBase(path));
-            File xml = new File(configBase, getConfigFile(path) + ".xml");
-            if (war.exists()) {
-                war.delete();
-            } else if (dir.exists()) {
-                undeployDir(dir);
-            } else {
-                xml.delete();
-            }
-            // Perform new deployment and remove internal HostConfig state
-            check(path);
-        }
-
-    }
-
-    /**
-     * Delete the specified directory, including all of its contents and
-     * subdirectories recursively.
-     * 
-     * @param dir
-     *            File object representing the directory to be deleted
-     */
-    protected void undeployDir(File dir) {
-
-        String files[] = dir.list();
-        if (files == null) {
-            files = new String[0];
-        }
-        for (int i = 0; i < files.length; i++) {
-            File file = new File(dir, files[i]);
-            if (file.isDirectory()) {
-                undeployDir(file);
-            } else {
-                file.delete();
-            }
-        }
-        dir.delete();
-
-    }
-
-    /*
-     * Call watcher to check for deploy changes
-     * 
-     * @see org.apache.catalina.ha.ClusterDeployer#backgroundProcess()
-     */
-    public void backgroundProcess() {
-        if (started) {
-            count = (count + 1) % processDeployFrequency;
-            if (count == 0 && watchEnabled) {
-                watcher.check();
-            }
-        }
-
-    }
-
-    /*--Deployer Operations ------------------------------------*/
-
-    /**
-     * Invoke the check method on the deployer.
-     */
-    protected void check(String name) throws Exception {
-        String[] params = { name };
-        String[] signature = { "java.lang.String" };
-        mBeanServer.invoke(oname, "check", params, signature);
-    }
-
-    /**
-     * Invoke the check method on the deployer.
-     */
-    protected boolean isServiced(String name) throws Exception {
-        String[] params = { name };
-        String[] signature = { "java.lang.String" };
-        Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced",
-                params, signature);
-        return result.booleanValue();
-    }
-
-    /**
-     * Invoke the check method on the deployer.
-     */
-    protected void addServiced(String name) throws Exception {
-        String[] params = { name };
-        String[] signature = { "java.lang.String" };
-        mBeanServer.invoke(oname, "addServiced", params, signature);
-    }
-
-    /**
-     * Invoke the check method on the deployer.
-     */
-    protected void removeServiced(String name) throws Exception {
-        String[] params = { name };
-        String[] signature = { "java.lang.String" };
-        mBeanServer.invoke(oname, "removeServiced", params, signature);
-    }
-
-    /*--Instance Getters/Setters--------------------------------*/
-    public CatalinaCluster getCluster() {
-        return cluster;
-    }
-
-    public void setCluster(CatalinaCluster cluster) {
-        this.cluster = cluster;
-    }
-
-    public boolean equals(Object listener) {
-        return super.equals(listener);
-    }
-
-    public int hashCode() {
-        return super.hashCode();
-    }
-
-    public String getDeployDir() {
-        return deployDir;
-    }
-
-    public void setDeployDir(String deployDir) {
-        this.deployDir = deployDir;
-    }
-
-    public String getTempDir() {
-        return tempDir;
-    }
-
-    public void setTempDir(String tempDir) {
-        this.tempDir = tempDir;
-    }
-
-    public String getWatchDir() {
-        return watchDir;
-    }
-
-    public void setWatchDir(String watchDir) {
-        this.watchDir = watchDir;
-    }
-
-    public boolean isWatchEnabled() {
-        return watchEnabled;
-    }
-
-    public boolean getWatchEnabled() {
-        return watchEnabled;
-    }
-
-    public void setWatchEnabled(boolean watchEnabled) {
-        this.watchEnabled = watchEnabled;
-    }
-
-    /**
-     * Return the frequency of watcher checks.
-     */
-    public int getProcessDeployFrequency() {
-
-        return (this.processDeployFrequency);
-
-    }
-
-    /**
-     * Set the watcher checks frequency.
-     * 
-     * @param processExpiresFrequency
-     *            the new manager checks frequency
-     */
-    public void setProcessDeployFrequency(int processExpiresFrequency) {
-
-        if (processExpiresFrequency <= 0) {
-            return;
-        }
-        this.processDeployFrequency = processExpiresFrequency;
-    }
-
-    /**
-     * Copy a file to the specified temp directory.
-     * @param from copy from temp
-     * @param to   to host appBase directory
-     * @return true, copy successful
-     */
-    protected boolean copy(File from, File to) {
-        try {
-            if (!to.exists())
-                to.createNewFile();
-            java.io.FileInputStream is = new java.io.FileInputStream(from);
-            java.io.FileOutputStream os = new java.io.FileOutputStream(to,
-                    false);
-            byte[] buf = new byte[4096];
-            while (true) {
-                int len = is.read(buf);
-                if (len < 0)
-                    break;
-                os.write(buf, 0, len);
-            }
-            is.close();
-            os.close();
-        } catch (IOException e) {
-            log.error("Unable to copy file from:" + from + " to:" + to, e);
-            return false;
-        }
-        return true;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterDeployer;
+import org.apache.catalina.ha.ClusterListener;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.tomcat.util.modeler.Registry;
+
+
+/**
+ * <p>
+ * A farm war deployer is a class that is able to deploy/undeploy web
+ * applications in WAR form within the cluster.
+ * </p>
+ * Any host can act as the admin, and will have three directories
+ * <ul>
+ * <li>deployDir - the directory where we watch for changes</li>
+ * <li>applicationDir - the directory where we install applications</li>
+ * <li>tempDir - a temporaryDirectory to store binary data when downloading a
+ * war from the cluster</li>
+ * </ul>
+ * Currently we only support deployment of WAR files since they are easier to
+ * send across the wire.
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision$
+ */
+public class FarmWarDeployer extends ClusterListener implements ClusterDeployer, FileChangeListener {
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
+            .getLog(FarmWarDeployer.class);
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "FarmWarDeployer/1.2";
+
+    /*--Instance Variables--------------------------------------*/
+    protected CatalinaCluster cluster = null;
+
+    protected boolean started = false; //default 5 seconds
+
+    protected HashMap fileFactories = new HashMap();
+
+    protected String deployDir;
+
+    protected String tempDir;
+
+    protected String watchDir;
+
+    protected boolean watchEnabled = false;
+
+    protected WarWatcher watcher = null;
+
+    /**
+     * Iteration count for background processing.
+     */
+    private int count = 0;
+
+    /**
+     * Frequency of the Farm watchDir check. Cluster wide deployment will be
+     * done once for the specified amount of backgrondProcess calls (ie, the
+     * lower the amount, the most often the checks will occur).
+     */
+    protected int processDeployFrequency = 2;
+
+    /**
+     * Path where context descriptors should be deployed.
+     */
+    protected File configBase = null;
+
+    /**
+     * The associated host.
+     */
+    protected Host host = null;
+
+    /**
+     * The host appBase.
+     */
+    protected File appBase = null;
+
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+    /**
+     * The associated deployer ObjectName.
+     */
+    protected ObjectName oname = null;
+
+    /*--Constructor---------------------------------------------*/
+    public FarmWarDeployer() {
+    }
+
+    /**
+     * Return descriptive information about this deployer implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /*--Logic---------------------------------------------------*/
+    public void start() throws Exception {
+        if (started)
+            return;
+        getCluster().addClusterListener(this);
+        if (watchEnabled) {
+            watcher = new WarWatcher(this, new File(getWatchDir()));
+            if (log.isInfoEnabled())
+                log.info("Cluster deployment is watching " + getWatchDir()
+                         + " for changes.");
+        }
+    
+        // Check to correct engine and host setup
+        Object parent = getCluster().getContainer();
+        Engine engine = null;
+        if ( parent instanceof Host ) {
+            host = (Host) parent;
+            engine = (Engine) host.getParent();
+        }else {
+            engine = (Engine)parent;
+        }
+        try {
+            oname = new ObjectName(engine.getName() + ":type=Deployer,host="
+                    + host.getName());
+        } catch (Exception e) {
+            log.error("Can't construct MBean object name" + e);
+        }
+        configBase = new File(System.getProperty("catalina.base"), "conf");
+        if (engine != null) {
+            configBase = new File(configBase, engine.getName());
+        } else if (host != null) {
+            configBase = new File(configBase, host.getName());
+        }
+
+        // Retrieve the MBean server
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+
+        started = true;
+        count = 0;
+        if (log.isInfoEnabled())
+            log.info("Cluster FarmWarDeployer started.");
+    }
+
+    /*
+     * stop cluster wide deployments
+     * 
+     * @see org.apache.catalina.ha.ClusterDeployer#stop()
+     */
+    public void stop() throws LifecycleException {
+        started = false;
+        getCluster().removeClusterListener(this);
+        count = 0;
+        if (watcher != null) {
+            watcher.clear();
+            watcher = null;
+
+        }
+        if (log.isInfoEnabled())
+            log.info("Cluster FarmWarDeployer stopped.");
+    }
+
+    public void cleanDeployDir() {
+        throw new java.lang.UnsupportedOperationException(
+                "Method cleanDeployDir() not yet implemented.");
+    }
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param msg
+     *            ClusterMessage - the message received from the cluster
+     */
+    public void messageReceived(ClusterMessage msg) {
+        try {
+            if (msg instanceof FileMessage && msg != null) {
+                FileMessage fmsg = (FileMessage) msg;
+                if (log.isDebugEnabled())
+                    log.debug("receive cluster deployment [ path: "
+                            + fmsg.getContextPath() + " war:  "
+                            + fmsg.getFileName() + " ]");
+                FileMessageFactory factory = getFactory(fmsg);
+                // TODO correct second try after app is in service!
+                if (factory.writeMessage(fmsg)) {
+                    //last message received war file is completed
+                    String name = factory.getFile().getName();
+                    if (!name.endsWith(".war"))
+                        name = name + ".war";
+                    File deployable = new File(getDeployDir(), name);
+                    try {
+                        String path = fmsg.getContextPath();
+                        if (!isServiced(path)) {
+                            addServiced(path);
+                            try {
+                                remove(path);
+                                factory.getFile().renameTo(deployable);
+                                check(path);
+                            } finally {
+                                removeServiced(path);
+                            }
+                            if (log.isDebugEnabled())
+                                log.debug("deployment from " + path
+                                        + " finished.");
+                        } else
+                            log.error("Application " + path
+                                    + " in used. touch war file " + name
+                                    + " again!");
+                    } catch (Exception ex) {
+                        log.error(ex);
+                    } finally {
+                        removeFactory(fmsg);
+                    }
+                }
+            } else if (msg instanceof UndeployMessage && msg != null) {
+                try {
+                    UndeployMessage umsg = (UndeployMessage) msg;
+                    String path = umsg.getContextPath();
+                    if (log.isDebugEnabled())
+                        log.debug("receive cluster undeployment from " + path);
+                    if (!isServiced(path)) {
+                        addServiced(path);
+                        try {
+                            remove(path);
+                        } finally {
+                            removeServiced(path);
+                        }
+                        if (log.isDebugEnabled())
+                            log.debug("undeployment from " + path
+                                    + " finished.");
+                    } else
+                        log.error("Application "
+                            + path
+                            + " in used. Sorry not remove from backup cluster nodes!");
+                } catch (Exception ex) {
+                    log.error(ex);
+                }
+            }
+        } catch (java.io.IOException x) {
+            log.error("Unable to read farm deploy file message.", x);
+        }
+    }
+
+    /**
+     * create factory for all transported war files
+     * 
+     * @param msg
+     * @return Factory for all app message (war files)
+     * @throws java.io.FileNotFoundException
+     * @throws java.io.IOException
+     */
+    public synchronized FileMessageFactory getFactory(FileMessage msg)
+            throws java.io.FileNotFoundException, java.io.IOException {
+        File tmpFile = new File(msg.getFileName());
+        File writeToFile = new File(getTempDir(), tmpFile.getName());
+        FileMessageFactory factory = (FileMessageFactory) fileFactories.get(msg
+                .getFileName());
+        if (factory == null) {
+            factory = FileMessageFactory.getInstance(writeToFile, true);
+            fileFactories.put(msg.getFileName(), factory);
+        }
+        return factory;
+    }
+
+    /**
+     * Remove file (war) from messages)
+     * 
+     * @param msg
+     */
+    public void removeFactory(FileMessage msg) {
+        fileFactories.remove(msg.getFileName());
+    }
+
+    /**
+     * Before the cluster invokes messageReceived the cluster will ask the
+     * receiver to accept or decline the message, In the future, when messages
+     * get big, the accept method will only take a message header
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public boolean accept(ClusterMessage msg) {
+        return (msg instanceof FileMessage) || (msg instanceof UndeployMessage);
+    }
+
+    /**
+     * Install a new web application, whose web application archive is at the
+     * specified URL, into this container and all the other members of the
+     * cluster with the specified context path. A context path of "" (the empty
+     * string) should be used for the root application for this container.
+     * Otherwise, the context path must start with a slash.
+     * <p>
+     * If this application is successfully installed locally, a ContainerEvent
+     * of type <code>INSTALL_EVENT</code> will be sent to all registered
+     * listeners, with the newly created <code>Context</code> as an argument.
+     * 
+     * @param contextPath
+     *            The context path to which this application should be installed
+     *            (must be unique)
+     * @param war
+     *            A URL of type "jar:" that points to a WAR file, or type
+     *            "file:" that points to an unpacked directory structure
+     *            containing the web application to be installed
+     * 
+     * @exception IllegalArgumentException
+     *                if the specified context path is malformed (it must be ""
+     *                or start with a slash)
+     * @exception IllegalStateException
+     *                if the specified context path is already attached to an
+     *                existing web application
+     * @exception IOException
+     *                if an input/output error was encountered during
+     *                installation
+     */
+    public void install(String contextPath, URL war) throws IOException {
+        Member[] members = getCluster().getMembers();
+        Member localMember = getCluster().getLocalMember();
+        FileMessageFactory factory = FileMessageFactory.getInstance(new File(
+                war.getFile()), false);
+        FileMessage msg = new FileMessage(localMember, war.getFile(),
+                contextPath);
+        if(log.isDebugEnabled())
+            log.debug("Send cluster war deployment [ path:"
+                    + contextPath + " war: " + war + " ] started.");
+        msg = factory.readMessage(msg);
+        while (msg != null) {
+            for (int i = 0; i < members.length; i++) {
+                if (log.isDebugEnabled())
+                    log.debug("Send cluster war fragment [ path: "
+                            + contextPath + " war: " + war + " to: " +  members[i] + " ]");
+                getCluster().send(msg, members[i]);
+            }
+            msg = factory.readMessage(msg);
+        }
+        if(log.isDebugEnabled())
+            log.debug("Send cluster war deployment [ path: "
+                    + contextPath + " war: " + war + " ] finished.");
+    }
+
+    /**
+     * Remove an existing web application, attached to the specified context
+     * path. If this application is successfully removed, a ContainerEvent of
+     * type <code>REMOVE_EVENT</code> will be sent to all registered
+     * listeners, with the removed <code>Context</code> as an argument.
+     * Deletes the web application war file and/or directory if they exist in
+     * the Host's appBase.
+     * 
+     * @param contextPath
+     *            The context path of the application to be removed
+     * @param undeploy
+     *            boolean flag to remove web application from server
+     * 
+     * @exception IllegalArgumentException
+     *                if the specified context path is malformed (it must be ""
+     *                or start with a slash)
+     * @exception IllegalArgumentException
+     *                if the specified context path does not identify a
+     *                currently installed web application
+     * @exception IOException
+     *                if an input/output error occurs during removal
+     */
+    public void remove(String contextPath, boolean undeploy) throws IOException {
+        if (log.isInfoEnabled())
+            log.info("Cluster wide remove of web app " + contextPath);
+        Member localMember = getCluster().getLocalMember();
+        UndeployMessage msg = new UndeployMessage(localMember, System
+                .currentTimeMillis(), "Undeploy:" + contextPath + ":"
+                + System.currentTimeMillis(), contextPath, undeploy);
+        if (log.isDebugEnabled())
+            log.debug("Send cluster wide undeployment from "
+                    + contextPath );
+        cluster.send(msg);
+        // remove locally
+        if (undeploy) {
+            try {
+                if (!isServiced(contextPath)) {
+                    addServiced(contextPath);
+                    try {
+                        remove(contextPath);
+                    } finally {
+                        removeServiced(contextPath);
+                    }
+                } else
+                    log.error("Local remove from " + contextPath
+                            + "failed, other manager has app in service!");
+
+            } catch (Exception ex) {
+                log.error("local remove from " + contextPath + " failed", ex);
+            }
+        }
+
+    }
+
+    /*
+     * Modifcation from watchDir war detected!
+     * 
+     * @see org.apache.catalina.ha.deploy.FileChangeListener#fileModified(java.io.File)
+     */
+    public void fileModified(File newWar) {
+        try {
+            File deployWar = new File(getDeployDir(), newWar.getName());
+            copy(newWar, deployWar);
+            String contextName = getContextName(deployWar);
+            if (log.isInfoEnabled())
+                log.info("Installing webapp[" + contextName + "] from "
+                        + deployWar.getAbsolutePath());
+            try {
+                remove(contextName, false);
+            } catch (Exception x) {
+                log.error("No removal", x);
+            }
+            install(contextName, deployWar.toURL());
+        } catch (Exception x) {
+            log.error("Unable to install WAR file", x);
+        }
+    }
+
+    /*
+     * War remvoe from watchDir
+     * 
+     * @see org.apache.catalina.ha.deploy.FileChangeListener#fileRemoved(java.io.File)
+     */
+    public void fileRemoved(File removeWar) {
+        try {
+            String contextName = getContextName(removeWar);
+            if (log.isInfoEnabled())
+                log.info("Removing webapp[" + contextName + "]");
+            remove(contextName, true);
+        } catch (Exception x) {
+            log.error("Unable to remove WAR file", x);
+        }
+    }
+
+    /**
+     * Create a context path from war
+     * @param war War filename
+     * @return '/filename' or if war name is ROOT.war context name is empty string '' 
+     */
+    protected String getContextName(File war) {
+        String contextName = "/"
+        + war.getName().substring(0,
+                war.getName().lastIndexOf(".war"));
+        if("/ROOT".equals(contextName))
+            contextName= "" ;
+        return contextName ;
+    }
+    
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getConfigFile(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename);
+    }
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getDocBase(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1);
+        }
+        return (basename);
+    }
+
+    /**
+     * Return a File object representing the "application root" directory for
+     * our associated Host.
+     */
+    protected File getAppBase() {
+
+        if (appBase != null) {
+            return appBase;
+        }
+
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), host
+                    .getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+    /**
+     * Invoke the remove method on the deployer.
+     */
+    protected void remove(String path) throws Exception {
+        // TODO Handle remove also work dir content !
+        // Stop the context first to be nicer
+        Context context = (Context) host.findChild(path);
+        if (context != null) {
+            if(log.isDebugEnabled())
+                log.debug("Undeploy local context " +path );
+            ((Lifecycle) context).stop();
+            File war = new File(getAppBase(), getDocBase(path) + ".war");
+            File dir = new File(getAppBase(), getDocBase(path));
+            File xml = new File(configBase, getConfigFile(path) + ".xml");
+            if (war.exists()) {
+                war.delete();
+            } else if (dir.exists()) {
+                undeployDir(dir);
+            } else {
+                xml.delete();
+            }
+            // Perform new deployment and remove internal HostConfig state
+            check(path);
+        }
+
+    }
+
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     * 
+     * @param dir
+     *            File object representing the directory to be deleted
+     */
+    protected void undeployDir(File dir) {
+
+        String files[] = dir.list();
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            if (file.isDirectory()) {
+                undeployDir(file);
+            } else {
+                file.delete();
+            }
+        }
+        dir.delete();
+
+    }
+
+    /*
+     * Call watcher to check for deploy changes
+     * 
+     * @see org.apache.catalina.ha.ClusterDeployer#backgroundProcess()
+     */
+    public void backgroundProcess() {
+        if (started) {
+            count = (count + 1) % processDeployFrequency;
+            if (count == 0 && watchEnabled) {
+                watcher.check();
+            }
+        }
+
+    }
+
+    /*--Deployer Operations ------------------------------------*/
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void check(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "check", params, signature);
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected boolean isServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced",
+                params, signature);
+        return result.booleanValue();
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void addServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "addServiced", params, signature);
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void removeServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "removeServiced", params, signature);
+    }
+
+    /*--Instance Getters/Setters--------------------------------*/
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    public boolean equals(Object listener) {
+        return super.equals(listener);
+    }
+
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    public String getDeployDir() {
+        return deployDir;
+    }
+
+    public void setDeployDir(String deployDir) {
+        this.deployDir = deployDir;
+    }
+
+    public String getTempDir() {
+        return tempDir;
+    }
+
+    public void setTempDir(String tempDir) {
+        this.tempDir = tempDir;
+    }
+
+    public String getWatchDir() {
+        return watchDir;
+    }
+
+    public void setWatchDir(String watchDir) {
+        this.watchDir = watchDir;
+    }
+
+    public boolean isWatchEnabled() {
+        return watchEnabled;
+    }
+
+    public boolean getWatchEnabled() {
+        return watchEnabled;
+    }
+
+    public void setWatchEnabled(boolean watchEnabled) {
+        this.watchEnabled = watchEnabled;
+    }
+
+    /**
+     * Return the frequency of watcher checks.
+     */
+    public int getProcessDeployFrequency() {
+
+        return (this.processDeployFrequency);
+
+    }
+
+    /**
+     * Set the watcher checks frequency.
+     * 
+     * @param processExpiresFrequency
+     *            the new manager checks frequency
+     */
+    public void setProcessDeployFrequency(int processExpiresFrequency) {
+
+        if (processExpiresFrequency <= 0) {
+            return;
+        }
+        this.processDeployFrequency = processExpiresFrequency;
+    }
+
+    /**
+     * Copy a file to the specified temp directory.
+     * @param from copy from temp
+     * @param to   to host appBase directory
+     * @return true, copy successful
+     */
+    protected boolean copy(File from, File to) {
+        try {
+            if (!to.exists())
+                to.createNewFile();
+            java.io.FileInputStream is = new java.io.FileInputStream(from);
+            java.io.FileOutputStream os = new java.io.FileOutputStream(to,
+                    false);
+            byte[] buf = new byte[4096];
+            while (true) {
+                int len = is.read(buf);
+                if (len < 0)
+                    break;
+                os.write(buf, 0, len);
+            }
+            is.close();
+            os.close();
+        } catch (IOException e) {
+            log.error("Unable to copy file from:" + from + " to:" + to, e);
+            return false;
+        }
+        return true;
+    }
+
+}

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileChangeListener.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileChangeListener.java?view=diff&rev=467222&r1=467221&r2=467222
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileChangeListener.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileChangeListener.java Mon Oct 23 20:17:11 2006
@@ -1,24 +1,24 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
-import java.io.File;
-
-public interface FileChangeListener {
-    public void fileModified(File f);
-    public void fileRemoved(File f);
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
+import java.io.File;
+
+public interface FileChangeListener {
+    public void fileModified(File f);
+    public void fileRemoved(File f);
+}

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileChangeListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileChangeListener.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessage.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessage.java?view=diff&rev=467222&r1=467221&r2=467222
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessage.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessage.java Mon Oct 23 20:17:11 2006
@@ -1,113 +1,113 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
-
-import java.io.Serializable;
-
-import org.apache.catalina.ha.ClusterMessage;
-import org.apache.catalina.tribes.Member;
-import org.apache.catalina.ha.ClusterMessageBase;
-
-/**
- * Contains the data for a file being transferred over TCP, this is 
- * essentially a fragment of a file, read and written by the FileMessageFactory
- * @author Filip Hanik
- * @version 1.0
- */
-
-public class FileMessage extends ClusterMessageBase implements ClusterMessage, Serializable {
-    private int messageNumber;
-    private byte[] data;
-    private int dataLength;
-    
-    private long totalLength;
-    private long totalNrOfMsgs;
-    private String fileName;
-    private String contextPath;
-    
-    public FileMessage(Member source,
-                       String fileName,
-                       String contextPath) {
-        this.address=source;
-        this.fileName=fileName;
-        this.contextPath=contextPath;
-    }
-    
-    /*
-    public void writeExternal(ObjectOutput out) throws IOException {
-                   
-    }
-    
-    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-                  
-    }
-    */
-   
-    public int getMessageNumber() {
-        return messageNumber;
-    }
-    public void setMessageNumber(int messageNumber) {
-        this.messageNumber = messageNumber;
-    }
-    public long getTotalNrOfMsgs() {
-        return totalNrOfMsgs;
-    }
-    public void setTotalNrOfMsgs(long totalNrOfMsgs) {
-        this.totalNrOfMsgs = totalNrOfMsgs;
-    }
-    public byte[] getData() {
-        return data;
-    }
-    public void setData(byte[] data, int length) {
-        this.data = data;
-        this.dataLength = length;
-    }
-    public int getDataLength() {
-        return dataLength;
-    }
-    public void setDataLength(int dataLength) {
-        this.dataLength = dataLength;
-    }
-    public long getTotalLength() {
-        return totalLength;
-    }
-    public void setTotalLength(long totalLength) {
-        this.totalLength = totalLength;
-    }
-
-    public String getUniqueId() {
-        StringBuffer result = new StringBuffer(getFileName());
-        result.append("#-#");
-        result.append(getMessageNumber());
-        result.append("#-#");
-        result.append(System.currentTimeMillis());
-        return result.toString();
-    }
-
-    
-    public String getFileName() {
-        return fileName;
-    }
-    public void setFileName(String fileName) {
-        this.fileName = fileName;
-    }
-    public String getContextPath() {
-        return contextPath;
-    }
-    
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
+
+import java.io.Serializable;
+
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.ha.ClusterMessageBase;
+
+/**
+ * Contains the data for a file being transferred over TCP, this is 
+ * essentially a fragment of a file, read and written by the FileMessageFactory
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public class FileMessage extends ClusterMessageBase implements ClusterMessage, Serializable {
+    private int messageNumber;
+    private byte[] data;
+    private int dataLength;
+    
+    private long totalLength;
+    private long totalNrOfMsgs;
+    private String fileName;
+    private String contextPath;
+    
+    public FileMessage(Member source,
+                       String fileName,
+                       String contextPath) {
+        this.address=source;
+        this.fileName=fileName;
+        this.contextPath=contextPath;
+    }
+    
+    /*
+    public void writeExternal(ObjectOutput out) throws IOException {
+                   
+    }
+    
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+                  
+    }
+    */
+   
+    public int getMessageNumber() {
+        return messageNumber;
+    }
+    public void setMessageNumber(int messageNumber) {
+        this.messageNumber = messageNumber;
+    }
+    public long getTotalNrOfMsgs() {
+        return totalNrOfMsgs;
+    }
+    public void setTotalNrOfMsgs(long totalNrOfMsgs) {
+        this.totalNrOfMsgs = totalNrOfMsgs;
+    }
+    public byte[] getData() {
+        return data;
+    }
+    public void setData(byte[] data, int length) {
+        this.data = data;
+        this.dataLength = length;
+    }
+    public int getDataLength() {
+        return dataLength;
+    }
+    public void setDataLength(int dataLength) {
+        this.dataLength = dataLength;
+    }
+    public long getTotalLength() {
+        return totalLength;
+    }
+    public void setTotalLength(long totalLength) {
+        this.totalLength = totalLength;
+    }
+
+    public String getUniqueId() {
+        StringBuffer result = new StringBuffer(getFileName());
+        result.append("#-#");
+        result.append(getMessageNumber());
+        result.append("#-#");
+        result.append(System.currentTimeMillis());
+        return result.toString();
+    }
+
+    
+    public String getFileName() {
+        return fileName;
+    }
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+    public String getContextPath() {
+        return contextPath;
+    }
+    
+}

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessage.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessageFactory.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessageFactory.java?view=diff&rev=467222&r1=467221&r2=467222
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessageFactory.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessageFactory.java Mon Oct 23 20:17:11 2006
@@ -1,312 +1,312 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileNotFoundException;
-
-/**
- * This factory is used to read files and write files by splitting them up into
- * smaller messages. So that entire files don't have to be read into memory.
- * <BR>
- * The factory can be used as a reader or writer but not both at the same time.
- * When done reading or writing the factory will close the input or output
- * streams and mark the factory as closed. It is not possible to use it after
- * that. <BR>
- * To force a cleanup, call cleanup() from the calling object. <BR>
- * This class is not thread safe.
- * 
- * @author Filip Hanik
- * @version 1.0
- */
-public class FileMessageFactory {
-    /*--Static Variables----------------------------------------*/
-    public static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
-            .getLog(FileMessageFactory.class);
-
-    /**
-     * The number of bytes that we read from file
-     */
-    public static final int READ_SIZE = 1024 * 10; //10kb
-
-    /**
-     * The file that we are reading/writing
-     */
-    protected File file = null;
-
-    /**
-     * True means that we are writing with this factory. False means that we are
-     * reading with this factory
-     */
-    protected boolean openForWrite;
-
-    /**
-     * Once the factory is used, it can not be reused.
-     */
-    protected boolean closed = false;
-
-    /**
-     * When openForWrite=false, the input stream is held by this variable
-     */
-    protected FileInputStream in;
-
-    /**
-     * When openForWrite=true, the output stream is held by this variable
-     */
-    protected FileOutputStream out;
-
-    /**
-     * The number of messages we have read or written
-     */
-    protected int nrOfMessagesProcessed = 0;
-
-    /**
-     * The total size of the file
-     */
-    protected long size = 0;
-
-    /**
-     * The total number of packets that we split this file into
-     */
-    protected long totalNrOfMessages = 0;
-
-    /**
-     * The bytes that we hold the data in, not thread safe.
-     */
-    protected byte[] data = new byte[READ_SIZE];
-
-    /**
-     * Private constructor, either instantiates a factory to read or write. <BR>
-     * When openForWrite==true, then a the file, f, will be created and an
-     * output stream is opened to write to it. <BR>
-     * When openForWrite==false, an input stream is opened, the file has to
-     * exist.
-     * 
-     * @param f
-     *            File - the file to be read/written
-     * @param openForWrite
-     *            boolean - true means we are writing to the file, false means
-     *            we are reading from the file
-     * @throws FileNotFoundException -
-     *             if the file to be read doesn't exist
-     * @throws IOException -
-     *             if the system fails to open input/output streams to the file
-     *             or if it fails to create the file to be written to.
-     */
-    private FileMessageFactory(File f, boolean openForWrite)
-            throws FileNotFoundException, IOException {
-        this.file = f;
-        this.openForWrite = openForWrite;
-        if (log.isDebugEnabled())
-            log.debug("open file " + f + " write " + openForWrite);
-        if (openForWrite) {
-            if (!file.exists())
-                file.createNewFile();
-            out = new FileOutputStream(f);
-        } else {
-            size = file.length();
-            totalNrOfMessages = (size / READ_SIZE) + 1;
-            in = new FileInputStream(f);
-        }//end if
-
-    }
-
-    /**
-     * Creates a factory to read or write from a file. When opening for read,
-     * the readMessage can be invoked, and when opening for write the
-     * writeMessage can be invoked.
-     * 
-     * @param f
-     *            File - the file to be read or written
-     * @param openForWrite
-     *            boolean - true, means we are writing to the file, false means
-     *            we are reading from it
-     * @throws FileNotFoundException -
-     *             if the file to be read doesn't exist
-     * @throws IOException -
-     *             if it fails to create the file that is to be written
-     * @return FileMessageFactory
-     */
-    public static FileMessageFactory getInstance(File f, boolean openForWrite)
-            throws FileNotFoundException, IOException {
-        return new FileMessageFactory(f, openForWrite);
-    }
-
-    /**
-     * Reads file data into the file message and sets the size, totalLength,
-     * totalNrOfMsgs and the message number <BR>
-     * If EOF is reached, the factory returns null, and closes itself, otherwise
-     * the same message is returned as was passed in. This makes sure that not
-     * more memory is ever used. To remember, neither the file message or the
-     * factory are thread safe. dont hand off the message to one thread and read
-     * the same with another.
-     * 
-     * @param f
-     *            FileMessage - the message to be populated with file data
-     * @throws IllegalArgumentException -
-     *             if the factory is for writing or is closed
-     * @throws IOException -
-     *             if a file read exception occurs
-     * @return FileMessage - returns the same message passed in as a parameter,
-     *         or null if EOF
-     */
-    public FileMessage readMessage(FileMessage f)
-            throws IllegalArgumentException, IOException {
-        checkState(false);
-        int length = in.read(data);
-        if (length == -1) {
-            cleanup();
-            return null;
-        } else {
-            f.setData(data, length);
-            f.setTotalLength(size);
-            f.setTotalNrOfMsgs(totalNrOfMessages);
-            f.setMessageNumber(++nrOfMessagesProcessed);
-            return f;
-        }//end if
-    }
-
-    /**
-     * Writes a message to file. If (msg.getMessageNumber() ==
-     * msg.getTotalNrOfMsgs()) the output stream will be closed after writing.
-     * 
-     * @param msg
-     *            FileMessage - message containing data to be written
-     * @throws IllegalArgumentException -
-     *             if the factory is opened for read or closed
-     * @throws IOException -
-     *             if a file write error occurs
-     * @return returns true if the file is complete and outputstream is closed,
-     *         false otherwise.
-     */
-    public boolean writeMessage(FileMessage msg)
-            throws IllegalArgumentException, IOException {
-        if (!openForWrite)
-            throw new IllegalArgumentException(
-                    "Can't write message, this factory is reading.");
-        if (log.isDebugEnabled())
-            log.debug("Message " + msg + " data " + msg.getData()
-                    + " data length " + msg.getDataLength() + " out " + out);
-        if (out != null) {
-            out.write(msg.getData(), 0, msg.getDataLength());
-            nrOfMessagesProcessed++;
-            out.flush();
-            if (msg.getMessageNumber() == msg.getTotalNrOfMsgs()) {
-                out.close();
-                cleanup();
-                return true;
-            }//end if
-        } else {
-            if (log.isWarnEnabled())
-                log.warn("Receive Message again -- Sender ActTimeout to short [ path: "
-                                + msg.getContextPath()
-                                + " war: "
-                                + msg.getFileName()
-                                + " data: "
-                                + msg.getData()
-                                + " data length: " + msg.getDataLength() + " ]");
-        }
-        return false;
-    }//writeMessage
-
-    /**
-     * Closes the factory, its streams and sets all its references to null
-     */
-    public void cleanup() {
-        if (in != null)
-            try {
-                in.close();
-            } catch (Exception ignore) {
-            }
-        if (out != null)
-            try {
-                out.close();
-            } catch (Exception ignore) {
-            }
-        in = null;
-        out = null;
-        size = 0;
-        closed = true;
-        data = null;
-        nrOfMessagesProcessed = 0;
-        totalNrOfMessages = 0;
-    }
-
-    /**
-     * Check to make sure the factory is able to perform the function it is
-     * asked to do. Invoked by readMessage/writeMessage before those methods
-     * proceed.
-     * 
-     * @param openForWrite
-     *            boolean
-     * @throws IllegalArgumentException
-     */
-    protected void checkState(boolean openForWrite)
-            throws IllegalArgumentException {
-        if (this.openForWrite != openForWrite) {
-            cleanup();
-            if (openForWrite)
-                throw new IllegalArgumentException(
-                        "Can't write message, this factory is reading.");
-            else
-                throw new IllegalArgumentException(
-                        "Can't read message, this factory is writing.");
-        }
-        if (this.closed) {
-            cleanup();
-            throw new IllegalArgumentException("Factory has been closed.");
-        }
-    }
-
-    /**
-     * Example usage.
-     * 
-     * @param args
-     *            String[], args[0] - read from filename, args[1] write to
-     *            filename
-     * @throws Exception
-     */
-    public static void main(String[] args) throws Exception {
-
-        System.out
-                .println("Usage: FileMessageFactory fileToBeRead fileToBeWritten");
-        System.out
-                .println("Usage: This will make a copy of the file on the local file system");
-        FileMessageFactory read = getInstance(new File(args[0]), false);
-        FileMessageFactory write = getInstance(new File(args[1]), true);
-        FileMessage msg = new FileMessage(null, args[0], args[0]);
-        msg = read.readMessage(msg);
-        System.out.println("Expecting to write " + msg.getTotalNrOfMsgs()
-                + " messages.");
-        int cnt = 0;
-        while (msg != null) {
-            write.writeMessage(msg);
-            cnt++;
-            msg = read.readMessage(msg);
-        }//while
-        System.out.println("Actually wrote " + cnt + " messages.");
-    }///main
-
-    public File getFile() {
-        return file;
-    }
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+
+/**
+ * This factory is used to read files and write files by splitting them up into
+ * smaller messages. So that entire files don't have to be read into memory.
+ * <BR>
+ * The factory can be used as a reader or writer but not both at the same time.
+ * When done reading or writing the factory will close the input or output
+ * streams and mark the factory as closed. It is not possible to use it after
+ * that. <BR>
+ * To force a cleanup, call cleanup() from the calling object. <BR>
+ * This class is not thread safe.
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class FileMessageFactory {
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
+            .getLog(FileMessageFactory.class);
+
+    /**
+     * The number of bytes that we read from file
+     */
+    public static final int READ_SIZE = 1024 * 10; //10kb
+
+    /**
+     * The file that we are reading/writing
+     */
+    protected File file = null;
+
+    /**
+     * True means that we are writing with this factory. False means that we are
+     * reading with this factory
+     */
+    protected boolean openForWrite;
+
+    /**
+     * Once the factory is used, it can not be reused.
+     */
+    protected boolean closed = false;
+
+    /**
+     * When openForWrite=false, the input stream is held by this variable
+     */
+    protected FileInputStream in;
+
+    /**
+     * When openForWrite=true, the output stream is held by this variable
+     */
+    protected FileOutputStream out;
+
+    /**
+     * The number of messages we have read or written
+     */
+    protected int nrOfMessagesProcessed = 0;
+
+    /**
+     * The total size of the file
+     */
+    protected long size = 0;
+
+    /**
+     * The total number of packets that we split this file into
+     */
+    protected long totalNrOfMessages = 0;
+
+    /**
+     * The bytes that we hold the data in, not thread safe.
+     */
+    protected byte[] data = new byte[READ_SIZE];
+
+    /**
+     * Private constructor, either instantiates a factory to read or write. <BR>
+     * When openForWrite==true, then a the file, f, will be created and an
+     * output stream is opened to write to it. <BR>
+     * When openForWrite==false, an input stream is opened, the file has to
+     * exist.
+     * 
+     * @param f
+     *            File - the file to be read/written
+     * @param openForWrite
+     *            boolean - true means we are writing to the file, false means
+     *            we are reading from the file
+     * @throws FileNotFoundException -
+     *             if the file to be read doesn't exist
+     * @throws IOException -
+     *             if the system fails to open input/output streams to the file
+     *             or if it fails to create the file to be written to.
+     */
+    private FileMessageFactory(File f, boolean openForWrite)
+            throws FileNotFoundException, IOException {
+        this.file = f;
+        this.openForWrite = openForWrite;
+        if (log.isDebugEnabled())
+            log.debug("open file " + f + " write " + openForWrite);
+        if (openForWrite) {
+            if (!file.exists())
+                file.createNewFile();
+            out = new FileOutputStream(f);
+        } else {
+            size = file.length();
+            totalNrOfMessages = (size / READ_SIZE) + 1;
+            in = new FileInputStream(f);
+        }//end if
+
+    }
+
+    /**
+     * Creates a factory to read or write from a file. When opening for read,
+     * the readMessage can be invoked, and when opening for write the
+     * writeMessage can be invoked.
+     * 
+     * @param f
+     *            File - the file to be read or written
+     * @param openForWrite
+     *            boolean - true, means we are writing to the file, false means
+     *            we are reading from it
+     * @throws FileNotFoundException -
+     *             if the file to be read doesn't exist
+     * @throws IOException -
+     *             if it fails to create the file that is to be written
+     * @return FileMessageFactory
+     */
+    public static FileMessageFactory getInstance(File f, boolean openForWrite)
+            throws FileNotFoundException, IOException {
+        return new FileMessageFactory(f, openForWrite);
+    }
+
+    /**
+     * Reads file data into the file message and sets the size, totalLength,
+     * totalNrOfMsgs and the message number <BR>
+     * If EOF is reached, the factory returns null, and closes itself, otherwise
+     * the same message is returned as was passed in. This makes sure that not
+     * more memory is ever used. To remember, neither the file message or the
+     * factory are thread safe. dont hand off the message to one thread and read
+     * the same with another.
+     * 
+     * @param f
+     *            FileMessage - the message to be populated with file data
+     * @throws IllegalArgumentException -
+     *             if the factory is for writing or is closed
+     * @throws IOException -
+     *             if a file read exception occurs
+     * @return FileMessage - returns the same message passed in as a parameter,
+     *         or null if EOF
+     */
+    public FileMessage readMessage(FileMessage f)
+            throws IllegalArgumentException, IOException {
+        checkState(false);
+        int length = in.read(data);
+        if (length == -1) {
+            cleanup();
+            return null;
+        } else {
+            f.setData(data, length);
+            f.setTotalLength(size);
+            f.setTotalNrOfMsgs(totalNrOfMessages);
+            f.setMessageNumber(++nrOfMessagesProcessed);
+            return f;
+        }//end if
+    }
+
+    /**
+     * Writes a message to file. If (msg.getMessageNumber() ==
+     * msg.getTotalNrOfMsgs()) the output stream will be closed after writing.
+     * 
+     * @param msg
+     *            FileMessage - message containing data to be written
+     * @throws IllegalArgumentException -
+     *             if the factory is opened for read or closed
+     * @throws IOException -
+     *             if a file write error occurs
+     * @return returns true if the file is complete and outputstream is closed,
+     *         false otherwise.
+     */
+    public boolean writeMessage(FileMessage msg)
+            throws IllegalArgumentException, IOException {
+        if (!openForWrite)
+            throw new IllegalArgumentException(
+                    "Can't write message, this factory is reading.");
+        if (log.isDebugEnabled())
+            log.debug("Message " + msg + " data " + msg.getData()
+                    + " data length " + msg.getDataLength() + " out " + out);
+        if (out != null) {
+            out.write(msg.getData(), 0, msg.getDataLength());
+            nrOfMessagesProcessed++;
+            out.flush();
+            if (msg.getMessageNumber() == msg.getTotalNrOfMsgs()) {
+                out.close();
+                cleanup();
+                return true;
+            }//end if
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("Receive Message again -- Sender ActTimeout to short [ path: "
+                                + msg.getContextPath()
+                                + " war: "
+                                + msg.getFileName()
+                                + " data: "
+                                + msg.getData()
+                                + " data length: " + msg.getDataLength() + " ]");
+        }
+        return false;
+    }//writeMessage
+
+    /**
+     * Closes the factory, its streams and sets all its references to null
+     */
+    public void cleanup() {
+        if (in != null)
+            try {
+                in.close();
+            } catch (Exception ignore) {
+            }
+        if (out != null)
+            try {
+                out.close();
+            } catch (Exception ignore) {
+            }
+        in = null;
+        out = null;
+        size = 0;
+        closed = true;
+        data = null;
+        nrOfMessagesProcessed = 0;
+        totalNrOfMessages = 0;
+    }
+
+    /**
+     * Check to make sure the factory is able to perform the function it is
+     * asked to do. Invoked by readMessage/writeMessage before those methods
+     * proceed.
+     * 
+     * @param openForWrite
+     *            boolean
+     * @throws IllegalArgumentException
+     */
+    protected void checkState(boolean openForWrite)
+            throws IllegalArgumentException {
+        if (this.openForWrite != openForWrite) {
+            cleanup();
+            if (openForWrite)
+                throw new IllegalArgumentException(
+                        "Can't write message, this factory is reading.");
+            else
+                throw new IllegalArgumentException(
+                        "Can't read message, this factory is writing.");
+        }
+        if (this.closed) {
+            cleanup();
+            throw new IllegalArgumentException("Factory has been closed.");
+        }
+    }
+
+    /**
+     * Example usage.
+     * 
+     * @param args
+     *            String[], args[0] - read from filename, args[1] write to
+     *            filename
+     * @throws Exception
+     */
+    public static void main(String[] args) throws Exception {
+
+        System.out
+                .println("Usage: FileMessageFactory fileToBeRead fileToBeWritten");
+        System.out
+                .println("Usage: This will make a copy of the file on the local file system");
+        FileMessageFactory read = getInstance(new File(args[0]), false);
+        FileMessageFactory write = getInstance(new File(args[1]), true);
+        FileMessage msg = new FileMessage(null, args[0], args[0]);
+        msg = read.readMessage(msg);
+        System.out.println("Expecting to write " + msg.getTotalNrOfMsgs()
+                + " messages.");
+        int cnt = 0;
+        while (msg != null) {
+            write.writeMessage(msg);
+            cnt++;
+            msg = read.readMessage(msg);
+        }//while
+        System.out.println("Actually wrote " + cnt + " messages.");
+    }///main
+
+    public File getFile() {
+        return file;
+    }
+
 }

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessageFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/ha/deploy/FileMessageFactory.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org