Java tutorial
/** * ========================================================================================== * = JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION = * ========================================================================================== * * http://www.jahia.com * * Copyright (C) 2002-2018 Jahia Solutions Group SA. All rights reserved. * * THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES: * 1/GPL OR 2/JSEL * * 1/ GPL * ================================================================================== * * IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS: * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * * 2/ JSEL - Commercial and Supported Versions of the program * =================================================================================== * * IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS: * * Alternatively, commercial and supported versions of the program - also known as * Enterprise Distributions - must be used in accordance with the terms and conditions * contained in a separate written agreement between you and Jahia Solutions Group SA. * * If you are unsure which license is appropriate for your use, * please contact the sales department at sales@jahia.com. */ package org.jahia.utils.maven.plugin; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ConnectException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.resolver.ArtifactCollector; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.shared.dependency.tree.DependencyNode; import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.archiver.ArchiverException; import org.codehaus.plexus.archiver.zip.ZipUnArchiver; import org.codehaus.plexus.components.io.fileselectors.FileSelector; import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.console.ConsoleLogger; import org.codehaus.plexus.util.SelectorUtils; import org.jahia.configuration.deployers.ServerDeploymentInterface; import org.jahia.configuration.modules.ModuleDeployer; import org.jahia.utils.maven.plugin.support.AetherHelper; import org.jahia.utils.maven.plugin.support.AetherHelperFactory; import com.sun.jdi.Bootstrap; import com.sun.jdi.ReferenceType; import com.sun.jdi.VirtualMachine; import com.sun.jdi.connect.AttachingConnector; import com.sun.jdi.connect.Connector; import com.sun.jdi.connect.Connector.Argument; import com.sun.jdi.connect.IllegalConnectorArgumentsException; /** * Jahia server deployment mojo. * @author Serge Huber * @goal deploy * @requiresDependencyResolution runtime */ public class DeployMojo extends AbstractManagementMojo { private static final Set<String> JAHIA_SYSTEM_BUNDLES = new HashSet<String>( Arrays.asList("org.jahia.bundles.url.jahiawar", "org.jahia.bundles.extender.jahiamodules", "org.jahia.bundles.blueprint.extender.config", "org.jahia.bundles.http.bridge", "org.jahia.bundles.webconsole.config", "org.jahia.bundles.jspapiusage.repackaging", "org.jahia.bundles.configadmin.persistence", "org.jahia.bundles.clustering", "org.jahia.bundles.clustering.enabler", "org.jahia.bundles.hazelcast.discovery", "org.jahia.bundles.spring.bridge")); private static final Set<String> JAHIA_PACKAGE_PROJECTS = new HashSet<String>( Arrays.asList("jahia-data", "jahia-core-modules", "jahia-additional-modules", "jahia-ee-data", "jahia-ee-core-modules", "jahia-ee-additional-modules")); /** * The dependency tree builder to use. * * @component * @required * @readonly */ private DependencyTreeBuilder dependencyTreeBuilder; /** * The artifact metadata source to use. * * @component * @required * @readonly */ private ArtifactMetadataSource artifactMetadataSource; /** * The artifact collector to use. * * @component * @required * @readonly */ private ArtifactCollector artifactCollector; /** * @parameter expression="${jahia.debug.address}" default-value="socket:hostname=localhost,port=8000" */ private String address; /** * @parameter expression="${jahia.deploy.deployTests}" default-value="false" */ private boolean deployTests; private AetherHelper aetherHelper; /** * @component * @required * @readonly */ private PlexusContainer container; /** * The current build session instance. * * @parameter expression="${session}" * @required * @readonly */ private MavenSession mavenSession; public void doExecute() throws MojoExecutionException, MojoFailureException { try { if (targetServerDirectory != null) { deployProject(); } } catch (Exception e) { throw new MojoExecutionException("Error when deploying", e); } } public void doValidate() throws MojoExecutionException, MojoFailureException { ServerDeploymentInterface serverDeployer = null; try { serverDeployer = getDeployer(); } catch (Exception e) { throw new MojoExecutionException("Error while validating deployers", e); } if (serverDeployer == null) { throw new MojoFailureException("Server " + targetServerType + " v" + targetServerVersion + " not (yet) supported by this plugin."); } if (!getDeployer().validateInstallationDirectory()) { throw new MojoFailureException("Directory " + targetServerDirectory + " is not a valid installation directory for server " + getDeployer().getName()); } } private void deployProject() throws Exception { if (skipDeploy()) { getLog().info("jahia.deploy.skip is set to 'true' for the current project. Skip deploying it."); return; } if (project.getPackaging().equals("ear")) { deployEarProject(); } else if (project.getPackaging().equals("war")) { if (project.getGroupId().equals("org.jahia.server") || project.getGroupId().equals("org.jahia.extensions")) { deployWarProject(); } else if (project.getGroupId().equals("org.jahia.modules") || (deployTests && project.getGroupId().equals("org.jahia.test")) || project.getGroupId().endsWith(".jahia.modules")) { deployModuleProject(); } else if (project.getGroupId().equals("org.jahia.test") && !deployTests) { getLog().info( "Deployment of test projects " + "(with groupId 'org.jahia.test') is disabled by default. " + "You can enable it by specifying -Djahia.deploy.deployTests" + " option for the 'mvn jahia:deploy' command"); } else { getLog().warn("Unrecognized type of the WAR project. Skipping deployment"); } } else if (project.getPackaging().equals("jar")) { if (project.getGroupId().equals("org.jahia.test") && !deployTests) { getLog().info( "Deployment of test projects " + "(with groupId 'org.jahia.test') is disabled by default. " + "You can enable it by specifying -Djahia.deploy.deployTests" + " option for the 'mvn jahia:deploy' command"); } else { deployJarProject(); } } else if (project.getPackaging().equals("pom")) { deployPomProject(); } else if (project.getPackaging().equals("bundle")) { boolean isJahiaTaglib = project.getArtifactId().equals("jahia-taglib"); if (isJahiaTaglib) { deployJarProject(); } if (project.getGroupId().equals("org.jahia.bundles") && JAHIA_SYSTEM_BUNDLES.contains(project.getArtifactId()) || isJahiaTaglib) { String fileName = project.getArtifactId() + "-" + project.getVersion() + "." + "jar"; File srcFile = new File(output, fileName); File destDir = null; File karafDir = new File(getWebappDeploymentDir(), "WEB-INF/karaf/system"); boolean karafDeployment = karafDir.isDirectory(); if (karafDeployment) { destDir = new File( new File(karafDir, StringUtils.join(StringUtils.split(project.getGroupId(), '.'), File.separatorChar)), project.getArtifactId() + File.separatorChar + project.getVersion()); } else { destDir = new File(getWebappDeploymentDir(), "WEB-INF/bundles"); } FileUtils.copyFileToDirectory(srcFile, destDir); getLog().info("Copied " + srcFile + " to " + destDir); if (karafDeployment) { copyToKarafDeploy(srcFile); } else { removeCachedBundle(fileName, new File(getDataDir(), "bundles-deployed")); } } else { boolean isStandardModule = project.getGroupId().equals("org.jahia.module") || project.getGroupId().endsWith(".jahia.modules"); if (isStandardModule || isJahiaModuleBundle( new File(output, project.getArtifactId() + "-" + project.getVersion() + "." + "jar"))) { deployModuleProject(); } else { File srcFile = new File(output, project.getArtifactId() + "-" + project.getVersion() + "." + "jar"); File destDir = null; File karafDir = new File(getWebappDeploymentDir(), "WEB-INF/karaf/system"); boolean karafDeployment = karafDir.isDirectory(); if (karafDeployment) { destDir = new File(getDataDir(), "karaf/deploy"); } else { destDir = new File(getDataDir(), "bundles"); } FileUtils.copyFileToDirectory(srcFile, destDir); getLog().info("Copied " + srcFile + " to " + destDir); } } } } private void copyToKarafDeploy(File srcFile) throws IOException { File deployDir = new File(getDataDir(), "karaf/deploy"); getLog().info( "Copying file " + srcFile.getCanonicalPath() + " into folder " + deployDir.getCanonicalPath()); FileUtils.copyFileToDirectory(srcFile, deployDir, false); getLog().info("...done"); } private void removeCachedBundle(String fileName, File deployedBundeDir) { if (!deployedBundeDir.isDirectory()) { return; } for (File info : FileUtils.listFiles(deployedBundeDir, new NameFileFilter("bundle.info"), TrueFileFilter.INSTANCE)) { try { if (FileUtils.readFileToString(info).contains(fileName)) { try { FileUtils.deleteDirectory(info.getParentFile()); getLog().info("Deleted deployed bundle in folder " + info.getParentFile()); } catch (IOException e) { getLog().warn("Unable to deleted deployed bundle in folder " + info.getParentFile() + ". Cause: " + e.getMessage()); } break; } } catch (IOException e) { getLog().warn(e.getMessage()); } } } private boolean isJahiaModuleBundle(File file) { if (!file.exists()) { return false; } // check the manifest JarFile jar = null; try { jar = new JarFile(file, false); return jar.getManifest().getMainAttributes().containsKey(new Attributes.Name("Jahia-Module-Type")); } catch (IOException e) { getLog().error(e); } finally { if (jar != null) { try { jar.close(); } catch (IOException e) { getLog().warn(e); } } } return false; } private boolean skipDeploy() { return Boolean.valueOf(project.getProperties().getProperty("jahia.deploy.skip", "false")); } /** * Deploy all EAR dependencies ( WARs / SARs / RARs / shared resources ) to application server * @throws Exception */ private void deployEarProject() throws Exception { if (getDeployer().isEarDeployment()) { getLog().info("Deploying application server specific files for " + getDeployer().getName() + " in directory " + targetServerDirectory); File targetEarFolder = getDeployer().getDeploymentFilePath("digitalfactory", "ear"); getLog().info("Updating EAR resources in " + targetEarFolder); int updateFileCount = updateFiles(new File(baseDir, "src/main/resources"), targetEarFolder); getLog().info("Updated " + updateFileCount + " resources"); if ("jboss".equals(targetServerType)) { // for JBoss create deployment marker file FileUtils.touch(new File(targetEarFolder.getParentFile(), targetEarFolder.getName() + ".dodeploy")); } } } /** * Copy output folder of WAR / SAR / RAR project to application server * @throws Exception */ private void deployWarProject() throws Exception { File webappDir = getWebappDeploymentDir(); getLog().info("Update " + project.getPackaging() + " resources for " + getDeployer().getName() + " in directory " + webappDir); if ("was".equals(targetServerType)) { File source = new File(output, project.getBuild().getFinalName() + ".war"); File target = new File(webappDir + "/" + project.getBuild().getFinalName() + ".war"); try { FileUtils.copyFile(source, target); } catch (IOException e) { getLog().error("Error while deploying WAR project", e); } } else { try { ZipUnArchiver unarch = new ZipUnArchiver( new File(output, project.getBuild().getFinalName() + ".war")); unarch.enableLogging(getLog().isDebugEnabled() ? new ConsoleLogger(Logger.LEVEL_DEBUG, "console") : new ConsoleLogger()); if (!webappDir.exists() && !webappDir.mkdirs()) { throw new IOException("Unable to create target WAR directory " + webappDir); } unarch.setDestDirectory(webappDir); String warExcludes = getDeployer().getWarExcludes(); String[] excludes = warExcludes != null ? StringUtils.split(warExcludes, " ,") : null; if (excludes != null && excludes.length > 0) { IncludeExcludeFileSelector selector = new IncludeExcludeFileSelector(); selector.setExcludes(excludes); unarch.setFileSelectors(new FileSelector[] { selector }); } unarch.extract(); getLog().info("...done."); } catch (ArchiverException e) { getLog().error("Error while deploying WAR project", e); } } if (project.getArtifactId().equals("jahia-war") || project.getArtifactId().equals("jahia-ee-war")) { File dataPackage = getAetherHelper().resolveArtifactFile(project.getGroupId() + ":" + project.getArtifactId() + ":zip:data-package:" + project.getArtifact().getVersion()); if (dataPackage != null) { deployPackageFile(dataPackage); } } } /** * Copy template resources from output folder to the jsp/templates and WEB-INF/classes of jahia * @throws Exception */ private void deployModuleProject() throws Exception { File source = new File(output, project.getArtifactId() + "-" + project.getVersion() + "." + (project.getPackaging().equals("bundle") ? "jar" : project.getPackaging())); File target = new File(getDataDir(), "modules"); getLog().info("Deploying module " + source + " into " + target); new ModuleDeployer(target, new MojoLogger(getLog())).deployModule(source); getLog().info("...done"); } private void deployModuleAsDependency(Artifact module) throws Exception { File target = new File(getDataDir(), "modules"); getLog().info("Deploying module " + module.getArtifactId() + " into " + target + "..."); try { File file = resolveArtifactFile(module); new ModuleDeployer(target, new MojoLogger(getLog())).deployModule(file); } catch (Exception e) { getLog().error(e); } getLog().info("...done"); } private void deployPrepackagedSiteProject() throws Exception { if (project.getAttachedArtifacts().size() > 0) { Artifact artifact = (Artifact) project.getAttachedArtifacts() .get(project.getAttachedArtifacts().size() - 1); try { artifactResolver.resolve(artifact, project.getRemoteArtifactRepositories(), localRepository); File libDir = new File(getDataDir(), "prepackagedSites"); libDir.mkdirs(); File file = new File(libDir, artifact.getArtifactId() + ".zip"); getLog().info("Deploying prepackaged site " + artifact.getFile().getName() + " to " + file); FileUtils.copyFile(artifact.getFile(), file); } catch (Exception e) { e.printStackTrace(); } } } private void deployPrepackagedSiteAsDependency(Artifact artifact) throws Exception { File target = new File(getDataDir(), "prepackagedSites"); getLog().info("Deploying prepackaged site " + artifact.getArtifactId() + " into " + target + "..."); try { File file = resolveArtifactFile(artifact); FileUtils.copyFile(file, new File(target, artifact.getArtifactId() + ".zip")); } catch (Exception e) { getLog().error(e); } getLog().info("...done"); } /** * Copy JAR file to jahia webapp, tries to hotswap classes * @throws Exception */ private void deployJarProject() { Artifact artifact = project.getArtifact(); try { artifactResolver.resolve(artifact, project.getRemoteArtifactRepositories(), localRepository); File libDir = new File(new File(getWebappDeploymentDir(), "WEB-INF"), "lib"); getLog().info("Deploying jar file " + artifact.getFile().getName() + " to " + libDir); File deployedJar = new File(libDir, artifact.getFile().getName()); boolean needHotSwap = deployedJar.exists(); FileUtils.copyFileToDirectory(artifact.getFile(), libDir); if (needHotSwap) { hotSwap(deployedJar); } } catch (Exception e) { getLog().error("Error while deploying JAR project", e); } } /** * Look if the pom depends on a jahia-ear project and deploys it * @throws Exception */ private void deployPomProject() { try { boolean isJahiaServerGroup = project.getGroupId().equals("org.jahia.server"); if (isJahiaServerGroup && JAHIA_PACKAGE_PROJECTS.contains(project.getArtifactId())) { deployPackage(); } else if ((project.getParent() != null) && ("prepackagedSites".equals(project.getParent().getArtifactId())) || project.getGroupId().equals("org.jahia.prepackagedsites")) { deployPrepackagedSiteProject(); } else { boolean jdbcDrivers = isJahiaServerGroup && project.getArtifactId().startsWith("jdbc-drivers"); boolean sharedLibraries = isJahiaServerGroup && project.getArtifactId().equals("shared-libraries"); DependencyNode rootNode = getRootDependencyNode(); List<?> l = rootNode.getChildren(); for (Iterator<?> iterator = l.iterator(); iterator.hasNext();) { DependencyNode dependencyNode = (DependencyNode) iterator.next(); Artifact artifact = dependencyNode.getArtifact(); if (artifact.getGroupId().equals("org.jahia.server")) { String artifactId = artifact.getArtifactId(); if ((artifactId.equals("jahia-war") || artifactId.equals("jahia-ee-war") || artifactId.equals("jahia-gwt") && artifact.getType().equals("war")) && !StringUtils.equals(artifact.getClassifier(), "data-package")) { deployWarDependency(dependencyNode); } else if (artifactId.equals("shared-libraries") || artifactId.startsWith("jdbc-drivers")) { deploySharedLibraries(dependencyNode); } else if (JAHIA_PACKAGE_PROJECTS.contains(artifactId) || (artifactId.equals("jahia-war") || artifactId.equals("jahia-ee-war")) && StringUtils.equals(artifact.getClassifier(), "data-package")) { deployPackageFromDepenendency(artifact); } } else if (artifact.getGroupId().equals("org.jahia.modules") || (deployTests && artifact.getGroupId().equals("org.jahia.test")) || artifact.getGroupId().endsWith(".jahia.modules")) { deployModuleAsDependency(artifact); } else if (artifact.getGroupId().equals("org.jahia.prepackagedsites")) { deployPrepackagedSiteAsDependency(artifact); } if (sharedLibraries) { deploySharedLibrary(artifact); } else if (jdbcDrivers) { deployJdbcDriver(artifact); } } } } catch (Exception e) { getLog().error("Error while deploying POM project", e); } } private void deployPackage() { getLog().info("Deploying Digital Experience Manager data package " + project.getArtifactId() + "..."); try { File file = null; getLog().info("Resolving artifact file..."); if (project.getAttachedArtifacts().size() > 0) { Artifact artifact = (Artifact) project.getAttachedArtifacts() .get(project.getAttachedArtifacts().size() - 1); artifactResolver.resolve(artifact, project.getRemoteArtifactRepositories(), localRepository); file = artifact.getFile(); } else { file = getAetherHelper().resolveArtifactFile(project.getGroupId() + ":" + project.getArtifactId() + ":zip:package:" + project.getArtifact().getVersion()); } getLog().info("...resolved to: " + file); deployPackageFile(file); } catch (Exception e) { getLog().error(e); } } private void deployPackageFromDepenendency(Artifact dependency) { getLog().info("Deploying Digital Experience Manager data package " + dependency.getArtifactId() + "..."); try { File file = resolveArtifactFile(dependency); deployPackageFile(file); } catch (Exception e) { getLog().error(e); } } private File resolveArtifactFile(Artifact artifact) throws MojoExecutionException { File file = null; getLog().info("Resolving artifact file..."); file = getAetherHelper().resolveArtifactFile( artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getType() + ":" + (StringUtils.isNotEmpty(artifact.getClassifier()) ? (artifact.getClassifier() + ":") : "") + artifact.getVersion()); getLog().info("...resolved to: " + file); return file; } private void deployPackageFile(File packageFile) { getLog().info("Deploying Digital Experience Manager data package file " + packageFile + "..."); try { getLog().info("Extracting content to data directory " + getDataDir() + "..."); ZipUnArchiver unarch = new ZipUnArchiver(packageFile); unarch.enableLogging(getLog().isDebugEnabled() ? new ConsoleLogger(Logger.LEVEL_DEBUG, "console") : new ConsoleLogger()); unarch.setDestDirectory(getDataDir()); unarch.extract(); getLog().info("...done."); } catch (Exception e) { getLog().error(e); } } protected DependencyNode getRootDependencyNode() throws DependencyTreeBuilderException { return dependencyTreeBuilder.buildDependencyTree(project, localRepository, artifactFactory, artifactMetadataSource, null, artifactCollector); } private void deploySharedLibraries(DependencyNode dependencyNode) throws IOException, ArtifactResolutionException, ArtifactNotFoundException { boolean jdbcDrivers = dependencyNode.getArtifact().getArtifactId().startsWith("jdbc-drivers"); for (DependencyNode node : ((List<DependencyNode>) dependencyNode.getChildren())) { Artifact artifact = node.getArtifact(); artifactResolver.resolve(artifact, project.getRemoteArtifactRepositories(), localRepository); try { if (jdbcDrivers) { deployJdbcDriver(artifact); } else { deploySharedLibrary(artifact); } } catch (Exception e) { getLog().error("Error while deploying EAR dependency", e); } } } private void deploySharedLibrary(Artifact artifact) throws IOException { getLog().info("Copy shared resource " + artifact.getFile().getName()); getDeployer().deploySharedLibraries(artifact.getFile()); } private void deployJdbcDriver(Artifact artifact) throws IOException { getLog().info("Deploying JDBC driver " + artifact.getFile().getName()); getDeployer().deployJdbcDriver(artifact.getFile()); } /** * Deploy WAR artifact to application server * @param dependencyNode */ protected void deployWarDependency(DependencyNode dependencyNode) throws Exception { Artifact artifact = dependencyNode.getArtifact(); File webappDir = getWebappDeploymentDir(); getLog().info("Deploying artifact " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + "(file: " + artifact.getFile() + ")"); getLog().info("Updating " + artifact.getType() + " resources for " + getDeployer().getName() + " in directory " + webappDir); String[] excludes = getDeployer().getWarExcludes() != null ? StringUtils.split(getDeployer().getWarExcludes(), ",") : null; // if we are dealing with WAR overlay, we want to overwrite the target boolean overwrite = StringUtils.isNotEmpty(artifact.getClassifier()); try { ZipInputStream z = new ZipInputStream(new FileInputStream(artifact.getFile())); ZipEntry entry; int cnt = 0; while ((entry = z.getNextEntry()) != null) { if (!entry.isDirectory()) { if (excludes != null) { boolean doExclude = false; for (String excludePattern : excludes) { if (SelectorUtils.matchPath(excludePattern, entry.getName())) { doExclude = true; break; } } if (doExclude) { continue; } } File target = new File(webappDir, entry.getName()); if (overwrite || entry.getTime() > target.lastModified()) { target.getParentFile().mkdirs(); FileOutputStream fileOutputStream = new FileOutputStream(target); IOUtils.copy(z, fileOutputStream); fileOutputStream.close(); cnt++; } } else { //in the case of empty folders create anyway (new File(webappDir, entry.getName())).mkdir(); } } z.close(); getLog().info("Copied " + cnt + " files."); } catch (IOException e) { getLog().error("Error while deploying dependency", e); } } // *************** Hotswap private void hotSwap(File deployedJar) { int colonIndex = address.indexOf(':'); String connectorName = address.substring(0, colonIndex); if (connectorName.equals("socket")) connectorName = "com.sun.jdi.SocketAttach"; else if (connectorName.equals("shmem")) connectorName = "com.sun.jdi.SharedMemoryAttach"; String argumentsString = address.substring(colonIndex + 1); AttachingConnector connector = (AttachingConnector) findConnector(connectorName); Map<String, Argument> arguments = connector.defaultArguments(); StringTokenizer st = new StringTokenizer(argumentsString, ","); while (st.hasMoreTokens()) { String pair = st.nextToken(); int index = pair.indexOf('='); String name = pair.substring(0, index); String value = pair.substring(index + 1); Connector.Argument argument = (Connector.Argument) arguments.get(name); if (argument != null) { argument.setValue(value); } } Map<String, Long> dates = new HashMap<String, Long>(); try { ZipInputStream z = new ZipInputStream(new FileInputStream(deployedJar)); ZipEntry entry; while ((entry = z.getNextEntry()) != null) { dates.put(entry.getName(), entry.getTime()); } z.close(); } catch (IOException e) { e.printStackTrace(); } VirtualMachine vm = null; try { vm = connector.attach(arguments); getLog().info("Connected to " + vm.name() + " " + vm.version()); Map<String, File> files = new HashMap<String, File>(); parse(new File(output, "classes"), dates, "", files); getLog().debug("Classes : " + files.keySet()); if (!files.isEmpty()) { reload(vm, files); } } catch (ConnectException e) { getLog().warn("Cannot hotswap classes : " + e.getMessage()); } catch (IOException e) { e.printStackTrace(); } catch (IllegalConnectorArgumentsException e) { e.printStackTrace(); } finally { if (vm != null) { vm.dispose(); } } } private Connector findConnector(String name) { List<?> connectors = Bootstrap.virtualMachineManager().allConnectors(); Iterator<?> iter = connectors.iterator(); while (iter.hasNext()) { Connector connector = (Connector) iter.next(); if (connector.name().equals(name)) { return connector; } } return null; } private void parse(File folder, Map<String, Long> dates, String base, Map<String, File> result) { File[] files = folder.listFiles(); for (File file : files) { String filename = file.getName(); if (file.isDirectory()) { parse(file, dates, base + filename + ".", result); } else if (filename.endsWith(".class")) { String name = base + filename.substring(0, filename.lastIndexOf(".")); String classFileName = name.replace(".", "/") + ".class"; if (dates.containsKey(classFileName)) { long l = dates.get(classFileName); if (file.lastModified() > l) { result.put(name, file); getLog().debug("Updated class : " + file); } } } } } public void reload(VirtualMachine vm, Map<String, File> classFiles) { Map<ReferenceType, byte[]> map = new HashMap<ReferenceType, byte[]>(); for (String className : classFiles.keySet()) { List<?> classes = vm.classesByName(className); if (classes.size() != 1) { continue; } ReferenceType refType = (ReferenceType) classes.get(0); File f = classFiles.get(className); byte[] bytes = new byte[(int) f.length()]; try { InputStream in = new FileInputStream(f); in.read(bytes); in.close(); } catch (Exception e) { getLog().error("Error reading file " + f, e); continue; } map.put(refType, bytes); } try { vm.redefineClasses(map); getLog().info("Reloaded " + map.size() + " classes."); } catch (Exception e) { getLog().warn("Cannot reload classes : " + e.getMessage()); } } public AetherHelper getAetherHelper() throws MojoExecutionException { if (aetherHelper == null) { aetherHelper = AetherHelperFactory.create(container, project, mavenSession, getLog()); } return aetherHelper; } }