init
This commit is contained in:
787
java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
Normal file
787
java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
Normal file
@@ -0,0 +1,787 @@
|
||||
/*
|
||||
* 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.util.HashMap;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Engine;
|
||||
import org.apache.catalina.Host;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
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.catalina.util.ContextName;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.modeler.Registry;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A farm war deployer is a class that is able to deploy/undeploy web
|
||||
* applications in WAR from within the cluster.
|
||||
* </p>
|
||||
* Any host can act as the admin, and will have three directories
|
||||
* <ul>
|
||||
* <li>watchDir - the directory where we watch for changes</li>
|
||||
* <li>deployDir - 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 Peter Rossbach
|
||||
*/
|
||||
public class FarmWarDeployer extends ClusterListener
|
||||
implements ClusterDeployer, FileChangeListener {
|
||||
/*--Static Variables----------------------------------------*/
|
||||
private static final Log log = LogFactory.getLog(FarmWarDeployer.class);
|
||||
private static final StringManager sm = StringManager.getManager(FarmWarDeployer.class);
|
||||
|
||||
/*--Instance Variables--------------------------------------*/
|
||||
protected boolean started = false;
|
||||
|
||||
protected final HashMap<String, FileMessageFactory> fileFactories =
|
||||
new HashMap<>();
|
||||
|
||||
/**
|
||||
* Deployment directory.
|
||||
*/
|
||||
protected String deployDir;
|
||||
private File deployDirFile = null;
|
||||
|
||||
/**
|
||||
* Temporary directory.
|
||||
*/
|
||||
protected String tempDir;
|
||||
private File tempDirFile = null;
|
||||
|
||||
/**
|
||||
* Watch directory.
|
||||
*/
|
||||
protected String watchDir;
|
||||
private File watchDirFile = null;
|
||||
|
||||
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 backgroundProcess 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;
|
||||
|
||||
/**
|
||||
* MBean server.
|
||||
*/
|
||||
protected MBeanServer mBeanServer = null;
|
||||
|
||||
/**
|
||||
* The associated deployer ObjectName.
|
||||
*/
|
||||
protected ObjectName oname = null;
|
||||
|
||||
/**
|
||||
* The maximum valid time(in seconds) for FileMessageFactory.
|
||||
*/
|
||||
protected int maxValidTime = 5 * 60;
|
||||
|
||||
/*--Constructor---------------------------------------------*/
|
||||
public FarmWarDeployer() {
|
||||
}
|
||||
|
||||
/*--Logic---------------------------------------------------*/
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
if (started)
|
||||
return;
|
||||
Container hcontainer = getCluster().getContainer();
|
||||
if(!(hcontainer instanceof Host)) {
|
||||
log.error(sm.getString("farmWarDeployer.hostOnly"));
|
||||
return ;
|
||||
}
|
||||
host = (Host) hcontainer;
|
||||
|
||||
// Check to correct engine and host setup
|
||||
Container econtainer = host.getParent();
|
||||
if(!(econtainer instanceof Engine)) {
|
||||
log.error(sm.getString("farmWarDeployer.hostParentEngine",
|
||||
host.getName()));
|
||||
return ;
|
||||
}
|
||||
Engine engine = (Engine) econtainer;
|
||||
String hostname = null;
|
||||
hostname = host.getName();
|
||||
try {
|
||||
oname = new ObjectName(engine.getName() + ":type=Deployer,host="
|
||||
+ hostname);
|
||||
} catch (Exception e) {
|
||||
log.error(sm.getString("farmWarDeployer.mbeanNameFail",
|
||||
engine.getName(), hostname),e);
|
||||
return;
|
||||
}
|
||||
if (watchEnabled) {
|
||||
watcher = new WarWatcher(this, getWatchDirFile());
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(sm.getString(
|
||||
"farmWarDeployer.watchDir", getWatchDir()));
|
||||
}
|
||||
}
|
||||
|
||||
configBase = host.getConfigBaseFile();
|
||||
|
||||
// Retrieve the MBean server
|
||||
mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
|
||||
|
||||
started = true;
|
||||
count = 0;
|
||||
|
||||
getCluster().addClusterListener(this);
|
||||
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.started"));
|
||||
}
|
||||
|
||||
/*
|
||||
* stop cluster wide deployments
|
||||
*
|
||||
* @see org.apache.catalina.ha.ClusterDeployer#stop()
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws LifecycleException {
|
||||
started = false;
|
||||
getCluster().removeClusterListener(this);
|
||||
count = 0;
|
||||
if (watcher != null) {
|
||||
watcher.clear();
|
||||
watcher = null;
|
||||
|
||||
}
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.stopped"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Override
|
||||
public void messageReceived(ClusterMessage msg) {
|
||||
try {
|
||||
if (msg instanceof FileMessage) {
|
||||
FileMessage fmsg = (FileMessage) msg;
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.msgRxDeploy",
|
||||
fmsg.getContextName(), 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(getDeployDirFile(), name);
|
||||
try {
|
||||
String contextName = fmsg.getContextName();
|
||||
if (!isServiced(contextName)) {
|
||||
addServiced(contextName);
|
||||
try {
|
||||
remove(contextName);
|
||||
if (!factory.getFile().renameTo(deployable)) {
|
||||
log.error(sm.getString(
|
||||
"farmWarDeployer.renameFail",
|
||||
factory.getFile(), deployable));
|
||||
}
|
||||
check(contextName);
|
||||
} finally {
|
||||
removeServiced(contextName);
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString(
|
||||
"farmWarDeployer.deployEnd",
|
||||
contextName));
|
||||
} else
|
||||
log.error(sm.getString(
|
||||
"farmWarDeployer.servicingDeploy",
|
||||
contextName, name));
|
||||
} catch (Exception ex) {
|
||||
log.error(ex);
|
||||
} finally {
|
||||
removeFactory(fmsg);
|
||||
}
|
||||
}
|
||||
} else if (msg instanceof UndeployMessage) {
|
||||
try {
|
||||
UndeployMessage umsg = (UndeployMessage) msg;
|
||||
String contextName = umsg.getContextName();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.msgRxUndeploy",
|
||||
contextName));
|
||||
if (!isServiced(contextName)) {
|
||||
addServiced(contextName);
|
||||
try {
|
||||
remove(contextName);
|
||||
} finally {
|
||||
removeServiced(contextName);
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString(
|
||||
"farmWarDeployer.undeployEnd",
|
||||
contextName));
|
||||
} else
|
||||
log.error(sm.getString(
|
||||
"farmWarDeployer.servicingUndeploy",
|
||||
contextName));
|
||||
} catch (Exception ex) {
|
||||
log.error(ex);
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException x) {
|
||||
log.error(sm.getString("farmWarDeployer.msgIoe"), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create factory for all transported war files
|
||||
*
|
||||
* @param msg The file
|
||||
* @return Factory for all app message (war files)
|
||||
* @throws java.io.FileNotFoundException Missing file error
|
||||
* @throws java.io.IOException Other IO error
|
||||
*/
|
||||
public synchronized FileMessageFactory getFactory(FileMessage msg)
|
||||
throws java.io.FileNotFoundException, java.io.IOException {
|
||||
File writeToFile = new File(getTempDirFile(), msg.getFileName());
|
||||
FileMessageFactory factory = fileFactories.get(msg.getFileName());
|
||||
if (factory == null) {
|
||||
factory = FileMessageFactory.getInstance(writeToFile, true);
|
||||
factory.setMaxValidTime(maxValidTime);
|
||||
fileFactories.put(msg.getFileName(), factory);
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove file (war) from messages
|
||||
*
|
||||
* @param msg The file
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
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 name.
|
||||
* <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 contextName
|
||||
* The context name to which this application should be installed
|
||||
* (must be unique)
|
||||
* @param webapp
|
||||
* A WAR file or unpacked directory structure containing the web
|
||||
* application to be installed
|
||||
*
|
||||
* @exception IllegalArgumentException
|
||||
* if the specified context name is malformed
|
||||
* @exception IllegalStateException
|
||||
* if the specified context name is already deployed
|
||||
* @exception IOException
|
||||
* if an input/output error was encountered during
|
||||
* installation
|
||||
*/
|
||||
@Override
|
||||
public void install(String contextName, File webapp) throws IOException {
|
||||
Member[] members = getCluster().getMembers();
|
||||
if (members.length == 0) return;
|
||||
|
||||
Member localMember = getCluster().getLocalMember();
|
||||
FileMessageFactory factory =
|
||||
FileMessageFactory.getInstance(webapp, false);
|
||||
FileMessage msg = new FileMessage(localMember, webapp.getName(),
|
||||
contextName);
|
||||
if(log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.sendStart", contextName,
|
||||
webapp));
|
||||
msg = factory.readMessage(msg);
|
||||
while (msg != null) {
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.sendFragment",
|
||||
contextName, webapp, members[i]));
|
||||
getCluster().send(msg, members[i]);
|
||||
}
|
||||
msg = factory.readMessage(msg);
|
||||
}
|
||||
if(log.isDebugEnabled())
|
||||
log.debug(sm.getString(
|
||||
"farmWarDeployer.sendEnd", contextName, webapp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an existing web application, attached to the specified context
|
||||
* name. 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 contextName
|
||||
* The context name of the application to be removed
|
||||
* @param undeploy
|
||||
* boolean flag to remove web application from server
|
||||
*
|
||||
* @exception IllegalArgumentException
|
||||
* if the specified context name is malformed
|
||||
* @exception IllegalArgumentException
|
||||
* if the specified context name does not identify a
|
||||
* currently installed web application
|
||||
* @exception IOException
|
||||
* if an input/output error occurs during removal
|
||||
*/
|
||||
@Override
|
||||
public void remove(String contextName, boolean undeploy)
|
||||
throws IOException {
|
||||
if (getCluster().getMembers().length > 0) {
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.removeStart", contextName));
|
||||
Member localMember = getCluster().getLocalMember();
|
||||
UndeployMessage msg = new UndeployMessage(localMember, System
|
||||
.currentTimeMillis(), "Undeploy:" + contextName + ":"
|
||||
+ System.currentTimeMillis(), contextName);
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.removeTxMsg", contextName));
|
||||
cluster.send(msg);
|
||||
}
|
||||
// remove locally
|
||||
if (undeploy) {
|
||||
try {
|
||||
if (!isServiced(contextName)) {
|
||||
addServiced(contextName);
|
||||
try {
|
||||
remove(contextName);
|
||||
} finally {
|
||||
removeServiced(contextName);
|
||||
}
|
||||
} else
|
||||
log.error(sm.getString("farmWarDeployer.removeFailRemote",
|
||||
contextName));
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error(sm.getString("farmWarDeployer.removeFailLocal",
|
||||
contextName), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Modification from watchDir war detected!
|
||||
*
|
||||
* @see org.apache.catalina.ha.deploy.FileChangeListener#fileModified(File)
|
||||
*/
|
||||
@Override
|
||||
public void fileModified(File newWar) {
|
||||
try {
|
||||
File deployWar = new File(getDeployDirFile(), newWar.getName());
|
||||
ContextName cn = new ContextName(deployWar.getName(), true);
|
||||
if (deployWar.exists() && deployWar.lastModified() > newWar.lastModified()) {
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.alreadyDeployed", cn.getName()));
|
||||
return;
|
||||
}
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.modInstall",
|
||||
cn.getName(), deployWar.getAbsolutePath()));
|
||||
// install local
|
||||
if (!isServiced(cn.getName())) {
|
||||
addServiced(cn.getName());
|
||||
try {
|
||||
copy(newWar, deployWar);
|
||||
check(cn.getName());
|
||||
} finally {
|
||||
removeServiced(cn.getName());
|
||||
}
|
||||
} else {
|
||||
log.error(sm.getString("farmWarDeployer.servicingDeploy",
|
||||
cn.getName(), deployWar.getName()));
|
||||
}
|
||||
install(cn.getName(), deployWar);
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("farmWarDeployer.modInstallFail"), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* War remove from watchDir
|
||||
*
|
||||
* @see org.apache.catalina.ha.deploy.FileChangeListener#fileRemoved(File)
|
||||
*/
|
||||
@Override
|
||||
public void fileRemoved(File removeWar) {
|
||||
try {
|
||||
ContextName cn = new ContextName(removeWar.getName(), true);
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.removeLocal",
|
||||
cn.getName()));
|
||||
remove(cn.getName(), true);
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("farmWarDeployer.removeLocalFail"), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the remove method on the deployer.
|
||||
* @param contextName The context to remove
|
||||
* @throws Exception If an error occurs removing the context
|
||||
*/
|
||||
protected void remove(String contextName) throws Exception {
|
||||
// TODO Handle remove also work dir content !
|
||||
// Stop the context first to be nicer
|
||||
Context context = (Context) host.findChild(contextName);
|
||||
if (context != null) {
|
||||
if(log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.undeployLocal",
|
||||
contextName));
|
||||
context.stop();
|
||||
String baseName = context.getBaseName();
|
||||
File war = new File(host.getAppBaseFile(), baseName + ".war");
|
||||
File dir = new File(host.getAppBaseFile(), baseName);
|
||||
File xml = new File(configBase, baseName + ".xml");
|
||||
if (war.exists()) {
|
||||
if (!war.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", war));
|
||||
}
|
||||
} else if (dir.exists()) {
|
||||
undeployDir(dir);
|
||||
} else {
|
||||
if (!xml.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", xml));
|
||||
}
|
||||
}
|
||||
// Perform new deployment and remove internal HostConfig state
|
||||
check(contextName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
if (!file.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", file));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dir.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", dir));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call watcher to check for deploy changes
|
||||
*
|
||||
* @see org.apache.catalina.ha.ClusterDeployer#backgroundProcess()
|
||||
*/
|
||||
@Override
|
||||
public void backgroundProcess() {
|
||||
if (started) {
|
||||
if (watchEnabled) {
|
||||
count = (count + 1) % processDeployFrequency;
|
||||
if (count == 0) {
|
||||
watcher.check();
|
||||
}
|
||||
}
|
||||
removeInvalidFileFactories();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*--Deployer Operations ------------------------------------*/
|
||||
|
||||
/**
|
||||
* Check a context for deployment operations.
|
||||
* @param name The context name
|
||||
* @throws Exception Error invoking the deployer
|
||||
*/
|
||||
protected void check(String name) throws Exception {
|
||||
String[] params = { name };
|
||||
String[] signature = { "java.lang.String" };
|
||||
mBeanServer.invoke(oname, "check", params, signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verified if a context is being services.
|
||||
* @param name The context name
|
||||
* @return <code>true</code> if the context is being serviced
|
||||
* @throws Exception Error invoking 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a context as being services.
|
||||
* @param name The context name
|
||||
* @throws Exception Error invoking the deployer
|
||||
*/
|
||||
protected void addServiced(String name) throws Exception {
|
||||
String[] params = { name };
|
||||
String[] signature = { "java.lang.String" };
|
||||
mBeanServer.invoke(oname, "addServiced", params, signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a context as no longer being serviced.
|
||||
* @param name The context name
|
||||
* @throws Exception Error invoking 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--------------------------------*/
|
||||
@Override
|
||||
public boolean equals(Object listener) {
|
||||
return super.equals(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
public String getDeployDir() {
|
||||
return deployDir;
|
||||
}
|
||||
|
||||
public File getDeployDirFile() {
|
||||
if (deployDirFile != null) return deployDirFile;
|
||||
|
||||
File dir = getAbsolutePath(getDeployDir());
|
||||
this.deployDirFile = dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
public void setDeployDir(String deployDir) {
|
||||
this.deployDir = deployDir;
|
||||
}
|
||||
|
||||
public String getTempDir() {
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
public File getTempDirFile() {
|
||||
if (tempDirFile != null) return tempDirFile;
|
||||
|
||||
File dir = getAbsolutePath(getTempDir());
|
||||
this.tempDirFile = dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
public void setTempDir(String tempDir) {
|
||||
this.tempDir = tempDir;
|
||||
}
|
||||
|
||||
public String getWatchDir() {
|
||||
return watchDir;
|
||||
}
|
||||
|
||||
public File getWatchDirFile() {
|
||||
if (watchDirFile != null) return watchDirFile;
|
||||
|
||||
File dir = getAbsolutePath(getWatchDir());
|
||||
this.watchDirFile = dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public int getMaxValidTime() {
|
||||
return maxValidTime;
|
||||
}
|
||||
|
||||
public void setMaxValidTime(int maxValidTime) {
|
||||
this.maxValidTime = maxValidTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()) {
|
||||
if (!to.createNewFile()) {
|
||||
log.error(sm.getString("fileNewFail", to));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(sm.getString("farmWarDeployer.fileCopyFail",
|
||||
from, to), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
try (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);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(sm.getString("farmWarDeployer.fileCopyFail",
|
||||
from, to), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void removeInvalidFileFactories() {
|
||||
String[] fileNames = fileFactories.keySet().toArray(new String[0]);
|
||||
for (String fileName : fileNames) {
|
||||
FileMessageFactory factory = fileFactories.get(fileName);
|
||||
if (!factory.isValid()) {
|
||||
fileFactories.remove(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File getAbsolutePath(String path) {
|
||||
File dir = new File(path);
|
||||
if (!dir.isAbsolute()) {
|
||||
dir = new File(getCluster().getContainer().getCatalinaBase(),
|
||||
dir.getPath());
|
||||
}
|
||||
try {
|
||||
dir = dir.getCanonicalFile();
|
||||
} catch (IOException e) {// ignore
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
24
java/org/apache/catalina/ha/deploy/FileChangeListener.java
Normal file
24
java/org/apache/catalina/ha/deploy/FileChangeListener.java
Normal file
@@ -0,0 +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);
|
||||
}
|
||||
88
java/org/apache/catalina/ha/deploy/FileMessage.java
Normal file
88
java/org/apache/catalina/ha/deploy/FileMessage.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 org.apache.catalina.ha.ClusterMessageBase;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
/**
|
||||
* Contains the data for a file being transferred over TCP, this is
|
||||
* essentially a fragment of a file, read and written by the FileMessageFactory
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class FileMessage extends ClusterMessageBase {
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private int messageNumber;
|
||||
private byte[] data;
|
||||
private int dataLength;
|
||||
|
||||
private long totalNrOfMsgs;
|
||||
private final String fileName;
|
||||
private final String contextName;
|
||||
|
||||
public FileMessage(Member source,
|
||||
String fileName,
|
||||
String contextName) {
|
||||
this.address=source;
|
||||
this.fileName=fileName;
|
||||
this.contextName=contextName;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
StringBuilder result = new StringBuilder(getFileName());
|
||||
result.append("#-#");
|
||||
result.append(getMessageNumber());
|
||||
result.append("#-#");
|
||||
result.append(System.currentTimeMillis());
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
public String getContextName() {
|
||||
return contextName;
|
||||
}
|
||||
}
|
||||
402
java/org/apache/catalina/ha/deploy/FileMessageFactory.java
Normal file
402
java/org/apache/catalina/ha/deploy/FileMessageFactory.java
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* 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.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.buf.HexUtils;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class FileMessageFactory {
|
||||
/*--Static Variables----------------------------------------*/
|
||||
private static final Log log = LogFactory.getLog(FileMessageFactory.class);
|
||||
private static final StringManager sm = StringManager.getManager(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 final File file;
|
||||
|
||||
/**
|
||||
* True means that we are writing with this factory. False means that we are
|
||||
* reading with this factory
|
||||
*/
|
||||
protected final boolean openForWrite;
|
||||
|
||||
/**
|
||||
* Once the factory is used, it cannot 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 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 number of the last message processed. Message IDs are 1 based.
|
||||
*/
|
||||
protected AtomicLong lastMessageProcessed = new AtomicLong(0);
|
||||
|
||||
/**
|
||||
* Messages received out of order are held in the buffer until required. If
|
||||
* everything is worked as expected, messages will spend very little time in
|
||||
* the buffer.
|
||||
*/
|
||||
protected final Map<Long, FileMessage> msgBuffer = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* The bytes that we hold the data in, not thread safe.
|
||||
*/
|
||||
protected byte[] data = new byte[READ_SIZE];
|
||||
|
||||
/**
|
||||
* Flag that indicates if a thread is writing messages to disk. Access to
|
||||
* this flag must be synchronised.
|
||||
*/
|
||||
protected boolean isWriting = false;
|
||||
|
||||
/**
|
||||
* The time this instance was created. (in milliseconds)
|
||||
*/
|
||||
protected long creationTime = 0;
|
||||
|
||||
/**
|
||||
* The maximum valid time(in seconds) from creationTime.
|
||||
*/
|
||||
protected int maxValidTime = -1;
|
||||
|
||||
/**
|
||||
* 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())
|
||||
if (!file.createNewFile()) {
|
||||
throw new IOException(sm.getString("fileNewFail", file));
|
||||
}
|
||||
out = new FileOutputStream(f);
|
||||
} else {
|
||||
size = file.length();
|
||||
totalNrOfMessages = (size / READ_SIZE) + 1;
|
||||
in = new FileInputStream(f);
|
||||
}//end if
|
||||
creationTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.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(sm.getString("fileMessageFactory.cannotWrite"));
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Message " + msg + " data " + HexUtils.toHexString(msg.getData())
|
||||
+ " data length " + msg.getDataLength() + " out " + out);
|
||||
|
||||
if (msg.getMessageNumber() <= lastMessageProcessed.get()) {
|
||||
// Duplicate of message already processed
|
||||
log.warn(sm.getString("fileMessageFactory.duplicateMessage", msg.getContextName(), msg.getFileName(),
|
||||
HexUtils.toHexString(msg.getData()), Integer.valueOf(msg.getDataLength())));
|
||||
return false;
|
||||
}
|
||||
|
||||
FileMessage previous =
|
||||
msgBuffer.put(Long.valueOf(msg.getMessageNumber()), msg);
|
||||
if (previous != null) {
|
||||
// Duplicate of message not yet processed
|
||||
log.warn(sm.getString("fileMessageFactory.duplicateMessage", msg.getContextName(), msg.getFileName(),
|
||||
HexUtils.toHexString(msg.getData()), Integer.valueOf(msg.getDataLength())));
|
||||
return false;
|
||||
}
|
||||
|
||||
FileMessage next = null;
|
||||
synchronized (this) {
|
||||
if (!isWriting) {
|
||||
next = msgBuffer.get(Long.valueOf(lastMessageProcessed.get() + 1));
|
||||
if (next != null) {
|
||||
isWriting = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
while (next != null) {
|
||||
out.write(next.getData(), 0, next.getDataLength());
|
||||
lastMessageProcessed.incrementAndGet();
|
||||
out.flush();
|
||||
if (next.getMessageNumber() == next.getTotalNrOfMsgs()) {
|
||||
out.close();
|
||||
cleanup();
|
||||
return true;
|
||||
}
|
||||
synchronized(this) {
|
||||
next =
|
||||
msgBuffer.get(Long.valueOf(lastMessageProcessed.get() + 1));
|
||||
if (next == null) {
|
||||
isWriting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (IOException ignore) {
|
||||
}
|
||||
if (out != null)
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
in = null;
|
||||
out = null;
|
||||
size = 0;
|
||||
closed = true;
|
||||
data = null;
|
||||
nrOfMessagesProcessed = 0;
|
||||
totalNrOfMessages = 0;
|
||||
msgBuffer.clear();
|
||||
lastMessageProcessed = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 The value to check
|
||||
* @throws IllegalArgumentException if the state is not the expected one
|
||||
*/
|
||||
protected void checkState(boolean openForWrite)
|
||||
throws IllegalArgumentException {
|
||||
if (this.openForWrite != openForWrite) {
|
||||
cleanup();
|
||||
if (openForWrite) {
|
||||
throw new IllegalArgumentException(sm.getString("fileMessageFactory.cannotWrite"));
|
||||
} else {
|
||||
throw new IllegalArgumentException(sm.getString("fileMessageFactory.cannotRead"));
|
||||
}
|
||||
}
|
||||
if (this.closed) {
|
||||
cleanup();
|
||||
throw new IllegalArgumentException(sm.getString("fileMessageFactory.closed"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage.
|
||||
*
|
||||
* @param args
|
||||
* String[], args[0] - read from filename, args[1] write to
|
||||
* filename
|
||||
* @throws Exception An error occurred
|
||||
*/
|
||||
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);
|
||||
if (msg == null) {
|
||||
System.out.println("Empty input file : " + args[0]);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
if (maxValidTime > 0) {
|
||||
long timeNow = System.currentTimeMillis();
|
||||
int timeIdle = (int) ((timeNow - creationTime) / 1000L);
|
||||
if (timeIdle > maxValidTime) {
|
||||
cleanup();
|
||||
if (file.exists() && !file.delete()) {
|
||||
log.warn(sm.getString("fileMessageFactory.deleteFail", file));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getMaxValidTime() {
|
||||
return maxValidTime;
|
||||
}
|
||||
|
||||
public void setMaxValidTime(int maxValidTime) {
|
||||
this.maxValidTime = maxValidTime;
|
||||
}
|
||||
|
||||
}
|
||||
59
java/org/apache/catalina/ha/deploy/LocalStrings.properties
Normal file
59
java/org/apache/catalina/ha/deploy/LocalStrings.properties
Normal file
@@ -0,0 +1,59 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=webapp [{0}] are already deployed.
|
||||
farmWarDeployer.deleteFail=Failed to delete [{0}]
|
||||
farmWarDeployer.deployEnd=Deployment from [{0}] finished.
|
||||
farmWarDeployer.fileCopyFail=Unable to copy from [{0}] to [{1}]
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer can only work as host cluster subelement!
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer can only work if parent of [{0}] is an engine!
|
||||
farmWarDeployer.mbeanNameFail=Cannot construct MBean object name for engine [{0}] and host [{1}]
|
||||
farmWarDeployer.modInstall=Installing webapp [{0}] from [{1}]
|
||||
farmWarDeployer.modInstallFail=Unable to install WAR file
|
||||
farmWarDeployer.modRemoveFail=No removal
|
||||
farmWarDeployer.msgIoe=Unable to read farm deploy file message.
|
||||
farmWarDeployer.msgRxDeploy=Receive cluster deployment path [{0}], war [{1}]
|
||||
farmWarDeployer.msgRxUndeploy=Receive cluster undeployment from path [{0}]
|
||||
farmWarDeployer.removeFailLocal=Local remove from [{0}] failed
|
||||
farmWarDeployer.removeFailRemote=Local remove from [{0}] failed, other manager has app in service!
|
||||
farmWarDeployer.removeLocal=Removing webapp [{0}]
|
||||
farmWarDeployer.removeLocalFail=Unable to remove WAR file
|
||||
farmWarDeployer.removeStart=Cluster wide remove of web app [{0}]
|
||||
farmWarDeployer.removeTxMsg=Send cluster wide undeployment from [{0}]
|
||||
farmWarDeployer.renameFail=Failed to rename [{0}] to [{1}]
|
||||
farmWarDeployer.sendEnd=Send cluster war deployment path [{0}], war [{1}] finished.
|
||||
farmWarDeployer.sendFragment=Send cluster war fragment path [{0}], war [{1}] to [{2}]
|
||||
farmWarDeployer.sendStart=Send cluster war deployment path [{0}], war [{1}] started.
|
||||
farmWarDeployer.servicingDeploy=Application [{0}] is being serviced. Touch war file [{1}] again!
|
||||
farmWarDeployer.servicingUndeploy=Application [{0}] is being serviced and can''t be removed from backup cluster node
|
||||
farmWarDeployer.started=Cluster FarmWarDeployer started.
|
||||
farmWarDeployer.stopped=Cluster FarmWarDeployer stopped.
|
||||
farmWarDeployer.undeployEnd=Undeployment from [{0}] finished.
|
||||
farmWarDeployer.undeployLocal=Undeploy local context [{0}]
|
||||
farmWarDeployer.watchDir=Cluster deployment is watching [{0}] for changes.
|
||||
|
||||
fileMessageFactory.cannotRead=Cannot read message, this factory is writing
|
||||
fileMessageFactory.cannotWrite=Cannot write message, this factory is reading
|
||||
fileMessageFactory.closed=Factory has been closed
|
||||
fileMessageFactory.deleteFail=Failed to delete [{0}]
|
||||
fileMessageFactory.duplicateMessage=Received duplicate message. Is the Sender timeout too low? context: [{0}] filename: [{1}] data: [{2}] data length: [{3}]
|
||||
|
||||
fileNewFail=Unable to create [{0}]
|
||||
|
||||
warWatcher.cantListWatchDir=Cannot list files in WatchDir [{0}]: check to see if it is a directory and has read permissions.
|
||||
warWatcher.checkWarResult=WarInfo.check() returned [{0}] for [{1}]
|
||||
warWatcher.checkingWar=Checking WAR file [{0}]
|
||||
warWatcher.checkingWars=Checking WARs in [{0}]
|
||||
warWatcher.listedFileDoesNotExist=[{0}] was detected in [{1}] but does not exist. Check directory permissions on [{1}]?
|
||||
@@ -0,0 +1,25 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.modInstall=Installiere Webapplikation [{0}] von [{1}]
|
||||
farmWarDeployer.modInstallFail=WAR-Datei konnte nicht installiert werden
|
||||
farmWarDeployer.msgIoe=Die Farm-Deploy-Datei-Nachricht kann nicht gelesen werden.
|
||||
farmWarDeployer.servicingUndeploy=Applikation [{0}] ist noch aktiv und kann nicht vom Backup-Cluster-Knoten entfernt werden
|
||||
farmWarDeployer.undeployEnd=Undeployment von [{0}] beendet.
|
||||
|
||||
fileMessageFactory.duplicateMessage=Doppelte Nachricht empfangen. Ist der Timeout für den Sender zu niedrig? Context: [{0}] Dateiname: [{1}] Daten: [{2}] Datenlänge [{3}]
|
||||
|
||||
warWatcher.cantListWatchDir=Dateien in WatchDir [{0}] können nicht gelistet werdenm: Prüfen Sie dass Lesezugriff auf das Verzeichnis besteht
|
||||
warWatcher.checkingWar=WAR-Datei [{0}] wird geprüft.
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer sólo puede operar como un subelemento de una máquina del cluster!
|
||||
farmWarDeployer.modInstall=Installando webapp [{0}] desde [{1}]\n
|
||||
farmWarDeployer.modInstallFail=Incapaz de instalar WAR file
|
||||
farmWarDeployer.msgIoe=Incapáz de leer el archivo de despliegue de la granja
|
||||
farmWarDeployer.msgRxDeploy=Recibe el camino de despliegue del cluster [{0}], war [{1}]
|
||||
farmWarDeployer.removeFailLocal=Borrado local de [{0}] fallido
|
||||
farmWarDeployer.removeFailRemote=El borrado local de [{0}] falló, otro manager tiene la aplicación en servicio!
|
||||
farmWarDeployer.sendFragment=Fragmento war enviado al cluster con camino [{0}], war [{1}] a [{2}]\n
|
||||
farmWarDeployer.servicingUndeploy=La applicación [{0}] esta en servicion y no pude ser removida del nodo de respaldo del cluster
|
||||
farmWarDeployer.undeployEnd=El revertimiendo del despliegue de [{0}] ha terminado.\n
|
||||
|
||||
fileMessageFactory.deleteFail=Fallo al borrar [{0}]\n
|
||||
|
||||
warWatcher.cantListWatchDir=No se pueden listar archivos en WatchDir [{0}]: verifique si es un directorio y tiene permisos de lectura.\n
|
||||
warWatcher.checkWarResult=WarInfo.check() devolvió [{0}] para [{1}]
|
||||
warWatcher.checkingWar=Verificando archivo WAR [{0}]
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=l''application web [{0}] est déjà déployée
|
||||
farmWarDeployer.deleteFail=Pas réussi à supprimer [{0}]
|
||||
farmWarDeployer.deployEnd=Le déploiement de [{0}] est terminé
|
||||
farmWarDeployer.fileCopyFail=Impossible de copier depuis [{0}] vers [{1}]
|
||||
farmWarDeployer.hostOnly=Le FarmWarDeployer ne fonctionne qu'en tant que sous-élément d'un "host cluster" !
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer peut fonctionner uniquement si le parent de [{0}] est un moteur
|
||||
farmWarDeployer.mbeanNameFail=Impossible de construire le nom d''objet du mbean pour le moteur [{0}] et l''hôte [{1}]
|
||||
farmWarDeployer.modInstall=Installation en cours pour la webapp [{0}] depuis [{1}]
|
||||
farmWarDeployer.modInstallFail=Incapable d'installer le fichier WAR
|
||||
farmWarDeployer.msgIoe=Incapable de lire le message de déploiement dans la ferme
|
||||
farmWarDeployer.msgRxDeploy=Recu le chemin de déploiement [{0}] du cluster, war [{1}]
|
||||
farmWarDeployer.msgRxUndeploy=Réception d''un retrait de cluster ("cluster undeployment") du chemin [{0}]
|
||||
farmWarDeployer.removeFailLocal=Impossible d''enlever localement de [{0}]
|
||||
farmWarDeployer.removeFailRemote=La suppression locale de [{0}] a échouée, l''autre gestionnaire (manager) a l''app en fonction !
|
||||
farmWarDeployer.removeLocal=Retrait de l''application web [{0}]
|
||||
farmWarDeployer.removeLocalFail=Impossible d'enlever le fichier WAR
|
||||
farmWarDeployer.removeStart=Retrait de l''application web [{0}] dans tout le cluster
|
||||
farmWarDeployer.removeTxMsg=Envoi à tout le cluster du déploiement à partir de [{0}]
|
||||
farmWarDeployer.renameFail=Echec du renommage de [{0}] en [{1}]
|
||||
farmWarDeployer.sendEnd=Envoi du chemin de déploiement du war au cluster, war [{1}] terminé
|
||||
farmWarDeployer.sendFragment=Envoi du chemin du fragment du war du cluster [{0}], war [{1}] vers [{2}]
|
||||
farmWarDeployer.sendStart=Envoi du déploiement war en cluster chemin [{0}], war [{1}] démarré
|
||||
farmWarDeployer.servicingDeploy=L''application [{0}] est en cours de maintenance, mettez de nouveau à jour la date du fichier war [{1}]
|
||||
farmWarDeployer.servicingUndeploy=L''application [{0}] est en maintenance et ne peut être retirée du node backup du cluster
|
||||
farmWarDeployer.started=Le FarmWarDeployer du cluster a démarré
|
||||
farmWarDeployer.stopped=Le FarmWarDeployer du cluster a été arrêté
|
||||
farmWarDeployer.undeployEnd=Retrait de [{0}] terminé
|
||||
farmWarDeployer.undeployLocal=Le contexte local [{0}] est retiré
|
||||
farmWarDeployer.watchDir=Le déploiement du cluster surveille [{0}] pour des modifications
|
||||
|
||||
fileMessageFactory.cannotRead=Impossible de lire un message, cette fabrique est en train d'écrire
|
||||
fileMessageFactory.cannotWrite=Impossible d'écrire un message, cette fabrique est en train de lire
|
||||
fileMessageFactory.closed=La fabrique a été fermée
|
||||
fileMessageFactory.deleteFail=Impossible de supprimer [{0}]
|
||||
fileMessageFactory.duplicateMessage=Réception de message en double, le délai d''attente maximum de l''expéditeur pourrait être trop court; contexte: [{0}] nom de fichier: [{1}] données: [{2}] longueur des données: [{3}]
|
||||
|
||||
fileNewFail=Impossible de créer [{0}]
|
||||
|
||||
warWatcher.cantListWatchDir=Incapacité de lister les fichiers dans le répertoire WatchDir [{0}]: vérifiez qu''il s''agit d''un répertoire et qu''il a la permission de lecture.
|
||||
warWatcher.checkWarResult=WarInfo.check() a retourné [{0}] pour [{1}]
|
||||
warWatcher.checkingWar=Vérification du fichier WAR [{0}]
|
||||
warWatcher.checkingWars=Vérification des WARs dans [{0}]
|
||||
warWatcher.listedFileDoesNotExist=[{0}] a été détecté dans [{1}] mais n''existe pas, les permissions du répertoire pourraient être incorrectes
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=webapp [{0}]は既にデプロイされています。
|
||||
farmWarDeployer.deleteFail=[{0}] を削除できません。
|
||||
farmWarDeployer.deployEnd=[{0}]からの配備が完了しました。
|
||||
farmWarDeployer.fileCopyFail=[{0}] から [{1}] へコピーできません。
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer はHostクラスタのサブエレメントとしてのみ機能します
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer は親 [{0}] が Engine のインスタンスでなければ機能しません。
|
||||
farmWarDeployer.mbeanNameFail=エンジン[{0}]とホスト[{1}]のMBeanオブジェクト名を構築できません
|
||||
farmWarDeployer.modInstall=[{1}]からwebapp [{0}]をインストールしています。
|
||||
farmWarDeployer.modInstallFail=WAR ファイルをインストールできませんでした。
|
||||
farmWarDeployer.msgIoe=ファームデプロイファイルメッセージの読み取りに失敗しました。
|
||||
farmWarDeployer.msgRxDeploy=クラスタ展開パス[{0}]、WAR[{1}]を受信しました。
|
||||
farmWarDeployer.msgRxUndeploy=パス[{0}]からクラスタの展開解除を受信しました。
|
||||
farmWarDeployer.removeFailLocal=[{0}]からのローカル削除に失敗しました
|
||||
farmWarDeployer.removeFailRemote=ローカルの [{0}] を削除できませんでした。他のマネージャーノードでサービス中です !
|
||||
farmWarDeployer.removeLocal=webapp [{0}]を削除しています
|
||||
farmWarDeployer.removeLocalFail=WAR ファイルを削除できません。
|
||||
farmWarDeployer.removeStart=Webアプリケーション[{0}]のクラスタ削除。
|
||||
farmWarDeployer.removeTxMsg=コンテキスト [{0}] からクラスターに配置解除メッセージを送信しました。
|
||||
farmWarDeployer.renameFail=[{0}] から [{1}] へ名前を変更できません。
|
||||
farmWarDeployer.sendEnd=クラスタWarデプロイメント パス[{0}]を送信しました。WAR[{1}]を完了しました。
|
||||
farmWarDeployer.sendFragment=コンテキスト [{0}] の war [{1}] をクラスターメンバー [{2}] へ送信します。
|
||||
farmWarDeployer.sendStart=クラスタWar展開パス[{0}]を送信し、War[{1}]を開始しました。
|
||||
farmWarDeployer.servicingDeploy=アプリケーション [{0}] はすでにサービスを開始しています。もう一度 WAR ファイル [{1}] を更新してください。
|
||||
farmWarDeployer.servicingUndeploy=アプリケーション [{0}] はサービス中のためバックアップクラスタノードから削除できません。
|
||||
farmWarDeployer.started=クラスターの FarmWarDeployer を開始しました。
|
||||
farmWarDeployer.stopped=Cluster FarmWarDeployer が停止しました。
|
||||
farmWarDeployer.undeployEnd=コンテキスト [{0}] の配置解除が完了しました。
|
||||
farmWarDeployer.undeployLocal=ローカルコンテキスト [{0}] を配置解除します。
|
||||
farmWarDeployer.watchDir=クラスタデプロイメントの監視[{0}]が変更されています。
|
||||
|
||||
fileMessageFactory.cannotRead=メッセージを読むことができません。このFactoryは書き込み中です。
|
||||
fileMessageFactory.cannotWrite=メッセージを書き込めません、このFactoryは読み込み中です。
|
||||
fileMessageFactory.closed=FileMessageFactoryはクローズされています。
|
||||
fileMessageFactory.deleteFail=[{0}]を削除できませんでした
|
||||
fileMessageFactory.duplicateMessage=メッセージをもう一度受信します。SenderのActTimeoutが短すぎます。 名前:[{0}] war:[{1}] データ:[{2}] データ長:[{3}]
|
||||
|
||||
fileNewFail=[{0}]を作成できません。
|
||||
|
||||
warWatcher.cantListWatchDir=監視ディレクトリ [{0}] のファイル一覧を取得できません : ディレクトリの読み取り権限を確認してください。
|
||||
warWatcher.checkWarResult=WAR ファイル [{1}] について WarInfo.check() は [{0}] を返しました。
|
||||
warWatcher.checkingWar=WAR ファイル [{0}] をチェックしています。
|
||||
warWatcher.checkingWars=[{0}]のWARを確認します
|
||||
warWatcher.listedFileDoesNotExist=[{1}] にあるはずの [{0}] が存在しません。[{1}] のディレクトリ権限を確認してください。
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=webapp [{0}](들)이 이미 배치되어 있습니다.
|
||||
farmWarDeployer.deleteFail=[{0}]을(를) 삭제하지 못했습니다.
|
||||
farmWarDeployer.deployEnd=[{0}](으)로부터의 배치 작업이 완료됐습니다.
|
||||
farmWarDeployer.fileCopyFail=[{0}](으)로부터 [{1}](으)로 복사할 수 없습니다.
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer는 오직 하위 엘리먼트인 호스트 클러스터 엘리먼트에서 존재해야 합니다.
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer는, 오직 [{0}]의 부모가 엔진일 때에만, 정상 동작할 수 있습니다!
|
||||
farmWarDeployer.mbeanNameFail=엔진 [{0}]와(과) 호스트 [{1}]을(를) 위한 MBean 객체 이름을 구성할 수 없습니다.
|
||||
farmWarDeployer.modInstall=[{1}](으)로부터 웹 애플리케이션 [{0}]을(를) 설치합니다.
|
||||
farmWarDeployer.modInstallFail=WAR 파일을 설치할 수 없습니다.
|
||||
farmWarDeployer.msgIoe=farm deploy 파일 메시지를 읽을 수 없습니다.
|
||||
farmWarDeployer.msgRxDeploy=클러스터 배치 경로 [{0}]을(를) 받았음, war: [{1}]
|
||||
farmWarDeployer.msgRxUndeploy=경로 [{0}]에 대한 클러스터 배치 제거 메시지를 수신했습니다.
|
||||
farmWarDeployer.removeFailLocal=[{0}](으)로부터 로컬 삭제가 실패했습니다.
|
||||
farmWarDeployer.removeFailRemote=FarmWarDeployer가 컨텍스트 [{0}]을(를) 로컬에서 제거하지 못하였습니다. 다른 Manager가 해당 애플리케이션을 서비스 중에 있습니다!
|
||||
farmWarDeployer.removeLocal=웹 애플리케이션 [{0}]을(를) 제거합니다.
|
||||
farmWarDeployer.removeLocalFail=WAR 파일을 제거할 수 없습니다.
|
||||
farmWarDeployer.removeStart=웹 애플리케이션 [{0}]을(를) 전 클러스터에서 제거
|
||||
farmWarDeployer.removeTxMsg=전 클러스터에서 [{0}]에 대한 배치를 제거 할 것을 전송합니다.
|
||||
farmWarDeployer.renameFail=[{0}]을(를) [{1}](으)로 이름을 변경하지 못했습니다.
|
||||
farmWarDeployer.sendEnd=클러스터 war 배치 경로 [{0}]을(를) 전송합니다. war [{1}]은(는) 완료되었습니다.
|
||||
farmWarDeployer.sendFragment=클러스터 war 파일 (경로: [{0}]) [{1}]을(를) [{2}](으)로 전송합니다.
|
||||
farmWarDeployer.sendStart=클러스터 war 배치 경로 [{0}]을(를) 전송합니다, war [{1}]이(가) 시작되었습니다.
|
||||
farmWarDeployer.servicingDeploy=애플리케이션 [{0}]이(가) 서비스되고 있습니다. War 파일 [{1}]을(를) 다시 touch 하십시오!
|
||||
farmWarDeployer.servicingUndeploy=애플리케이션 [{0}]이(가) 서비스 되고 있는 중이어서, 백업 클러스터 노드로부터 제거될 수 없습니다.
|
||||
farmWarDeployer.started=클러스터 FarmWarDeployer가 시작되었습니다.
|
||||
farmWarDeployer.stopped=클러스터 FarmWarDeployer가 중지되었습니다.
|
||||
farmWarDeployer.undeployEnd=컨텍스트 [{0}]의 배치를 제거했습니다.
|
||||
farmWarDeployer.undeployLocal=로컬 컨텍스트 [{0}]의 배치를 제거합니다.
|
||||
farmWarDeployer.watchDir=클러스터 배치관리자가 변경사항들을 탐지하기 위해 [{0}]을(를) 감시합니다.
|
||||
|
||||
fileMessageFactory.cannotRead=팩토리가 쓰고 있는 중이라서, 메시지를 읽을 수 없습니다.
|
||||
fileMessageFactory.cannotWrite=팩토리가 읽고 있는 중이라서, 메시지를 쓸 수 없습니다.
|
||||
fileMessageFactory.closed=팩토리가 이미 닫혀 있습니다.
|
||||
fileMessageFactory.deleteFail=[{0}]을(를) 삭제하지 못했습니다.
|
||||
fileMessageFactory.duplicateMessage=중복된 메시지를 받았습니다. Sender의 제한 시간 초과 값이 너무 작게 설정되었나요? 컨텍스트: [{0}], 파일명: [{1}], 데이터: [{2}], 데이터 길이: [{3}]
|
||||
|
||||
fileNewFail=[{0}]을(를) 생성할 수 없습니다.
|
||||
|
||||
warWatcher.cantListWatchDir=WatchDir [{0}] 내의 파일 목록을 구할 수 없습니다. 해당 디렉토리가 존재하는지 그리고 읽기 권한이 있는지 점검하십시오.
|
||||
warWatcher.checkWarResult=WarInfo.check()가 [{1}]을(를) 위해 [{0}]을(를) 반환했습니다.
|
||||
warWatcher.checkingWar=WAR 파일 [{0}]을(를) 점검합니다.
|
||||
warWatcher.checkingWars=[{0}] 내의 WAR들을 점검합니다.
|
||||
warWatcher.listedFileDoesNotExist=[{0}]이(가) [{1}]에서 탐지되었으나, 존재하지 않습니다. [{1}]에 대한 디렉토리 접근 허가 설정을 점검해 보시겠습니까?
|
||||
@@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.modInstall=Установка веб приложения [{0}] из [{1}]
|
||||
|
||||
warWatcher.checkingWar=Проверяем WAR файл [{}]
|
||||
@@ -0,0 +1,38 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.deleteFail=无法删除 [{0}]
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer 只有做为 host cluster 的子元素是才生效
|
||||
farmWarDeployer.mbeanNameFail=无法为引擎[{0}]和主机[{1}]构造MBean对象名
|
||||
farmWarDeployer.modInstall=从 [{1}] 安装 webapp [{0}]
|
||||
farmWarDeployer.modInstallFail=无法安装 WAR 文件
|
||||
farmWarDeployer.msgIoe=无法读取服务器场部署文件消息。
|
||||
farmWarDeployer.msgRxDeploy=接收集群部署路径[{0}],战争[{1}]
|
||||
farmWarDeployer.msgRxUndeploy=从路径[{0}]接收未部署群集
|
||||
farmWarDeployer.removeFailLocal=从[{0}]本地移除失败
|
||||
farmWarDeployer.removeFailRemote=本地从[{0}]删除失败,其他经理有app在服务!
|
||||
farmWarDeployer.removeLocalFail=无法移除WAR文件
|
||||
farmWarDeployer.renameFail=将 [{0}] 重命名为 [{1}] 失败
|
||||
farmWarDeployer.sendFragment=将群集战争片段路径[{0}],战争[{1}]发送到[{2}]
|
||||
farmWarDeployer.servicingDeploy=应用程序[{0}]正在服务。再次触摸WAR文件[{1}]!
|
||||
farmWarDeployer.servicingUndeploy=正在处理应用程序[{0}],无法从备份群集节点中删除它
|
||||
farmWarDeployer.undeployEnd=从[{0}]取消部署完成。
|
||||
farmWarDeployer.undeployLocal=不能部署本地上下文[{0}]
|
||||
|
||||
fileMessageFactory.deleteFail=无法删除 [{0}]
|
||||
|
||||
warWatcher.cantListWatchDir=无法列出WatchDir文件夹 [{0}] 中的文件:检查该路径是否为目录且应用具有读取权限。
|
||||
warWatcher.checkWarResult=WarInfo.check() 为[{1}]返回[{0}]
|
||||
warWatcher.checkingWar=检查 WAR 文件 [{0}]
|
||||
69
java/org/apache/catalina/ha/deploy/UndeployMessage.java
Normal file
69
java/org/apache/catalina/ha/deploy/UndeployMessage.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 org.apache.catalina.ha.ClusterMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
public class UndeployMessage implements ClusterMessage {
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private Member address;
|
||||
private long timestamp;
|
||||
private String uniqueId;
|
||||
private final String contextName;
|
||||
|
||||
public UndeployMessage(Member address,
|
||||
long timestamp,
|
||||
String uniqueId,
|
||||
String contextName) {
|
||||
this.address = address;
|
||||
this.timestamp= timestamp;
|
||||
this.uniqueId = uniqueId;
|
||||
this.contextName = contextName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Member getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddress(Member address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
public String getContextName() {
|
||||
return contextName;
|
||||
}
|
||||
}
|
||||
225
java/org/apache/catalina/ha/deploy/WarWatcher.java
Normal file
225
java/org/apache/catalina/ha/deploy/WarWatcher.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* The <b>WarWatcher </b> watches the deployDir for changes made to the
|
||||
* directory (adding new WAR files->deploy or remove WAR files->undeploy)
|
||||
* and notifies a listener of the changes made.
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
* @version 1.1
|
||||
*/
|
||||
public class WarWatcher {
|
||||
|
||||
/*--Static Variables----------------------------------------*/
|
||||
private static final Log log = LogFactory.getLog(WarWatcher.class);
|
||||
private static final StringManager sm = StringManager.getManager(WarWatcher.class);
|
||||
|
||||
/*--Instance Variables--------------------------------------*/
|
||||
/**
|
||||
* Directory to watch for war files
|
||||
*/
|
||||
protected final File watchDir;
|
||||
|
||||
/**
|
||||
* Parent to be notified of changes
|
||||
*/
|
||||
protected final FileChangeListener listener;
|
||||
|
||||
/**
|
||||
* Currently deployed files
|
||||
*/
|
||||
protected final Map<String, WarInfo> currentStatus = new HashMap<>();
|
||||
|
||||
/*--Constructor---------------------------------------------*/
|
||||
|
||||
public WarWatcher(FileChangeListener listener, File watchDir) {
|
||||
this.listener = listener;
|
||||
this.watchDir = watchDir;
|
||||
}
|
||||
|
||||
/*--Logic---------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* check for modification and send notification to listener
|
||||
*/
|
||||
public void check() {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("warWatcher.checkingWars", watchDir));
|
||||
File[] list = watchDir.listFiles(new WarFilter());
|
||||
if (list == null) {
|
||||
log.warn(sm.getString("warWatcher.cantListWatchDir",
|
||||
watchDir));
|
||||
|
||||
list = new File[0];
|
||||
}
|
||||
//first make sure all the files are listed in our current status
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if(!list[i].exists())
|
||||
log.warn(sm.getString("warWatcher.listedFileDoesNotExist",
|
||||
list[i], watchDir));
|
||||
|
||||
addWarInfo(list[i]);
|
||||
}
|
||||
|
||||
// Check all the status codes and update the FarmDeployer
|
||||
for (Iterator<Map.Entry<String,WarInfo>> i =
|
||||
currentStatus.entrySet().iterator(); i.hasNext();) {
|
||||
Map.Entry<String,WarInfo> entry = i.next();
|
||||
WarInfo info = entry.getValue();
|
||||
if(log.isTraceEnabled())
|
||||
log.trace(sm.getString("warWatcher.checkingWar",
|
||||
info.getWar()));
|
||||
int check = info.check();
|
||||
if (check == 1) {
|
||||
listener.fileModified(info.getWar());
|
||||
} else if (check == -1) {
|
||||
listener.fileRemoved(info.getWar());
|
||||
//no need to keep in memory
|
||||
i.remove();
|
||||
}
|
||||
if(log.isTraceEnabled())
|
||||
log.trace(sm.getString("warWatcher.checkWarResult",
|
||||
Integer.valueOf(check),
|
||||
info.getWar()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* add cluster war to the watcher state
|
||||
* @param warfile The WAR to add
|
||||
*/
|
||||
protected void addWarInfo(File warfile) {
|
||||
WarInfo info = currentStatus.get(warfile.getAbsolutePath());
|
||||
if (info == null) {
|
||||
info = new WarInfo(warfile);
|
||||
info.setLastState(-1); //assume file is non existent
|
||||
currentStatus.put(warfile.getAbsolutePath(), info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clear watcher state
|
||||
*/
|
||||
public void clear() {
|
||||
currentStatus.clear();
|
||||
}
|
||||
|
||||
|
||||
/*--Inner classes-------------------------------------------*/
|
||||
|
||||
/**
|
||||
* File name filter for war files
|
||||
*/
|
||||
protected static class WarFilter implements java.io.FilenameFilter {
|
||||
@Override
|
||||
public boolean accept(File path, String name) {
|
||||
if (name == null)
|
||||
return false;
|
||||
return name.endsWith(".war");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* File information on existing WAR files
|
||||
*/
|
||||
protected static class WarInfo {
|
||||
protected final File war;
|
||||
|
||||
protected long lastChecked = 0;
|
||||
|
||||
protected long lastState = 0;
|
||||
|
||||
public WarInfo(File war) {
|
||||
this.war = war;
|
||||
this.lastChecked = war.lastModified();
|
||||
if (!war.exists())
|
||||
lastState = -1;
|
||||
}
|
||||
|
||||
public boolean modified() {
|
||||
return war.exists() && war.lastModified() > lastChecked;
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return war.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if the file has been added/modified, 0 if the file is
|
||||
* unchanged and -1 if the file has been removed
|
||||
*
|
||||
* @return int 1=file added; 0=unchanged; -1=file removed
|
||||
*/
|
||||
public int check() {
|
||||
//file unchanged by default
|
||||
int result = 0;
|
||||
|
||||
if (modified()) {
|
||||
//file has changed - timestamp
|
||||
result = 1;
|
||||
lastState = result;
|
||||
} else if ((!exists()) && (!(lastState == -1))) {
|
||||
//file was removed
|
||||
result = -1;
|
||||
lastState = result;
|
||||
} else if ((lastState == -1) && exists()) {
|
||||
//file was added
|
||||
result = 1;
|
||||
lastState = result;
|
||||
}
|
||||
this.lastChecked = System.currentTimeMillis();
|
||||
return result;
|
||||
}
|
||||
|
||||
public File getWar() {
|
||||
return war;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return war.getAbsolutePath().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof WarInfo) {
|
||||
WarInfo wo = (WarInfo) other;
|
||||
return wo.getWar().equals(getWar());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setLastState(int lastState) {
|
||||
this.lastState = lastState;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
51
java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml
Normal file
51
java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<mbeans-descriptors>
|
||||
<mbean
|
||||
name="FarmWarDeployer"
|
||||
className="org.apache.catalina.mbeans.ClassNameMBean"
|
||||
description="Farm Deployer"
|
||||
domain="Catalina"
|
||||
group="Cluster"
|
||||
type="org.apache.catalina.ha.deploy.FarmWarDeployer">
|
||||
<attribute
|
||||
name="deployDir"
|
||||
description="Deployment directory."
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="tempDir"
|
||||
description="The temporaryDirectory to store binary data when downloading a war from the cluster"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="watchDir"
|
||||
description="The directory where we watch for changes"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="watchEnabled"
|
||||
description="Is watching enabled?"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="processDeployFrequency"
|
||||
description="Frequency of the Farm watchDir check."
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="maxValidTime"
|
||||
description="The maximum valid time of FileMessageFactory."
|
||||
type="int"/>
|
||||
</mbean>
|
||||
</mbeans-descriptors>
|
||||
Reference in New Issue
Block a user