org.apache.openejb.maven.plugin.AbstractTomEEMojo Maven / Gradle / Ivy
/*
* 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.openejb.maven.plugin;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.openejb.config.RemoteServer;
import org.apache.openejb.loader.Files;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.Zips;
import org.apache.openejb.maven.plugin.cli.Args;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.NetworkUtil;
import org.apache.openejb.util.OpenEjbVersion;
import org.apache.tomee.util.QuickServerXmlParser;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.logging.SimpleFormatter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE;
import static org.apache.maven.artifact.repository.ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN;
import static org.apache.maven.artifact.repository.ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY;
import static org.apache.maven.artifact.repository.ArtifactRepositoryPolicy.UPDATE_POLICY_NEVER;
import static org.apache.maven.artifact.versioning.VersionRange.createFromVersion;
import static org.apache.openejb.util.JarExtractor.delete;
import static org.codehaus.plexus.util.FileUtils.deleteDirectory;
import static org.codehaus.plexus.util.IOUtil.close;
import static org.codehaus.plexus.util.IOUtil.copy;
public abstract class AbstractTomEEMojo extends AbstractAddressMojo {
// if we get let say > 5 patterns like it we should create a LocationAnalyzer
// for < 5 patterns it should be fine
private static final String NAME_STR = "?name=";
private static final String UNZIP_PREFIX = "unzip:";
private static final String REMOVE_PREFIX = "remove:";
public static final String QUIT_CMD = "quit";
public static final String EXIT_CMD = "exit";
public static final String TOM_EE = "TomEE";
@Component
protected ArtifactFactory factory;
@Component
protected ArtifactResolver resolver;
@Parameter(defaultValue = "${localRepository}", readonly = true)
protected ArtifactRepository local;
@Parameter(defaultValue = "${project.remoteArtifactRepositories}", readonly = true)
protected List remoteRepos;
@Parameter(property = "tomee-plugin.skipCurrentProject", defaultValue = "false")
protected boolean skipCurrentProject;
@Parameter(property = "tomee-plugin.version", defaultValue = "-1")
protected String tomeeVersion;
@Parameter(property = "tomee-plugin.groupId", defaultValue = "org.apache.openejb")
protected String tomeeGroupId;
@Parameter(property = "tomee-plugin.artifactId", defaultValue = "apache-tomee")
protected String tomeeArtifactId;
/**
* while tar.gz is not managed it is readonly
*/
@Parameter(property = "tomee-plugin.type", defaultValue = "zip", readonly = true)
protected String tomeeType;
@Parameter(property = "tomee-plugin.apache-repos", defaultValue = "snapshots")
protected String apacheRepos;
@Parameter(property = "tomee-plugin.classifier", defaultValue = "webprofile")
protected String tomeeClassifier;
@Parameter(property = "tomee-plugin.shutdown", defaultValue = "8005")
protected int tomeeShutdownPort;
@Parameter(property = "tomee-plugin.shutdown.attempts", defaultValue = "60")
protected int tomeeShutdownAttempts;
@Parameter(property = "tomee-plugin.shutdown-command", defaultValue = "SHUTDOWN")
protected String tomeeShutdownCommand;
@Parameter(property = "tomee-plugin.ajp", defaultValue = "8009")
protected int tomeeAjpPort;
@Parameter(property = "tomee-plugin.https")
protected Integer tomeeHttpsPort;
@Parameter(property = "tomee-plugin.args")
protected String args;
@Parameter(property = "tomee-plugin.debug", defaultValue = "false")
protected boolean debug;
@Parameter(property = "tomee-plugin.simple-log", defaultValue = "false")
protected boolean simpleLog;
@Parameter(property = "tomee-plugin.debugPort", defaultValue = "5005")
protected int debugPort;
@Parameter(defaultValue = "${project.basedir}/src/main/webapp", property = "tomee-plugin.webappResources")
protected File webappResources;
@Parameter(defaultValue = "${project.build.outputDirectory}", property = "tomee-plugin.webappClasses")
protected File webappClasses;
@Parameter(defaultValue = "${project.build.directory}/apache-tomee", property = "tomee-plugin.catalina-base")
protected File catalinaBase;
/**
* rename the current artifact
*/
@Parameter
protected String context;
/**
* relative to tomee.base.
*/
@Parameter(defaultValue = "webapps")
protected String webappDir;
/**
* relative to tomee.base.
*/
@Parameter(defaultValue = "apps")
protected String appDir;
/**
* relative to tomee.base.
*/
@Parameter(defaultValue = "lib")
protected String libDir;
@Parameter(defaultValue = "${project.basedir}/src/main")
protected File mainDir;
@Parameter(defaultValue = "${project.build.directory}")
protected File target;
@Parameter(property = "tomee-plugin.conf", defaultValue = "${project.basedir}/src/main/tomee/conf")
protected File config;
@Parameter(property = "tomee-plugin.bin", defaultValue = "${project.basedir}/src/main/tomee/bin")
protected File bin;
@Parameter(property = "tomee-plugin.lib", defaultValue = "${project.basedir}/src/main/tomee/lib")
protected File lib;
@Parameter
protected Map systemVariables;
@Parameter
private List classpaths;
/**
* forcing nice default for war development (WEB-INF/classes and web resources)
*/
@Parameter(property = "tomee-plugin.webappDefaultConfig", defaultValue = "false")
protected boolean webappDefaultConfig;
/**
* use a real random instead of secure random. saves few ms at startup.
*/
@Parameter(property = "tomee-plugin.quick-session", defaultValue = "true")
protected boolean quickSession;
@Parameter
protected List customizers;
@Parameter(defaultValue = "${project}", readonly = true, required = true)
protected MavenProject project;
/**
* force webapp to be reloadable
*/
@Parameter(property = "tomee-plugin.force-reloadable", defaultValue = "false")
protected boolean forceReloadable;
/**
* supported formats:
* --> groupId:artifactId:version...
* --> unzip:groupId:artifactId:version...
* --> remove:prefix (often prefix = artifactId)
*/
@Parameter
protected List libs;
@Parameter
protected List endorsedLibs;
@Parameter
protected List javaagents;
@Parameter(property = "tomee-plugin.persist-javaagents", defaultValue = "false")
protected boolean persistJavaagents;
@Parameter
protected List webapps;
@Parameter
protected List apps;
@Parameter(property = "tomee-plugin.classes", defaultValue = "${project.build.outputDirectory}", readonly = true)
protected File classes;
@Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.${project.packaging}")
protected File warFile;
@Parameter(property = "tomee-plugin.remove-default-webapps", defaultValue = "true")
protected boolean removeDefaultWebapps;
@Parameter(property = "tomee-plugin.deploy-openejb-internal-application", defaultValue = "false")
protected boolean deployOpenEjbApplication;
@Parameter(property = "tomee-plugin.remove-tomee-webapps", defaultValue = "true")
protected boolean removeTomeeWebapp;
@Parameter(property = "tomee-plugin.ejb-remote", defaultValue = "true")
protected boolean ejbRemote;
@Parameter(defaultValue = "${project.packaging}", readonly = true)
protected String packaging;
@Parameter(property = "tomee-plugin.keep-server-xml", defaultValue = "false")
protected boolean keepServerXmlAsthis;
@Parameter(property = "tomee-plugin.check-started", defaultValue = "false")
protected boolean checkStarted;
@Parameter(property = "tomee-plugin.use-console", defaultValue = "true")
protected boolean useConsole;
@Parameter(property = "tomee-plugin.exiting", defaultValue = "false")
protected boolean tomeeAlreadyInstalled;
/**
* The current user system settings for use in Maven.
*/
@Parameter(defaultValue = "${settings}", readonly = true)
protected Settings settings;
/**
* use openejb-standalone automatically instead of TomEE
*/
@Parameter(property = "tomee-plugin.openejb", defaultValue = "false")
protected boolean useOpenEJB;
/**
* for TomEE and wars only, which docBase to use for this war.
*/
@Parameter
protected List docBases;
/**
* for TomEE and wars only, add some external repositories to classloader.
*/
@Parameter
protected List externalRepositories;
/**
* when you set docBases to src/main/webapp setting it to true will allow hot refresh.
*/
@Parameter(property = "tomee-plugin.skipWarResources", defaultValue = "false")
protected boolean skipWarResources = false;
protected File deployedFile = null;
protected RemoteServer server = null;
protected String container = TOM_EE;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
fixConfig();
if ("-1".equals(tomeeVersion)) {
final String version = OpenEjbVersion.get().getVersion();
tomeeVersion = "1" + version.substring(1, version.length());
}
if (!tomeeAlreadyInstalled) {
final Collection existingWebapps; // added before using the plugin with maven dependency plugin or sthg like that
if (removeDefaultWebapps) {
existingWebapps = webappsAlreadyAdded();
} else {
existingWebapps = Collections.emptyList();
}
unzip(resolve());
if (removeDefaultWebapps) { // do it first to let add other war
removeDefaultWebapps(removeTomeeWebapp, existingWebapps);
}
copyLibs(libs, new File(catalinaBase, libDir), "jar");
copyLibs(endorsedLibs, new File(catalinaBase, "endorsed"), "jar");
copyLibs(webapps, new File(catalinaBase, webappDir), "war");
copyLibs(apps, new File(catalinaBase, appDir), "jar");
overrideConf(config, "conf");
overrideConf(lib, "lib");
final Collection copied = overrideConf(bin, "bin");
for (final File copy : copied) {
if (copy.getName().endsWith(".bat") || copy.getName().endsWith(".sh")) {
if (!copy.setExecutable(true)) {
getLog().warn("can't make " + copy.getPath() + " executable");
}
}
}
if (classpaths == null) { // NPE protection for activateSimpleLog() and run()
classpaths = new ArrayList();
}
if (simpleLog) {
activateSimpleLog();
}
if (!keepServerXmlAsthis) {
overrideAddresses();
}
if (!skipCurrentProject) {
copyWar();
}
if (customizers != null) {
final Thread thread = Thread.currentThread();
final ClassLoader currentLoader = thread.getContextClassLoader();
final ClassLoader tccl = createClassLoader(currentLoader);
thread.setContextClassLoader(tccl);
try {
// a customizer is a Runnable with or without a constructor taking a File as parameter (catalina base)
// one goal is to avoid coupling as much as possible with this plugin
//
// if really needed we could introduce a Customizer interface but then it has more impacts on your packaging/config
for (final String customizer : customizers) {
try {
final Class> clazz = tccl.loadClass(customizer);
try {
final Constructor> cons = clazz.getConstructor(File.class);
Runnable.class.cast(cons.newInstance(catalinaBase)).run();
} catch (final NoSuchMethodException e) {
try {
Runnable.class.cast(clazz.newInstance()).run();
} catch (final Exception e1) {
throw new MojoExecutionException("can't create customizer: " + currentLoader, e);
}
}
} catch (final ClassNotFoundException e) {
throw new MojoExecutionException("can't find customizer: " + currentLoader, e);
} catch (final InvocationTargetException e) {
throw new MojoExecutionException("can't create customizer: " + currentLoader, e);
} catch (final InstantiationException e) {
throw new MojoExecutionException("can't create customizer: " + currentLoader, e);
} catch (final IllegalAccessException e) {
throw new MojoExecutionException("can't create customizer: " + currentLoader, e);
}
}
} finally {
try {
if (tccl != null && Closeable.class.isInstance(tccl)) {
Closeable.class.cast(tccl).close();
}
} catch (final IOException e) {
// no-op
}
thread.setContextClassLoader(currentLoader);
}
}
}
run();
}
@SuppressWarnings("unchecked")
private ClassLoader createClassLoader(final ClassLoader parent) {
final List urls = new ArrayList();
for (final Artifact artifact : (Collection) project.getArtifacts()) {
try {
urls.add(artifact.getFile().toURI().toURL());
} catch (final MalformedURLException e) {
getLog().warn("can't use artifact " + artifact.toString());
}
}
if (classes != null && classes.exists()) {
try {
urls.add(classes.toURI().toURL());
} catch (final MalformedURLException e) {
getLog().warn("can't use path " + classes.getAbsolutePath());
}
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parent);
}
protected void fixConfig() {
if (useOpenEJB) {
tomeeGroupId = "org.apache.openejb";
tomeeArtifactId = "openejb-standalone";
tomeeClassifier = null;
tomeeShutdownCommand = "Q";
if (8005 == tomeeShutdownPort) { // default admin port
tomeeShutdownPort = 4200;
}
if (tomeeVersion.startsWith("1.")) {
tomeeVersion = OpenEjbVersion.get().getVersion();
}
if (catalinaBase.getName().equals("apache-tomee") && catalinaBase.getParentFile().equals(target)) {
catalinaBase = new File(target, "apache-openejb");
}
if (config.getParentFile().getName().equals("tomee") && config.getParentFile().getParentFile().equals(mainDir)) {
config = new File(mainDir, "openejb/conf");
}
if (lib.getParentFile().getName().equals("tomee") && lib.getParentFile().getParentFile().equals(mainDir)) {
lib = new File(mainDir, "openejb/lib");
}
if (bin.getParentFile().getName().equals("tomee") && bin.getParentFile().getParentFile().equals(mainDir)) {
bin = new File(mainDir, "openejb/bin");
}
}
}
protected String getAdditionalClasspath() {
if (!classpaths.isEmpty()) {
final StringBuilder cpBuilder = new StringBuilder();
for (final String cp : classpaths) {
cpBuilder.append(cp);
cpBuilder.append(File.pathSeparatorChar);
}
return cpBuilder.substring(0, cpBuilder.length() - 1); // Dump the final path separator
}
return null;
}
private List webappsAlreadyAdded() {
final List list = new ArrayList();
final File webapps = new File(catalinaBase, webappDir);
if (webapps.exists() && webapps.isDirectory()) {
final File[] files = webapps.listFiles();
if (files != null) {
for (final File f : files) {
list.add(f.getName());
}
}
}
return list;
}
private void activateSimpleLog() {
// replacing java.util.logging.SimpleFormatter by SimpleTomEEFormatter
final File loggingProperties = new File(catalinaBase, "conf/logging.properties");
if (loggingProperties.exists() && !new File(config, "conf/logging.properties").exists()) {
try {
String content = IO.slurp(loggingProperties);
if (!content.contains("java.util.logging.ConsoleHandler.formatter")) {
content += System.getProperty("line.separator") + "java.util.logging.ConsoleHandler.formatter = org.apache.tomee.jul.formatter.SimpleTomEEFormatter";
} else {
content = content.replace(SimpleFormatter.class.getName(), "org.apache.tomee.jul.formatter.SimpleTomEEFormatter");
}
doWrite(loggingProperties, content);
} catch (final Exception e) {
getLog().error("Can't set SimpleTomEEFormatter", e);
}
}
}
private void removeDefaultWebapps(final boolean removeTomee, final Collection providedWebapps) {
final File webapps = new File(catalinaBase, webappDir);
if (webapps.isDirectory()) {
final File[] files = webapps.listFiles();
if (null != files) {
for (final File webapp : files) {
final String name = webapp.getName();
if (webapp.isDirectory() && !providedWebapps.contains(name) && (removeTomee || !name.equals("tomee"))) {
try {
deleteDirectory(webapp);
} catch (final IOException ignored) {
// no-op
}
}
}
}
}
getLog().info("Removed not mandatory default webapps");
}
private void copyLibs(final List files, final File destParent, final String defaultType) {
if (files == null || files.isEmpty()) {
return;
}
if (!destParent.exists() && !destParent.mkdirs()) {
getLog().warn("can't create '" + destParent.getPath() + "'");
}
for (final String file : files) {
updateLib(file, destParent, defaultType);
}
}
private void updateLib(final String rawLib, final File destParent, final String defaultType) {
InputStream is = null;
OutputStream os = null;
// special hook to get more info
String lib = rawLib;
String extractedName = null;
if (lib.contains(NAME_STR)) {
lib = lib.substring(0, rawLib.indexOf(NAME_STR));
extractedName = rawLib.substring(rawLib.indexOf(NAME_STR) + NAME_STR.length(), rawLib.length());
if (!extractedName.endsWith(".jar") && !extractedName.endsWith(".war")
&& !extractedName.endsWith(".ear") && !extractedName.endsWith(".rar")) {
extractedName = extractedName + "." + defaultType;
}
}
boolean unzip = false;
if (lib.startsWith(UNZIP_PREFIX)) {
lib = lib.substring(UNZIP_PREFIX.length());
unzip = true;
}
if (lib.startsWith(REMOVE_PREFIX)) {
final String prefix = lib.substring(REMOVE_PREFIX.length());
final File[] files = destParent.listFiles(new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.startsWith(prefix);
}
});
if (files != null) {
for (final File file : files) {
if (!IO.delete(file)) {
file.deleteOnExit();
}
getLog().info("Deleted " + file.getPath());
}
}
} else {
try {
final File file = mvnToFile(lib, defaultType);
if (!unzip) {
final File dest;
if (extractedName == null) {
dest = new File(destParent, file.getName());
} else {
dest = new File(destParent, extractedName);
}
is = new BufferedInputStream(new FileInputStream(file));
os = new BufferedOutputStream(new FileOutputStream(dest));
copy(is, os);
getLog().info("Copied '" + lib + "' in '" + dest.getAbsolutePath());
} else {
Zips.unzip(file, destParent, true);
getLog().info("Unzipped '" + lib + "' in '" + destParent.getAbsolutePath());
}
} catch (final Exception e) {
getLog().error(e.getMessage(), e);
throw new TomEEException(e.getMessage(), e);
} finally {
close(is);
close(os);
}
}
}
private File mvnToFile(final String lib, final String defaultType) throws ArtifactResolutionException, ArtifactNotFoundException {
final String[] infos = lib.split(":");
final String classifier;
final String type;
if (infos.length < 3) {
throw new TomEEException("format for librairies should be ::[:[:]]");
}
if (infos.length >= 4) {
type = infos[3];
} else {
type = defaultType;
}
if (infos.length == 5) {
classifier = infos[4];
} else {
classifier = null;
}
final Artifact artifact = factory.createDependencyArtifact(infos[0], infos[1], createFromVersion(infos[2]), type, classifier, SCOPE_COMPILE);
resolver.resolve(artifact, remoteRepos, local);
return artifact.getFile();
}
private void copyWar() {
if ("pom".equals(packaging)) {
return;
}
final boolean war = "war".equals(packaging);
final String name = destinationName();
final File out;
if (war) {
out = new File(catalinaBase, webappDir + "/" + name);
} else {
final File parent = new File(catalinaBase, appDir);
if (!parent.exists() && !parent.mkdirs()) {
getLog().warn("can't create '" + parent.getPath() + "'");
}
out = new File(parent, name);
}
delete(out);
if (!warFile.isDirectory() && name.endsWith("." + packaging)) {
final String dir = name.substring(0, name.lastIndexOf('.'));
final File unpacked;
if (war) {
unpacked = new File(catalinaBase, webappDir + "/" + dir);
} else {
unpacked = new File(catalinaBase, appDir + "/" + dir);
}
delete(unpacked);
}
if (warFile.exists() && warFile.isDirectory()) {
try {
IO.copyDirectory(warFile, out);
} catch (final IOException e) {
throw new TomEEException(e.getMessage(), e);
}
} else if (warFile.exists()) {
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(warFile);
os = new FileOutputStream(out);
copy(is, os);
getLog().info("Installed '" + warFile.getAbsolutePath() + "' in " + out.getAbsolutePath());
} catch (final Exception e) {
throw new TomEEException(e.getMessage(), e);
} finally {
close(is);
close(os);
}
} else {
getLog().warn("'" + warFile + "' doesn't exist, ignoring (maybe run mvn package before this plugin)");
}
deployedFile = out;
}
protected String destinationName() {
if (context != null) {
if (!context.contains(".") && !warFile.isDirectory()) {
return context + "." + packaging;
}
return context;
}
return warFile.getName();
}
private void overrideAddresses() {
final File serverXml = new File(catalinaBase, "conf/server.xml");
if (!serverXml.exists()) { // openejb
return;
}
final QuickServerXmlParser parser = QuickServerXmlParser.parse(serverXml);
String value = read(serverXml);
File keystoreFile = new File(parser.keystore());
if (!keystoreFile.exists()) {
keystoreFile = new File(System.getProperty("user.home"), ".keystore");
}
if (!keystoreFile.exists()) {
keystoreFile = new File("target", ".keystore");
}
final String keystoreFilePath = (keystoreFile.exists() ? keystoreFile.getAbsolutePath() : "");
if (tomeeHttpsPort != null && tomeeHttpsPort > 0 && parser.value("HTTPS", null) == null) {
// ensure connector is not commented
value = value.replace("", "\n"
+ " \n");
}
if (tomeeHttpsPort == null) {
// avoid NPE
tomeeHttpsPort = 8443;
}
FileWriter writer = null;
try {
writer = new FileWriter(serverXml);
writer.write(value
.replace(parser.http(), Integer.toString(this.getTomeeHttpPortChecked()))
.replace(parser.https(), Integer.toString(this.getTomeeHttpsPortChecked()))
.replace(parser.ajp(), Integer.toString(tomeeAjpPort))
.replace(parser.stop(), Integer.toString(this.getTomeeShutdownPortChecked()))
.replace(parser.host(), tomeeHost)
.replace(parser.appBase(), webappDir));
} catch (final IOException e) {
throw new TomEEException(e.getMessage(), e);
} finally {
close(writer);
}
}
private static String read(final File file) {
FileInputStream in = null;
try {
in = new FileInputStream(file);
final StringBuilder sb = new StringBuilder();
int i = in.read();
while (i != -1) {
sb.append((char) i);
i = in.read();
}
return sb.toString();
} catch (final Exception e) {
throw new TomEEException(e.getMessage(), e);
} finally {
close(in);
}
}
private Collection overrideConf(final File dir, final String baseDir) {
if (!dir.exists()) {
return Collections.emptyList();
}
final File[] files = dir.listFiles();
if (files != null) {
final Collection copied = new ArrayList();
for (final File f : files) {
if (f.isHidden()) {
continue;
}
final String file = baseDir + "/" + f.getName();
final File destination = new File(catalinaBase, file);
if (f.isDirectory()) {
Files.mkdirs(destination);
try {
IO.copyDirectory(f, destination);
} catch (final IOException e) {
throw new TomEEException(e.getMessage(), e);
}
} else {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(f);
out = new FileOutputStream(destination);
copy(in, out);
copied.add(f);
getLog().info("Override '" + file + "'");
} catch (final Exception e) {
throw new TomEEException(e.getMessage(), e);
} finally {
close(in);
close(out);
}
}
}
return copied;
}
return Collections.emptyList();
}
protected void run() {
if (classpaths == null) { // NPE protection when execute is skipped and mojo delegates to run directly
classpaths = new ArrayList();
}
final List strings = generateJVMArgs();
// init env for RemoteServer
System.setProperty("openejb.home", catalinaBase.getAbsolutePath());
if (debug) {
System.setProperty("openejb.server.debug", "true");
System.setProperty("server.debug.port", Integer.toString(debugPort));
}
System.setProperty("server.shutdown.port", Integer.toString(this.getTomeeShutdownPortChecked()));
System.setProperty("server.shutdown.command", tomeeShutdownCommand);
server = new RemoteServer(getConnectAttempts(), debug);
server.setAdditionalClasspath(getAdditionalClasspath());
addShutdownHooks(server); // some shutdown hooks are always added (see UpdatableTomEEMojo)
if (TOM_EE.equals(container)) {
server.setPortStartup(this.getTomeeHttpPortChecked());
getLog().info("Running '" + getClass().getName().replace("TomEEMojo", "").toLowerCase(Locale.ENGLISH)
+ "'. Configured TomEE in plugin is " + tomeeHost + ":" + this.getTomeeHttpPortChecked()
+ " (plugin shutdown port is " + this.getTomeeShutdownPortChecked() + " and https port is " + this.getTomeeHttpsPortChecked() + ")");
} else {
getLog().info("Running '" + getClass().getSimpleName().replace("TomEEMojo", "").toLowerCase(Locale.ENGLISH));
}
final InputStream originalIn = System.in; // piped when starting resmote server so saving it
serverCmd(server, strings);
if (getWaitTomEE()) {
final CountDownLatch stopCondition = new CountDownLatch(1);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
stopServer(stopCondition);
}
});
if (useConsole) {
final Scanner reader = new Scanner(originalIn);
System.out.flush();
getLog().info("Waiting for command: " + availableCommands());
String line;
while ((line = getNextLine(reader)) != null) {
if (isQuit(line)) {
break;
}
if ("ignore".equals(line)) {
continue;
}
if (!handleLine(line.trim())) {
System.out.flush();
getLog().warn("Command '" + line + "' not understood. Use one of " + availableCommands());
}
}
reader.close();
stopServer(stopCondition); // better than using shutdown hook since it doesn't rely on the hook which are not sent by eclipse for instance
}
try {
stopCondition.await();
} catch (final InterruptedException e) {
// no-op
}
}
}
private synchronized int getTomeeHttpPortChecked() {
if (this.tomeeHttpPort <= 0) {
this.tomeeHttpPort = NetworkUtil.getNextAvailablePort();
}
return this.tomeeHttpPort;
}
private synchronized int getTomeeHttpsPortChecked() {
if (this.tomeeHttpsPort <= 0) {
this.tomeeHttpsPort = NetworkUtil.getNextAvailablePort();
}
return this.tomeeHttpsPort;
}
private synchronized int getTomeeShutdownPortChecked() {
if (this.tomeeShutdownPort <= 0) {
this.tomeeShutdownPort = NetworkUtil.getNextAvailablePort();
}
return this.tomeeShutdownPort;
}
private String getNextLine(final Scanner reader) {
try {
return reader.nextLine();
} catch (final NoSuchElementException e) {
return "ignore";
}
}
protected List generateJVMArgs() {
final String deployOpenEjbAppKey = "openejb.system.apps";
final String servletCompliance = "org.apache.catalina.STRICT_SERVLET_COMPLIANCE";
boolean deactivateStrictServletCompliance = args == null || !args.contains(servletCompliance);
final List strings = new ArrayList();
if (systemVariables != null) {
for (final Map.Entry entry : systemVariables.entrySet()) {
final String key = entry.getKey();
if (servletCompliance.equals(key)) {
deactivateStrictServletCompliance = false;
}
final String value = entry.getValue();
if (value == null) {
strings.add("-D" + key);
} else if (value.contains(" ")) {
strings.add(String.format("'-D%s=%s'", key, value));
} else {
strings.add(String.format("-D%s=%s", key, value));
}
if (deployOpenEjbAppKey.equals(key)) {
deployOpenEjbApplication = true;
}
}
}
if (webappDefaultConfig) {
forceDefaultForNiceWebAppDevelopment();
}
if (deactivateStrictServletCompliance) {
strings.add("-D" + servletCompliance + "=false");
}
if (quickSession) {
strings.add("-Dopenejb.session.manager=org.apache.tomee.catalina.session.QuickSessionManager");
}
if (removeTomeeWebapp && ejbRemote) { // if we have tomee webapp no need to activate ejb remote support this way
strings.add("-Dtomee.remote.support=true");
}
if (!deployOpenEjbApplication) { // true is the default so don't need to set the property
if (args == null || !args.contains("-D" + deployOpenEjbAppKey)) {
strings.add("-D" + deployOpenEjbAppKey + "=false");
}
}
if (args != null) {
strings.addAll(Args.parse(args));
}
if (javaagents != null) {
addJavaagents(strings);
}
if (forceReloadable) {
strings.add("-Dtomee.force-reloadable=true");
}
if (!getWaitTomEE()) {
strings.add("-Dtomee.noshutdownhook=true");
}
String appName = null; // computed lazily
if (docBases != null && !docBases.isEmpty()) {
if ("war".equals(packaging)) {
appName = destinationName().replace(".war", "");
if (appName.startsWith("/")) {
appName = appName.substring(1);
}
strings.add("-Dtomee." + appName + ".docBases=" + filesToString(docBases));
strings.add("-Dtomee." + appName + ".docBases.cache=false"); // doesn't work for dev if activated
} else {
getLog().warn("docBases parameter only valid for a war");
}
}
if (externalRepositories != null && !externalRepositories.isEmpty()) {
if ("war".equals(packaging)) {
appName = appName == null ? destinationName().replace(".war", "") : appName;
if (appName.startsWith("/")) {
appName = appName.substring(1);
}
strings.add("-Dtomee." + appName + ".externalRepositories=" + filesToString(externalRepositories));
} else {
getLog().warn("externalRepositories parameter only valid for a war");
}
}
if (skipWarResources) {
strings.add("-Dtomee.skip-war-resources=" + skipWarResources);
}
return strings;
}
private void addJavaagents(final List strings) {
final String existingJavaagent = "\\\"-javaagent:$CATALINA_HOME/lib/openejb-javaagent.jar\\\"";
final StringBuilder javaagentString = new StringBuilder(existingJavaagent);
for (final String rawJavaagent : javaagents) {
final String javaagent;
final String args;
int argsIdx = rawJavaagent.indexOf('=');
if (argsIdx < 0) {
argsIdx = rawJavaagent.indexOf('?');
}
if (argsIdx > 0) {
javaagent = rawJavaagent.substring(0, argsIdx);
args = rawJavaagent.substring(argsIdx);
} else {
javaagent = rawJavaagent;
args = "";
}
String path = javaagent;
if (!new File(javaagent).isFile()) {
try {
final File jar = mvnToFile(javaagent, "jar");
if (persistJavaagents) {
final File javaagentFolder = new File(catalinaBase, "javaagent");
Files.mkdirs(javaagentFolder);
final String name = jar.getName();
path = "$CATALINA_HOME/javaagent/" + name;
IO.copy(jar, new File(javaagentFolder, name));
}
strings.add("-javaagent:" + jar.getAbsolutePath() + args);
} catch (final Exception e) {
getLog().warn("Can't find " + javaagent);
strings.add("-javaagent:" + javaagent);
}
} else {
strings.add("-javaagent:" + javaagent);
}
if (persistJavaagents) {
javaagentString.append(" -javaagent:").append(path).append(args);
}
}
if (persistJavaagents) {
try {
{
final File catalinaSh = new File(catalinaBase, "bin/catalina.sh");
final String content = IO.slurp(catalinaSh).replace(existingJavaagent, javaagentString.toString());
doWrite(catalinaSh, content);
}
{
final File catalinaBat = new File(catalinaBase, "bin/catalina.bat");
final String content = IO.slurp(catalinaBat)
.replace(
"\"-javaagent:%CATALINA_HOME%\\lib\\openejb-javaagent.jar\"",
javaagentString.toString()
.replace('\'', '"')
.replace('/', '\\')
.replace("$CATALINA_HOME", "%CATALINA_HOME%"));
doWrite(catalinaBat, content);
}
} catch (final IOException ioe) {
throw new OpenEJBRuntimeException(ioe);
}
}
}
private void forceDefaultForNiceWebAppDevelopment() {
if (!deployOpenEjbApplication) {
getLog().info("Forcing deployOpenEjbApplication=true to be able to type 'reload[ENTER]' when classes are updated");
deployOpenEjbApplication = true;
}
if (!forceReloadable) {
getLog().info("Forcing forceReloadable=true to be able to type 'reload[ENTER]' when classes are updated");
forceReloadable = true;
}
if (!skipWarResources) {
getLog().info("Forcing skipWarResources=true to be able to refresh resources with F5");
skipWarResources = true;
}
if (docBases == null) {
docBases = new ArrayList();
}
if (docBases.isEmpty() && webappResources.exists()) {
getLog().info("adding " + webappResources.toString() + " docBase");
docBases.add(webappResources);
}
if (externalRepositories == null) {
externalRepositories = new ArrayList();
}
if (externalRepositories.isEmpty() && webappClasses.exists()) {
getLog().info("adding " + webappClasses.toString() + " externalRepository");
externalRepositories.add(webappClasses);
}
}
private static String filesToString(final Collection files) {
final Collection paths = new ArrayList(files.size());
for (final File path : files) { // don't use relative paths (toString())
paths.add(path.getAbsolutePath());
}
return Join.join(",", paths);
}
protected Collection availableCommands() {
return Arrays.asList(QUIT_CMD, EXIT_CMD);
}
protected synchronized void stopServer(final CountDownLatch stopCondition) {
if (server == null) {
return;
}
try {
server.stop();
} catch (final Exception e) {
// no-op
}
try {
server.getServer().waitFor();
getLog().info(container + " stopped");
} catch (final Exception e) {
getLog().error("Can't stop " + container, e);
}
server = null;
stopCondition.countDown();
}
private static boolean isQuit(String line) {
if (QUIT_CMD.equalsIgnoreCase(line) || EXIT_CMD.equalsIgnoreCase(line)) {
return true;
}
//http://youtrack.jetbrains.com/issue/IDEA-94826
line = new StringBuilder(line).reverse().toString();
return QUIT_CMD.equalsIgnoreCase(line) || EXIT_CMD.equalsIgnoreCase(line);
}
protected boolean handleLine(final String line) {
return false;
}
protected void serverCmd(final RemoteServer server, final List strings) {
final Process p = this.server.getServer();
if (null == p) {
try {
server.start(strings, getCmd(), checkStarted);
} catch (final Exception e) {
//TODO - Optional server.destroy() call
getLog().warn("Failed to check or track server startup on port: " + this.getTomeeHttpPortChecked());
}
}
}
protected void addShutdownHooks(final RemoteServer server) {
// no-op
}
protected int getConnectAttempts() {
return (tomeeShutdownAttempts == 0 ? 60 : tomeeShutdownAttempts);
}
protected boolean getWaitTomEE() {
return true;
}
private File resolve() {
if (!settings.isOffline()) {
try {
if ("snapshots".equals(apacheRepos) || "true".equals(apacheRepos)) {
remoteRepos.add(new DefaultArtifactRepository("apache", "https://repository.apache.org/content/repositories/snapshots/",
new DefaultRepositoryLayout(),
new ArtifactRepositoryPolicy(true, UPDATE_POLICY_DAILY, CHECKSUM_POLICY_WARN),
new ArtifactRepositoryPolicy(false, UPDATE_POLICY_NEVER, CHECKSUM_POLICY_WARN)));
} else {
try {
new URI(apacheRepos); // to check it is a uri
remoteRepos.add(new DefaultArtifactRepository("additional-repo-tomee-mvn-plugin", apacheRepos,
new DefaultRepositoryLayout(),
new ArtifactRepositoryPolicy(true, UPDATE_POLICY_DAILY, CHECKSUM_POLICY_WARN),
new ArtifactRepositoryPolicy(true, UPDATE_POLICY_NEVER, CHECKSUM_POLICY_WARN)));
} catch (final URISyntaxException e) {
// ignored, use classical repos
}
}
} catch (final UnsupportedOperationException uoe) {
// can happen if remoterepos is unmodifiable (possible in complex builds)
// no-op
}
} else if (remoteRepos != null && remoteRepos.isEmpty()) {
remoteRepos = new ArrayList();
}
if ((tomeeClassifier != null && (tomeeClassifier.isEmpty() || tomeeClassifier.equals("ignore")))
|| ("org.apache.openejb".equals(tomeeGroupId) && "openejb-standalone".equals(tomeeArtifactId))) {
tomeeClassifier = null;
}
try {
final Artifact artifact = factory.createDependencyArtifact(tomeeGroupId, tomeeArtifactId, createFromVersion(tomeeVersion), tomeeType, tomeeClassifier, SCOPE_COMPILE);
resolver.resolve(artifact, remoteRepos, local);
return artifact.getFile();
} catch (final Exception e) {
getLog().error(e.getMessage(), e);
throw new TomEEException(e.getMessage(), e);
}
}
private void unzip(final File mvnTomEE) {
ZipFile in = null;
try {
in = new ZipFile(mvnTomEE);
final Enumeration extends ZipEntry> entries = in.entries();
while (entries.hasMoreElements()) {
final ZipEntry entry = entries.nextElement();
String name = entry.getName();
int idx = name.indexOf("/");
if (idx < 0) {
idx = name.indexOf(File.separator);
}
if (idx < 0) {
continue;
}
name = name.substring(idx + 1);
final File dest = new File(catalinaBase.getAbsolutePath(), name);
if (!dest.exists()) {
final File parent = dest.getParentFile();
if ((!parent.exists() && !parent.mkdirs())
|| (!parent.canWrite() && !parent.setWritable(true))
|| (!parent.canRead() && !parent.setReadable(true))) {
throw new RuntimeException("Failed to create or set permissions on: " + parent);
}
}
if (entry.isDirectory()) {
if (!dest.exists() && !dest.mkdir()) {
throw new RuntimeException("Failed to create: " + dest);
}
} else {
final FileOutputStream fos = new FileOutputStream(dest);
try {
copy(in.getInputStream(entry), fos);
} catch (final IOException e) {
// ignored
}
close(fos);
if (!dest.canRead() && !dest.setReadable(true)) {
throw new RuntimeException("Failed to set readable on: " + dest);
}
if (dest.getName().endsWith(".sh")) {
if (!dest.canExecute() && !dest.setExecutable(true)) {
throw new RuntimeException("Failed to set executable on: " + dest);
}
}
}
}
File file = new File(catalinaBase, "conf/tomee.xml");
if (file.exists()) {
container = TOM_EE;
} else {
container = "OpenEJB";
file = new File(catalinaBase, "conf/openejb.xml");
if (file.exists()) {
webappDir = "apps";
}
}
ensureAppsFolderExistAndIsConfiguredByDefault(file);
getLog().info(container + " was unzipped in '" + catalinaBase.getAbsolutePath() + "'");
} catch (final Exception e) {
throw new TomEEException(e.getMessage(), e);
} finally {
if (in != null) {
try {
in.close();
} catch (final IOException e) {
// no-op
}
}
}
}
private void ensureAppsFolderExistAndIsConfiguredByDefault(final File file) throws IOException {
if ("openejb".equals(container.toLowerCase(Locale.ENGLISH))
|| (file.exists()
&& (
(apps != null && !apps.isEmpty())
|| (!"pom".equals(packaging) && !"war".equals(packaging))))) { // webapps doesn't need apps folder in tomee
final FileWriter writer = new FileWriter(file);
final String rootTag = container.toLowerCase(Locale.ENGLISH);
writer.write("\n" +
"<" + rootTag + ">\n" +
" \n" +
"" + rootTag + ">\n");
writer.close();
final File appsFolder = new File(catalinaBase, "apps");
if (!appsFolder.exists() && !appsFolder.mkdirs()) {
throw new RuntimeException("Failed to create: " + appsFolder);
}
}
}
private static void doWrite(final File file, final String content) throws IOException {
final FileWriter writer = new FileWriter(file);
try {
writer.write(content);
} finally {
IO.close(writer);
}
}
public abstract String getCmd();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy