📄 launchservlet.java
字号:
package de.fhm.jkf.launch.sv;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.ZipEntry;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import de.fhm.jkf.launch.clsv.ArchiveInfo;
import de.fhm.jkf.launch.clsv.JarFilenameFilter;
import de.fhm.jkf.launch.clsv.LaunchParameter;
/**
* @author Theodor Willax
*
* <br><br><center><table border="1" width="80%"><hr>
* <strong><a href="http://jkf.sourceforge.net">The JKF Project</a></strong>
* <p>
* Copyright (C) 2002 by Theodor Willax
* <p>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* <p>
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* <p>
* You should have received a copy of the <a href="http://www.gnu.org/copyleft/lesser.html">
* GNU Lesser General Public License</a> along with this library; if not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
* <hr></table></center>
*
* This is the first communication point for the user to get
* a launcher for his application. It is thread save, because
* no status data is stored in the instance variables. It is
* an HTTP-Servlet, because it's the only protocol which can
* simply be used as a tunnel through proxies and firewalls.
* <br>
* The java archives used for the application the launcher should serve
* are stored in a directory on the server. It is set via the parameter
* <code>archiveDir</code> in the <code>web.xml</code> for the
* jkf_launcher web application.
* <br>
* Configuration files necessery for the <code>jkf-framework</code> should
* be stored in a subdirectory of the <code>archiveDir</code> named
* <code>config</code>. They will be transfered to the client automatically on
* application startup.
*/
public class LaunchServlet extends HttpServlet {
/**
* The launcher jar archive file. It starts the application
* at client side. It's path is read out of the servlet init
* parameter <tt>launchArchive</tt>.
*/
private File launchArchive;
/**
* The application properties file, which will be merged
* into the launcher archive. It's necessery for the client to
* get information about the main class to launch and the servlet
* URL where to get the archives. It's path is read out
* of the servlet init parameter <tt>appStartPropertyFile</tt>.
* <br>
* If no value for this property is specified, we assume that
* the <code>application.properties</code> file is allright in
* the jkf_launcher.jar archive (in root directory).
*/
private File appStartPropertyFile;
/**
* Contains information about archives like contained classes,
* archive name and version information.
*/
private List archiveInfo;
/**
* The directory the archives neccessary for the application are
* stored. Read out of the servlet init parameter <tt>archiveDir</tt>.
*/
private File archiveDir;
/**
* Initializes the servlet. Reads the init params needed for creating the
* launcher archive with the correct properties file.
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
launchArchive = new File(getInitParameter("launchArchive"));
if (launchArchive.isFile() == false) {
throw new IllegalArgumentException(
"launchArchive is not a File: "
+ getInitParameter("launchArchive"));
}
String prop = getInitParameter("appStartPropertyFile");
if ((prop != null) && (prop.length() > 0)) {
appStartPropertyFile = new File(prop);
if (appStartPropertyFile.isFile() == false) {
throw new IllegalArgumentException(
"appStartPropertyFile is not a File: "
+ getInitParameter("appStartPropertyFile"));
}
} else {
getServletContext().log(
"not appStartPropertyFile set => "
+ "leave jkf_launcher.jar untouched");
}
archiveDir = new File(getInitParameter("archiveDir"));
if (archiveDir.isDirectory() == false) {
throw new IllegalArgumentException(
"archiveDir is not a Directory: "
+ getInitParameter("archiveDir"));
}
// generate archive list
try {
generateArchiveInfo(archiveDir);
} catch (IOException e) {
throw new ServletException(e);
}
}
/**
* Generates the information necesseray to find an archive to a specified
* classname. Also contains version information about the archive the class
* is in.
*
* @param archiveDir The directory all needed jar archives for the
* hosted application are in.
*
* @exception IOException if something during the archive handling
* goes wrong.
*/
private void generateArchiveInfo(File archiveDir) throws IOException {
getServletContext().log(
getClass().getName() + ".generateArchiveInfo() called");
File[] jars = archiveDir.listFiles(new JarFilenameFilter());
archiveInfo = new LinkedList();
for (int i = 0; i < jars.length; i++) {
getServletContext().log("building list for: " + jars[i].getName());
Set set = new HashSet();
JarFile jf = new JarFile(jars[i]);
Enumeration enum = jf.entries();
while (enum.hasMoreElements()) {
ZipEntry ze = (ZipEntry) enum.nextElement();
// make class loader class name out of jar file name
String cn = ze.getName();
if (cn.endsWith(".class")) {
cn = cn.replace('/', '.');
cn = cn.substring(0, cn.lastIndexOf(".class"));
}
getServletContext().log("add list entry: " + cn);
set.add(cn);
}
Manifest mf = jf.getManifest();
String version = null;
if (mf != null) {
Attributes a = mf.getMainAttributes();
version = a.getValue("Implementation-Version");
}
archiveInfo.add(new ArchiveInfo(set, jars[i].getName(), version));
}
}
/**
* Handles GET requests. Dispatches it to <code>doWork</code>.
*/
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {
getServletContext().log(getClass().getName() + ".doGet() called");
doWork(req, res);
}
/**
* Handles POST requests. Dispatches it to <code>doWork</code>.
*/
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException {
getServletContext().log(getClass().getName() + ".doPost() called");
doWork(req, res);
}
/**
* Does the real work for each request. Serves the launcher archive to the
* client. Includes the <tt>application.properties</tt> file for this
* application into the launcher archives root directory if set.
* <br>
* Could be verified by saving the archive from the browser and call
* <code>jar tf jkf_launcher.jar</code> on it.
* <br>
* Serves also single archives and an archive list if requested.
* The http parameters which may be set are in the <code>LaunchParameter</code>
* class listed.
*
* @see de.fhm.kjf.launch.clsv.LaunchParameter
*/
private void doWork(HttpServletRequest req, HttpServletResponse res)
throws IOException {
if (req.getParameter(LaunchParameter.GET_ARCHIVE + "") != null) {
// send requested archive
getServletContext().log(LaunchParameter.GET_ARCHIVE + " requested");
String archiveName =
req.getParameter(LaunchParameter.GET_ARCHIVE + "");
if (archiveName != null) {
res.setContentType("application/java-archive");
int len;
byte[] buf = new byte[4096];
File f =
new File(
archiveDir.getAbsolutePath()
+ File.separator
+ archiveName);
long size = f.length();
res.setHeader("archive-length", Long.toString(size));
InputStream in =
new BufferedInputStream(new FileInputStream(f));
OutputStream out = res.getOutputStream();
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
// @todo errorhandling if archive not found
} else if (
req.getParameter(LaunchParameter.GET_ARCH_LIST + "") != null) {
// send compressed archive list
getServletContext().log(
LaunchParameter.GET_ARCH_LIST + " requested");
ObjectOutputStream out =
new ObjectOutputStream(
new DeflaterOutputStream(res.getOutputStream()));
out.writeObject(archiveInfo);
out.close();
} else if (
req.getParameter(LaunchParameter.GET_CONFIG_FILES + "") != null) {
// send configuration files as jar archive packed
getServletContext().log(
LaunchParameter.GET_CONFIG_FILES + " reqeusted");
File configDir =
new File(
archiveDir.getAbsolutePath() + File.separator + "config");
if (configDir.isDirectory()) {
int len;
byte[] buf = new byte[4096];
res.setContentType("application/java-archive");
File configFiles[] = configDir.listFiles();
JarOutputStream jout =
new JarOutputStream(res.getOutputStream());
for (int i = 0; i < configFiles.length; i++) {
JarEntry je = new JarEntry(configFiles[i].getName());
jout.putNextEntry(je);
InputStream in =
new BufferedInputStream(
new FileInputStream(configFiles[i]));
while ((len = in.read(buf)) > 0) {
jout.write(buf, 0, len);
}
in.close();
jout.closeEntry();
}
jout.close();
} else {
throw new IllegalArgumentException(
"no valid config directory: "
+ configDir.getAbsolutePath());
}
} else {
// send launcher archive
getServletContext().log("launcher requested (default)");
res.setContentType("application/java-archive");
res.setHeader("Content-disposition", "filename=jkf_launcher.jar");
int len;
byte[] buf = new byte[4096];
JarEntry je;
JarInputStream jin =
new JarInputStream(new FileInputStream(launchArchive));
Manifest mf = new JarFile(launchArchive).getManifest();
JarOutputStream jout =
new JarOutputStream(res.getOutputStream(), mf);
// write contents of jkf launcher jar to client
while ((je = jin.getNextJarEntry()) != null) {
jout.putNextEntry(je);
while ((len = jin.read(buf)) > 0) {
jout.write(buf, 0, len);
}
}
jin.close();
// write appStartPropertyFile within jkf launcher jar to client
if (appStartPropertyFile != null) {
InputStream in =
new BufferedInputStream(
new FileInputStream(appStartPropertyFile));
jout.putNextEntry(new JarEntry("application.properties"));
while ((len = in.read(buf)) > 0) {
jout.write(buf, 0, len);
}
in.close();
}
jout.closeEntry();
jout.close();
}
}
/**
* Cleans up any allocated resources. <code>null</code>S the instance
* variables.
*/
public void destroy() {
getServletContext().log(getClass().getName() + ".destroy()");
launchArchive = null;
appStartPropertyFile = null;
archiveInfo.clear();
archiveInfo = null;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -