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><description>/<version></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><description>/<version></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