You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by js...@apache.org on 2017/04/16 16:18:09 UTC
[1/8] geode git commit: GEODE-2686: Remove JarClassLoader
Repository: geode
Updated Branches:
refs/heads/develop f272762f8 -> 6f7f94399
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
index c3d7f5e..b111e45 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
@@ -24,7 +24,7 @@ import org.apache.geode.cache.Cache;
import org.apache.geode.distributed.internal.ClusterConfigurationService;
import org.apache.geode.distributed.internal.InternalLocator;
import org.apache.geode.internal.ClassPathLoader;
-import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.internal.DeployedJar;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.lang.StringUtils;
@@ -36,6 +36,8 @@ import org.apache.geode.test.dunit.rules.Server;
import java.io.File;
import java.io.Serializable;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -137,7 +139,9 @@ public class ClusterConfig implements Serializable {
.collect(Collectors.toSet());
Set<String> actualJarNames = toSetIgnoringHiddenFiles(
serverVM.getWorkingDir().list((dir, filename) -> filename.contains(".jar")));
- assertThat(actualJarNames).isEqualTo(expectedJarNames);
+
+ // We will end up with extra jars on disk if they are deployed and then undeployed
+ assertThat(expectedJarNames).isSubsetOf(actualJarNames);
// verify config exists in memory
serverVM.invoke(() -> {
@@ -154,22 +158,21 @@ public class ClusterConfig implements Serializable {
}
for (String jar : this.getJarNames()) {
- JarClassLoader jarClassLoader = findJarClassLoader(jar);
- assertThat(jarClassLoader).isNotNull();
- assertThat(Class.forName(nameOfClassContainedInJar(jar), true, jarClassLoader)).isNotNull();
+ DeployedJar deployedJar = ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jar);
+ assertThat(deployedJar).isNotNull();
+ assertThat(Class.forName(nameOfClassContainedInJar(jar), true,
+ new URLClassLoader(new URL[] {deployedJar.getFileURL()}))).isNotNull();
}
- });
- }
- private static JarClassLoader findJarClassLoader(final String jarName) {
- Collection<ClassLoader> classLoaders = ClassPathLoader.getLatest().getClassLoaders();
- for (ClassLoader classLoader : classLoaders) {
- if (classLoader instanceof JarClassLoader
- && ((JarClassLoader) classLoader).getJarName().equals(jarName)) {
- return (JarClassLoader) classLoader;
+ // If we have extra jars on disk left over from undeploy, make sure they aren't used
+ Set<String> undeployedJarNames = new HashSet<>(actualJarNames);
+ undeployedJarNames.removeAll(expectedJarNames);
+ for (String jar : undeployedJarNames) {
+ DeployedJar undeployedJar =
+ ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jar);
+ assertThat(undeployedJar).isNull();
}
- }
- return null;
+ });
}
@@ -183,7 +186,7 @@ public class ClusterConfig implements Serializable {
}
private static String getServerJarName(String jarName) {
- return JarDeployer.JAR_PREFIX + jarName + "#1";
+ return jarName.replace(".jar", "") + ".v1.jar";
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
index 0a4785d..19a1662 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
@@ -14,6 +14,7 @@
*/
package org.apache.geode.test.dunit.rules;
+import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException;
import static org.assertj.core.api.Assertions.assertThat;
import org.apache.geode.internal.lang.StringUtils;
@@ -23,6 +24,7 @@ import org.apache.geode.management.internal.cli.HeadlessGfsh;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.result.CommandResult;
import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.test.dunit.IgnoredException;
import org.apache.geode.test.junit.rules.DescribedExternalResource;
import org.json.JSONArray;
import org.junit.rules.TemporaryFolder;
@@ -58,6 +60,7 @@ public class GfshShellConnectionRule extends DescribedExternalResource {
private PortType portType = PortType.jmxManger;
private HeadlessGfsh gfsh = null;
private boolean connected = false;
+ private IgnoredException ignoredException;
private TemporaryFolder temporaryFolder = new TemporaryFolder();
public GfshShellConnectionRule() {
@@ -78,6 +81,9 @@ public class GfshShellConnectionRule extends DescribedExternalResource {
protected void before(Description description) throws Throwable {
this.gfsh = new HeadlessGfsh(getClass().getName(), 30,
temporaryFolder.newFolder("gfsh_files").getAbsolutePath());
+ ignoredException =
+ addIgnoredException("java.rmi.NoSuchObjectException: no such object in table");
+
// do not auto connect if no port initialized
if (portSupplier == null) {
return;
@@ -168,6 +174,10 @@ public class GfshShellConnectionRule extends DescribedExternalResource {
@Override
protected void after(Description description) throws Throwable {
close();
+
+ if (ignoredException != null) {
+ ignoredException.remove();
+ }
}
public void disconnect() throws Exception {
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java
index 5f4cd74..2a6a03b 100644
--- a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java
+++ b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java
@@ -33,7 +33,7 @@ import org.apache.geode.test.junit.runner.SuiteRunner;
ListAndDescribeDiskStoreCommandsDUnitTest.class, ListIndexCommandDUnitTest.class,
MemberCommandsDUnitTest.class, MiscellaneousCommandsDUnitTest.class,
QueueCommandsDUnitTest.class, ShellCommandsDUnitTest.class, ShowDeadlockDUnitTest.class,
- ShowMetricsDUnitTest.class, ShowStackTraceDUnitTest.class, UserCommandsDUnitTest.class})
+ ShowMetricsDUnitTest.class, ShowStackTraceDUnitTest.class})
public class CommandOverHttpDUnitTest {
@ClassRule
public static ProvideSystemProperty provideSystemProperty =
[6/8] geode git commit: GEODE-2705: Jars undeployed from cluster
configuration will not be loaded from disk on member restart
Posted by js...@apache.org.
GEODE-2705: Jars undeployed from cluster configuration will not be loaded from disk on member restart
Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/ee11b0a4
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/ee11b0a4
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/ee11b0a4
Branch: refs/heads/develop
Commit: ee11b0a43b66a42eb10a16b92993436b2298c042
Parents: 6fd2d12
Author: Jared Stewart <js...@pivotal.io>
Authored: Thu Apr 6 10:22:26 2017 -0700
Committer: Jared Stewart <js...@pivotal.io>
Committed: Sun Apr 16 09:10:01 2017 -0700
----------------------------------------------------------------------
.../org/apache/geode/internal/DeployedJar.java | 6 +
.../org/apache/geode/internal/JarDeployer.java | 148 +++++++++++--------
.../cache/ClusterConfigurationLoader.java | 30 +++-
.../geode/internal/cache/GemFireCacheImpl.java | 7 +-
.../ClassPathLoaderIntegrationTest.java | 10 +-
.../geode/internal/ClassPathLoaderTest.java | 58 --------
.../internal/JarDeployerIntegrationTest.java | 63 +++++++-
.../geode/management/DeployJarTestSuite.java | 4 +-
.../internal/configuration/ClusterConfig.java | 23 ++-
.../ClusterConfigDeployJarDUnitTest.java | 76 ++++++++++
10 files changed, 278 insertions(+), 147 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java b/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
index f4f4028..8adec1f 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
@@ -85,6 +85,9 @@ public class DeployedJar {
this(versionedJarFile, jarName, Files.readAllBytes(versionedJarFile.toPath()));
}
+ /**
+ * Writes the given jarBytes to versionedJarFile
+ */
public DeployedJar(File versionedJarFile, final String jarName, byte[] jarBytes)
throws IOException {
Assert.assertTrue(jarBytes != null, "jarBytes cannot be null");
@@ -377,6 +380,9 @@ public class DeployedJar {
return new byte[0];
}
+ /**
+ * @return the unversioned name of this jar file, e.g. myJar.jar
+ */
public String getJarName() {
return this.jarName;
}
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
index ad5c435..669802c 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
@@ -18,10 +18,6 @@ import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.geode.GemFireException;
-import org.apache.geode.GemFireIOException;
-import org.apache.geode.SystemFailure;
import org.apache.geode.internal.logging.LogService;
import org.apache.logging.log4j.Logger;
@@ -34,13 +30,9 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
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.Comparator;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -83,11 +75,23 @@ public class JarDeployer implements Serializable {
return this.deployDirectory;
}
+ /**
+ * Writes the jarBytes for the given jarName to the next version of that jar file (if the bytes do
+ * not match the latest deployed version)
+ *
+ * @return the DeployedJar that was written from jarBytes, or null if those bytes matched the
+ * latest deployed version
+ */
public DeployedJar deployWithoutRegistering(final String jarName, final byte[] jarBytes)
throws IOException {
lock.lock();
try {
+ boolean shouldDeployNewVersion = shouldDeployNewVersion(jarName, jarBytes);
+ if (!shouldDeployNewVersion) {
+ return null;
+ }
+
verifyWritableDeployDirectory();
File newVersionedJarFile = getNextVersionedJarFile(jarName);
@@ -129,6 +133,7 @@ public class JarDeployer implements Serializable {
lock.unlock();
}
+
protected File getNextVersionedJarFile(String unversionedJarName) {
File[] oldVersions = findSortedOldVersionsOfJar(unversionedJarName);
@@ -246,21 +251,17 @@ public class JarDeployer implements Serializable {
}
}
- protected Set<String> findDistinctDeployedJars() {
+ protected Set<String> findDistinctDeployedJarsOnDisk() {
// Find all deployed JAR files
- final File[] oldFiles = this.deployDirectory.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(final File file, final String name) {
- return versionedPattern.matcher(name).matches();
- }
- });
+ final File[] oldFiles =
+ this.deployDirectory.listFiles((file, name) -> versionedPattern.matcher(name).matches());
// Now add just the original JAR name to the set
- final Set<String> jarNames = new HashSet<String>();
+ final Set<String> jarNames = new HashSet<>();
for (File oldFile : oldFiles) {
Matcher matcher = versionedPattern.matcher(oldFile.getName());
matcher.find();
- jarNames.add(matcher.group(1));
+ jarNames.add(matcher.group(1) + ".jar");
}
return jarNames;
}
@@ -368,60 +369,39 @@ public class JarDeployer implements Serializable {
String newJarName = unversionedJarNameWithoutExtension + ".v" + jarVersion + ".jar";
File newJar = new File(this.deployDirectory, newJarName);
- logger.debug("Renaming deployed jar from " + oldJar.getCanonicalPath() + " to "
- + newJar.getCanonicalPath());
+ logger.debug("Renaming deployed jar from {} to {}", oldJar.getCanonicalPath(),
+ newJar.getCanonicalPath());
FileUtils.moveFile(oldJar, newJar);
- FileUtils.deleteQuietly(oldJar);
}
/**
- * Re-deploy all previously deployed JAR files.
+ * Re-deploy all previously deployed JAR files on disk.
*/
- public void loadPreviouslyDeployedJars() {
+ public void loadPreviouslyDeployedJarsFromDisk() {
+ logger.info("Loading previously deployed jars");
lock.lock();
try {
verifyWritableDeployDirectory();
renameJarsWithOldNamingConvention();
- final Set<String> jarNames = findDistinctDeployedJars();
+ final Set<String> jarNames = findDistinctDeployedJarsOnDisk();
if (jarNames.isEmpty()) {
return;
}
- Map<String, DeployedJar> latestVersionOfEachJar = new LinkedHashMap<>();
+ List<DeployedJar> latestVersionOfEachJar = new ArrayList<>();
for (String jarName : jarNames) {
- final File[] jarFiles = findSortedOldVersionsOfJar(jarName);
-
- Optional<File> latestValidDeployedJarOptional =
- Arrays.stream(jarFiles).filter(Objects::nonNull).filter(jarFile -> {
- try {
- return DeployedJar.isValidJarContent(FileUtils.readFileToByteArray(jarFile));
- } catch (IOException e) {
- return false;
- }
- }).findFirst();
-
- if (!latestValidDeployedJarOptional.isPresent()) {
- // No valid version of this jar
- continue;
- }
+ DeployedJar deployedJar = findLatestValidDeployedJarFromDisk(jarName);
- File latestValidDeployedJar = latestValidDeployedJarOptional.get();
- latestVersionOfEachJar.put(jarName, new DeployedJar(latestValidDeployedJar, jarName));
-
- // Remove any old left-behind versions of this JAR file
- for (File jarFile : jarFiles) {
- if (!latestValidDeployedJar.equals(jarFile)) {
- FileUtils.deleteQuietly(jarFile);
- }
+ if (deployedJar != null) {
+ latestVersionOfEachJar.add(deployedJar);
+ deleteOtherVersionsOfJar(deployedJar);
}
}
- registerNewVersions(latestVersionOfEachJar.values().stream().collect(toList()));
- // ClassPathLoader.getLatest().deploy(latestVersionOfEachJar.keySet().toArray(),
- // latestVersionOfEachJar.values().toArray())
+ registerNewVersions(latestVersionOfEachJar);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
@@ -429,6 +409,43 @@ public class JarDeployer implements Serializable {
}
}
+ /**
+ * Deletes all versions of this jar on disk other than the given version
+ */
+ public void deleteOtherVersionsOfJar(DeployedJar deployedJar) {
+ logger.info("Deleting all versions of " + deployedJar.getJarName() + " other than "
+ + deployedJar.getFileName());
+ final File[] jarFiles = findSortedOldVersionsOfJar(deployedJar.getJarName());
+
+ Stream.of(jarFiles).filter(jarFile -> !jarFile.equals(deployedJar.getFile()))
+ .forEach(jarFile -> {
+ logger.info("Deleting old version of jar: " + jarFile.getAbsolutePath());
+ FileUtils.deleteQuietly(jarFile);
+ });
+ }
+
+ public DeployedJar findLatestValidDeployedJarFromDisk(String unversionedJarName)
+ throws IOException {
+ final File[] jarFiles = findSortedOldVersionsOfJar(unversionedJarName);
+
+ Optional<File> latestValidDeployedJarOptional =
+ Arrays.stream(jarFiles).filter(Objects::nonNull).filter(jarFile -> {
+ try {
+ return DeployedJar.isValidJarContent(FileUtils.readFileToByteArray(jarFile));
+ } catch (IOException e) {
+ return false;
+ }
+ }).findFirst();
+
+ if (!latestValidDeployedJarOptional.isPresent()) {
+ // No valid version of this jar
+ return null;
+ }
+
+ File latestValidDeployedJar = latestValidDeployedJarOptional.get();
+
+ return new DeployedJar(latestValidDeployedJar, unversionedJarName);
+ }
public URL[] getDeployedJarURLs() {
return this.deployedJars.values().stream().map(DeployedJar::getFileURL).toArray(URL[]::new);
@@ -441,6 +458,7 @@ public class JarDeployer implements Serializable {
try {
for (DeployedJar deployedJar : deployedJars) {
if (deployedJar != null) {
+ logger.info("Registering new version of jar: {}", deployedJar.toString());
DeployedJar oldJar = this.deployedJars.put(deployedJar.getJarName(), deployedJar);
if (oldJar != null) {
oldJar.cleanUp();
@@ -488,13 +506,7 @@ public class JarDeployer implements Serializable {
String jarName = jarNames[i];
byte[] newJarBytes = jarBytes[i];
- boolean shouldDeployNewVersion = shouldDeployNewVersion(jarName, newJarBytes);
-
- if (shouldDeployNewVersion) {
- deployedJars[i] = deployWithoutRegistering(jarName, newJarBytes);
- } else {
- deployedJars[i] = null;
- }
+ deployedJars[i] = deployWithoutRegistering(jarName, newJarBytes);
}
return registerNewVersions(Arrays.asList(deployedJars));
@@ -511,7 +523,7 @@ public class JarDeployer implements Serializable {
}
if (oldDeployedJar.hasSameContentAs(newJarBytes)) {
- logger.warn("Jar is identical to the latest deployed version: ",
+ logger.warn("Jar is identical to the latest deployed version: {}",
oldDeployedJar.getFileCanonicalPath());
return false;
@@ -520,6 +532,11 @@ public class JarDeployer implements Serializable {
return true;
}
+ /**
+ * Returns the latest registered {@link DeployedJar} for the given JarName
+ *
+ * @param jarName - the unversioned jar name, e.g. myJar.jar
+ */
public DeployedJar findDeployedJar(String jarName) {
return this.deployedJars.get(jarName);
}
@@ -565,9 +582,24 @@ public class JarDeployer implements Serializable {
deployedJar.cleanUp();
+ deleteAllVersionsOfJar(jarName);
return deployedJar.getFileCanonicalPath();
} finally {
lock.unlock();
}
}
+
+ public void deleteAllVersionsOfJar(String unversionedJarName) {
+ lock.lock();
+ try {
+ File[] jarFiles = findSortedOldVersionsOfJar(unversionedJarName);
+ for (File jarFile : jarFiles) {
+ logger.info("Deleting: {}", jarFile.getAbsolutePath());
+ FileUtils.deleteQuietly(jarFile);
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ }
}
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
index 2b627b2..55e3542 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
@@ -14,6 +14,9 @@
*/
package org.apache.geode.internal.cache;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -27,7 +30,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
+import java.util.stream.Stream;
+import org.apache.commons.lang.ArrayUtils;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.logging.log4j.Logger;
@@ -61,21 +66,36 @@ public class ClusterConfigurationLoader {
*/
public static void deployJarsReceivedFromClusterConfiguration(Cache cache,
ConfigurationResponse response) throws IOException, ClassNotFoundException {
+ logger.info("Requesting cluster configuration");
if (response == null) {
return;
}
String[] jarFileNames = response.getJarNames();
byte[][] jarBytes = response.getJars();
+ logger.info("Got response with jars: {}", Stream.of(jarFileNames).collect(joining(",")));
if (jarFileNames != null && jarBytes != null) {
- List<DeployedJar> deployedJars =
- ClassPathLoader.getLatest().getJarDeployer().deploy(jarFileNames, jarBytes);
+ JarDeployer jarDeployer = ClassPathLoader.getLatest().getJarDeployer();
+ jarDeployer.suspendAll();
+ try {
+ List<String> extraJarsOnServer =
+ jarDeployer.findDeployedJars().stream().map(DeployedJar::getJarName)
+ .filter(jarName -> !ArrayUtils.contains(jarFileNames, jarName)).collect(toList());
+
+ for (String extraJar : extraJarsOnServer) {
+ logger.info("Removing jar not present in cluster configuration: {}", extraJar);
+ jarDeployer.deleteAllVersionsOfJar(extraJar);
+ }
- deployedJars.stream().filter(Objects::nonNull)
- .forEach((jar) -> logger.info("Deployed " + (jar.getFile().getAbsolutePath())));
+ List<DeployedJar> deployedJars = jarDeployer.deploy(jarFileNames, jarBytes);
+
+ deployedJars.stream().filter(Objects::nonNull)
+ .forEach((jar) -> logger.info("Deployed: {}", jar.getFile().getAbsolutePath()));
+ } finally {
+ jarDeployer.resumeAll();
+ }
}
- // TODO: Jared - Does this need to actually undeploy extra jars like the javadoc says?
}
/***
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
index fb311e7..069b608 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
@@ -108,7 +108,6 @@ import org.apache.geode.distributed.internal.membership.InternalDistributedMembe
import org.apache.geode.i18n.LogWriterI18n;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.ClassPathLoader;
-import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.SystemTimer;
import org.apache.geode.internal.cache.control.InternalResourceManager;
import org.apache.geode.internal.cache.control.InternalResourceManager.ResourceType;
@@ -1238,8 +1237,10 @@ public class GemFireCacheImpl
initializeServices();
try {
- // Deploy all the jars from the deploy working dir.
- ClassPathLoader.getLatest().getJarDeployer().loadPreviouslyDeployedJars();
+ if (configurationResponse == null) {
+ // Deploy all the jars from the deploy working dir.
+ ClassPathLoader.getLatest().getJarDeployer().loadPreviouslyDeployedJarsFromDisk();
+ }
ClusterConfigurationLoader.applyClusterXmlConfiguration(this, configurationResponse,
system.getConfig());
initializeDeclarativeCache();
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
index d30feb6..14108c7 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
@@ -91,7 +91,7 @@ public class ClassPathLoaderIntegrationTest {
fos.write(new byte[TEMP_FILE_BYTES_COUNT]);
fos.close();
- System.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
+ // System.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
ClassPathLoader.setLatestToDefault(temporaryFolder.getRoot());
}
@@ -226,9 +226,7 @@ public class ClassPathLoaderIntegrationTest {
outStream.write(jarBytes);
outStream.close();
- Properties properties = new Properties();
- properties.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
- ServerStarterRule serverStarterRule = new ServerStarterRule();
+ ServerStarterRule serverStarterRule = new ServerStarterRule(temporaryFolder.getRoot());
serverStarterRule.startServer();
GemFireCacheImpl gemFireCache = GemFireCacheImpl.getInstance();
@@ -248,9 +246,7 @@ public class ClassPathLoaderIntegrationTest {
File jarVersion1 = createVersionOfJar("Version1", "MyFunction", "MyJar.jar");
File jarVersion2 = createVersionOfJar("Version2", "MyFunction", "MyJar.jar");
- Properties properties = new Properties();
- properties.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
- ServerStarterRule serverStarterRule = new ServerStarterRule();
+ ServerStarterRule serverStarterRule = new ServerStarterRule(temporaryFolder.getRoot());
serverStarterRule.startServer();
GemFireCacheImpl gemFireCache = GemFireCacheImpl.getInstance();
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
index 0d26caf..0e37075 100755
--- a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
@@ -494,39 +494,6 @@ public class ClassPathLoaderTest {
}
}
- private static void exploreClassLoader(ClassLoader cl, int indent) {
- String prefix = "";
- for (int i = 0; i < indent; i++) {
- prefix += "\t";
- }
- System.out.println(prefix + "ClassLoader toString() = " + cl);
-
- Class<?> clazz = cl.getClass();
- System.out.println(prefix + "ClassLoader getClass().getName() = " + clazz.getName());
- exploreClassLoaderSuperClass(prefix, clazz);
-
- try {
- URL[] urls = ((URLClassLoader) cl).getURLs();
- StringBuilder sb = new StringBuilder(prefix).append("ClassLoader getURLs = [");
- for (int i = 0; i < urls.length; i++) {
- if (i > 0) {
- sb.append(", ");
- }
- sb.append(urls[i].toString());
- }
- sb.append("]");
- System.out.println(sb.toString());
- } catch (Exception e) {
- System.out.println(prefix + "ClassLoader is not a URLClassLoader");
- }
-
- ClassLoader parent = cl.getParent();
- if (parent != null) {
- System.out.println(prefix + "ClassLoader has parent...");
- exploreClassLoader(parent, ++indent);
- }
- }
-
private static void exploreClassLoaderSuperClass(String prefix, Class<?> clazz) {
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null) {
@@ -646,31 +613,6 @@ public class ClassPathLoaderTest {
}
}
- static class OneClassClassLoader extends ClassLoader {
-
- private final GeneratingClassLoader genClassLoader = new GeneratingClassLoader();
- private String className;
-
- public OneClassClassLoader(final String className) {
- super(null); // no parent!!
- this.className = className;
- }
-
- @Override
- public Class<?> findClass(String name) throws ClassNotFoundException {
- if (!name.equals(className)) {
- throw new ClassNotFoundException();
- } else {
- return this.genClassLoader.findClass(name);
- }
- }
-
- @Override
- public boolean equals(final Object other) {
- return (other instanceof OneClassClassLoader);
- }
- }
-
@SuppressWarnings("serial")
static class BrokenError extends Error {
}
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
index 9e42c20..e9af0e7 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
@@ -17,7 +17,6 @@
package org.apache.geode.internal;
-import static org.apache.geode.internal.Assert.fail;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -31,7 +30,6 @@ import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.util.Set;
-import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -87,7 +85,7 @@ public class JarDeployerIntegrationTest {
assertThat(sortedOldJars).hasSize(2);
assertThat(sortedOldJars[0].getName()).contains(".v2.");
assertThat(sortedOldJars[1].getName()).contains(".v1.");
- assertThat(jarDeployer.findDistinctDeployedJars()).hasSize(1);
+ assertThat(jarDeployer.findDistinctDeployedJarsOnDisk()).hasSize(1);
}
@Test
@@ -208,4 +206,63 @@ public class JarDeployerIntegrationTest {
}
+ @Test
+ public void testDeleteAllVersionsOfJar() throws Exception {
+ File deployDir = jarDeployer.getDeployDirectory();
+
+ File jarAVersion1 = new File(deployDir, "myJarA.v1.jar");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion1);
+
+ File jarAVersion2 = new File(deployDir, "myJarA.v2.jar");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion2);
+
+ File jarBVersion2 = new File(deployDir, "myJarB.v2.jar");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion2);
+
+ File jarBVersion3 = new File(deployDir, "myJarB.v3.jar");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion3);
+
+ jarDeployer.deleteAllVersionsOfJar("myJarA.jar");
+
+ assertThat(jarAVersion1).doesNotExist();
+ assertThat(jarAVersion2).doesNotExist();
+ assertThat(jarBVersion2).exists();
+ assertThat(jarBVersion3).exists();
+ }
+
+
+ @Test
+ public void testDeleteOtherVersionsOfJar() throws Exception {
+ File deployDir = jarDeployer.getDeployDirectory();
+
+ File jarAVersion1 = new File(deployDir, "myJarA.v1.jar");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion1);
+
+ File jarAVersion2 = new File(deployDir, "myJarA.v2.jar");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion2);
+
+ File jarBVersion2 = new File(deployDir, "myJarB.v2.jar");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion2);
+
+ File jarBVersion3 = new File(deployDir, "myJarB.v3.jar");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion3);
+
+ DeployedJar deployedJarBVersion3 = new DeployedJar(jarBVersion3, "myJarB.jar");
+ jarDeployer.deleteOtherVersionsOfJar(deployedJarBVersion3);
+
+ assertThat(jarAVersion1).exists();
+ assertThat(jarAVersion2).exists();
+ assertThat(jarBVersion2).doesNotExist();
+ assertThat(jarBVersion3).exists();
+
+ DeployedJar deployedJarAVersion1 = new DeployedJar(jarAVersion1, "myJarA.jar");
+ jarDeployer.deleteOtherVersionsOfJar(deployedJarAVersion1);
+
+ assertThat(jarAVersion1).exists();
+ assertThat(jarAVersion2).doesNotExist();
+ assertThat(jarBVersion2).doesNotExist();
+ assertThat(jarBVersion3).exists();
+ }
+
+
}
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
index 3149432..ee46cbf 100644
--- a/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
+++ b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
@@ -20,12 +20,14 @@ import org.apache.geode.internal.DeployedJarJUnitTest;
import org.apache.geode.internal.JarDeployerIntegrationTest;
import org.apache.geode.management.internal.cli.commands.DeployCommandRedeployDUnitTest;
import org.apache.geode.management.internal.cli.commands.DeployCommandsDUnitTest;
+import org.apache.geode.management.internal.configuration.ClusterConfigDeployJarDUnitTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({DeployedJarJUnitTest.class, DeployCommandsDUnitTest.class,
JarDeployerIntegrationTest.class, ClassPathLoaderIntegrationTest.class,
- ClassPathLoaderTest.class, DeployCommandRedeployDUnitTest.class})
+ ClassPathLoaderTest.class, DeployCommandRedeployDUnitTest.class,
+ ClusterConfigDeployJarDUnitTest.class})
public class DeployJarTestSuite {
}
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
index b111e45..fc920c4 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfig.java
@@ -17,6 +17,7 @@
package org.apache.geode.management.internal.configuration;
+import static java.util.stream.Collectors.toSet;
import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE_SIZE_LIMIT;
import static org.assertj.core.api.Assertions.assertThat;
@@ -47,6 +48,7 @@ import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class ClusterConfig implements Serializable {
private List<ConfigGroup> groups;
@@ -89,7 +91,7 @@ public class ClusterConfig implements Serializable {
public void verifyLocator(MemberVM<Locator> locatorVM) {
Set<String> expectedGroupConfigs =
- this.getGroups().stream().map(ConfigGroup::getName).collect(Collectors.toSet());
+ this.getGroups().stream().map(ConfigGroup::getName).collect(toSet());
// verify info exists in memeory
locatorVM.invoke(() -> {
@@ -135,10 +137,12 @@ public class ClusterConfig implements Serializable {
public void verifyServer(MemberVM<Server> serverVM) throws ClassNotFoundException {
// verify files exist in filesystem
- Set<String> expectedJarNames = this.getJarNames().stream().map(ClusterConfig::getServerJarName)
- .collect(Collectors.toSet());
- Set<String> actualJarNames = toSetIgnoringHiddenFiles(
- serverVM.getWorkingDir().list((dir, filename) -> filename.contains(".jar")));
+ Set<String> expectedJarNames = this.getJarNames().stream().collect(toSet());
+
+ String[] actualJarFiles =
+ serverVM.getWorkingDir().list((dir, filename) -> filename.contains(".jar"));
+ Set<String> actualJarNames = Stream.of(actualJarFiles)
+ .map(jar -> jar.replaceAll("\\.v\\d+\\.jar", ".jar")).collect(toSet());
// We will end up with extra jars on disk if they are deployed and then undeployed
assertThat(expectedJarNames).isSubsetOf(actualJarNames);
@@ -168,6 +172,7 @@ public class ClusterConfig implements Serializable {
Set<String> undeployedJarNames = new HashSet<>(actualJarNames);
undeployedJarNames.removeAll(expectedJarNames);
for (String jar : undeployedJarNames) {
+ System.out.println("Verifying undeployed jar: " + jar);
DeployedJar undeployedJar =
ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jar);
assertThat(undeployedJar).isNull();
@@ -181,15 +186,9 @@ public class ClusterConfig implements Serializable {
if (array == null) {
return new HashSet<>();
}
- return Arrays.stream(array).filter((String name) -> !name.startsWith("."))
- .collect(Collectors.toSet());
- }
-
- private static String getServerJarName(String jarName) {
- return jarName.replace(".jar", "") + ".v1.jar";
+ return Arrays.stream(array).filter((String name) -> !name.startsWith(".")).collect(toSet());
}
-
private static String nameOfClassContainedInJar(String jarName) {
switch (jarName) {
case "cluster.jar":
http://git-wip-us.apache.org/repos/asf/geode/blob/ee11b0a4/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
index 7cc84d6..980f81f 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
@@ -17,6 +17,7 @@ package org.apache.geode.management.internal.configuration;
import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
import static org.assertj.core.api.Assertions.assertThat;
import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
@@ -143,6 +144,7 @@ public class ClusterConfigDeployJarDUnitTest extends ClusterConfigBaseTest {
serverProps.setProperty(GROUPS, "group2");
MemberVM server2 = lsRule.startServerVM(2, serverProps, locator.getPort());
serverProps.setProperty(GROUPS, "group1,group2");
+ serverProps.setProperty(LOG_LEVEL, "info");
MemberVM server3 = lsRule.startServerVM(3, serverProps, locator.getPort());
ConfigGroup cluster = new ConfigGroup("cluster");
@@ -178,6 +180,80 @@ public class ClusterConfigDeployJarDUnitTest extends ClusterConfigBaseTest {
// test undeploy cluster
gfshConnector.executeAndVerifyCommand("undeploy --jar=cluster.jar");
+
+ cluster = cluster.removeJar("cluster.jar");
+ server3Config.verify(locator);
+ server1Config.verify(server1);
+ server2Config.verify(server2);
+ server3Config.verify(server3);
+
+ gfshConnector.executeAndVerifyCommand("undeploy --jar=group1.jar --group=group1");
+
+ group1 = group1.removeJar("group1.jar");
+ /*
+ * TODO: This is the current (weird) behavior If you started server4 with group1,group2 after
+ * this undeploy command, it would have group1.jar (brought from
+ * cluster_config/group2/group1.jar on locator) whereas server3 (also in group1,group2) does not
+ * have this jar.
+ */
+ ClusterConfig weirdServer3Config =
+ new ClusterConfig(cluster, group1, new ConfigGroup(group2).removeJar("group1.jar"));
+
+ server3Config.verify(locator);
+ server1Config.verify(server1);
+ server2Config.verify(server2);
+ weirdServer3Config.verify(server3);
+ }
+
+ @Test
+ public void testUndeployWithServerBounce() throws Exception {
+ // set up the locator/servers
+ MemberVM locator = lsRule.startLocatorVM(0, locatorProps);
+ serverProps.setProperty(GROUPS, "group1");
+ MemberVM server1 = lsRule.startServerVM(1, serverProps, locator.getPort());
+ serverProps.setProperty(GROUPS, "group2");
+ MemberVM server2 = lsRule.startServerVM(2, serverProps, locator.getPort());
+ serverProps.setProperty(GROUPS, "group1,group2");
+ serverProps.setProperty(LOG_LEVEL, "info");
+ MemberVM server3 = lsRule.startServerVM(3, serverProps, locator.getPort());
+
+ ConfigGroup cluster = new ConfigGroup("cluster");
+ ConfigGroup group1 = new ConfigGroup("group1");
+ ConfigGroup group2 = new ConfigGroup("group2");
+ ClusterConfig expectedClusterConfig = new ClusterConfig(cluster);
+ ClusterConfig server1Config = new ClusterConfig(cluster, group1);
+ ClusterConfig server2Config = new ClusterConfig(cluster, group2);
+ ClusterConfig server3Config = new ClusterConfig(cluster, group1, group2);
+
+ gfshConnector.connect(locator);
+ assertThat(gfshConnector.isConnected()).isTrue();
+
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + clusterJar);
+
+ // deploy cluster.jar to the cluster
+ cluster.addJar("cluster.jar");
+ expectedClusterConfig.verify(locator);
+ expectedClusterConfig.verify(server1);
+ expectedClusterConfig.verify(server2);
+ expectedClusterConfig.verify(server3);
+
+ // deploy group1.jar to both group1 and group2
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + group1Jar + " --group=group1,group2");
+
+ group1.addJar("group1.jar");
+ group2.addJar("group1.jar");
+ server3Config.verify(locator);
+ server1Config.verify(server1);
+ server2Config.verify(server2);
+ server3Config.verify(server3);
+
+ server3.getVM().bounce();
+
+ // test undeploy cluster
+ gfshConnector.executeAndVerifyCommand("undeploy --jar=cluster.jar");
+ server3 = lsRule.startServerVM(3, serverProps, locator.getPort());
+
+
cluster = cluster.removeJar("cluster.jar");
server3Config.verify(locator);
server1Config.verify(server1);
[2/8] geode git commit: GEODE-2686: Remove JarClassLoader
Posted by js...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDUnitTest.java
deleted file mode 100644
index a365899..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDUnitTest.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * 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.geode.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.apache.geode.cache.execute.Execution;
-import org.apache.geode.cache.execute.FunctionService;
-import org.apache.geode.cache.execute.ResultCollector;
-import org.apache.geode.distributed.ConfigurationProperties;
-import org.apache.geode.distributed.DistributedSystem;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.test.dunit.Assert;
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.SerializableRunnable;
-import org.apache.geode.test.dunit.VM;
-import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
-import org.apache.geode.test.junit.categories.DistributedTest;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileLock;
-import java.nio.file.Files;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Pattern;
-
-/**
- * Unit tests for the JarDeployer class
- *
- * @since GemFire 7.0
- */
-@Category(DistributedTest.class)
-@SuppressWarnings("serial")
-public class JarDeployerDUnitTest extends JUnit4CacheTestCase {
-
- static FileLock savedFileLock = null;
- private final ClassBuilder classBuilder = new ClassBuilder();
-
- @Override
- public final void preTearDownCacheTestCase() throws Exception {
- JarDeployer jarDeployer = new JarDeployer();
- for (JarClassLoader jarClassLoader : jarDeployer.findJarClassLoaders()) {
- if (jarClassLoader.getJarName().startsWith("JarDeployerDUnit")) {
- jarDeployer.undeploy(jarClassLoader.getJarName());
- }
- }
- for (String functionName : FunctionService.getRegisteredFunctions().keySet()) {
- if (functionName.startsWith("JarDeployerDUnit")) {
- FunctionService.unregisterFunction(functionName);
- }
- }
- disconnectAllFromDS();
- deleteSavedJarFiles();
- }
-
-
-
- @Test
- public void testDeployExclusiveLock() throws IOException, ClassNotFoundException {
- final JarDeployer jarDeployer = new JarDeployer();
- final File currentDir = new File(".").getAbsoluteFile();
- final VM vm = Host.getHost(0).getVM(0);
-
- // Deploy the Class JAR file
- final File jarFile1 = jarDeployer.getNextVersionJarFile("JarDeployerDUnit.jar");
- byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDELA");
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitDELA");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- assertNotNull(ClassPathLoader.getLatest().getResource("JarDeployerDUnitDELA.class"));
-
- // Attempt to acquire an exclusive lock in the other VM
- vm.invoke(new SerializableRunnable() {
- @Override
- public void run() {
- FileOutputStream outStream = null;
- FileLock fileLock = null;
-
- try {
- outStream = new FileOutputStream(jarFile1, true);
- fileLock = outStream.getChannel().tryLock(0, 1, false);
- if (fileLock != null) {
- fail("Should not have been able to obtain exclusive lock on file:"
- + jarFile1.getAbsolutePath());
- }
- } catch (FileNotFoundException fnfex) {
- Assert.fail("JAR file not found where expected", fnfex);
- } catch (IOException ioex) {
- Assert.fail("IOException when trying to obtain exclusive lock", ioex);
- } finally {
- if (outStream != null) {
- try {
- outStream.close();
- } catch (IOException ioex) {
- fail("Could not close lock file output stream");
- }
- }
- if (fileLock != null) {
- try {
- fileLock.channel().close();
- } catch (IOException ioex) {
- fail("Could not close lock file channel");
- }
- }
- }
- }
- });
- }
-
- @Test
- public void testDeploySharedLock() throws IOException, ClassNotFoundException {
- final JarDeployer jarDeployer = new JarDeployer();
- final File currentDir = new File(".").getAbsoluteFile();
- final VM vm = Host.getHost(0).getVM(0);
-
- // Deploy the JAR file
- final File jarFile1 = jarDeployer.getNextVersionJarFile("JarDeployerDUnit.jar");
- byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDSLA");
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitDSLA");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- // Acquire a shared lock in the other VM
- vm.invoke(new SerializableRunnable() {
- @Override
- public void run() {
- if (!jarFile1.exists()) {
- fail("JAR file not found where expected: " + jarFile1.getName());
- }
- try {
- JarDeployerDUnitTest.savedFileLock = acquireSharedLock(jarFile1);
- } catch (IOException ioex) {
- fail("Unable to acquire the shared file lock");
- }
- }
- });
-
- // Now update the JAR file and make sure the first one isn't deleted
- jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDSLB");
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitDSLB");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitC");
- fail("Class should not be found on Classpath: JarDeployerDUniDSLA");
- } catch (ClassNotFoundException expected) { // expected
- }
-
- if (!jarFile1.exists()) {
- fail("JAR file should not have been deleted: " + jarFile1.getName());
- }
-
- vm.invoke(new SerializableRunnable() {
- @Override
- public void run() {
- try {
- releaseLock(JarDeployerDUnitTest.savedFileLock, jarFile1);
- } catch (IOException ioex) {
- fail("Unable to release the shared file lock");
- }
- }
- });
- }
-
- @Test
- public void testUndeploySharedLock() throws IOException, ClassNotFoundException {
- final JarDeployer jarDeployer = new JarDeployer();
- final File currentDir = new File(".").getAbsoluteFile();
- final VM vm = Host.getHost(0).getVM(0);
-
- // Deploy the JAR file
- final File jarFile1 = jarDeployer.getNextVersionJarFile("JarDeployerDUnit.jar");
- byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitUSL");
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitUSL");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- // Acquire a shared lock in the other VM
- vm.invoke(new SerializableRunnable() {
- @Override
- public void run() {
- if (!jarFile1.exists()) {
- fail("JAR file not found where expected: " + jarFile1.getName());
- }
- try {
- JarDeployerDUnitTest.savedFileLock = acquireSharedLock(jarFile1);
- } catch (IOException ioex) {
- fail("Unable to acquire the shared file lock");
- }
- }
- });
-
- // Now undeploy the JAR file and make sure the first one isn't deleted
- jarDeployer.undeploy("JarDeployerDUnit.jar");
-
- if (!jarFile1.exists()) {
- fail("JAR file should not have been deleted: " + jarFile1.getName());
- }
-
- vm.invoke(new SerializableRunnable() {
- @Override
- public void run() {
- try {
- releaseLock(JarDeployerDUnitTest.savedFileLock, jarFile1);
- } catch (IOException ioex) {
- fail("Unable to release the shared file lock");
- }
- }
- });
- }
-
- @Test
- public void testDeployUpdateByAnotherVM() throws IOException, ClassNotFoundException {
- final JarDeployer jarDeployer = new JarDeployer();
- final File currentDir = new File(".").getAbsoluteFile();
- final VM vm = Host.getHost(0).getVM(0);
-
- final File jarFile1 = jarDeployer.getNextVersionJarFile("JarDeployerDUnit.jar");
- byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDUBAVMA");
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitDUBAVMA");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- final File jarFile2 = jarDeployer.getNextVersionJarFile(jarFile1.getName());
- final byte[] vmJarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDUBAVMB");
- vm.invoke(new SerializableRunnable() {
- @Override
- public void run() {
- if (!jarFile1.exists()) {
- fail("JAR file not found where expected: " + jarFile1.getName());
- }
-
- // The other VM writes out a newer version of the JAR file.
- try {
- writeJarBytesToFile(jarFile2, vmJarBytes);
- } catch (IOException ioex) {
- fail("Could not write JAR File");
- }
- }
- });
-
- // This VM is told to deploy the same JAR file.
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {vmJarBytes});
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitDUBAVMB");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitDUBAVMA");
- fail("Class should not be found on Classpath: JarDeployerDUnitDUBAVMA");
- } catch (ClassNotFoundException expected) { // expected
- }
-
- if (!jarFile2.exists()) {
- fail("JAR file should not have been deleted: " + jarFile2.getName());
- }
-
- // Make sure the second deploy didn't create a 3rd version of the JAR file.
- final File jarFile3 = jarDeployer.getNextVersionJarFile(jarFile2.getName());
- if (jarFile3.exists()) {
- fail("JAR file should not have been created: " + jarFile3.getName());
- }
- }
-
- @Test
- public void testLoadPreviouslyDeployedJars() throws IOException {
- final File parentJarFile = new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitAParent.jar#1");
- final File usesJarFile = new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitUses.jar#1");
- final File functionJarFile =
- new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitFunction.jar#1");
-
- // Write out a JAR files.
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("package jddunit.parent;");
- stringBuffer.append("public class JarDeployerDUnitParent {");
- stringBuffer.append("public String getValueParent() {");
- stringBuffer.append("return \"PARENT\";}}");
-
- byte[] jarBytes = this.classBuilder.createJarFromClassContent(
- "jddunit/parent/JarDeployerDUnitParent", stringBuffer.toString());
- FileOutputStream outStream = new FileOutputStream(parentJarFile);
- outStream.write(jarBytes);
- outStream.close();
-
- stringBuffer = new StringBuffer();
- stringBuffer.append("package jddunit.uses;");
- stringBuffer.append("public class JarDeployerDUnitUses {");
- stringBuffer.append("public String getValueUses() {");
- stringBuffer.append("return \"USES\";}}");
-
- jarBytes = this.classBuilder.createJarFromClassContent("jddunit/uses/JarDeployerDUnitUses",
- stringBuffer.toString());
- outStream = new FileOutputStream(usesJarFile);
- outStream.write(jarBytes);
- outStream.close();
-
- stringBuffer = new StringBuffer();
- stringBuffer.append("package jddunit.function;");
- stringBuffer.append("import jddunit.parent.JarDeployerDUnitParent;");
- stringBuffer.append("import jddunit.uses.JarDeployerDUnitUses;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer.append(
- "public class JarDeployerDUnitFunction extends JarDeployerDUnitParent implements Function {");
- stringBuffer.append("private JarDeployerDUnitUses uses = new JarDeployerDUnitUses();");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(getValueParent() + \":\" + uses.getValueUses());}");
- stringBuffer.append("public String getId() {return \"JarDeployerDUnitFunction\";}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
-
- ClassBuilder functionClassBuilder = new ClassBuilder();
- functionClassBuilder.addToClassPath(parentJarFile.getAbsolutePath());
- functionClassBuilder.addToClassPath(usesJarFile.getAbsolutePath());
- jarBytes = functionClassBuilder.createJarFromClassContent(
- "jddunit/function/JarDeployerDUnitFunction", stringBuffer.toString());
- outStream = new FileOutputStream(functionJarFile);
- outStream.write(jarBytes);
- outStream.close();
-
- // Start the distributed system and check to see if the function executes correctly
- DistributedSystem distributedSystem = getSystem();
- getCache();
-
- Execution execution =
- FunctionService.onMember(distributedSystem, distributedSystem.getDistributedMember());
- ResultCollector resultCollector = execution.execute("JarDeployerDUnitFunction");
- @SuppressWarnings("unchecked")
- List<String> result = (List<String>) resultCollector.getResult();
- assertEquals("PARENT:USES", result.get(0));
- }
-
- @Test
- public void testDeployToAlternateDirectory() throws IOException, ClassNotFoundException {
- final File alternateDir = new File("JarDeployerDUnit");
- alternateDir.mkdir();
-
- // Add the alternate directory to the distributed system, get it back out, and then create
- // a JarDeployer object with it.
- Properties properties = new Properties();
- properties.put(ConfigurationProperties.DEPLOY_WORKING_DIR, alternateDir.getAbsolutePath());
- InternalDistributedSystem distributedSystem = getSystem(properties);
- final JarDeployer jarDeployer =
- new JarDeployer(distributedSystem.getConfig().getDeployWorkingDir());
-
- File jarFile = jarDeployer.getNextVersionJarFile("JarDeployerDUnit.jar");
- byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDTAC");
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
-
- try {
- ClassPathLoader.getLatest().forName("JarDeployerDUnitDTAC");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- if (!jarFile.exists()) {
- fail("JAR file not found where expected: " + jarFile.getName());
- }
-
- if (!doesFileMatchBytes(jarFile, jarBytes)) {
- fail("Contents of JAR file do not match those provided: " + jarFile.getName());
- }
- }
-
-
-
- @Test
- public void testSuspendAndResume() throws IOException, ClassNotFoundException {
- AtomicReference<Boolean> okayToResume = new AtomicReference<>(false);
-
- final JarDeployer jarDeployer = new JarDeployer();
- byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitSAR");
- final JarDeployer suspendingJarDeployer = new JarDeployer();
- final CountDownLatch latch = new CountDownLatch(1);
-
- Thread thread = new Thread() {
- @Override
- public void run() {
- try {
- suspendingJarDeployer.suspendAll();
- latch.countDown();
- Thread.sleep(3000);
- } catch (InterruptedException iex) {
- // It doesn't matter, just fail the test
- }
- okayToResume.set(true);
- suspendingJarDeployer.resumeAll();
- }
- };
- thread.start();
-
- try {
- latch.await();
- } catch (InterruptedException iex) {
- // It doesn't matter, just fail the test
- }
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
- if (!okayToResume.get()) {
- fail("JarDeployer did not suspend as expected");
- }
- }
-
-
- @Test
- public void testZeroLengthFile() throws IOException, ClassNotFoundException {
- final JarDeployer jarDeployer = new JarDeployer();
-
- try {
- jarDeployer.deploy(new String[] {"JarDeployerDUnitZLF.jar"}, new byte[][] {new byte[0]});
- fail("Zero length files are not deployable");
- } catch (IllegalArgumentException expected) {
- // Expected
- }
-
- try {
- jarDeployer.deploy(new String[] {"JarDeployerDUnitZLF1.jar", "JarDeployerDUnitZLF2.jar"},
- new byte[][] {this.classBuilder.createJarFromName("JarDeployerDUnitZLF1"), new byte[0]});
- fail("Zero length files are not deployable");
- } catch (IllegalArgumentException expected) {
- // Expected
- }
- }
-
- @Test
- public void testInvalidJarFile() throws IOException, ClassNotFoundException {
- final JarDeployer jarDeployer = new JarDeployer();
-
- try {
- jarDeployer.deploy(new String[] {"JarDeployerDUnitIJF.jar"},
- new byte[][] {"INVALID JAR CONTENT".getBytes()});
- fail("Non-JAR files are not deployable");
- } catch (IllegalArgumentException expected) {
- // Expected
- }
-
- try {
- jarDeployer.deploy(new String[] {"JarDeployerDUnitIJF1.jar", "JarDeployerDUnitIJF2.jar"},
- new byte[][] {this.classBuilder.createJarFromName("JarDeployerDUnitIJF1"),
- "INVALID JAR CONTENT".getBytes()});
- fail("Non-JAR files are not deployable");
- } catch (IllegalArgumentException expected) {
- // Expected
- }
-
- final VM vm = Host.getHost(0).getVM(1);
- vm.invoke(new SerializableRunnable() {
- @Override
- public void run() {
- File invalidFile = new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitIJF.jar#3");
- try {
- RandomAccessFile randomAccessFile = new RandomAccessFile(invalidFile, "rw");
- randomAccessFile.write("GARBAGE".getBytes(), 0, 7);
- randomAccessFile.close();
- } catch (IOException ioex) {
- Assert.fail("Error trying to create garbage file for test", ioex);
- }
-
- getSystem();
- getCache();
-
- if (invalidFile.exists()) {
- fail("Invalid JAR file should have been deleted at startup");
- }
- }
- });
- }
-
- FileLock acquireSharedLock(final File file) throws IOException {
- return new FileInputStream(file).getChannel().lock(0, 1, true);
- }
-
- void releaseLock(final FileLock fileLock, final File lockFile) throws IOException {
- if (lockFile == null) {
- return;
- }
-
- try {
- if (fileLock != null) {
- fileLock.release();
- fileLock.channel().close();
- }
- } finally {
- if (!lockFile.delete()) {
- lockFile.deleteOnExit();
- }
- }
- }
-
- protected boolean doesFileMatchBytes(final File file, final byte[] bytes) throws IOException {
- // If the don't have the same number of bytes then nothing to do
- if (file.length() != bytes.length) {
- return false;
- }
-
- // Open the file then loop comparing each byte
- int index = 0;
- try (InputStream inStream = new FileInputStream(file)) {
- for (; index < bytes.length; index++) {
- if (((byte) inStream.read()) != bytes[index])
- break;
- }
- }
-
- // If we didn't get to the end then something was different
- return index >= bytes.length;
- }
-
- private void deleteSavedJarFiles() throws IOException {
- Pattern pattern = Pattern.compile("^" + JarDeployer.JAR_PREFIX + "JarDeployerDUnit.*#\\d++$");
- File[] files = new File(".").listFiles((dir1, name) -> pattern.matcher(name).matches());
- if (files != null) {
- for (File file : files) {
- Files.delete(file.toPath());
- }
- }
- }
-
- void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException {
- final OutputStream outStream = new FileOutputStream(jarFile);
- outStream.write(jarBytes);
- outStream.close();
- }
-}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
index 71daecc..9e42c20 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
@@ -11,9 +11,12 @@
* 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.geode.internal;
+
import static org.apache.geode.internal.Assert.fail;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -22,162 +25,187 @@ import org.apache.geode.test.junit.categories.IntegrationTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.contrib.java.lang.system.RestoreSystemProperties;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
-import java.nio.file.Files;
+import java.util.Set;
+import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
@Category(IntegrationTest.class)
public class JarDeployerIntegrationTest {
-
private ClassBuilder classBuilder;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
- @Rule
- public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+ JarDeployer jarDeployer;
@Before
public void setup() {
- System.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
classBuilder = new ClassBuilder();
- ClassPathLoader.setLatestToDefault();
+ jarDeployer = new JarDeployer(temporaryFolder.getRoot());
}
- @Test
- public void testDeployFileAndChange() throws Exception {
- final JarDeployer jarDeployer = new JarDeployer();
+ private byte[] createJarWithClass(String className) throws IOException {
+ String stringBuilder = "package integration.parent;" + "public class " + className + " {}";
- // First deploy of the JAR file
- byte[] jarBytes = this.classBuilder.createJarFromName("ClassA");
- JarClassLoader jarClassLoader =
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes})[0];
- File deployedJar = new File(jarClassLoader.getFileCanonicalPath());
+ return this.classBuilder.createJarFromClassContent("integration/parent/" + className,
+ stringBuilder);
+ }
+
+ @Test
+ public void testFileVersioning() throws Exception {
+ String jarName = "JarDeployerIntegrationTest.jar";
- assertThat(deployedJar).exists();
- assertThat(deployedJar.getName()).contains("#1");
- assertThat(deployedJar.getName()).doesNotContain("#2");
+ byte[] firstJarBytes = createJarWithClass("ClassA");
- assertThat(ClassPathLoader.getLatest().forName("ClassA")).isNotNull();
+ // First deploy of the JAR file
+ DeployedJar firstDeployedJar = jarDeployer.deployWithoutRegistering(jarName, firstJarBytes);
- assertThat(doesFileMatchBytes(deployedJar, jarBytes));
+ assertThat(firstDeployedJar.getFile()).exists().hasBinaryContent(firstJarBytes);
+ assertThat(firstDeployedJar.getFile().getName()).contains(".v1.").doesNotContain(".v2.");
// Now deploy an updated JAR file and make sure that the next version of the JAR file
- // was created and the first one was deleted.
- jarBytes = this.classBuilder.createJarFromName("ClassB");
- JarClassLoader newJarClassLoader =
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes})[0];
- File nextDeployedJar = new File(newJarClassLoader.getFileCanonicalPath());
-
- assertThat(nextDeployedJar.exists());
- assertThat(nextDeployedJar.getName()).contains("#2");
- assertThat(doesFileMatchBytes(nextDeployedJar, jarBytes));
+ // was created
+ byte[] secondJarBytes = createJarWithClass("ClassB");
- assertThat(ClassPathLoader.getLatest().forName("ClassB")).isNotNull();
+ DeployedJar secondDeployedJar = jarDeployer.deployWithoutRegistering(jarName, secondJarBytes);
+ File secondDeployedJarFile = new File(secondDeployedJar.getFileCanonicalPath());
- assertThatThrownBy(() -> ClassPathLoader.getLatest().forName("ClassA"))
- .isExactlyInstanceOf(ClassNotFoundException.class);
+ assertThat(secondDeployedJarFile).exists().hasBinaryContent(secondJarBytes);
+ assertThat(secondDeployedJarFile.getName()).contains(".v2.").doesNotContain(".v1.");
- assertThat(jarDeployer.findSortedOldVersionsOfJar("JarDeployerDUnit.jar")).hasSize(1);
+ File[] sortedOldJars = jarDeployer.findSortedOldVersionsOfJar(jarName);
+ assertThat(sortedOldJars).hasSize(2);
+ assertThat(sortedOldJars[0].getName()).contains(".v2.");
+ assertThat(sortedOldJars[1].getName()).contains(".v1.");
assertThat(jarDeployer.findDistinctDeployedJars()).hasSize(1);
}
@Test
- public void testDeployNoUpdateWhenNoChange() throws Exception {
- final JarDeployer jarDeployer = new JarDeployer();
-
- // First deploy of the JAR file
- byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDNUWNC");
- JarClassLoader jarClassLoader =
- jarDeployer.deploy(new String[] {"JarDeployerDUnit2.jar"}, new byte[][] {jarBytes})[0];
- File deployedJar = new File(jarClassLoader.getFileCanonicalPath());
-
- assertThat(deployedJar).exists();
- assertThat(deployedJar.getName()).contains("#1");
- JarClassLoader newJarClassLoader =
- jarDeployer.deploy(new String[] {"JarDeployerDUnit2.jar"}, new byte[][] {jarBytes})[0];
- assertThat(newJarClassLoader).isNull();
- }
-
- @Test
- public void testDeployToInvalidDirectory() throws IOException, ClassNotFoundException {
+ public void testDeployToInvalidDirectory() throws Exception {
final File alternateDir = new File(temporaryFolder.getRoot(), "JarDeployerDUnit");
alternateDir.delete();
final JarDeployer jarDeployer = new JarDeployer(alternateDir);
+
final CyclicBarrier barrier = new CyclicBarrier(2);
final byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDTID");
// Test to verify that deployment fails if the directory doesn't exist.
assertThatThrownBy(() -> {
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
+ jarDeployer.deployWithoutRegistering("JarDeployerIntegrationTest.jar", jarBytes);
}).isInstanceOf(IOException.class);
// Test to verify that deployment succeeds if the directory doesn't
// initially exist, but is then created while the JarDeployer is looping
// looking for a valid directory.
- Thread thread = new Thread() {
- @Override
- public void run() {
- try {
- barrier.await();
- } catch (Exception e) {
- fail(e);
- }
-
- try {
- jarDeployer.deploy(new String[] {"JarDeployerDUnit.jar"}, new byte[][] {jarBytes});
- } catch (Exception e) {
- fail(e);
- }
- }
- };
- thread.start();
-
- try {
+ Future<Boolean> done = Executors.newSingleThreadExecutor().submit(() -> {
barrier.await();
- Thread.sleep(500);
- alternateDir.mkdir();
- thread.join();
- } catch (Exception e) {
- fail(e);
- }
+ jarDeployer.deployWithoutRegistering("JarDeployerIntegrationTest.jar", jarBytes);
+ return true;
+ });
+
+ barrier.await();
+ Thread.sleep(500);
+ alternateDir.mkdir();
+ assertThat(done.get(2, TimeUnit.MINUTES)).isTrue();
}
@Test
public void testVersionNumberCreation() throws Exception {
- JarDeployer jarDeployer = new JarDeployer();
-
- File versionedName = jarDeployer.getNextVersionJarFile("myJar.jar");
- assertThat(versionedName.getName()).isEqualTo(JarDeployer.JAR_PREFIX + "myJar.jar" + "#1");
+ File versionedName = jarDeployer.getNextVersionedJarFile("myJar.jar");
+ assertThat(versionedName.getName()).isEqualTo("myJar.v1.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("ClassA");
- JarClassLoader jarClassLoader =
- jarDeployer.deploy(new String[] {"myJar.jar"}, new byte[][] {jarBytes})[0];
- File deployedJar = new File(jarClassLoader.getFileCanonicalPath());
+ File deployedJarFile = jarDeployer.deployWithoutRegistering("myJar.jar", jarBytes).getFile();
- assertThat(deployedJar.getName()).isEqualTo(JarDeployer.JAR_PREFIX + "myJar.jar" + "#1");
- assertThat(jarDeployer.getNextVersionJarFile(deployedJar.getName()).getName())
- .isEqualTo(JarDeployer.JAR_PREFIX + "myJar.jar" + "#2");
+ assertThat(deployedJarFile.getName()).isEqualTo("myJar.v1.jar");
+ File secondDeployedJarFile =
+ jarDeployer.deployWithoutRegistering("myJar.jar", jarBytes).getFile();
+
+ assertThat(secondDeployedJarFile.getName()).isEqualTo("myJar.v2.jar");
}
@Test
- public void testVersionNumberMatcher() throws Exception {
- JarDeployer jarDeployer = new JarDeployer();
- int version = jarDeployer.extractVersionFromFilename(
- temporaryFolder.newFile(JarDeployer.JAR_PREFIX + "MyJar.jar" + "#1"));
+ public void testVersionNumberMatcher() throws IOException {
+ int version =
+ jarDeployer.extractVersionFromFilename(temporaryFolder.newFile("MyJar.v1.jar").getName());
assertThat(version).isEqualTo(1);
}
- private boolean doesFileMatchBytes(final File file, final byte[] bytes) throws IOException {
- return bytes == Files.readAllBytes(file.toPath());
+ @Test
+ public void testRenamingOfOldJarFiles() throws Exception {
+ File deployDir = jarDeployer.getDeployDirectory();
+
+ File jarAVersion1 = new File(deployDir, "vf.gf#myJarA.jar#1");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion1);
+
+ File jarAVersion2 = new File(deployDir, "vf.gf#myJarA.jar#2");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion2);
+
+ File jarBVersion2 = new File(deployDir, "vf.gf#myJarB.jar#2");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion2);
+
+ File jarBVersion3 = new File(deployDir, "vf.gf#myJarB.jar#3");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion3);
+
+ Set<File> deployedJarsBeforeRename = Stream
+ .of(jarAVersion1, jarAVersion2, jarBVersion2, jarBVersion3).collect(Collectors.toSet());
+
+ jarDeployer.renameJarsWithOldNamingConvention();
+
+ deployedJarsBeforeRename.forEach(oldJar -> assertThat(oldJar).doesNotExist());
+
+ File renamedJarAVersion1 = new File(deployDir, "myJarA.v1.jar");
+ File renamedJarAVersion2 = new File(deployDir, "myJarA.v2.jar");
+ File renamedJarBVersion2 = new File(deployDir, "myJarB.v2.jar");
+ File renamedJarBVersion3 = new File(deployDir, "myJarB.v3.jar");
+ Set<File> expectedJarsAfterRename = Stream
+ .of(renamedJarAVersion1, renamedJarAVersion2, renamedJarBVersion2, renamedJarBVersion3)
+ .collect(Collectors.toSet());
+
+ Set<File> actualJarsInDeployDir =
+ Stream.of(jarDeployer.getDeployDirectory().listFiles()).collect(Collectors.toSet());
+
+ assertThat(actualJarsInDeployDir).isEqualTo(expectedJarsAfterRename);
}
+ @Test
+ public void testOldJarNameMatcher() throws Exception {
+ File deployDir = jarDeployer.getDeployDirectory();
+
+ File jarAVersion1 = new File(deployDir, "vf.gf#myJarA.jar#1");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion1);
+
+ File jarAVersion2 = new File(deployDir, "vf.gf#myJarA.jar#2");
+ this.classBuilder.writeJarFromName("ClassA", jarAVersion2);
+
+ File jarBVersion2 = new File(deployDir, "vf.gf#myJarB.jar#2");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion2);
+
+ File jarBVersion3 = new File(deployDir, "vf.gf#myJarB.jar#3");
+ this.classBuilder.writeJarFromName("ClassB", jarBVersion3);
+
+ Set<File> jarsWithOldNamingConvention = Stream
+ .of(jarAVersion1, jarAVersion2, jarBVersion2, jarBVersion3).collect(Collectors.toSet());
+
+ jarsWithOldNamingConvention.forEach(
+ jarFile -> assertThat(jarDeployer.isOldNamingConvention(jarFile.getName())).isTrue());
+
+ Set<File> foundJarsWithOldNamingConvention = jarDeployer.findJarsWithOldNamingConvention();
+ assertThat(foundJarsWithOldNamingConvention).isEqualTo(jarsWithOldNamingConvention);
+ }
+
+
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
index 0cc003e..dcbbeb0 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
@@ -20,6 +20,22 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.geode.internal.ClassPathLoader;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;
@@ -38,7 +54,7 @@ import org.apache.geode.cache.persistence.PersistentID;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.ClassBuilder;
-import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.internal.DeployedJar;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.cache.persistence.BackupManager;
import org.apache.geode.internal.util.IOUtils;
@@ -1078,15 +1094,16 @@ public class IncrementalBackupDUnitTest extends JUnit4CacheTestCase {
/*
* Deploy a "dummy"�jar to the VM.
*/
- vm0.invoke(new SerializableCallable() {
+ File deployedJarFile = (File) vm0.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
- JarDeployer deployer = new JarDeployer();
- deployer.deploy(new String[] {jarName}, new byte[][] {classBytes});
- return null;
+ DeployedJar deployedJar =
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, classBytes);
+ return deployedJar.getFile();
}
});
+ assert (deployedJarFile.exists());
/*
* Perform backup. Make sure it is successful.
*/
@@ -1149,10 +1166,10 @@ public class IncrementalBackupDUnitTest extends JUnit4CacheTestCase {
vm0.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
- JarDeployer deployer = new JarDeployer();
- for (JarClassLoader jarClassLoader : deployer.findJarClassLoaders()) {
+ for (DeployedJar jarClassLoader : ClassPathLoader.getLatest().getJarDeployer()
+ .findDeployedJars()) {
if (jarClassLoader.getJarName().startsWith(jarName)) {
- deployer.undeploy(jarClassLoader.getJarName());
+ ClassPathLoader.getLatest().getJarDeployer().undeploy(jarClassLoader.getJarName());
}
}
return null;
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
new file mode 100644
index 0000000..3149432
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
@@ -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.
+ */
+package org.apache.geode.management;
+
+import org.apache.geode.internal.ClassPathLoaderIntegrationTest;
+import org.apache.geode.internal.ClassPathLoaderTest;
+import org.apache.geode.internal.DeployedJarJUnitTest;
+import org.apache.geode.internal.JarDeployerIntegrationTest;
+import org.apache.geode.management.internal.cli.commands.DeployCommandRedeployDUnitTest;
+import org.apache.geode.management.internal.cli.commands.DeployCommandsDUnitTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({DeployedJarJUnitTest.class, DeployCommandsDUnitTest.class,
+ JarDeployerIntegrationTest.class, ClassPathLoaderIntegrationTest.class,
+ ClassPathLoaderTest.class, DeployCommandRedeployDUnitTest.class})
+public class DeployJarTestSuite {
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java
new file mode 100644
index 0000000..8280f5d
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.distributed.DistributedSystem;
+import org.apache.geode.internal.ClassBuilder;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
+import org.apache.geode.test.dunit.rules.Locator;
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.dunit.rules.Server;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.List;
+
+@Category(DistributedTest.class)
+public class DeployCommandRedeployDUnitTest implements Serializable {
+ private static final String VERSION1 = "Version1";
+ private static final String VERSION2 = "Version2";
+
+ private static final String jarNameA = "DeployCommandRedeployDUnitTestA.jar";
+ private static final String functionA = "DeployCommandRedeployDUnitFunctionA";
+ private File jarAVersion1;
+ private File jarAVersion2;
+
+ private static final String jarNameB = "DeployCommandRedeployDUnitTestB.jar";
+ private static final String functionB = "DeployCommandRedeployDUnitFunctionB";
+ private static final String packageB = "jddunit.function";
+ private static final String fullyQualifiedFunctionB = packageB + "." + functionB;
+ private File jarBVersion1;
+ private File jarBVersion2;
+
+ private MemberVM locator;
+ private MemberVM server;
+
+ @Rule
+ public LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
+
+ @Rule
+ public transient GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
+
+ @Before
+ public void setup() throws Exception {
+ jarAVersion1 = createJarWithFunctionA(VERSION1);
+ jarAVersion2 = createJarWithFunctionA(VERSION2);
+
+ jarBVersion1 = createJarWithFunctionB(VERSION1);
+ jarBVersion2 = createJarWithFunctionB(VERSION2);
+
+ locator = lsRule.startLocatorVM(0);
+ server = lsRule.startServerVM(1, locator.getPort());
+
+ gfshConnector.connectAndVerify(locator);
+ }
+
+ @Test
+ public void redeployJarsWithNewVersionsOfFunctions() throws Exception {
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarAVersion1.getCanonicalPath());
+ server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
+ server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION1));
+
+
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarBVersion1.getCanonicalPath());
+ server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
+ server.invoke(() -> assertThatCanLoad(jarNameB, fullyQualifiedFunctionB));
+ server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION1));
+ server.invoke(() -> assertThatFunctionHasVersion(functionB, VERSION1));
+
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarBVersion2.getCanonicalPath());
+ server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
+ server.invoke(() -> assertThatCanLoad(jarNameB, fullyQualifiedFunctionB));
+ server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION1));
+ server.invoke(() -> assertThatFunctionHasVersion(functionB, VERSION2));
+
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarAVersion2.getCanonicalPath());
+ server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
+ server.invoke(() -> assertThatCanLoad(jarNameB, fullyQualifiedFunctionB));
+ server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION2));
+ server.invoke(() -> assertThatFunctionHasVersion(functionB, VERSION2));
+ }
+
+ // Note that jar A is a Declarable Function, while jar B is only a Function.
+ // Also, the function for jar A resides in the default package, whereas jar B specifies a package.
+ // This ensures that this test has identical coverage to some tests that it replaced.
+ private File createJarWithFunctionA(String version) throws Exception {
+ String classContents =
+ "import java.util.Properties;" + "import org.apache.geode.cache.Declarable;"
+ + "import org.apache.geode.cache.execute.Function;"
+ + "import org.apache.geode.cache.execute.FunctionContext;" + "public class " + functionA
+ + " implements Function, Declarable {" + "public String getId() {return \"" + functionA
+ + "\";}" + "public void init(Properties props) {}"
+ + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\""
+ + version + "\");}" + "public boolean hasResult() {return true;}"
+ + "public boolean optimizeForWrite() {return false;}"
+ + "public boolean isHA() {return false;}}";
+
+ File jar = new File(lsRule.getTempFolder().newFolder(jarNameA + version), this.jarNameA);
+ ClassBuilder functionClassBuilder = new ClassBuilder();
+ functionClassBuilder.writeJarFromContent(functionA, classContents, jar);
+
+ return jar;
+ }
+
+ private File createJarWithFunctionB(String version) throws IOException {
+ String classContents =
+ "package " + packageB + ";" + "import org.apache.geode.cache.execute.Function;"
+ + "import org.apache.geode.cache.execute.FunctionContext;" + "public class " + functionB
+ + " implements Function {" + "public boolean hasResult() {return true;}"
+ + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\""
+ + version + "\");}" + "public String getId() {return \"" + functionB + "\";}"
+ + "public boolean optimizeForWrite() {return false;}"
+ + "public boolean isHA() {return false;}}";
+
+ File jar = new File(lsRule.getTempFolder().newFolder(jarNameB + version), this.jarNameB);
+ ClassBuilder functionClassBuilder = new ClassBuilder();
+ functionClassBuilder.writeJarFromContent("jddunit/function/" + functionB, classContents, jar);
+
+ return jar;
+ }
+
+ private void assertThatFunctionHasVersion(String functionId, String version) {
+ GemFireCacheImpl gemFireCache = GemFireCacheImpl.getInstance();
+ DistributedSystem distributedSystem = gemFireCache.getDistributedSystem();
+ Execution execution =
+ FunctionService.onMember(distributedSystem, distributedSystem.getDistributedMember());
+ List<String> result = (List<String>) execution.execute(functionId).getResult();
+ assertThat(result.get(0)).isEqualTo(version);
+ }
+
+ private void assertThatCanLoad(String jarName, String className) throws ClassNotFoundException {
+ assertThat(ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jarName)).isNotNull();
+ assertThat(ClassPathLoader.getLatest().forName(className)).isNotNull();
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
index 7b0823b..6df2572 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
@@ -14,53 +14,28 @@
*/
package org.apache.geode.management.internal.cli.commands;
-import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
-import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_BIND_ADDRESS;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
-import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.NAME;
-import static org.apache.geode.test.dunit.Assert.assertEquals;
-import static org.apache.geode.test.dunit.Assert.assertFalse;
-import static org.apache.geode.test.dunit.Assert.assertTrue;
-import static org.apache.geode.test.dunit.Assert.fail;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertNotNull;
-import org.apache.geode.distributed.Locator;
-import org.apache.geode.distributed.internal.DistributionManager;
-import org.apache.geode.distributed.internal.InternalLocator;
-import org.apache.geode.distributed.internal.ClusterConfigurationService;
-import org.apache.geode.internal.AvailablePort;
-import org.apache.geode.internal.AvailablePortHelper;
import org.apache.geode.internal.ClassBuilder;
-import org.apache.geode.internal.JarDeployer;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.remote.CommandExecutionContext;
-import org.apache.geode.management.internal.cli.remote.CommandProcessor;
+import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.management.internal.cli.result.CommandResult;
-import org.apache.geode.test.dunit.Assert;
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.SerializableRunnable;
-import org.apache.geode.test.dunit.VM;
-import org.apache.geode.test.dunit.Wait;
-import org.apache.geode.test.dunit.WaitCriterion;
-import org.apache.geode.test.dunit.rules.ServerStarterRule;
+import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
+import org.apache.geode.test.dunit.rules.Locator;
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.dunit.rules.Server;
import org.apache.geode.test.junit.categories.DistributedTest;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
+import java.io.Serializable;
import java.util.Properties;
-import java.util.regex.Pattern;
/**
* Unit tests for the DeployCommands class
@@ -69,453 +44,238 @@ import java.util.regex.Pattern;
*/
@SuppressWarnings("serial")
@Category(DistributedTest.class)
-public class DeployCommandsDUnitTest extends CliCommandTestBase {
-
- private final Pattern pattern =
- Pattern.compile("^" + JarDeployer.JAR_PREFIX + "DeployCommandsDUnit.*#\\d++$");
- private File newDeployableJarFile;
- private transient ClassBuilder classBuilder;
- private transient CommandProcessor commandProcessor;
-
- @Override
- public final void postSetUpCliCommandTestBase() throws Exception {
- this.newDeployableJarFile = new File(this.temporaryFolder.getRoot().getCanonicalPath()
- + File.separator + "DeployCommandsDUnit1.jar");
- this.classBuilder = new ClassBuilder();
- this.commandProcessor = new CommandProcessor();
- assertFalse(this.commandProcessor.isStopped());
-
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- public void run() {
- deleteSavedJarFiles();
- }
- });
- deleteSavedJarFiles();
+public class DeployCommandsDUnitTest implements Serializable {
+ private static final String GROUP1 = "Group1";
+ private static final String GROUP2 = "Group2";
+
+ private final String class1 = "DeployCommandsDUnitA";
+ private final String class2 = "DeployCommandsDUnitB";
+ private final String class3 = "DeployCommandsDUnitC";
+ private final String class4 = "DeployCommandsDUnitD";
+
+ private final String jarName1 = "DeployCommandsDUnit1.jar";
+ private final String jarName2 = "DeployCommandsDUnit2.jar";
+ private final String jarName3 = "DeployCommandsDUnit3.jar";
+ private final String jarName4 = "DeployCommandsDUnit4.jar";
+
+ private File jar1;
+ private File jar2;
+ private File jar3;
+ private File jar4;
+ private File subdirWithJars3and4;
+
+ private MemberVM locator;
+ private MemberVM server1;
+ private MemberVM server2;
+
+ @Rule
+ public LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
+
+ @Rule
+ public transient GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
+
+ @Before
+ public void setup() throws Exception {
+ ClassBuilder classBuilder = new ClassBuilder();
+ File jarsDir = lsRule.getTempFolder().newFolder();
+ jar1 = new File(jarsDir, jarName1);
+ jar2 = new File(jarsDir, jarName2);
+
+ subdirWithJars3and4 = new File(jarsDir, "subdir");
+ subdirWithJars3and4.mkdirs();
+ jar3 = new File(subdirWithJars3and4, jarName3);
+ jar4 = new File(subdirWithJars3and4, jarName4);
+
+ classBuilder.writeJarFromName(class1, jar1);
+ classBuilder.writeJarFromName(class2, jar2);
+ classBuilder.writeJarFromName(class3, jar3);
+ classBuilder.writeJarFromName(class4, jar4);
+
+ locator = lsRule.startLocatorVM(0);
+
+ Properties props = new Properties();
+ props.setProperty(GROUPS, GROUP1);
+ server1 = lsRule.startServerVM(1, props, locator.getPort());
+
+ props.setProperty(GROUPS, GROUP2);
+ server2 = lsRule.startServerVM(2, props, locator.getPort());
+
+ gfshConnector.connectAndVerify(locator);
}
- @SuppressWarnings("serial")
- @Override
- protected final void preTearDownCliCommandTestBase() throws Exception {
- Host.getHost(0).getVM(1).invoke(new SerializableRunnable() {
- public void run() {
- DistributionManager.isDedicatedAdminVM = false;
- }
- });
+ @Test
+ public void deployJarToOneGroup() throws Exception {
+ // Deploy a jar to a single group
+ CommandResult cmdResult =
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar2 + " --group=" + GROUP1);
+ String resultString = commandResultToString(cmdResult);
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- public void run() {
- deleteSavedJarFiles();
- }
- });
- deleteSavedJarFiles();
+ assertThat(resultString).contains(server1.getName());
+ assertThat(resultString).doesNotContain(server2.getName());
+ assertThat(resultString).contains(jarName2);
+
+ server1.invoke(() -> assertThatCanLoad(jarName2, class2));
+ server2.invoke(() -> assertThatCannotLoad(jarName2, class2));
}
@Test
- public void testDeploy() throws Exception {
- final Properties props = new Properties();
- final Host host = Host.getHost(0);
- final VM vm = host.getVM(0);
- final String vmName = "VM" + vm.getPid();
-
- // Create the cache in this VM
- props.setProperty(NAME, "Controller");
- props.setProperty(GROUPS, "Group1");
- getSystem(props);
- getCache();
-
- // Create the cache in the other VM
- vm.invoke(new SerializableRunnable() {
- public void run() {
- props.setProperty(NAME, vmName);
- props.setProperty(GROUPS, "Group2");
- getSystem(props);
- getCache();
- }
+ public void deployMultipleJarsToOneGroup() throws Exception {
+ // Deploy of multiple JARs to a single group
+ CommandResult cmdResult = gfshConnector.executeAndVerifyCommand(
+ "deploy --group=" + GROUP1 + " --dir=" + subdirWithJars3and4.getCanonicalPath());
+ String resultString = commandResultToString(cmdResult);
+
+ assertThat(resultString).describedAs(resultString).contains(server1.getName());
+ assertThat(resultString).doesNotContain(server2.getName());
+ assertThat(resultString).contains(jarName3);
+ assertThat(resultString).contains(jarName4);
+
+ server1.invoke(() -> {
+ assertThatCanLoad(jarName3, class3);
+ assertThatCanLoad(jarName4, class4);
+ });
+ server2.invoke(() -> {
+ assertThatCannotLoad(jarName3, class3);
+ assertThatCannotLoad(jarName4, class4);
});
- DeployCommands deployCommands = new DeployCommands();
-
- // Single JAR all members
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit1.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitA")});
- Result result = deployCommands.deploy(null, "DeployCommandsDUnit1.jar", null);
-
- assertEquals(true, result.hasNextLine());
-
- String resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(1, countMatchesInString(resultString, "Controller"));
- assertEquals(1, countMatchesInString(resultString, vmName));
- assertEquals(4, countMatchesInString(resultString, "DeployCommandsDUnit1.jar"));
-
- // Single JAR with group
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit2.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitB")});
- result = deployCommands.deploy(new String[] {"Group2"}, "DeployCommandsDUnit2.jar", null);
-
- assertEquals(true, result.hasNextLine());
-
- resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(false, resultString.contains("Controller"));
- assertEquals(1, countMatchesInString(resultString, vmName));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit2.jar"));
-
- // Multiple JARs to all members
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit3.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitC"),
- "DeployCommandsDUnit4.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitD")});
- result = deployCommands.deploy(null, null, "AnyDirectory");
-
- assertEquals(true, result.hasNextLine());
-
- resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(2, countMatchesInString(resultString, "Controller"));
- assertEquals(2, countMatchesInString(resultString, vmName));
- assertEquals(4, countMatchesInString(resultString, "DeployCommandsDUnit3.jar"));
- assertEquals(4, countMatchesInString(resultString, "DeployCommandsDUnit4.jar"));
-
- // Multiple JARs to a group
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit5.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitE"),
- "DeployCommandsDUnit6.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitF")});
- result = deployCommands.deploy(new String[] {"Group1"}, null, "AnyDirectory");
-
- assertEquals(true, result.hasNextLine());
-
- resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(2, countMatchesInString(resultString, "Controller"));
- assertEquals(false, resultString.contains(vmName));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit5.jar"));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit6.jar"));
- }
- @Test
- public void testUndeploy() throws Exception {
- final Properties props = new Properties();
- final Host host = Host.getHost(0);
- final VM vm = host.getVM(0);
- final String vmName = "VM" + vm.getPid();
-
- // Create the cache in this VM
- props.setProperty(NAME, "Controller");
- props.setProperty(GROUPS, "Group1");
- getSystem(props);
- getCache();
-
- // Create the cache in the other VM
- vm.invoke(new SerializableRunnable() {
- public void run() {
- props.setProperty(NAME, vmName);
- props.setProperty(GROUPS, "Group2");
- getSystem(props);
- getCache();
- }
+ // Undeploy of multiple jars by specifying group
+ gfshConnector.executeAndVerifyCommand("undeploy --group=" + GROUP1);
+ server1.invoke(() -> {
+ assertThatCannotLoad(jarName3, class3);
+ assertThatCannotLoad(jarName4, class4);
+ });
+ server2.invoke(() -> {
+ assertThatCannotLoad(jarName3, class3);
+ assertThatCannotLoad(jarName4, class4);
});
-
- DeployCommands deployCommands = new DeployCommands();
-
- // Deploy a couple of JAR files which can be undeployed
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit1.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitA")});
- deployCommands.deploy(new String[] {"Group1"}, "DeployCommandsDUnit1.jar", null);
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit2.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitB")});
- deployCommands.deploy(new String[] {"Group2"}, "DeployCommandsDUnit2.jar", null);
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit3.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitC")});
- deployCommands.deploy(null, "DeployCommandsDUnit3.jar", null);
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit4.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitD")});
- deployCommands.deploy(null, "DeployCommandsDUnit4.jar", null);
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit5.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitE")});
- deployCommands.deploy(null, "DeployCommandsDUnit5.jar", null);
-
- // Undeploy for 1 group
- Result result = deployCommands.undeploy(new String[] {"Group1"}, "DeployCommandsDUnit1.jar");
- assertEquals(true, result.hasNextLine());
- String resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(1, countMatchesInString(resultString, "Controller"));
- assertEquals(false, resultString.contains(vmName));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit1.jar"));
-
- // Multiple Undeploy for all members
- result = deployCommands.undeploy(null, "DeployCommandsDUnit2.jar, DeployCommandsDUnit3.jar");
- assertEquals(true, result.hasNextLine());
- resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(2, countMatchesInString(resultString, "Controller"));
- assertEquals(2, countMatchesInString(resultString, vmName));
- assertEquals(3, countMatchesInString(resultString, "DeployCommandsDUnit2.jar"));
- assertEquals(4, countMatchesInString(resultString, "DeployCommandsDUnit3.jar"));
-
- // Undeploy all (no JAR specified)
- result = deployCommands.undeploy(null, null);
- assertEquals(true, result.hasNextLine());
- resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(2, countMatchesInString(resultString, "Controller"));
- assertEquals(2, countMatchesInString(resultString, vmName));
- assertEquals(4, countMatchesInString(resultString, "DeployCommandsDUnit4.jar"));
- assertEquals(4, countMatchesInString(resultString, "DeployCommandsDUnit5.jar"));
}
@Test
- public void testListDeployed() throws Exception {
- final Properties props = new Properties();
- final Host host = Host.getHost(0);
- final VM vm = host.getVM(0);
- final String vmName = "VM" + vm.getPid();
-
- // Create the cache in this VM
- props.setProperty(NAME, "Controller");
- props.setProperty(GROUPS, "Group1");
- getSystem(props);
- getCache();
-
- // Create the cache in the other VM
- vm.invoke(new SerializableRunnable() {
- public void run() {
- props.setProperty(NAME, vmName);
- props.setProperty(GROUPS, "Group2");
- getSystem(props);
- getCache();
- }
- });
-
- DeployCommands deployCommands = new DeployCommands();
-
- // Deploy a couple of JAR files which can be listed
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit1.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitA")});
- deployCommands.deploy(new String[] {"Group1"}, "DeployCommandsDUnit1.jar", null);
- CommandExecutionContext.setBytesFromShell(new byte[][] {"DeployCommandsDUnit2.jar".getBytes(),
- this.classBuilder.createJarFromName("DeployCommandsDUnitB")});
- deployCommands.deploy(new String[] {"Group2"}, "DeployCommandsDUnit2.jar", null);
-
- // List for all members
- Result result = deployCommands.listDeployed(null);
- assertEquals(true, result.hasNextLine());
- String resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(1, countMatchesInString(resultString, "Controller"));
- assertEquals(1, countMatchesInString(resultString, vmName));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit1.jar"));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit2.jar"));
-
- // List for members in Group1
- result = deployCommands.listDeployed("Group1");
- assertEquals(true, result.hasNextLine());
- resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(1, countMatchesInString(resultString, "Controller"));
- assertEquals(false, resultString.contains(vmName));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit1.jar"));
- assertEquals(false, resultString.contains("DeployCommandsDUnit2.jar"));
-
- // List for members in Group2
- result = deployCommands.listDeployed("Group2");
- assertEquals(true, result.hasNextLine());
- resultString = result.nextLine();
- assertEquals(false, resultString.contains("ERROR"));
- assertEquals(false, resultString.contains("Controller"));
- assertEquals(1, countMatchesInString(resultString, vmName));
- assertEquals(false, resultString.contains("DeployCommandsDUnit1.jar"));
- assertEquals(2, countMatchesInString(resultString, "DeployCommandsDUnit2.jar"));
+ public void deployJarToAllServers() throws Exception {
+ // Deploy a jar to all servers
+ CommandResult cmdResult = gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar1);
+
+ String resultString = commandResultToString(cmdResult);
+ assertThat(resultString).contains(server1.getName());
+ assertThat(resultString).contains(server2.getName());
+ assertThat(resultString).contains(jarName1);
+
+ server1.invoke(() -> assertThatCanLoad(jarName1, class1));
+ server2.invoke(() -> assertThatCanLoad(jarName1, class1));
+
+ // Undeploy of jar by specifying group
+ gfshConnector.executeAndVerifyCommand("undeploy --group=" + GROUP1);
+ server1.invoke(() -> assertThatCannotLoad(jarName1, class1));
+ server2.invoke(() -> assertThatCanLoad(jarName1, class1));
}
- /**
- * Does an end-to-end test using the complete CLI framework while ensuring that the shared
- * configuration is updated.
- */
@Test
- public void testEndToEnd() throws Exception {
- final String groupName = getName();
- final int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(2);
- jmxPort = ports[0];
- httpPort = ports[1];
- try {
- jmxHost = InetAddress.getLocalHost().getHostName();
- } catch (UnknownHostException ignore) {
- jmxHost = "localhost";
- }
+ public void deployMultipleJarsToAllServers() throws Exception {
+ gfshConnector.executeAndVerifyCommand("deploy --dir=" + subdirWithJars3and4.getCanonicalPath());
- // Start the Locator and wait for shared configuration to be available
- final int locatorPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
- final String locatorLogPath = this.temporaryFolder.getRoot().getCanonicalPath() + File.separator
- + "locator-" + locatorPort + ".log";
-
- final Properties locatorProps = new Properties();
- locatorProps.setProperty(NAME, "Locator");
- locatorProps.setProperty(MCAST_PORT, "0");
- locatorProps.setProperty(LOG_LEVEL, "fine");
- locatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
- locatorProps.setProperty(JMX_MANAGER, "true");
- locatorProps.setProperty(JMX_MANAGER_START, "true");
- locatorProps.setProperty(JMX_MANAGER_BIND_ADDRESS, String.valueOf(jmxHost));
- locatorProps.setProperty(JMX_MANAGER_PORT, String.valueOf(jmxPort));
- locatorProps.setProperty(HTTP_SERVICE_PORT, String.valueOf(httpPort));
-
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- @Override
- public void run() {
- final File locatorLogFile = new File(locatorLogPath);
- try {
- final InternalLocator locator = (InternalLocator) Locator.startLocatorAndDS(locatorPort,
- locatorLogFile, null, locatorProps);
-
- WaitCriterion wc = new WaitCriterion() {
- @Override
- public boolean done() {
- return locator.isSharedConfigurationRunning();
- }
-
- @Override
- public String description() {
- return "Waiting for shared configuration to be started";
- }
- };
- Wait.waitForCriterion(wc, 5000, 500, true);
-
- } catch (IOException e) {
- fail("Unable to create a locator with a shared configuration", e);
- }
- }
+ server1.invoke(() -> {
+ assertThatCanLoad(jarName3, class3);
+ assertThatCanLoad(jarName4, class4);
+ });
+ server2.invoke(() -> {
+ assertThatCanLoad(jarName3, class3);
+ assertThatCanLoad(jarName4, class4);
});
- connect(jmxHost, jmxPort, httpPort, getDefaultShell());
+ gfshConnector.executeAndVerifyCommand("undeploy");
- Host.getHost(0).getVM(1).invoke(() -> {
- Properties properties = new Properties();
- properties.setProperty("name", "Manager");
- properties.setProperty("groups", groupName);
- ServerStarterRule serverStarterRule = new ServerStarterRule();
- serverStarterRule.withProperties(properties).withConnectionToLocator(locatorPort)
- .startServer();
+ server1.invoke(() -> {
+ assertThatCannotLoad(jarName3, class3);
+ assertThatCannotLoad(jarName4, class4);
+ });
+ server2.invoke(() -> {
+ assertThatCannotLoad(jarName3, class3);
+ assertThatCannotLoad(jarName4, class4);
});
+ }
- // Create a JAR file
- this.classBuilder.writeJarFromName("DeployCommandsDUnitA", this.newDeployableJarFile);
+ @Test
+ public void undeployOfMultipleJars() throws Exception {
+ gfshConnector.executeAndVerifyCommand("deploy --dir=" + subdirWithJars3and4.getCanonicalPath());
- // Deploy the JAR
- CommandResult cmdResult =
- executeCommand("deploy --jar=" + this.newDeployableJarFile.getCanonicalPath());
- assertEquals(Result.Status.OK, cmdResult.getStatus());
-
- String stringResult = commandResultToString(cmdResult);
- assertEquals(3, countLinesInString(stringResult, false));
- assertTrue(stringContainsLine(stringResult, "Member.*JAR.*JAR Location"));
- assertTrue(stringContainsLine(stringResult, "Manager.*DeployCommandsDUnit1.jar.*"
- + JarDeployer.JAR_PREFIX + "DeployCommandsDUnit1.jar#1"));
-
- // Undeploy the JAR
- cmdResult = executeCommand("undeploy --jar=DeployCommandsDUnit1.jar");
- assertEquals(Result.Status.OK, cmdResult.getStatus());
-
- stringResult = commandResultToString(cmdResult);
- assertEquals(3, countLinesInString(stringResult, false));
- assertThat(stringContainsLine(stringResult, "Member.*JAR.*Un-Deployed From JAR Location"))
- .describedAs(stringResult).isTrue();
- assertThat(stringContainsLine(stringResult, "Manager.*DeployCommandsDUnit1.jar.*"
- + JarDeployer.JAR_PREFIX + "DeployCommandsDUnit1.jar#1")).describedAs(stringResult)
- .isTrue();;
-
-
- // Deploy the JAR to a group
- cmdResult = executeCommand(
- "deploy --jar=" + this.newDeployableJarFile.getCanonicalPath() + " --group=" + groupName);
- assertThat(cmdResult.getStatus()).describedAs(cmdResult.toString()).isEqualTo(Result.Status.OK);
-
- stringResult = commandResultToString(cmdResult);
- assertEquals(3, countLinesInString(stringResult, false));
- assertThat(stringContainsLine(stringResult, "Member.*JAR.*JAR Location"))
- .describedAs(stringResult).isTrue();
-
- assertThat(stringContainsLine(stringResult, "Manager.*DeployCommandsDUnit1.jar.*"
- + JarDeployer.JAR_PREFIX + "DeployCommandsDUnit1.jar#1")).describedAs(stringResult)
- .isTrue();
-
- // Make sure the deployed jar in the shared config
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- @Override
- public void run() {
- ClusterConfigurationService sharedConfig =
- ((InternalLocator) Locator.getLocator()).getSharedConfiguration();
- try {
- assertTrue(sharedConfig.getConfiguration(groupName).getJarNames()
- .contains("DeployCommandsDUnit1.jar"));
- } catch (Exception e) {
- Assert.fail("Error occurred in cluster configuration service", e);
- }
- }
+ server1.invoke(() -> {
+ assertThatCanLoad(jarName3, class3);
+ assertThatCanLoad(jarName4, class4);
+ });
+ server2.invoke(() -> {
+ assertThatCanLoad(jarName3, class3);
+ assertThatCanLoad(jarName4, class4);
});
- // List deployed for group
- cmdResult = executeCommand("list deployed --group=" + groupName);
- assertEquals(Result.Status.OK, cmdResult.getStatus());
-
- stringResult = commandResultToString(cmdResult);
- assertEquals(3, countLinesInString(stringResult, false));
- assertTrue(stringContainsLine(stringResult, "Member.*JAR.*JAR Location"));
- assertTrue(stringContainsLine(stringResult, "Manager.*DeployCommandsDUnit1.jar.*"
- + JarDeployer.JAR_PREFIX + "DeployCommandsDUnit1.jar#1"));
-
- // Undeploy for group
- cmdResult = executeCommand("undeploy --group=" + groupName);
- assertEquals(Result.Status.OK, cmdResult.getStatus());
-
- stringResult = commandResultToString(cmdResult);
- assertEquals(3, countLinesInString(stringResult, false));
- assertTrue(stringContainsLine(stringResult, "Member.*JAR.*Un-Deployed From JAR Location"));
- assertTrue(stringContainsLine(stringResult, "Manager.*DeployCommandsDUnit1.jar.*"
- + JarDeployer.JAR_PREFIX + "DeployCommandsDUnit1.jar#1"));
-
- // Make sure the deployed jar was removed from the shared config
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- @Override
- public void run() {
- ClusterConfigurationService sharedConfig =
- ((InternalLocator) Locator.getLocator()).getSharedConfiguration();
- try {
- assertFalse(sharedConfig.getConfiguration(groupName).getJarNames()
- .contains("DeployCommandsDUnit1.jar"));
- } catch (Exception e) {
- Assert.fail("Error occurred in cluster configuration service", e);
- }
- }
+ gfshConnector
+ .executeAndVerifyCommand("undeploy --jars=" + jar3.getName() + "," + jar4.getName());
+ server1.invoke(() -> {
+ assertThatCannotLoad(jarName3, class3);
+ assertThatCannotLoad(jarName4, class4);
});
+ server2.invoke(() -> {
+ assertThatCannotLoad(jarName3, class3);
+ assertThatCannotLoad(jarName4, class4);
+ });
+ }
- // List deployed with nothing deployed
- cmdResult = executeCommand("list deployed");
- assertEquals(Result.Status.OK, cmdResult.getStatus());
- assertTrue(
- commandResultToString(cmdResult).contains(CliStrings.LIST_DEPLOYED__NO_JARS_FOUND_MESSAGE));
+ private void assertThatCanLoad(String jarName, String className) throws ClassNotFoundException {
+ assertThat(ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jarName)).isNotNull();
+ assertThat(ClassPathLoader.getLatest().forName(className)).isNotNull();
}
- private void deleteSavedJarFiles() {
- this.newDeployableJarFile.delete();
+ private void assertThatCannotLoad(String jarName, String className) {
+ assertThat(ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jarName)).isNull();
+ assertThatThrownBy(() -> ClassPathLoader.getLatest().forName(className))
+ .isExactlyInstanceOf(ClassNotFoundException.class);
+ }
- File dirFile = new File(".");
- // Find all deployed JAR files
- File[] oldJarFiles = dirFile.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(final File file, final String name) {
- return DeployCommandsDUnitTest.this.pattern.matcher(name).matches();
- }
- });
+ @Test
+ public void testListDeployed() throws Exception {
+ // Deploy a couple of JAR files which can be listed
+ gfshConnector.executeAndVerifyCommand(
+ "deploy jar --group=" + GROUP1 + " --jar=" + jar1.getCanonicalPath());
+ gfshConnector.executeAndVerifyCommand(
+ "deploy jar --group=" + GROUP2 + " --jar=" + jar2.getCanonicalPath());
+
+ // List for all members
+ CommandResult commandResult = gfshConnector.executeAndVerifyCommand("list deployed");
+ String resultString = commandResultToString(commandResult);
+ assertThat(resultString).contains(server1.getName());
+ assertThat(resultString).contains(server2.getName());
+ assertThat(resultString).contains(jarName1);
+ assertThat(resultString).contains(jarName2);
+
+ // List for members in Group1
+ commandResult = gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP1);
+ resultString = commandResultToString(commandResult);
+ assertThat(resultString).contains(server1.getName());
+ assertThat(resultString).doesNotContain(server2.getName());
+
+ assertThat(resultString).contains(jarName1);
+ assertThat(resultString).doesNotContain(jarName2);
+
+ // List for members in Group2
+ commandResult = gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP2);
+ resultString = commandResultToString(commandResult);
+ assertThat(resultString).doesNotContain(server1.getName());
+ assertThat(resultString).contains(server2.getName());
+
+ assertThat(resultString).doesNotContain(jarName1);
+ assertThat(resultString).contains(jarName2);
+ }
- // Now delete them
- if (oldJarFiles != null) {
- for (File oldJarFile : oldJarFiles) {
- oldJarFile.delete();
- }
+ protected static String commandResultToString(final CommandResult commandResult) {
+ assertNotNull(commandResult);
+ commandResult.resetToFirstLine();
+ StringBuilder buffer = new StringBuilder(commandResult.getHeader());
+ while (commandResult.hasNextLine()) {
+ buffer.append(commandResult.nextLine());
}
+ buffer.append(commandResult.getFooter());
+ return buffer.toString();
}
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserCommandsDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserCommandsDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserCommandsDUnitTest.java
deleted file mode 100644
index 24f5cdb..0000000
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserCommandsDUnitTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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.geode.management.internal.cli.commands;
-
-import static org.apache.geode.test.dunit.Assert.assertEquals;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.geode.distributed.ConfigurationProperties;
-import org.apache.geode.internal.ClassBuilder;
-import org.apache.geode.internal.ClassPathLoader;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.CommandManager;
-import org.apache.geode.management.internal.cli.result.CommandResult;
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.SerializableRunnable;
-import org.apache.geode.test.junit.categories.DistributedTest;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Properties;
-
-/**
- * Unit tests for configuring user commands.
- *
- * @since GemFire 8.0
- */
-@Category(DistributedTest.class)
-public class UserCommandsDUnitTest extends CliCommandTestBase {
-
- private static final long serialVersionUID = 1L;
- final File jarDirectory = new File((new File(
- ClassPathLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath()))
- .getParent(),
- "ext");
- final File jarFile = new File(this.jarDirectory, "UserCommandsDUnit.jar");
- boolean deleteJarDirectory = false;
-
- @Override
- public final void postSetUpCliCommandTestBase() throws Exception {
- createUserCommandJarFile();
- }
-
- @Override
- public final void postTearDownCacheTestCase() throws Exception {
- if (this.deleteJarDirectory) {
- FileUtils.deleteDirectory(this.jarDirectory);
- } else {
- FileUtils.forceDelete(this.jarFile);
- }
-
- System.clearProperty(CommandManager.USER_CMD_PACKAGES_PROPERTY);
- ClassPathLoader.setLatestToDefault();
- CommandManager.clearInstance();
-
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void run() {
- System.clearProperty(CommandManager.USER_CMD_PACKAGES_PROPERTY);
- ClassPathLoader.setLatestToDefault();
- CommandManager.clearInstance();
- }
- });
- }
-
- public void createUserCommandJarFile() throws IOException {
- this.deleteJarDirectory = this.jarDirectory.mkdir();
-
- StringBuffer stringBuffer = new StringBuffer();
-
- stringBuffer.append("package junit.ucdunit;");
- stringBuffer.append("import org.springframework.shell.core.CommandMarker;");
- stringBuffer
- .append("import org.springframework.shell.core.annotation.CliAvailabilityIndicator;");
- stringBuffer.append("import org.springframework.shell.core.annotation.CliCommand;");
- stringBuffer.append("import org.springframework.shell.core.annotation.CliOption;");
- stringBuffer.append("import org.apache.geode.management.cli.Result;");
- stringBuffer.append("import org.apache.geode.management.internal.cli.CliUtil;");
- stringBuffer.append("import org.apache.geode.management.internal.cli.result.ResultBuilder;");
- stringBuffer.append("import org.apache.geode.management.internal.cli.shell.Gfsh;");
-
- stringBuffer.append(
- "public final class UCDunitClass implements CommandMarker { public UCDunitClass() {}");
- stringBuffer.append("@CliCommand(value = { \"ucdunitcmd\" }, help = \"ucdunitcmd help\")");
- stringBuffer.append(
- "public final Result ucdunitcmd(@CliOption(key = { \"name\" }, help = \"ucdunitcmd name help\") String name) {");
- stringBuffer.append("return ResultBuilder.createInfoResult(\"ucdunitcmd \" + name); }");
- stringBuffer.append("@CliAvailabilityIndicator({ \"ucdunitcmd\" })");
- stringBuffer.append("public final boolean isAvailable() { return true; } }");
-
- ClassBuilder classBuilder = new ClassBuilder();
- final byte[] jarBytes = classBuilder.createJarFromClassContent("junit/ucdunit/UCDunitClass",
- stringBuffer.toString());
-
- final FileOutputStream outStream = new FileOutputStream(this.jarFile);
- outStream.write(jarBytes);
- outStream.close();
- }
-
- @Test
- public void testCommandLineProperty() {
- System.setProperty(CommandManager.USER_CMD_PACKAGES_PROPERTY, "junit.ucdunit");
-
- ClassPathLoader.setLatestToDefault();
- CommandManager.clearInstance();
-
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void run() {
- System.setProperty(CommandManager.USER_CMD_PACKAGES_PROPERTY, "junit.ucdunit");
- ClassPathLoader.setLatestToDefault();
- CommandManager.clearInstance();
- }
- });
-
- setUpJmxManagerOnVm0ThenConnect(null);
-
- CommandResult cmdResult = executeCommand("ucdunitcmd");
- assertEquals(Result.Status.OK, cmdResult.getStatus());
- }
-
- @Test
- public void testGemFireProperty() {
- System.setProperty(CommandManager.USER_CMD_PACKAGES_PROPERTY, "junit.ucdunit");
-
- ClassPathLoader.setLatestToDefault();
- CommandManager.clearInstance();
-
- Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void run() {
- ClassPathLoader.setLatestToDefault();
- CommandManager.clearInstance();
- }
- });
-
- Properties properties = new Properties();
- properties.setProperty(ConfigurationProperties.USER_COMMAND_PACKAGES, "junit.ucdunit");
- setUpJmxManagerOnVm0ThenConnect(properties);
-
- CommandResult cmdResult = executeCommand("ucdunitcmd");
- assertEquals(Result.Status.OK, cmdResult.getStatus());
- }
-}
[3/8] geode git commit: GEODE-2686: Remove JarClassLoader
Posted by js...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
index 6baddaf..0d26caf 100755
--- a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderTest.java
@@ -14,7 +14,9 @@
*/
package org.apache.geode.internal;
-import static org.junit.Assert.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.io.BufferedInputStream;
import java.io.File;
@@ -62,7 +64,22 @@ public class ClassPathLoaderTest {
public void testLatestExists() throws Exception {
System.out.println("\nStarting ClassPathLoaderTest#testLatestExists");
- assertNotNull(ClassPathLoader.getLatest());
+ assertThat(ClassPathLoader.getLatest()).isNotNull();
+ }
+
+ @Test
+ public void testZeroLengthFile() throws IOException, ClassNotFoundException {
+ assertThatThrownBy(() -> {
+ ClassPathLoader.getLatest().getJarDeployer().deploy(new String[] {"JarDeployerDUnitZLF.jar"},
+ new byte[][] {new byte[0]});
+ }).isInstanceOf(IllegalArgumentException.class);
+
+ assertThatThrownBy(() -> {
+ ClassPathLoader.getLatest().getJarDeployer().deploy(
+ new String[] {"JarDeployerDUnitZLF1.jar", "JarDeployerDUnitZLF2.jar"},
+ new byte[][] {new ClassBuilder().createJarFromName("JarDeployerDUnitZLF1"), new byte[0]});
+
+ }).isInstanceOf(IllegalArgumentException.class);
}
/**
@@ -73,13 +90,10 @@ public class ClassPathLoaderTest {
public void testForNameThrowsClassNotFoundException() throws Exception {
System.out.println("\nStarting ClassPathLoaderTest#testForNameThrowsClassNotFoundException");
- try {
- String classToLoad = "com.nowhere.DoesNotExist";
- ClassPathLoader.getLatest().forName(classToLoad);
- fail();
- } catch (ClassNotFoundException expected) {
- // Expected
- }
+ String classToLoad = "com.nowhere.DoesNotExist";
+
+ assertThatThrownBy(() -> ClassPathLoader.getLatest().forName(classToLoad))
+ .isInstanceOf(ClassNotFoundException.class);
}
/**
@@ -92,7 +106,7 @@ public class ClassPathLoaderTest {
String classToLoad = "org.apache.geode.internal.classpathloaderjunittest.DoesExist";
Class<?> clazz = ClassPathLoader.getLatest().forName(classToLoad);
- assertNotNull(clazz);
+ assertThat(clazz).isNotNull();
}
/**
@@ -105,10 +119,10 @@ public class ClassPathLoaderTest {
String resourceToGet = "org/apache/geode/internal/classpathloaderjunittest/DoesExist.class";
URL url = ClassPathLoader.getLatest().getResource(resourceToGet);
- assertNotNull(url);
+ assertThat(url).isNotNull();
InputStream is = url != null ? url.openStream() : null;
- assertNotNull(is);
+ assertThat(is).isNotNull();
int totalBytesRead = 0;
byte[] input = new byte[256];
@@ -122,7 +136,7 @@ public class ClassPathLoaderTest {
// if the following fails then maybe javac changed and DoesExist.class
// contains other than 374 bytes of data... consider updating this test
- assertEquals(GENERATED_CLASS_BYTES_COUNT, totalBytesRead);
+ assertThat(totalBytesRead).isEqualTo(GENERATED_CLASS_BYTES_COUNT);
}
/**
@@ -135,12 +149,12 @@ public class ClassPathLoaderTest {
String resourceToGet = "org/apache/geode/internal/classpathloaderjunittest/DoesExist.class";
Enumeration<URL> urls = ClassPathLoader.getLatest().getResources(resourceToGet);
- assertNotNull(urls);
- assertTrue(urls.hasMoreElements());
+ assertThat(urls).isNotNull();
+ assertThat(urls.hasMoreElements()).isTrue();
URL url = urls.nextElement();
InputStream is = url != null ? url.openStream() : null;
- assertNotNull(is);
+ assertThat(is).isNotNull();
int totalBytesRead = 0;
byte[] input = new byte[256];
@@ -154,7 +168,7 @@ public class ClassPathLoaderTest {
// if the following fails then maybe javac changed and DoesExist.class
// contains other than 374 bytes of data... consider updating this test
- assertEquals(GENERATED_CLASS_BYTES_COUNT, totalBytesRead);
+ assertThat(totalBytesRead).isEqualTo(GENERATED_CLASS_BYTES_COUNT);
}
/**
@@ -167,7 +181,7 @@ public class ClassPathLoaderTest {
String resourceToGet = "org/apache/geode/internal/classpathloaderjunittest/DoesExist.class";
InputStream is = ClassPathLoader.getLatest().getResourceAsStream(resourceToGet);
- assertNotNull(is);
+ assertThat(is).isNotNull();
int totalBytesRead = 0;
byte[] input = new byte[256];
@@ -181,7 +195,7 @@ public class ClassPathLoaderTest {
// if the following fails then maybe javac changed and DoesExist.class
// contains other than 374 bytes of data... consider updating this test
- assertEquals(GENERATED_CLASS_BYTES_COUNT, totalBytesRead);
+ assertThat(totalBytesRead).isEqualTo(GENERATED_CLASS_BYTES_COUNT);
}
/**
@@ -197,44 +211,22 @@ public class ClassPathLoaderTest {
String classToLoad = "com.nowhere.TestGeneratingClassLoader";
Class<?> clazz = gcl.loadClass(classToLoad);
- assertNotNull(clazz);
- assertEquals(classToLoad, clazz.getName());
+ assertThat(clazz).isNotNull();
+ assertThat(clazz.getName()).isEqualTo(classToLoad);
Object obj = clazz.newInstance();
- assertEquals(clazz.getName(), obj.getClass().getName());
+ assertThat(obj.getClass().getName()).isEqualTo(clazz.getName());
- try {
+ assertThatThrownBy(() -> {
Class.forName(classToLoad);
- fail("Should have thrown ClassNotFoundException");
- } catch (ClassNotFoundException expected) {
- // Expected
- }
+ }).isInstanceOf(ClassNotFoundException.class);
Class<?> clazzForName = Class.forName(classToLoad, true, gcl);
- assertNotNull(clazzForName);
- assertEquals(clazz, clazzForName);
+ assertThat(clazzForName).isNotNull();
+ assertThat(clazzForName).isEqualTo(clazz);
Object objForName = clazzForName.newInstance();
- assertEquals(classToLoad, objForName.getClass().getName());
- }
-
- /**
- * Verifies that custom loader is used to load class.
- */
- @Test
- public void testForNameWithCustomLoader() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testForNameWithCustomLoader");
-
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
-
- String classToLoad = "com.nowhere.TestForNameWithCustomLoader";
- Class<?> clazz = dcl.forName(classToLoad);
- assertNotNull(clazz);
- assertEquals(classToLoad, clazz.getName());
-
- Object obj = clazz.newInstance();
- assertEquals(classToLoad, obj.getClass().getName());
+ assertThat(objForName.getClass().getName()).isEqualTo(classToLoad);
}
/**
@@ -251,7 +243,7 @@ public class ClassPathLoaderTest {
String classToLoad = "[Ljava.lang.String;";
Class<?> clazz = null;
clazz = dcl.forName(classToLoad);
- assertEquals(classToLoad, clazz.getName());
+ assertThat(clazz.getName()).isEqualTo(classToLoad);
}
/**
@@ -265,33 +257,27 @@ public class ClassPathLoaderTest {
final ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
final String classToLoad = "com.nowhere.TestForNameWithTCCL";
- try {
+ assertThatThrownBy(() -> {
dcl.forName(classToLoad);
- fail("Should have thrown ClassNotFoundException");
- } catch (ClassNotFoundException expected) {
- // Expected
- }
+
+ }).isInstanceOf(ClassNotFoundException.class);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
// ensure that TCCL is only CL that can find this class
Thread.currentThread().setContextClassLoader(new GeneratingClassLoader());
Class<?> clazz = dcl.forName(classToLoad);
- assertNotNull(clazz);
+ assertThat(clazz).isNotNull();
Object instance = clazz.newInstance();
- assertNotNull(instance);
- assertEquals(classToLoad, instance.getClass().getName());
+ assertThat(instance).isNotNull();
+ assertThat(instance.getClass().getName()).isEqualTo(classToLoad);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
- try {
+ assertThatThrownBy(() -> {
dcl.forName(classToLoad);
- fail("Should have thrown ClassNotFoundException");
- } catch (ClassNotFoundException expected) {
- // Expected
- }
-
+ }).isInstanceOf(ClassNotFoundException.class);
}
/**
@@ -305,20 +291,17 @@ public class ClassPathLoaderTest {
ClassLoader cl = new NullClassLoader();
String classToLoad = "java.lang.String";
- try {
+ assertThatThrownBy(() -> {
Class.forName(classToLoad, true, cl);
- fail();
- } catch (ClassNotFoundException expected) {
- // Expected
- }
+ }).isInstanceOf(ClassNotFoundException.class);
String resourceToGet = "java/lang/String.class";
URL url = cl.getResource(resourceToGet);
- assertNull(url);
+ assertThat(url).isNull();
InputStream is = cl.getResourceAsStream(resourceToGet);
- assertNull(is);
+ assertThat(is).isNull();
}
/**
@@ -333,15 +316,15 @@ public class ClassPathLoaderTest {
String classToLoad = "java.lang.String";
Class<?> clazz = Class.forName(classToLoad, true, cl);
- assertNotNull(clazz);
+ assertThat(clazz).isNotNull();
String resourceToGet = "java/lang/String.class";
URL url = cl.getResource(resourceToGet);
- assertNotNull(url);
+ assertThat(url).isNotNull();
InputStream is = cl.getResourceAsStream(resourceToGet);
- assertNotNull(is);
+ assertThat(is).isNotNull();
}
/**
@@ -355,28 +338,19 @@ public class ClassPathLoaderTest {
ClassLoader cl = new BrokenClassLoader();
String classToLoad = "java.lang.String";
- try {
+
+ assertThatThrownBy(() -> {
Class.forName(classToLoad, true, cl);
- fail();
- } catch (ClassNotFoundException e) {
- throw e;
- } catch (BrokenError expected) {
- // Expected
- }
+ }).isInstanceOf(BrokenError.class);
String resourceToGet = "java/lang/String.class";
- try {
+ assertThatThrownBy(() -> {
cl.getResource(resourceToGet);
- fail();
- } catch (BrokenError expected) {
- // Expected
- }
- try {
+ }).isInstanceOf(BrokenError.class);
+
+ assertThatThrownBy(() -> {
cl.getResourceAsStream(resourceToGet);
- fail();
- } catch (BrokenError expected) {
- // Expected
- }
+ }).isInstanceOf(BrokenError.class);
}
/**
@@ -390,7 +364,6 @@ public class ClassPathLoaderTest {
System.out.println("\nStarting ClassPathLoaderTest#testBrokenTCCLThrowsErrors");
ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl.addOrReplace(new NullClassLoader());
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
@@ -398,29 +371,18 @@ public class ClassPathLoaderTest {
Thread.currentThread().setContextClassLoader(new BrokenClassLoader());
String classToLoad = "java.lang.String";
- try {
+ assertThatThrownBy(() -> {
dcl.forName(classToLoad);
- fail();
- } catch (ClassNotFoundException e) {
- throw e;
- } catch (BrokenError expected) {
- // Expected
- }
+ }).isInstanceOf(BrokenError.class);
String resourceToGet = "java/lang/String.class";
- try {
+ assertThatThrownBy(() -> {
dcl.getResource(resourceToGet);
- fail();
- } catch (BrokenError expected) {
- // Expected
- }
+ }).isInstanceOf(BrokenError.class);
- try {
+ assertThatThrownBy(() -> {
dcl.getResourceAsStream(resourceToGet);
- fail();
- } catch (BrokenError expected) {
- // Expected
- }
+ }).isInstanceOf(BrokenError.class);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
@@ -436,7 +398,6 @@ public class ClassPathLoaderTest {
// create DCL such that parent cannot find anything
ClassPathLoader dcl = ClassPathLoader.createWithDefaults(true);
- dcl.addOrReplace(new NullClassLoader());
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
@@ -445,52 +406,13 @@ public class ClassPathLoaderTest {
String classToLoad = "java.lang.String";
Class<?> clazz = dcl.forName(classToLoad);
- assertNotNull(clazz);
+ assertThat(clazz).isNotNull();
String resourceToGet = "java/lang/String.class";
URL url = dcl.getResource(resourceToGet);
- assertNotNull(url);
+ assertThat(url).isNotNull();
InputStream is = dcl.getResourceAsStream(resourceToGet);
- assertNotNull(is);
- } finally {
- Thread.currentThread().setContextClassLoader(cl);
- }
- }
-
- /**
- * Verifies that the 3rd custom loader will find the class. Parent cannot find it and TCCL is
- * broken. This verifies that all custom loaders are checked and that the custom loaders are all
- * checked before TCCL.
- */
- @Test
- public void testForNameWithMultipleCustomLoaders() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testForNameWithMultipleCustomLoaders");
-
- // create DCL such that the 3rd loader should find the class
- // first custom loader becomes parent which won't find anything
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- final GeneratingClassLoader generatingClassLoader = new GeneratingClassLoader();
- dcl = dcl.addOrReplace(generatingClassLoader);
- dcl = dcl.addOrReplace(new SimpleClassLoader(getClass().getClassLoader()));
- dcl = dcl.addOrReplace(new NullClassLoader());
-
- String classToLoad = "com.nowhere.TestForNameWithMultipleCustomLoaders";
-
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- try {
- // set TCCL to throw errors which makes sure we find before checking TCCL
- Thread.currentThread().setContextClassLoader(new BrokenClassLoader());
-
- Class<?> clazz = dcl.forName(classToLoad);
- assertNotNull(clazz);
- assertEquals(classToLoad, clazz.getName());
- assertTrue("Class not loaded by a GeneratingClassLoader.",
- clazz.getClassLoader() instanceof GeneratingClassLoader);
- assertEquals("Class not loaded by generatingClassLoader.", generatingClassLoader,
- clazz.getClassLoader());
-
- Object obj = clazz.newInstance();
- assertEquals(classToLoad, obj.getClass().getName());
+ assertThat(is).isNotNull();
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
@@ -508,28 +430,24 @@ public class ClassPathLoaderTest {
String classToLoad = "com.nowhere.TestExcludeTCCL";
- try {
+ assertThatThrownBy(() -> {
dcl.forName(classToLoad);
- fail("Should have thrown ClassNotFoundException");
- } catch (ClassNotFoundException expected) {
- // Expected
- }
+
+ }).isInstanceOf(ClassNotFoundException.class);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
+
try {
- // ensure that TCCL is only CL that can find this class
Thread.currentThread().setContextClassLoader(new GeneratingClassLoader());
- dcl.forName(classToLoad);
- fail("Should have thrown ClassNotFoundException");
- } catch (ClassNotFoundException expected) {
- // Expected
+
+ assertThatThrownBy(() -> {
+ dcl.forName(classToLoad);
+ }).isInstanceOf(ClassNotFoundException.class);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
-
}
-
/**
* Verifies that <tt>getResource</tt> will skip TCCL if <tt>excludeThreadContextClassLoader</tt>
* has been set to true.
@@ -541,13 +459,13 @@ public class ClassPathLoaderTest {
ClassPathLoader dcl = ClassPathLoader.createWithDefaults(true);
String resourceToGet = "com/nowhere/testGetResourceExcludeTCCL.rsc";
- assertNull(dcl.getResource(resourceToGet));
+ assertThat(dcl.getResource(resourceToGet)).isNull();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
// ensure that TCCL is only CL that can find this resource
Thread.currentThread().setContextClassLoader(new GeneratingClassLoader());
- assertNull(dcl.getResource(resourceToGet));
+ assertThat(dcl.getResource(resourceToGet)).isNull();
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
@@ -564,161 +482,18 @@ public class ClassPathLoaderTest {
ClassPathLoader dcl = ClassPathLoader.createWithDefaults(true);
String resourceToGet = "com/nowhere/testGetResourceAsStreamExcludeTCCL.rsc";
- assertNull(dcl.getResourceAsStream(resourceToGet));
+ assertThat(dcl.getResourceAsStream(resourceToGet)).isNull();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
// ensure that TCCL is only CL that can find this resource
Thread.currentThread().setContextClassLoader(new GeneratingClassLoader());
- assertNull(dcl.getResourceAsStream(resourceToGet));
- } finally {
- Thread.currentThread().setContextClassLoader(cl);
- }
- }
-
- @Test
- public void testAddFindsLatestClassLoader() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testAddFindsLatestClassLoader");
-
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
-
- String classToLoad = "com.nowhere.TestAddFindsLatestClassLoader";
- Class<?> clazz = dcl.forName(classToLoad);
- assertNotNull(clazz);
-
- dcl = dcl.addOrReplace(new BrokenClassLoader());
-
- try {
- dcl.forName(classToLoad);
- fail();
- } catch (BrokenError expected) {
- // Expected
- }
- }
-
- /**
- * Verifies removing a ClassLoader.
- */
- @Test
- public void testRemoveClassLoader() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testRemoveClassLoader");
-
- GeneratingClassLoader genClassLoader = new GeneratingClassLoader();
- ClassPathLoader cpl = ClassPathLoader.createWithDefaults(false);
- cpl = cpl.addOrReplace(genClassLoader);
-
- String classToLoad = "com.nowhere.TestRemoveClassLoader";
- Class<?> clazz = cpl.forName(classToLoad);
- assertNotNull(clazz);
-
- cpl = cpl.remove(genClassLoader);
-
- try {
- clazz = cpl.forName(classToLoad);
- fail();
- } catch (ClassNotFoundException expected) {
- // Expected
- }
- }
-
- /**
- * Verifies that a ClassLoader will be replaced when added more than once.
- */
- @Test
- public void testClassLoaderReplace() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testClassLoaderReplace");
-
- String class1ToLoad = "ClassA";
- String class2ToLoad = "ClassB";
-
- ClassPathLoader cpl = ClassPathLoader.createWithDefaults(false);
- cpl = cpl.addOrReplace(new OneClassClassLoader(class1ToLoad));
-
- try {
- @SuppressWarnings("unused")
- Class<?> clazz = cpl.forName(class1ToLoad);
- } catch (ClassNotFoundException unexpected) {
- fail();
- }
-
- try {
- @SuppressWarnings("unused")
- Class<?> clazz = cpl.forName(class2ToLoad);
- fail();
- } catch (ClassNotFoundException expected) {
- // Expected
- }
-
- cpl = cpl.addOrReplace(new OneClassClassLoader(class2ToLoad));
- try {
- @SuppressWarnings("unused")
- Class<?> clazz = cpl.forName(class2ToLoad);
- } catch (ClassNotFoundException unexpected) {
- fail();
- }
-
- try {
- @SuppressWarnings("unused")
- Class<?> clazz = cpl.forName(class1ToLoad);
- fail();
- } catch (ClassNotFoundException expected) {
- // Expected
- }
- }
-
- @Test
- public void testAsClassLoaderLoadClassWithMultipleCustomLoaders() throws Exception {
- System.out.println(
- "\nStarting ClassPathLoaderTest#testAsClassLoaderLoadClassWithMultipleCustomLoaders");
-
- // create DCL such that the 3rd loader should find the class
- // first custom loader becomes parent which won't find anything
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- final GeneratingClassLoader generatingClassLoader = new GeneratingClassLoader();
- dcl = dcl.addOrReplace(generatingClassLoader);
- dcl = dcl.addOrReplace(new SimpleClassLoader(getClass().getClassLoader()));
- dcl = dcl.addOrReplace(new NullClassLoader());
-
- final String classToLoad = "com.nowhere.TestForNameWithMultipleCustomLoaders";
-
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- try {
- // set TCCL to throw errors which makes sure we find before checking TCCL
- Thread.currentThread().setContextClassLoader(new BrokenClassLoader());
-
- final ClassLoader classLoader = dcl.asClassLoader();
- final Class<?> clazz = classLoader.loadClass(classToLoad);
- assertNotNull(clazz);
- assertEquals(classToLoad, clazz.getName());
- assertTrue(clazz.getClassLoader() instanceof GeneratingClassLoader);
- assertEquals(generatingClassLoader, clazz.getClassLoader());
-
- final Object obj = clazz.newInstance();
- assertEquals(classToLoad, obj.getClass().getName());
-
- final Class<?> clazz2 = dcl.forName(classToLoad);
- assertSame("Should load same class as calling classLoader.", clazz, clazz2);
-
- final Class<?> clazz3 = Class.forName(classToLoad, true, classLoader);
- assertSame("Should load same class as calling classLoader.", clazz, clazz3);
-
+ assertThat(dcl.getResourceAsStream(resourceToGet)).isNull();
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
}
- private static void exploreClassLoaders() {
- System.out.println("Thread.currentThread().getContextClassLoader()...");
- exploreClassLoader(Thread.currentThread().getContextClassLoader(), 1);
-
- System.out.println("class.getClassLoader()...");
- exploreClassLoader(ClassPathLoaderTest.class.getClassLoader(), 1);
-
- System.out.println("ClassLoader.getSystemClassLoader()...");
- exploreClassLoader(ClassLoader.getSystemClassLoader(), 1);
- }
-
private static void exploreClassLoader(ClassLoader cl, int indent) {
String prefix = "";
for (int i = 0; i < indent; i++) {
@@ -734,8 +509,9 @@ public class ClassPathLoaderTest {
URL[] urls = ((URLClassLoader) cl).getURLs();
StringBuilder sb = new StringBuilder(prefix).append("ClassLoader getURLs = [");
for (int i = 0; i < urls.length; i++) {
- if (i > 0)
+ if (i > 0) {
sb.append(", ");
+ }
sb.append(urls[i].toString());
}
sb.append("]");
@@ -816,7 +592,7 @@ public class ClassPathLoaderTest {
/**
* Currently unused but potentially useful for some future test. This causes this loader to only
* generate a class that the parent could not find.
- *
+ *
* @param parent the parent class loader to check with first
*/
@SuppressWarnings("unused")
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java
new file mode 100644
index 0000000..7216463
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java
@@ -0,0 +1,538 @@
+/*
+ * 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.geode.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.cache.execute.ResultSender;
+import org.apache.geode.internal.cache.execute.FunctionContextImpl;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Random;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * TODO: Need to fix this testDeclarableFunctionsWithParms and testClassOnClasspath on Windows:
+ */
+@Category(IntegrationTest.class)
+public class DeployedJarJUnitTest {
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ private final ClassBuilder classBuilder = new ClassBuilder();
+
+ @Before
+ public void setup() throws Exception {
+ File workingDir = temporaryFolder.newFolder();
+
+ ClassPathLoader.setLatestToDefault(workingDir);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ for (String functionName : FunctionService.getRegisteredFunctions().keySet()) {
+ FunctionService.unregisterFunction(functionName);
+ }
+
+ ClassPathLoader.setLatestToDefault();
+ }
+
+ @Test
+ public void testIsValidJarContent() throws IOException {
+ assertTrue(
+ DeployedJar.isValidJarContent(this.classBuilder.createJarFromName("JarClassLoaderJUnitA")));
+ }
+
+ @Test
+ public void testIsInvalidJarContent() {
+ assertFalse(DeployedJar.isValidJarContent("INVALID JAR CONTENT".getBytes()));
+ }
+
+ @Test
+ public void testClassOnClasspath() throws Exception {
+ // Deploy the first JAR file and make sure the class is on the Classpath
+ byte[] jarBytes =
+ this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitA",
+ "package com.jcljunit; public class JarClassLoaderJUnitA {}");
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
+
+ try {
+ ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA");
+ } catch (ClassNotFoundException cnfex) {
+ fail("JAR file not correctly added to Classpath");
+ }
+
+ // Update the JAR file and make sure the first class is no longer on the Classpath
+ // and the second one is.
+ jarBytes = this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitB",
+ "package com.jcljunit; public class JarClassLoaderJUnitB {}");
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
+
+ try {
+ ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitB");
+ } catch (ClassNotFoundException cnfex) {
+ fail("JAR file not correctly added to Classpath");
+ }
+
+ try {
+ ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA");
+ fail("Class should not be found on Classpath");
+ } catch (ClassNotFoundException expected) { // expected
+ }
+
+ }
+
+ @Test
+ public void testFailingCompilation() throws Exception {
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("import org.apache.geode.cache.Declarable;");
+ stringBuffer.append("import org.apache.geode.cache.execute.Function;");
+ stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
+ stringBuffer.append("public class JarClassLoaderJUnitFunction implements Function {}");
+ String functionString = stringBuffer.toString();
+
+ try {
+ this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
+ fail("This code should have failed to compile and thrown an exception");
+ } catch (Exception ex) {
+ // All good
+ }
+ }
+
+ @Test
+ public void testFunctions() throws IOException, ClassNotFoundException {
+ // Test creating a JAR file with a function
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("import java.util.Properties;");
+ stringBuffer.append("import org.apache.geode.cache.Declarable;");
+ stringBuffer.append("import org.apache.geode.cache.execute.Function;");
+ stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
+ stringBuffer.append("public class JarClassLoaderJUnitFunction implements Function {");
+ stringBuffer.append("public void init(Properties props) {}");
+ stringBuffer.append("public boolean hasResult() {return true;}");
+ stringBuffer.append(
+ "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"GOODv1\");}");
+ stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}");
+ stringBuffer.append("public boolean optimizeForWrite() {return false;}");
+ stringBuffer.append("public boolean isHA() {return false;}}");
+ String functionString = stringBuffer.toString();
+
+ byte[] jarBytes =
+ this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
+
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
+
+ Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
+ assertNotNull(function);
+ TestResultSender resultSender = new TestResultSender();
+ FunctionContext functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
+ function.execute(functionContext);
+ assertEquals("GOODv1", (String) resultSender.getResults());
+
+ // Test updating the function with a new JAR file
+ functionString = functionString.replace("v1", "v2");
+ jarBytes =
+ this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
+
+ function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
+ assertNotNull(function);
+ resultSender = new TestResultSender();
+ functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
+ function.execute(functionContext);
+ assertEquals("GOODv2", (String) resultSender.getResults());
+
+ // Test returning null for the Id
+ String functionNullIdString =
+ functionString.replace("return \"JarClassLoaderJUnitFunction\"", "return null");
+ jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction",
+ functionNullIdString);
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
+
+ assertNull(FunctionService.getFunction("JarClassLoaderJUnitFunction"));
+
+ // Test removing the JAR
+ ClassPathLoader.getLatest().getJarDeployer().undeploy("JarClassLoaderJUnit.jar");
+ assertNull(FunctionService.getFunction("JarClassLoaderJUnitFunction"));
+ }
+
+ /**
+ * Ensure that abstract functions aren't added to the Function Service.
+ */
+ @Test
+ public void testAbstractFunction() throws IOException, ClassNotFoundException {
+ // Add an abstract Function to the Classpath
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("import org.apache.geode.cache.execute.Function;");
+ stringBuffer.append("public abstract class JarClassLoaderJUnitFunction implements Function {");
+ stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}}");
+ String functionString = stringBuffer.toString();
+
+ byte[] jarBytes =
+ this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitFunction.jar",
+ jarBytes);
+
+ try {
+ ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunction");
+ } catch (ClassNotFoundException cnfex) {
+ fail("JAR file not correctly added to Classpath");
+ }
+
+ Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
+ assertNull(function);
+ }
+
+ @Test
+ public void testDeclarableFunctionsWithNoCacheXml() throws Exception {
+
+ final String jarName = "JarClassLoaderJUnitNoXml.jar";
+
+ // Add a Declarable Function without parameters for the class to the Classpath
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("import java.util.Properties;");
+ stringBuffer.append("import org.apache.geode.cache.Declarable;");
+ stringBuffer.append("import org.apache.geode.cache.execute.Function;");
+ stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
+ stringBuffer
+ .append("public class JarClassLoaderJUnitFunctionNoXml implements Function, Declarable {");
+ stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunctionNoXml\";}");
+ stringBuffer.append("public void init(Properties props) {}");
+ stringBuffer.append(
+ "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"NOPARMSv1\");}");
+ stringBuffer.append("public boolean hasResult() {return true;}");
+ stringBuffer.append("public boolean optimizeForWrite() {return false;}");
+ stringBuffer.append("public boolean isHA() {return false;}}");
+ String functionString = stringBuffer.toString();
+
+ byte[] jarBytes = this.classBuilder
+ .createJarFromClassContent("JarClassLoaderJUnitFunctionNoXml", functionString);
+
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, jarBytes);
+
+ try {
+ ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunctionNoXml");
+ } catch (ClassNotFoundException cnfex) {
+ fail("JAR file not correctly added to Classpath");
+ }
+
+ // Check to see if the function without parameters executes correctly
+ Function function = FunctionService.getFunction("JarClassLoaderJUnitFunctionNoXml");
+ assertNotNull(function);
+ TestResultSender resultSender = new TestResultSender();
+ function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
+ assertEquals("NOPARMSv1", (String) resultSender.getResults());
+ }
+
+ @Test
+ public void testDependencyBetweenJars() throws IOException, ClassNotFoundException {
+ final File parentJarFile = temporaryFolder.newFile("JarClassLoaderJUnitParent.jar");
+ final File usesJarFile = temporaryFolder.newFile("JarClassLoaderJUnitUses.jar");
+
+ JarDeployer jarDeployer = ClassPathLoader.getLatest().getJarDeployer();
+
+ // Write out a JAR files.
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("package jcljunit.parent;");
+ stringBuffer.append("public class JarClassLoaderJUnitParent {");
+ stringBuffer.append("public String getValueParent() {");
+ stringBuffer.append("return \"PARENT\";}}");
+
+ byte[] jarBytes = this.classBuilder.createJarFromClassContent(
+ "jcljunit/parent/JarClassLoaderJUnitParent", stringBuffer.toString());
+ writeJarBytesToFile(parentJarFile, jarBytes);
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitParent.jar", jarBytes);
+
+ stringBuffer = new StringBuffer();
+ stringBuffer.append("package jcljunit.uses;");
+ stringBuffer.append("public class JarClassLoaderJUnitUses {");
+ stringBuffer.append("public String getValueUses() {");
+ stringBuffer.append("return \"USES\";}}");
+
+ jarBytes = this.classBuilder.createJarFromClassContent("jcljunit/uses/JarClassLoaderJUnitUses",
+ stringBuffer.toString());
+ writeJarBytesToFile(usesJarFile, jarBytes);
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUses.jar", jarBytes);
+
+ stringBuffer = new StringBuffer();
+ stringBuffer.append("package jcljunit.function;");
+ stringBuffer.append("import jcljunit.parent.JarClassLoaderJUnitParent;");
+ stringBuffer.append("import jcljunit.uses.JarClassLoaderJUnitUses;");
+ stringBuffer.append("import org.apache.geode.cache.execute.Function;");
+ stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
+ stringBuffer.append(
+ "public class JarClassLoaderJUnitFunction extends JarClassLoaderJUnitParent implements Function {");
+ stringBuffer.append("private JarClassLoaderJUnitUses uses = new JarClassLoaderJUnitUses();");
+ stringBuffer.append("public boolean hasResult() {return true;}");
+ stringBuffer.append(
+ "public void execute(FunctionContext context) {context.getResultSender().lastResult(getValueParent() + \":\" + uses.getValueUses());}");
+ stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}");
+ stringBuffer.append("public boolean optimizeForWrite() {return false;}");
+ stringBuffer.append("public boolean isHA() {return false;}}");
+
+ ClassBuilder functionClassBuilder = new ClassBuilder();
+ functionClassBuilder.addToClassPath(parentJarFile.getAbsolutePath());
+ functionClassBuilder.addToClassPath(usesJarFile.getAbsolutePath());
+ jarBytes = functionClassBuilder.createJarFromClassContent(
+ "jcljunit/function/JarClassLoaderJUnitFunction", stringBuffer.toString());
+
+
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitFunction.jar",
+ jarBytes);
+
+
+ Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
+ assertNotNull(function);
+ TestResultSender resultSender = new TestResultSender();
+ FunctionContext functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
+ function.execute(functionContext);
+ assertEquals("PARENT:USES", (String) resultSender.getResults());
+ }
+
+ @Test
+ public void testFindResource() throws IOException, ClassNotFoundException {
+ final String fileName = "file.txt";
+ final String fileContent = "FILE CONTENT";
+
+ byte[] jarBytes = this.classBuilder.createJarFromFileContent(fileName, fileContent);
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitResource.jar",
+ jarBytes);
+
+ InputStream inputStream = ClassPathLoader.getLatest().getResourceAsStream(fileName);
+ assertNotNull(inputStream);
+
+ final byte[] fileBytes = new byte[fileContent.length()];
+ inputStream.read(fileBytes);
+ inputStream.close();
+ assertTrue(fileContent.equals(new String(fileBytes)));
+ }
+
+ @Test
+ public void testUpdateClassInJar() throws IOException, ClassNotFoundException {
+ // First use of the JAR file
+ byte[] jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass",
+ "public class JarClassLoaderJUnitTestClass { public Integer getValue5() { return new Integer(5); } }");
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes);
+
+ try {
+ Class<?> clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass");
+ Object object = clazz.newInstance();
+ Method getValue5Method = clazz.getMethod("getValue5", new Class[] {});
+ Integer value = (Integer) getValue5Method.invoke(object, new Object[] {});
+ assertEquals(value.intValue(), 5);
+
+ } catch (InvocationTargetException itex) {
+ fail("JAR file not correctly added to Classpath" + itex);
+ } catch (NoSuchMethodException nsmex) {
+ fail("JAR file not correctly added to Classpath" + nsmex);
+ } catch (InstantiationException iex) {
+ fail("JAR file not correctly added to Classpath" + iex);
+ } catch (IllegalAccessException iaex) {
+ fail("JAR file not correctly added to Classpath" + iaex);
+ } catch (ClassNotFoundException cnfex) {
+ fail("JAR file not correctly added to Classpath" + cnfex);
+ }
+
+ // Now create an updated JAR file and make sure that the method from the new
+ // class is available.
+ jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass",
+ "public class JarClassLoaderJUnitTestClass { public Integer getValue10() { return new Integer(10); } }");
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes);
+
+
+ try {
+ Class<?> clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass");
+ Object object = clazz.newInstance();
+ Method getValue10Method = clazz.getMethod("getValue10", new Class[] {});
+ Integer value = (Integer) getValue10Method.invoke(object, new Object[] {});
+ assertEquals(value.intValue(), 10);
+
+ } catch (InvocationTargetException itex) {
+ fail("JAR file not correctly added to Classpath" + itex);
+ } catch (NoSuchMethodException nsmex) {
+ fail("JAR file not correctly added to Classpath" + nsmex);
+ } catch (InstantiationException iex) {
+ fail("JAR file not correctly added to Classpath" + iex);
+ } catch (IllegalAccessException iaex) {
+ fail("JAR file not correctly added to Classpath" + iaex);
+ } catch (ClassNotFoundException cnfex) {
+ fail("JAR file not correctly added to Classpath" + cnfex);
+ }
+ }
+
+ @Test
+ public void testMultiThread() throws IOException, ClassNotFoundException {
+ // Add two JARs to the classpath
+ byte[] jarBytes = this.classBuilder.createJarFromName("JarClassLoaderJUnitA");
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitA.jar", jarBytes);
+
+ jarBytes = this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitB",
+ "package com.jcljunit; public class JarClassLoaderJUnitB {}");
+ ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitB.jar", jarBytes);
+
+ String[] classNames = new String[] {"JarClassLoaderJUnitA", "com.jcljunit.JarClassLoaderJUnitB",
+ "NON-EXISTENT CLASS"};
+
+ // Spawn some threads which try to instantiate these classes
+ final int threadCount = 10;
+ final int numLoops = 1000;
+ final CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount + 1);
+ for (int i = 0; i < threadCount; i++) {
+ new ForNameExerciser(cyclicBarrier, numLoops, classNames).start();
+ }
+
+ // Wait for all of the threads to be ready
+ try {
+ cyclicBarrier.await();
+ } catch (InterruptedException iex) {
+ fail("Interrupted while waiting for barrier");
+ } catch (BrokenBarrierException bbex) {
+ fail("Broken barrier while waiting");
+ }
+
+ // Loop while each thread tries N times to instantiate a non-existent class
+ for (int i = 0; i < numLoops; i++) {
+ try {
+ cyclicBarrier.await(5, TimeUnit.SECONDS);
+ } catch (InterruptedException iex) {
+ fail("Interrupted while waiting for barrier");
+ } catch (TimeoutException tex) {
+ ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+ long[] threadIds = threadMXBean.findDeadlockedThreads();
+
+ if (threadIds != null) {
+ StringBuffer deadLockTrace = new StringBuffer();
+ for (long threadId : threadIds) {
+ ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId, 100);
+ deadLockTrace.append(threadInfo.getThreadName()).append("\n");
+ for (StackTraceElement stackTraceElem : threadInfo.getStackTrace()) {
+ deadLockTrace.append("\t").append(stackTraceElem).append("\n");
+ }
+ }
+
+ fail("Deadlock with trace:\n" + deadLockTrace.toString());
+ }
+
+ fail("Timeout while waiting for barrier - no deadlock detected");
+ } catch (BrokenBarrierException bbex) {
+ fail("Broken barrier while waiting");
+ }
+ }
+ }
+
+
+ private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException {
+ final OutputStream outStream = new FileOutputStream(jarFile);
+ outStream.write(jarBytes);
+ outStream.close();
+ }
+
+ private static class TestResultSender implements ResultSender<Object> {
+ private Object result;
+
+ public TestResultSender() {}
+
+ protected Object getResults() {
+ return this.result;
+ }
+
+ @Override
+ public void lastResult(final Object lastResult) {
+ this.result = lastResult;
+ }
+
+ @Override
+ public void sendResult(final Object oneResult) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendException(final Throwable t) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ static final Random random = new Random();
+
+ private class ForNameExerciser extends Thread {
+ private final CyclicBarrier cyclicBarrier;
+ private final int numLoops;
+ private final String[] classNames;
+
+ ForNameExerciser(final CyclicBarrier cyclicBarrier, final int numLoops,
+ final String[] classNames) {
+ this.cyclicBarrier = cyclicBarrier;
+ this.numLoops = numLoops;
+ this.classNames = classNames;
+ }
+
+ @Override
+ public void run() {
+ try {
+ this.cyclicBarrier.await();
+ } catch (InterruptedException iex) {
+ fail("Interrupted while waiting for latch");
+ } catch (BrokenBarrierException bbex) {
+ fail("Broken barrier while waiting");
+ }
+ for (int i = 0; i < this.numLoops; i++) {
+ try {
+ // Random select a name from the list of class names and try to load it
+ String className = this.classNames[random.nextInt(this.classNames.length)];
+ ClassPathLoader.getLatest().forName(className);
+ } catch (ClassNotFoundException expected) { // expected
+ }
+ try {
+ this.cyclicBarrier.await();
+ } catch (InterruptedException iex) {
+ fail("Interrupted while waiting for barrrier");
+ } catch (BrokenBarrierException bbex) {
+ fail("Broken barrier while waiting");
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/internal/JarClassLoaderJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/JarClassLoaderJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/JarClassLoaderJUnitTest.java
deleted file mode 100644
index adc1d2e..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/JarClassLoaderJUnitTest.java
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * 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.geode.internal;
-
-import static org.apache.geode.distributed.ConfigurationProperties.*;
-import static org.junit.Assert.*;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.lang.management.ManagementFactory;
-import java.lang.management.ThreadInfo;
-import java.lang.management.ThreadMXBean;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Properties;
-import java.util.Random;
-import java.util.concurrent.BrokenBarrierException;
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.regex.Pattern;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.cache.CacheFactory;
-import org.apache.geode.cache.execute.Function;
-import org.apache.geode.cache.execute.FunctionContext;
-import org.apache.geode.cache.execute.FunctionService;
-import org.apache.geode.cache.execute.ResultSender;
-import org.apache.geode.internal.cache.InternalCache;
-import org.apache.geode.internal.cache.execute.FunctionContextImpl;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * TODO: Need to fix this testDeclarableFunctionsWithParms and testClassOnClasspath on Windows:
- */
-@Category(IntegrationTest.class)
-public class JarClassLoaderJUnitTest {
-
- private static final String JAR_PREFIX = "vf.gf#";
-
- private final ClassBuilder classBuilder = new ClassBuilder();
- final Pattern pattern = Pattern.compile("^" + JAR_PREFIX + "JarClassLoaderJUnit.*#\\d++$");
-
- private InternalCache cache;
-
- @After
- public void tearDown() throws Exception {
- for (ClassLoader classLoader : ClassPathLoader.getLatest().getClassLoaders()) {
- if (classLoader instanceof JarClassLoader) {
- JarClassLoader jarClassLoader = (JarClassLoader) classLoader;
- if (jarClassLoader.getJarName().startsWith("JarClassLoaderJUnit")) {
- ClassPathLoader.getLatest().removeAndSetLatest(jarClassLoader);
- }
- }
- }
- for (String functionName : FunctionService.getRegisteredFunctions().keySet()) {
- if (functionName.startsWith("JarClassLoaderJUnit")) {
- FunctionService.unregisterFunction(functionName);
- }
- }
-
- if (this.cache != null) {
- this.cache.close();
- }
-
- deleteSavedJarFiles();
- }
-
- @Test
- public void testValidJarContent() throws IOException {
- assertTrue(JarClassLoader
- .isValidJarContent(this.classBuilder.createJarFromName("JarClassLoaderJUnitA")));
- }
-
- @Test
- public void testInvalidJarContent() {
- assertFalse(JarClassLoader.isValidJarContent("INVALID JAR CONTENT".getBytes()));
- }
-
- @Test
- public void testClassOnClasspath() throws IOException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#1");
- final File jarFile2 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#2");
- ClassPathLoader classPathLoader = ClassPathLoader.createWithDefaults(false);
-
- // Deploy the first JAR file and make sure the class is on the Classpath
- byte[] jarBytes =
- this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitA",
- "package com.jcljunit; public class JarClassLoaderJUnitA {}");
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader = new JarClassLoader(jarFile1, "JarClassLoaderJUnit.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
-
- try {
- classPathLoader.forName("com.jcljunit.JarClassLoaderJUnitA");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- // Update the JAR file and make sure the first class is no longer on the Classpath
- // and the second one is.
- jarBytes = this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitB",
- "package com.jcljunit; public class JarClassLoaderJUnitB {}");
- writeJarBytesToFile(jarFile2, jarBytes);
- classLoader = new JarClassLoader(jarFile2, "JarClassLoaderJUnit.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
-
- try {
- classPathLoader.forName("com.jcljunit.JarClassLoaderJUnitB");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- try {
- classPathLoader.forName("com.jcljunit.JarClassLoaderJUnitA");
- fail("Class should not be found on Classpath");
- } catch (ClassNotFoundException expected) { // expected
- }
-
- classPathLoader.remove(classLoader);
- }
-
- @Test
- public void testFailingCompilation() throws Exception {
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer.append("public class JarClassLoaderJUnitFunction implements Function {}");
- String functionString = stringBuffer.toString();
-
- try {
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- fail("This code should have failed to compile and thrown an exception");
- } catch (Exception ex) {
- // All good
- }
- }
-
- @Test
- public void testFunctions() throws IOException, ClassNotFoundException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#1");
- final File jarFile2 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#2");
- ClassPathLoader classPathLoader = ClassPathLoader.createWithDefaults(false);
-
- // Test creating a JAR file with a function
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import java.util.Properties;");
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer.append("public class JarClassLoaderJUnitFunction implements Function {");
- stringBuffer.append("public void init(Properties props) {}");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"GOODv1\");}");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
- String functionString = stringBuffer.toString();
-
- byte[] jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader = new JarClassLoader(jarFile1, "JarClassLoaderJUnit.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
- TestResultSender resultSender = new TestResultSender();
- FunctionContext functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
- function.execute(functionContext);
- assertEquals("GOODv1", (String) resultSender.getResults());
-
- // Test updating the function with a new JAR file
- functionString = functionString.replace("v1", "v2");
- jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile2, jarBytes);
- classLoader = new JarClassLoader(jarFile2, "JarClassLoaderJUnit.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
- resultSender = new TestResultSender();
- functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
- function.execute(functionContext);
- assertEquals("GOODv2", (String) resultSender.getResults());
-
- // Test returning null for the Id
- String functionNullIdString =
- functionString.replace("return \"JarClassLoaderJUnitFunction\"", "return null");
- jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction",
- functionNullIdString);
- writeJarBytesToFile(jarFile1, jarBytes);
- classLoader = new JarClassLoader(jarFile1, "JarClassLoaderJUnit.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
- assertNull(FunctionService.getFunction("JarClassLoaderJUnitFunction"));
-
- // Test removing the JAR
- classPathLoader = classPathLoader.remove(classLoader);
- assertNull(FunctionService.getFunction("JarClassLoaderJUnitFunction"));
- }
-
- /**
- * Ensure that abstract functions aren't added to the Function Service.
- */
- @Test
- public void testAbstractFunction() throws IOException, ClassNotFoundException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#1");
-
- Properties properties = new Properties();
- properties.setProperty(MCAST_PORT, "0");
- CacheFactory cacheFactory = new CacheFactory(properties);
- this.cache = (InternalCache) cacheFactory.create();
-
- // Add an abstract Function to the Classpath
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("public abstract class JarClassLoaderJUnitFunction implements Function {");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}}");
- String functionString = stringBuffer.toString();
-
- byte[] jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader =
- new JarClassLoader(jarFile1, "JarClassLoaderJUnitFunction.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- try {
- ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunction");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNull(function);
- }
-
- @Test
- public void testDeclarableFunctionsWithNoCacheXml() throws IOException, ClassNotFoundException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnitNoXml.jar#1");
-
- // Add a Declarable Function without parameters for the class to the Classpath
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import java.util.Properties;");
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer
- .append("public class JarClassLoaderJUnitFunctionNoXml implements Function, Declarable {");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunctionNoXml\";}");
- stringBuffer.append("public void init(Properties props) {}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"NOPARMSv1\");}");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
- String functionString = stringBuffer.toString();
-
- byte[] jarBytes = this.classBuilder
- .createJarFromClassContent("JarClassLoaderJUnitFunctionNoXml", functionString);
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader =
- new JarClassLoader(jarFile1, "JarClassLoaderJUnitFunctionNoXml.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- try {
- ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunctionNoXml");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- // Check to see if the function without parameters executes correctly
- Function function = FunctionService.getFunction("JarClassLoaderJUnitFunctionNoXml");
- assertNotNull(function);
- TestResultSender resultSender = new TestResultSender();
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("NOPARMSv1", (String) resultSender.getResults());
- }
-
- @Test
- public void testDeclarableFunctionsWithoutParms() throws IOException, ClassNotFoundException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#1");
- final File jarFile2 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#2");
-
- Properties properties = new Properties();
- properties.setProperty(MCAST_PORT, "0");
- CacheFactory cacheFactory = new CacheFactory(properties);
- this.cache = (InternalCache) cacheFactory.create();
-
- // Add a Declarable Function without parameters for the class to the Classpath
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import java.util.Properties;");
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer
- .append("public class JarClassLoaderJUnitFunction implements Function, Declarable {");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}");
- stringBuffer.append("public void init(Properties props) {}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"NOPARMSv1\");}");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
- String functionString = stringBuffer.toString();
-
- byte[] jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader =
- new JarClassLoader(jarFile1, "JarClassLoaderJUnitFunction.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- try {
- ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunction");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- // Create a cache.xml file and configure the cache with it
- stringBuffer = new StringBuffer();
- stringBuffer.append("<?xml version=\"1.0\"?>");
- stringBuffer.append("<!DOCTYPE cache PUBLIC");
- stringBuffer.append(" \"-//GemStone Systems, Inc.//GemFire Declarative Caching 7.0//EN\"");
- stringBuffer.append(" \"http://www.gemstone.com/dtd/cache7_0.dtd\">");
- stringBuffer.append("<cache>");
- stringBuffer.append(" <function-service>");
- stringBuffer.append(" <function>");
- stringBuffer.append(" <class-name>JarClassLoaderJUnitFunction</class-name>");
- stringBuffer.append(" </function>");
- stringBuffer.append(" </function-service>");
- stringBuffer.append("</cache>");
- String cacheXmlString = stringBuffer.toString();
- this.cache.loadCacheXml(new ByteArrayInputStream(cacheXmlString.getBytes()));
-
- // Check to see if the function without parameters executes correctly
- Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
- TestResultSender resultSender = new TestResultSender();
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("NOPARMSv1", (String) resultSender.getResults());
-
- // Update the second function (change the value returned from execute) by deploying a JAR file
- functionString = functionString.replace("v1", "v2");
- jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile2, jarBytes);
-
- classLoader = new JarClassLoader(jarFile2, "JarClassLoaderJUnitFunction.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- // Check to see if the updated function without parameters executes correctly
- function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("NOPARMSv2", (String) resultSender.getResults());
- }
-
- @Test
- public void testDeclarableFunctionsWithParms() throws IOException, ClassNotFoundException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#1");
- final File jarFile2 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#2");
-
- Properties properties = new Properties();
- properties.setProperty(MCAST_PORT, "0");
- CacheFactory cacheFactory = new CacheFactory(properties);
- this.cache = (InternalCache) cacheFactory.create();
-
- // Add a Declarable Function with parameters to the class to the Classpath
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import java.util.Properties;");
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer
- .append("public class JarClassLoaderJUnitFunction implements Function, Declarable {");
- stringBuffer.append("private Properties properties;");
- stringBuffer.append(
- "public String getId() {if(this.properties==null) {return \"JarClassLoaderJUnitFunction\";} else {return (String) this.properties.get(\"id\");}}");
- stringBuffer.append("public void init(Properties props) {properties = props;}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(properties.get(\"returnValue\") + \"v1\");}");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
- String functionString = stringBuffer.toString();
-
- byte[] jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader =
- new JarClassLoader(jarFile1, "JarClassLoaderJUnitFunction.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- try {
- ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunction");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- // Create a cache.xml file and configure the cache with it
- stringBuffer = new StringBuffer();
- stringBuffer.append("<?xml version=\"1.0\"?>");
- stringBuffer.append("<!DOCTYPE cache PUBLIC");
- stringBuffer.append(" \"-//GemStone Systems, Inc.//GemFire Declarative Caching 7.0//EN\"");
- stringBuffer.append(" \"http://www.gemstone.com/dtd/cache7_0.dtd\">");
- stringBuffer.append("<cache>");
- stringBuffer.append(" <function-service>");
- stringBuffer.append(" <function>");
- stringBuffer.append(" <class-name>JarClassLoaderJUnitFunction</class-name>");
- stringBuffer.append(
- " <parameter name=\"id\"><string>JarClassLoaderJUnitFunctionA</string></parameter>");
- stringBuffer.append(" <parameter name=\"returnValue\"><string>DOG</string></parameter>");
- stringBuffer.append(" </function>");
- stringBuffer.append(" <function>");
- stringBuffer.append(" <class-name>JarClassLoaderJUnitFunction</class-name>");
- stringBuffer.append(
- " <parameter name=\"id\"><string>JarClassLoaderJUnitFunctionB</string></parameter>");
- stringBuffer.append(" <parameter name=\"returnValue\"><string>CAT</string></parameter>");
- stringBuffer.append(" </function>");
- stringBuffer.append(" </function-service>");
- stringBuffer.append("</cache>");
- String cacheXmlString = stringBuffer.toString();
- this.cache.loadCacheXml(new ByteArrayInputStream(cacheXmlString.getBytes()));
-
- // Check to see if the functions with parameters execute correctly
- Function function = FunctionService.getFunction("JarClassLoaderJUnitFunctionA");
- assertNotNull(function);
- TestResultSender resultSender = new TestResultSender();
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("DOGv1", (String) resultSender.getResults());
-
- function = FunctionService.getFunction("JarClassLoaderJUnitFunctionB");
- assertNotNull(function);
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("CATv1", (String) resultSender.getResults());
-
- // Update the first function (change the value returned from execute)
- functionString = functionString.replace("v1", "v2");
- jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile2, jarBytes);
- classLoader = new JarClassLoader(jarFile2, "JarClassLoaderJUnitFunction.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- // Check to see if the updated functions with parameters execute correctly
- function = FunctionService.getFunction("JarClassLoaderJUnitFunctionA");
- assertNotNull(function);
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("DOGv2", (String) resultSender.getResults());
-
- function = FunctionService.getFunction("JarClassLoaderJUnitFunctionB");
- assertNotNull(function);
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("CATv2", (String) resultSender.getResults());
-
- // Update cache xml to add a new function and replace an existing one
- cacheXmlString =
- cacheXmlString.replace("JarClassLoaderJUnitFunctionA", "JarClassLoaderJUnitFunctionC")
- .replace("CAT", "BIRD");
- this.cache.loadCacheXml(new ByteArrayInputStream(cacheXmlString.getBytes()));
-
- // Update the first function (change the value returned from execute)
- functionString = functionString.replace("v2", "v3");
- jarBytes =
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- writeJarBytesToFile(jarFile1, jarBytes);
- classLoader = new JarClassLoader(jarFile1, "JarClassLoaderJUnitFunction.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- // Check to see if the updated functions with parameters execute correctly
- function = FunctionService.getFunction("JarClassLoaderJUnitFunctionA");
- assertNotNull(function);
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("DOGv3", (String) resultSender.getResults());
-
- function = FunctionService.getFunction("JarClassLoaderJUnitFunctionC");
- assertNotNull(function);
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("DOGv3", (String) resultSender.getResults());
-
- function = FunctionService.getFunction("JarClassLoaderJUnitFunctionB");
- assertNotNull(function);
- function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("BIRDv3", (String) resultSender.getResults());
- }
-
- @Test
- public void testDependencyBetweenJars() throws IOException, ClassNotFoundException {
- final File parentJarFile = new File(JAR_PREFIX + "JarClassLoaderJUnitParent.jar#1");
- final File usesJarFile = new File(JAR_PREFIX + "JarClassLoaderJUnitUses.jar#1");
- final File functionJarFile = new File(JAR_PREFIX + "JarClassLoaderJUnitFunction.jar#1");
-
- // Write out a JAR files.
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("package jcljunit.parent;");
- stringBuffer.append("public class JarClassLoaderJUnitParent {");
- stringBuffer.append("public String getValueParent() {");
- stringBuffer.append("return \"PARENT\";}}");
-
- byte[] jarBytes = this.classBuilder.createJarFromClassContent(
- "jcljunit/parent/JarClassLoaderJUnitParent", stringBuffer.toString());
- writeJarBytesToFile(parentJarFile, jarBytes);
- JarClassLoader parentClassLoader =
- new JarClassLoader(parentJarFile, "JarClassLoaderJUnitParent.jar", jarBytes);
-
- stringBuffer = new StringBuffer();
- stringBuffer.append("package jcljunit.uses;");
- stringBuffer.append("public class JarClassLoaderJUnitUses {");
- stringBuffer.append("public String getValueUses() {");
- stringBuffer.append("return \"USES\";}}");
-
- jarBytes = this.classBuilder.createJarFromClassContent("jcljunit/uses/JarClassLoaderJUnitUses",
- stringBuffer.toString());
- writeJarBytesToFile(usesJarFile, jarBytes);
- JarClassLoader usesClassLoader =
- new JarClassLoader(usesJarFile, "JarClassLoaderJUnitUses.jar", jarBytes);
-
- stringBuffer = new StringBuffer();
- stringBuffer.append("package jcljunit.function;");
- stringBuffer.append("import jcljunit.parent.JarClassLoaderJUnitParent;");
- stringBuffer.append("import jcljunit.uses.JarClassLoaderJUnitUses;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer.append(
- "public class JarClassLoaderJUnitFunction extends JarClassLoaderJUnitParent implements Function {");
- stringBuffer.append("private JarClassLoaderJUnitUses uses = new JarClassLoaderJUnitUses();");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(getValueParent() + \":\" + uses.getValueUses());}");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
-
- ClassBuilder functionClassBuilder = new ClassBuilder();
- functionClassBuilder.addToClassPath(parentJarFile.getAbsolutePath());
- functionClassBuilder.addToClassPath(usesJarFile.getAbsolutePath());
- jarBytes = functionClassBuilder.createJarFromClassContent(
- "jcljunit/function/JarClassLoaderJUnitFunction", stringBuffer.toString());
- writeJarBytesToFile(functionJarFile, jarBytes);
- JarClassLoader functionClassLoader =
- new JarClassLoader(functionJarFile, "JarClassLoaderJUnitFunction.jar", jarBytes);
-
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(functionClassLoader);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(parentClassLoader);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(usesClassLoader);
-
- functionClassLoader.loadClassesAndRegisterFunctions();
-
- Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
- TestResultSender resultSender = new TestResultSender();
- FunctionContext functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
- function.execute(functionContext);
- assertEquals("PARENT:USES", (String) resultSender.getResults());
- }
-
- @Test
- public void testFindResource() throws IOException, ClassNotFoundException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnitResource.jar#1");
- ClassPathLoader classPathLoader = ClassPathLoader.createWithDefaults(false);
- final String fileName = "file.txt";
- final String fileContent = "FILE CONTENT";
-
- byte[] jarBytes = this.classBuilder.createJarFromFileContent(fileName, fileContent);
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader =
- new JarClassLoader(jarFile1, "JarClassLoaderJUnitResource.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- InputStream inputStream = classLoader.getResourceAsStream(fileName);
- assertNotNull(inputStream);
-
- final byte[] fileBytes = new byte[fileContent.length()];
- inputStream.read(fileBytes);
- inputStream.close();
- assertTrue(fileContent.equals(new String(fileBytes)));
- }
-
- @Test
- public void testUpdateClassInJar() throws IOException, ClassNotFoundException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#1");
- final File jarFile2 = new File(JAR_PREFIX + "JarClassLoaderJUnit.jar#2");
- ClassPathLoader classPathLoader = ClassPathLoader.createWithDefaults(false);
-
- // First use of the JAR file
- byte[] jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass",
- "public class JarClassLoaderJUnitTestClass { public Integer getValue5() { return new Integer(5); } }");
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader = new JarClassLoader(jarFile1, "JarClassLoaderJUnit.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- try {
- Class<?> clazz = classPathLoader.forName("JarClassLoaderJUnitTestClass");
- Object object = clazz.newInstance();
- Method getValue5Method = clazz.getMethod("getValue5", new Class[] {});
- Integer value = (Integer) getValue5Method.invoke(object, new Object[] {});
- assertEquals(value.intValue(), 5);
-
- } catch (InvocationTargetException itex) {
- fail("JAR file not correctly added to Classpath" + itex);
- } catch (NoSuchMethodException nsmex) {
- fail("JAR file not correctly added to Classpath" + nsmex);
- } catch (InstantiationException iex) {
- fail("JAR file not correctly added to Classpath" + iex);
- } catch (IllegalAccessException iaex) {
- fail("JAR file not correctly added to Classpath" + iaex);
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath" + cnfex);
- }
-
- // Now create an updated JAR file and make sure that the method from the new
- // class is available.
- jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass",
- "public class JarClassLoaderJUnitTestClass { public Integer getValue10() { return new Integer(10); } }");
- writeJarBytesToFile(jarFile2, jarBytes);
- classLoader = new JarClassLoader(jarFile2, "JarClassLoaderJUnit.jar", jarBytes);
- classPathLoader = classPathLoader.addOrReplace(classLoader);
- classLoader.loadClassesAndRegisterFunctions();
-
- try {
- Class<?> clazz = classPathLoader.forName("JarClassLoaderJUnitTestClass");
- Object object = clazz.newInstance();
- Method getValue10Method = clazz.getMethod("getValue10", new Class[] {});
- Integer value = (Integer) getValue10Method.invoke(object, new Object[] {});
- assertEquals(value.intValue(), 10);
-
- } catch (InvocationTargetException itex) {
- fail("JAR file not correctly added to Classpath" + itex);
- } catch (NoSuchMethodException nsmex) {
- fail("JAR file not correctly added to Classpath" + nsmex);
- } catch (InstantiationException iex) {
- fail("JAR file not correctly added to Classpath" + iex);
- } catch (IllegalAccessException iaex) {
- fail("JAR file not correctly added to Classpath" + iaex);
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath" + cnfex);
- }
- }
-
- @Test
- public void testMultiThread() throws IOException {
- final File jarFile1 = new File(JAR_PREFIX + "JarClassLoaderJUnitA.jar#1");
- final File jarFile2 = new File(JAR_PREFIX + "JarClassLoaderJUnitB.jar#1");
-
- // Add two JARs to the classpath
- byte[] jarBytes = this.classBuilder.createJarFromName("JarClassLoaderJUnitA");
- writeJarBytesToFile(jarFile1, jarBytes);
- JarClassLoader classLoader = new JarClassLoader(jarFile1, "JarClassLoaderJUnitA.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
-
- jarBytes = this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitB",
- "package com.jcljunit; public class JarClassLoaderJUnitB {}");
- writeJarBytesToFile(jarFile2, jarBytes);
- classLoader = new JarClassLoader(jarFile2, "JarClassLoaderJUnitB.jar", jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(classLoader);
-
- String[] classNames = new String[] {"JarClassLoaderJUnitA", "com.jcljunit.JarClassLoaderJUnitB",
- "NON-EXISTENT CLASS"};
-
- // Spawn some threads which try to instantiate these classes
- final int threadCount = 10;
- final int numLoops = 1000;
- final CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount + 1);
- for (int i = 0; i < threadCount; i++) {
- new ForNameExerciser(cyclicBarrier, numLoops, classNames).start();
- }
-
- // Wait for all of the threads to be ready
- try {
- cyclicBarrier.await();
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for barrier");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
- }
-
- // Loop while each thread tries N times to instantiate a non-existent class
- for (int i = 0; i < numLoops; i++) {
- try {
- cyclicBarrier.await(5, TimeUnit.SECONDS);
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for barrier");
- } catch (TimeoutException tex) {
- ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
- long[] threadIds = threadMXBean.findDeadlockedThreads();
-
- if (threadIds != null) {
- StringBuffer deadLockTrace = new StringBuffer();
- for (long threadId : threadIds) {
- ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId, 100);
- deadLockTrace.append(threadInfo.getThreadName()).append("\n");
- for (StackTraceElement stackTraceElem : threadInfo.getStackTrace()) {
- deadLockTrace.append("\t").append(stackTraceElem).append("\n");
- }
- }
-
- fail("Deadlock with trace:\n" + deadLockTrace.toString());
- }
-
- fail("Timeout while waiting for barrier - no deadlock detected");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
- }
- }
- }
-
- private void deleteSavedJarFiles() {
- File dirFile = new File(".");
-
- // Find all created JAR files
- File[] oldJarFiles = dirFile.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(final File file, final String name) {
- return JarClassLoaderJUnitTest.this.pattern.matcher(name).matches();
- }
- });
-
- // Now delete them
- if (oldJarFiles != null) {
- for (File oldJarFile : oldJarFiles) {
- if (!oldJarFile.delete()) {
- RandomAccessFile randomAccessFile = null;
- try {
- randomAccessFile = new RandomAccessFile(oldJarFile, "rw");
- randomAccessFile.setLength(0);
- } catch (IOException ioex) {
- fail("IOException when trying to deal with a stubborn JAR file");
- } finally {
- try {
- if (randomAccessFile != null) {
- randomAccessFile.close();
- }
- } catch (IOException ioex) {
- fail("IOException when trying to deal with a stubborn JAR file");
- }
- }
- oldJarFile.deleteOnExit();
- }
- }
- }
- }
-
- private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException {
- final OutputStream outStream = new FileOutputStream(jarFile);
- outStream.write(jarBytes);
- outStream.close();
- }
-
- private static class TestResultSender implements ResultSender<Object> {
- private Object result;
-
- public TestResultSender() {}
-
- protected Object getResults() {
- return this.result;
- }
-
- @Override
- public void lastResult(final Object lastResult) {
- this.result = lastResult;
- }
-
- @Override
- public void sendResult(final Object oneResult) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void sendException(final Throwable t) {
- throw new UnsupportedOperationException();
- }
- }
-
- static final Random random = new Random();
-
- private class ForNameExerciser extends Thread {
- private final CyclicBarrier cyclicBarrier;
- private final int numLoops;
- private final String[] classNames;
-
- ForNameExerciser(final CyclicBarrier cyclicBarrier, final int numLoops,
- final String[] classNames) {
- this.cyclicBarrier = cyclicBarrier;
- this.numLoops = numLoops;
- this.classNames = classNames;
- }
-
- @Override
- public void run() {
- try {
- this.cyclicBarrier.await();
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for latch");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
- }
- for (int i = 0; i < this.numLoops; i++) {
- try {
- // Random select a name from the list of class names and try to load it
- String className = this.classNames[random.nextInt(this.classNames.length)];
- ClassPathLoader.getLatest().forName(className);
- } catch (ClassNotFoundException expected) { // expected
- }
- try {
- this.cyclicBarrier.await();
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for barrrier");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
- }
- }
- }
- }
-}
[5/8] geode git commit: GEODE-2686: Remove JarClassLoader
Posted by js...@apache.org.
GEODE-2686: Remove JarClassLoader
- Remove JarClassLoader
- Replace ClassPathLoader's collection of JarClassLoaders with a single URLClassLoader
- Change naming scheme for deployed jars from 'vf.gf#myJar.jar#1' to 'myJar.v1.jar'
Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/6fd2d123
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/6fd2d123
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/6fd2d123
Branch: refs/heads/develop
Commit: 6fd2d123a6c4dbb0c7af0bbf135314bda0c6d5e9
Parents: f272762
Author: Jared Stewart <js...@pivotal.io>
Authored: Thu Jan 19 12:00:04 2017 -0800
Committer: Jared Stewart <js...@pivotal.io>
Committed: Sun Apr 16 09:10:00 2017 -0700
----------------------------------------------------------------------
.../apache/geode/internal/ClassPathLoader.java | 515 ++---------
.../org/apache/geode/internal/DeployedJar.java | 442 ++++++++++
.../geode/internal/InternalDataSerializer.java | 2 +-
.../apache/geode/internal/JarClassLoader.java | 721 ----------------
.../org/apache/geode/internal/JarDeployer.java | 699 +++++++--------
.../cache/ClusterConfigurationLoader.java | 40 +-
.../geode/internal/cache/GemFireCacheImpl.java | 4 +-
.../cache/persistence/BackupManager.java | 10 +-
.../internal/cli/functions/DeployFunction.java | 11 +-
.../cli/functions/ListDeployedFunction.java | 10 +-
.../cli/functions/UndeployFunction.java | 15 +-
.../ClassPathLoaderIntegrationTest.java | 454 +++++-----
.../geode/internal/ClassPathLoaderTest.java | 402 ++-------
.../geode/internal/DeployedJarJUnitTest.java | 538 ++++++++++++
.../geode/internal/JarClassLoaderJUnitTest.java | 851 -------------------
.../geode/internal/JarDeployerDUnitTest.java | 574 -------------
.../internal/JarDeployerIntegrationTest.java | 214 +++--
.../cache/IncrementalBackupDUnitTest.java | 33 +-
.../geode/management/DeployJarTestSuite.java | 31 +
.../DeployCommandRedeployDUnitTest.java | 159 ++++
.../cli/commands/DeployCommandsDUnitTest.java | 662 +++++----------
.../cli/commands/UserCommandsDUnitTest.java | 164 ----
.../internal/configuration/ClusterConfig.java | 35 +-
.../dunit/rules/GfshShellConnectionRule.java | 10 +
.../cli/commands/CommandOverHttpDUnitTest.java | 2 +-
25 files changed, 2323 insertions(+), 4275 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/ClassPathLoader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/ClassPathLoader.java b/geode-core/src/main/java/org/apache/geode/internal/ClassPathLoader.java
index 9ab7c30..41cce05 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/ClassPathLoader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/ClassPathLoader.java
@@ -14,6 +14,9 @@
*/
package org.apache.geode.internal;
+import static java.util.stream.Collectors.joining;
+
+import org.apache.commons.io.FileUtils;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.util.CollectionUtils;
@@ -27,6 +30,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -62,271 +66,54 @@ public final class ClassPathLoader {
*
* See also http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html
*/
-
- public static final String ENABLE_TRACE_PROPERTY =
- DistributionConfig.GEMFIRE_PREFIX + "ClassPathLoader.enableTrace";
- public static final String ENABLE_TRACE_DEFAULT_VALUE = "false";
- private final boolean ENABLE_TRACE = false;
-
private static final Logger logger = LogService.getLogger();
public static final String EXCLUDE_TCCL_PROPERTY =
DistributionConfig.GEMFIRE_PREFIX + "excludeThreadContextClassLoader";
public static final boolean EXCLUDE_TCCL_DEFAULT_VALUE = false;
- private boolean excludeTCCL;
-
- // This calculates the location of the extlib directory relative to the
- // location of the gemfire jar file. If for some reason the ClassPathLoader
- // class is found in a directory instead of a JAR file (as when testing),
- // then it will be relative to the location of the root of the package and
- // class.
- public static final String EXT_LIB_DIR_PARENT_PROPERTY =
- DistributionConfig.GEMFIRE_PREFIX + "ClassPathLoader.EXT_LIB_DIR";
- public static final String EXT_LIB_DIR_PARENT_DEFAULT =
- ClassPathLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath();
-
- static final File defineEXT_LIB_DIR() {
- return new File(
- (new File(System.getProperty(EXT_LIB_DIR_PARENT_PROPERTY, EXT_LIB_DIR_PARENT_DEFAULT)))
- .getParent(),
- "ext");
- }
-
- // This token is placed into the list of class loaders to determine where
- // to insert the TCCL when in forName(...), getResource(...), etc.
- private static final ClassLoader TCCL_PLACEHOLDER = new ClassLoader() { // This is never used for
- // class loading
- };
-
- private static final AtomicReference<ClassPathLoader> latest =
- new AtomicReference<ClassPathLoader>();
-
- private final List<ClassLoader> classLoaders;
-
- private static final Set<ClassLoader> defaultLoaders;
- static {
- defaultLoaders = new HashSet<ClassLoader>();
- try {
- ClassLoader classLoader = ClassPathLoader.class.getClassLoader();
- if (classLoader != null) {
- defaultLoaders.add(classLoader);
- }
- } catch (SecurityException sex) {
- // Nothing to do, just don't add it
- }
- try {
- ClassLoader classLoader = ClassLoader.getSystemClassLoader();
- if (classLoader != null) {
- defaultLoaders.add(classLoader);
- }
- } catch (SecurityException sex) {
- // Nothing to do, just don't add it
- }
+ private static volatile ClassPathLoader latest;
- setLatestToDefault();
- }
+ private volatile URLClassLoader classLoaderForDeployedJars;
+ private final JarDeployer jarDeployer;
- /**
- * Starting at the files or directories identified by 'files', search for valid JAR files and
- * return a list of their URLs. Sub-directories will also be searched.
- *
- * @param files Files or directories to search for valid JAR content.
- *
- * @return A list of URLs for all JAR files found.
- */
- private static List<URL> getJarURLsFromFiles(final File... files) {
- final List<URL> urls = new ArrayList<URL>();
-
- Assert.assertTrue(files != null, "file list cannot be null");
-
- for (File file : files) {
- if (file.exists()) {
- if (file.isDirectory()) {
- urls.addAll(getJarURLsFromFiles(file.listFiles()));
- } else {
- if (!JarClassLoader.hasValidJarContent(file)) {
- logger.warn("Invalid JAR content when attempting to create ClassLoader for file: {}",
- file.getAbsolutePath());
- continue;
- }
+ private boolean excludeTCCL;
- try {
- urls.add(file.toURI().toURL());
- } catch (MalformedURLException muex) {
- logger.warn(
- "Encountered invalid URL when attempting to create ClassLoader for file: {}:{}",
- file.getAbsolutePath(), muex.getMessage());
- continue;
- }
- }
- }
- }
+ public void rebuildClassLoaderForDeployedJars() {
+ ClassLoader parent = ClassPathLoader.class.getClassLoader();
- return urls;
+ this.classLoaderForDeployedJars = new URLClassLoader(jarDeployer.getDeployedJarURLs(), parent);
}
- private ClassPathLoader(final List<ClassLoader> classLoaders, final boolean excludeTCCL) {
-
- Assert.assertTrue(classLoaders != null, "custom loaders must not be null");
- for (ClassLoader classLoader : classLoaders) {
- Assert.assertTrue(classLoader != null, "null classloaders not allowed");
- }
-
- this.classLoaders = new ArrayList<ClassLoader>(classLoaders);
+ public ClassPathLoader(boolean excludeTCCL) {
this.excludeTCCL = excludeTCCL;
+ this.jarDeployer = new JarDeployer();
+ rebuildClassLoaderForDeployedJars();
}
- /**
- * Get a copy of the collection of ClassLoaders currently in use.
- *
- * @return Collection of ClassLoaders currently in use.
- */
- public Collection<ClassLoader> getClassLoaders() {
- List<ClassLoader> classLoadersCopy = new ArrayList<ClassLoader>(this.classLoaders);
-
- for (int i = 0; i < classLoadersCopy.size(); i++) {
- if (classLoadersCopy.get(i).equals(TCCL_PLACEHOLDER)) {
- if (excludeTCCL) {
- classLoadersCopy.remove(i);
- } else {
- classLoadersCopy.set(i, Thread.currentThread().getContextClassLoader());
- }
- break;
- }
- }
-
- return classLoadersCopy;
- }
-
- // This is exposed for testing.
- static ClassPathLoader createWithDefaults(final boolean excludeTCCL) {
- List<ClassLoader> classLoaders = new LinkedList<ClassLoader>();
-
- classLoaders.add(TCCL_PLACEHOLDER);
-
- for (final ClassLoader classLoader : defaultLoaders) {
- classLoaders.add(classLoader);
- }
-
- // Add user JAR files from the EXT_LIB_DIR directory using a single ClassLoader
- try {
- File EXT_LIB_DIR = defineEXT_LIB_DIR();
- if (EXT_LIB_DIR.exists()) {
- if (!EXT_LIB_DIR.isDirectory() || !EXT_LIB_DIR.canRead()) {
- logger.warn("Cannot read from directory when attempting to load JAR files: {}",
- EXT_LIB_DIR.getAbsolutePath());
- } else {
- List<URL> extLibJarURLs = getJarURLsFromFiles(EXT_LIB_DIR);
- ClassLoader classLoader =
- new URLClassLoader(extLibJarURLs.toArray(new URL[extLibJarURLs.size()]));
- classLoaders.add(classLoader);
- }
- }
- } catch (SecurityException sex) {
- // Nothing to do, just don't add it
- }
-
- return new ClassPathLoader(classLoaders, excludeTCCL);
+ public ClassPathLoader(boolean excludeTCCL, File workingDir) {
+ this.excludeTCCL = excludeTCCL;
+ this.jarDeployer = new JarDeployer(workingDir);
+ rebuildClassLoaderForDeployedJars();
}
public static ClassPathLoader setLatestToDefault() {
- return setLatestToDefault(Boolean.getBoolean(EXCLUDE_TCCL_PROPERTY));
+ latest = new ClassPathLoader(Boolean.getBoolean(EXCLUDE_TCCL_PROPERTY));
+ return latest;
}
- public static ClassPathLoader setLatestToDefault(final boolean excludeTCCL) {
- ClassPathLoader classPathLoader = createWithDefaults(excludeTCCL);
-
- // Clean up JarClassLoaders that attached to the previous ClassPathLoader
- ClassPathLoader oldClassPathLoader = latest.getAndSet(classPathLoader);
- if (oldClassPathLoader != null) {
- for (ClassLoader classLoader : oldClassPathLoader.classLoaders) {
- if (classLoader instanceof JarClassLoader) {
- ((JarClassLoader) classLoader).cleanUp();
- }
- }
- }
-
- return classPathLoader;
+ public static ClassPathLoader setLatestToDefault(File workingDir) {
+ latest = new ClassPathLoader(Boolean.getBoolean(EXCLUDE_TCCL_PROPERTY), workingDir);
+ return latest;
}
- // This is exposed for testing.
- ClassPathLoader addOrReplace(final ClassLoader classLoader) {
- final boolean isDebugEnabled = logger.isTraceEnabled();
- if (isDebugEnabled) {
- logger.trace("adding classLoader: {}", classLoader);
- }
-
- List<ClassLoader> classLoadersCopy = new ArrayList<ClassLoader>(this.classLoaders);
- classLoadersCopy.add(0, classLoader);
-
- // Ensure there is only one instance of this class loader in the list
- ClassLoader removingClassLoader = null;
- int index = classLoadersCopy.lastIndexOf(classLoader);
- if (index != 0) {
- removingClassLoader = classLoadersCopy.get(index);
- if (isDebugEnabled) {
- logger.trace("removing previous classLoader: {}", removingClassLoader);
- }
- classLoadersCopy.remove(index);
- }
-
- if (removingClassLoader != null && removingClassLoader instanceof JarClassLoader) {
- ((JarClassLoader) removingClassLoader).cleanUp();
- }
-
- return new ClassPathLoader(classLoadersCopy, this.excludeTCCL);
- }
-
- /**
- * Add or replace the provided {@link ClassLoader} to the list held by this ClassPathLoader. Then
- * use the resulting list to create a new ClassPathLoader and set it as the latest.
- *
- * @param classLoader {@link ClassLoader} to add
- */
- public ClassPathLoader addOrReplaceAndSetLatest(final ClassLoader classLoader) {
- ClassPathLoader classPathLoader = addOrReplace(classLoader);
- latest.set(classPathLoader);
- return classPathLoader;
+ public JarDeployer getJarDeployer() {
+ return this.jarDeployer;
}
// This is exposed for testing.
- ClassPathLoader remove(final ClassLoader classLoader) {
- final boolean isDebugEnabled = logger.isTraceEnabled();
- if (isDebugEnabled) {
- logger.trace("removing classLoader: {}", classLoader);
- }
-
- List<ClassLoader> classLoadersCopy = new ArrayList<ClassLoader>();
- classLoadersCopy.addAll(this.classLoaders);
-
- if (!classLoadersCopy.contains(classLoader)) {
- if (isDebugEnabled) {
- logger.trace("cannot remove classLoader since it doesn't exist: {}", classLoader);
- }
- return this;
- }
-
- classLoadersCopy.remove(classLoader);
-
- if (classLoader instanceof JarClassLoader) {
- ((JarClassLoader) classLoader).cleanUp();
- }
-
- return new ClassPathLoader(classLoadersCopy, this.excludeTCCL);
- }
-
- /**
- * Remove the provided {@link ClassLoader} from the list held by this ClassPathLoader. Then use
- * the resulting list to create a new ClassPathLoader and set it as the latest. Silently ignores
- * requests to remove non-existent ClassLoaders.
- *
- * @param classLoader {@link ClassLoader} to remove
- */
- public ClassPathLoader removeAndSetLatest(final ClassLoader classLoader) {
- ClassPathLoader classPathLoader = remove(classLoader);
- latest.set(classPathLoader);
- return classPathLoader;
+ static ClassPathLoader createWithDefaults(final boolean excludeTCCL) {
+ return new ClassPathLoader(excludeTCCL);
}
public URL getResource(final String name) {
@@ -334,52 +121,26 @@ public final class ClassPathLoader {
if (isDebugEnabled) {
logger.trace("getResource({})", name);
}
- URL url = null;
- ClassLoader tccl = null;
- if (!excludeTCCL) {
- tccl = Thread.currentThread().getContextClassLoader();
- }
- for (ClassLoader classLoader : this.classLoaders) {
- if (classLoader == TCCL_PLACEHOLDER) {
- try {
- if (tccl != null) {
- if (isDebugEnabled) {
- logger.trace("getResource trying TCCL: {}", tccl);
- }
- url = tccl.getResource(name);
- if (url != null) {
- if (isDebugEnabled) {
- logger.trace("getResource found by TCCL");
- }
- return url;
- }
- } else {
- if (isDebugEnabled) {
- logger.trace("getResource skipping TCCL because it's null");
- }
- }
- } catch (SecurityException sex) {
- // Continue to next ClassLoader
- }
- } else if (excludeTCCL || !classLoader.equals(tccl)) {
- if (isDebugEnabled) {
- logger.trace("getResource trying classLoader: {}", classLoader);
- }
- url = classLoader.getResource(name);
+ for (ClassLoader classLoader : getClassLoaders()) {
+ if (isDebugEnabled) {
+ logger.trace("getResource trying: {}", classLoader);
+ }
+ try {
+ URL url = classLoader.getResource(name);
+
if (url != null) {
if (isDebugEnabled) {
- logger.trace("getResource found by classLoader: {}", classLoader);
+ logger.trace("getResource found by: {}", classLoader);
}
return url;
}
+ } catch (SecurityException e) {
+ // try next classLoader
}
}
- if (isDebugEnabled) {
- logger.trace("getResource returning null");
- }
- return url;
+ return null;
}
public Class<?> forName(final String name) throws ClassNotFoundException {
@@ -387,53 +148,25 @@ public final class ClassPathLoader {
if (isDebugEnabled) {
logger.trace("forName({})", name);
}
- Class<?> clazz = null;
- ClassLoader tccl = null;
- if (!excludeTCCL) {
- tccl = Thread.currentThread().getContextClassLoader();
- }
- for (ClassLoader classLoader : this.classLoaders) {
+ for (ClassLoader classLoader : this.getClassLoaders()) {
+ if (isDebugEnabled) {
+ logger.trace("forName trying: {}", classLoader);
+ }
try {
- if (classLoader == TCCL_PLACEHOLDER) {
- if (tccl != null) {
- if (isDebugEnabled) {
- logger.trace("forName trying TCCL: {}", tccl);
- }
- clazz = Class.forName(name, true, tccl);
- if (clazz != null) {
- if (isDebugEnabled) {
- logger.trace("forName found by TCCL");
- }
- return clazz;
- } else {
- if (isDebugEnabled) {
- logger.trace("forName skipping TCCL because it's null");
- }
- }
- }
- } else if (excludeTCCL || !classLoader.equals(tccl)) {
+ Class<?> clazz = Class.forName(name, true, classLoader);
+
+ if (clazz != null) {
if (isDebugEnabled) {
- logger.trace("forName trying classLoader: {}", classLoader);
- }
- clazz = Class.forName(name, true, classLoader);
- if (clazz != null) {
- if (isDebugEnabled) {
- logger.trace("forName found by classLoader: {}", classLoader);
- }
- return clazz;
+ logger.trace("forName found by: {}", classLoader);
}
+ return clazz;
}
- } catch (SecurityException sex) {
- // Continue to next ClassLoader
- } catch (ClassNotFoundException cnfex) {
- // Continue to next ClassLoader
+ } catch (SecurityException | ClassNotFoundException e) {
+ // try next classLoader
}
}
- if (isDebugEnabled) {
- logger.trace("forName throwing ClassNotFoundException");
- }
throw new ClassNotFoundException(name);
}
@@ -442,20 +175,10 @@ public final class ClassPathLoader {
*/
public Class<?> getProxyClass(final Class<?>[] classObjs) {
IllegalArgumentException ex = null;
- ClassLoader tccl = null;
- if (!excludeTCCL) {
- tccl = Thread.currentThread().getContextClassLoader();
- }
- for (ClassLoader classLoader : this.classLoaders) {
+ for (ClassLoader classLoader : this.getClassLoaders()) {
try {
- if (classLoader == TCCL_PLACEHOLDER) {
- if (tccl != null) {
- return Proxy.getProxyClass(tccl, classObjs);
- }
- } else if (excludeTCCL || !classLoader.equals(tccl)) {
- return Proxy.getProxyClass(classLoader, classObjs);
- }
+ return Proxy.getProxyClass(classLoader, classObjs);
} catch (SecurityException sex) {
// Continue to next classloader
} catch (IllegalArgumentException iaex) {
@@ -464,7 +187,6 @@ public final class ClassPathLoader {
}
}
- assert ex != null;
if (ex != null) {
throw ex;
}
@@ -475,19 +197,9 @@ public final class ClassPathLoader {
public String toString() {
final StringBuilder sb = new StringBuilder(getClass().getName());
sb.append("@").append(System.identityHashCode(this)).append("{");
- sb.append("isLatest=").append(getLatest() == this);
sb.append(", excludeTCCL=").append(this.excludeTCCL);
sb.append(", classLoaders=[");
- for (int i = 0; i < this.classLoaders.size(); i++) {
- if (i > 0) {
- sb.append(", ");
- }
- sb.append(this.classLoaders.get(i).toString());
- }
- sb.append("]");
- if (!this.excludeTCCL) {
- sb.append(", TCCL=").append(Thread.currentThread().getContextClassLoader());
- }
+ sb.append(this.getClassLoaders().stream().map(ClassLoader::toString).collect(joining(", ")));
sb.append("]}");
return sb.toString();
}
@@ -514,13 +226,12 @@ public final class ClassPathLoader {
/**
* Returns an input stream for reading the specified resource.
- *
+ *
* <p>
* The search order is described in the documentation for {@link #getResource(String)}.
* </p>
*
* @param name The resource name
- *
* @return An input stream for reading the resource, or <tt>null</tt> if the resource could not be
* found
*/
@@ -553,122 +264,51 @@ public final class ClassPathLoader {
return getResourceAsStream(name);
}
+
/**
* Finds all the resources with the given name. This method will first search the class loader of
* the context class for the resource before searching all other {@link ClassLoader}s.
*
* @param contextClass The class whose class loader will first be searched
- *
* @param name The resource name
- *
* @return An enumeration of {@link java.net.URL <tt>URL</tt>} objects for the resource. If no
* resources could be found, the enumeration will be empty. Resources that the class
* loader doesn't have access to will not be in the enumeration.
- *
* @throws IOException If I/O errors occur
- *
* @see ClassLoader#getResources(String)
*/
public Enumeration<URL> getResources(final Class<?> contextClass, final String name)
throws IOException {
- final boolean isDebugEnabled = logger.isTraceEnabled();
+ final LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
- if (isDebugEnabled) {
- logger.trace(new StringBuilder("getResources(").append(name).append(")"));
+ if (contextClass != null) {
+ CollectionUtils.addAll(urls, contextClass.getClassLoader().getResources(name));
}
- final LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
-
- try {
- if (contextClass != null) {
- CollectionUtils.addAll(urls, contextClass.getClassLoader().getResources(name));
+ for (ClassLoader classLoader : getClassLoaders()) {
+ Enumeration<URL> resources = classLoader.getResources(name);
+ if (resources != null && resources.hasMoreElements()) {
+ CollectionUtils.addAll(urls, resources);
}
- } catch (IOException ignore) {
- // ignore and search others
}
- Enumeration<URL> resources = null;
- ClassLoader tccl = null;
- if (!excludeTCCL) {
- tccl = Thread.currentThread().getContextClassLoader();
- }
+ return Collections.enumeration(urls);
+ }
- IOException ioException = null;
- for (ClassLoader classLoader : this.classLoaders) {
- ioException = null; // reset to null for next ClassLoader
- if (classLoader == TCCL_PLACEHOLDER) {
- try {
- if (tccl != null) {
- if (isDebugEnabled) {
- logger.trace("getResources trying TCCL: {}", tccl);
- }
- resources = tccl.getResources(name);
- if (resources != null && resources.hasMoreElements()) {
- if (isDebugEnabled) {
- logger.trace("getResources found by TCCL");
- }
- CollectionUtils.addAll(urls, resources);
- }
- } else {
- if (isDebugEnabled) {
- logger.trace("getResources skipping TCCL because it's null");
- }
- }
- } catch (SecurityException ignore) {
- // Continue to next ClassLoader
- } catch (IOException ignore) {
- ioException = ignore;
- // Continue to next ClassLoader
- }
- } else if (excludeTCCL || !classLoader.equals(tccl)) {
- try {
- if (isDebugEnabled) {
- logger.trace("getResources trying classLoader: {}", classLoader);
- }
- resources = classLoader.getResources(name);
- if (resources != null && resources.hasMoreElements()) {
- if (logger.isTraceEnabled()) {
- logger.trace(
- new StringBuilder("getResources found by classLoader: ").append(classLoader));
- }
- CollectionUtils.addAll(urls, resources);
- }
- } catch (IOException ignore) {
- ioException = ignore;
- // Continue to next ClassLoader
- }
- }
- }
+ public Enumeration<URL> getResources(final String name) throws IOException {
+ return getResources(null, name);
+ }
- if (ioException != null) {
- if (isDebugEnabled) {
- logger.trace("getResources throwing IOException");
- }
- throw ioException;
- }
+ private List<ClassLoader> getClassLoaders() {
+ ArrayList<ClassLoader> classLoaders = new ArrayList<>();
- if (isDebugEnabled) {
- logger.trace("getResources returning empty enumeration");
+ if (!excludeTCCL) {
+ classLoaders.add(Thread.currentThread().getContextClassLoader());
}
- return Collections.enumeration(urls);
- }
+ classLoaders.add(classLoaderForDeployedJars);
- /**
- * Finds all the resources with the given name.
- *
- * @param name The resource name
- *
- * @return An enumeration of {@link java.net.URL <tt>URL</tt>} objects for the resource. If no
- * resources could be found, the enumeration will be empty. Resources that the class
- * loader doesn't have access to will not be in the enumeration.
- *
- * @throws IOException If I/O errors occur
- *
- * @see ClassLoader#getResources(String)
- */
- public Enumeration<URL> getResources(String name) throws IOException {
- return getResources(null, name);
+ return classLoaders;
}
/**
@@ -707,7 +347,14 @@ public final class ClassPathLoader {
}
public static ClassPathLoader getLatest() {
- return latest.get();
+ if (latest == null) {
+ synchronized (ClassPathLoader.class) {
+ if (latest == null)
+ setLatestToDefault();
+ }
+ }
+
+ return latest;
}
/**
@@ -717,7 +364,7 @@ public final class ClassPathLoader {
* @since GemFire 8.1
*/
public static final ClassLoader getLatestAsClassLoader() {
- return latest.get().asClassLoader();
+ return latest.asClassLoader();
}
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java b/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
new file mode 100644
index 0000000..f4f4028
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
@@ -0,0 +1,442 @@
+/*
+ * 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.geode.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import org.apache.geode.cache.Cache;
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.cache.CacheClosedException;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.Declarable;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.pdx.internal.TypeRegistry;
+import sun.nio.ch.ChannelInputStream;
+
+/**
+ * ClassLoader for a single JAR file.
+ *
+ * @since GemFire 7.0
+ */
+public class DeployedJar {
+ private final static Logger logger = LogService.getLogger();
+ private final static MessageDigest messageDigest = getMessageDigest();
+
+ private final String jarName;
+ private final File file;
+ private final byte[] md5hash;
+ private final Collection<Function> registeredFunctions = new ArrayList<Function>();
+
+ private static MessageDigest getMessageDigest() {
+ try {
+ return MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException nsaex) {
+ // Failure just means we can't do a simple compare for content equality
+ }
+ return null;
+ }
+
+ public File getFile() {
+ return this.file;
+ }
+
+ public int getVersion() {
+ return JarDeployer.extractVersionFromFilename(file.getName());
+ }
+
+ public DeployedJar(File versionedJarFile, String jarName) throws IOException {
+ this(versionedJarFile, jarName, Files.readAllBytes(versionedJarFile.toPath()));
+ }
+
+ public DeployedJar(File versionedJarFile, final String jarName, byte[] jarBytes)
+ throws IOException {
+ Assert.assertTrue(jarBytes != null, "jarBytes cannot be null");
+ Assert.assertTrue(jarName != null, "jarName cannot be null");
+ Assert.assertTrue(versionedJarFile != null, "versionedJarFile cannot be null");
+
+ this.file = versionedJarFile;
+ this.jarName = jarName;
+
+ final byte[] fileContent = getJarContent();
+ if (!Arrays.equals(fileContent, jarBytes)) {
+ throw new FileNotFoundException("JAR file: " + versionedJarFile.getAbsolutePath()
+ + ", was modified prior to obtaining a lock: " + jarName);
+ }
+
+ if (!isValidJarContent(getJarContent())) {
+ throw new IllegalArgumentException(
+ "File does not contain valid JAR content: " + versionedJarFile.getAbsolutePath());
+ }
+
+ if (messageDigest != null) {
+ this.md5hash = messageDigest.digest(jarBytes);
+ } else {
+ this.md5hash = null;
+ }
+ }
+
+ /**
+ * Peek into the JAR data and make sure that it is valid JAR content.
+ *
+ * @param inputStream InputStream containing data to be validated.
+ * @return True if the data has JAR content, false otherwise
+ */
+ private static boolean hasValidJarContent(final InputStream inputStream) {
+ JarInputStream jarInputStream = null;
+ boolean valid = false;
+
+ try {
+ jarInputStream = new JarInputStream(inputStream);
+ valid = (jarInputStream.getNextJarEntry() != null);
+ } catch (IOException ignore) {
+ // Ignore this exception and just return false
+ } finally {
+ try {
+ jarInputStream.close();
+ } catch (IOException ioex) {
+ // Ignore this exception and just return result
+ }
+ }
+
+ return valid;
+ }
+
+ /**
+ * Peek into the JAR data and make sure that it is valid JAR content.
+ *
+ * @param jarBytes Bytes of data to be validated.
+ * @return True if the data has JAR content, false otherwise
+ */
+ public static boolean isValidJarContent(final byte[] jarBytes) {
+ return hasValidJarContent(new ByteArrayInputStream(jarBytes));
+ }
+
+ /**
+ * Peek into the JAR data and make sure that it is valid JAR content.
+ *
+ * @param jarFile File whose contents should be validated.
+ * @return True if the data has JAR content, false otherwise
+ */
+ public static boolean hasValidJarContent(final File jarFile) {
+ try {
+ return hasValidJarContent(new FileInputStream(jarFile));
+ } catch (IOException ioex) {
+ return false;
+ }
+ }
+
+ /**
+ * Scan the JAR file and attempt to load all classes and register any function classes found.
+ */
+ // This method will process the contents of the JAR file as stored in this.jarByteContent
+ // instead of reading from the original JAR file. This is done because we can't open up
+ // the original file and then close it without releasing the shared lock that was obtained
+ // in the constructor. Once this method is finished, all classes will have been loaded and
+ // there will no longer be a need to hang on to the original contents so they will be
+ // discarded.
+ public synchronized void loadClassesAndRegisterFunctions() throws ClassNotFoundException {
+ final boolean isDebugEnabled = logger.isDebugEnabled();
+ if (isDebugEnabled) {
+ logger.debug("Registering functions with DeployedJar: {}", this);
+ }
+
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.getJarContent());
+
+ JarInputStream jarInputStream = null;
+ try {
+ jarInputStream = new JarInputStream(byteArrayInputStream);
+ JarEntry jarEntry = jarInputStream.getNextJarEntry();
+
+ while (jarEntry != null) {
+ if (jarEntry.getName().endsWith(".class")) {
+ if (isDebugEnabled) {
+ logger.debug("Attempting to load class: {}, from JAR file: {}", jarEntry.getName(),
+ this.file.getAbsolutePath());
+ }
+
+ final String className = jarEntry.getName().replaceAll("/", "\\.").substring(0,
+ (jarEntry.getName().length() - 6));
+ try {
+ Class<?> clazz = ClassPathLoader.getLatest().forName(className);
+ Collection<Function> registerableFunctions = getRegisterableFunctionsFromClass(clazz);
+ for (Function function : registerableFunctions) {
+ FunctionService.registerFunction(function);
+ if (isDebugEnabled) {
+ logger.debug("Registering function class: {}, from JAR file: {}", className,
+ this.file.getAbsolutePath());
+ }
+ this.registeredFunctions.add(function);
+ }
+ } catch (ClassNotFoundException cnfex) {
+ logger.error("Unable to load all classes from JAR file: {}",
+ this.file.getAbsolutePath(), cnfex);
+ throw cnfex;
+ } catch (NoClassDefFoundError ncdfex) {
+ logger.error("Unable to load all classes from JAR file: {}",
+ this.file.getAbsolutePath(), ncdfex);
+ throw ncdfex;
+ }
+ }
+ jarEntry = jarInputStream.getNextJarEntry();
+ }
+ } catch (IOException ioex) {
+ logger.error("Exception when trying to read class from ByteArrayInputStream", ioex);
+ } finally {
+ if (jarInputStream != null) {
+ try {
+ jarInputStream.close();
+ } catch (IOException ioex) {
+ logger.error("Exception attempting to close JAR input stream", ioex);
+ }
+ }
+ }
+ }
+
+ synchronized void cleanUp() {
+ for (Function function : this.registeredFunctions) {
+ FunctionService.unregisterFunction(function.getId());
+ }
+ this.registeredFunctions.clear();
+
+ try {
+ TypeRegistry typeRegistry =
+ ((GemFireCacheImpl) CacheFactory.getAnyInstance()).getPdxRegistry();
+ if (typeRegistry != null) {
+ typeRegistry.flushCache();
+ }
+ } catch (CacheClosedException ccex) {
+ // That's okay, it just means there was nothing to flush to begin with
+ }
+ }
+
+ /**
+ * Uses MD5 hashes to determine if the original byte content of this DeployedJar is the same as
+ * that past in.
+ *
+ * @param compareToBytes Bytes to compare the original content to
+ * @return True of the MD5 hash is the same o
+ */
+ public boolean hasSameContentAs(final byte[] compareToBytes) {
+ // If the MD5 hash can't be calculated then silently return no match
+ if (messageDigest == null || this.md5hash == null) {
+ return Arrays.equals(compareToBytes, getJarContent());
+ }
+
+ byte[] compareToMd5 = messageDigest.digest(compareToBytes);
+ if (logger.isDebugEnabled()) {
+ logger.debug("For JAR file: {}, Comparing MD5 hash {} to {}", this.file.getAbsolutePath(),
+ new String(this.md5hash), new String(compareToMd5));
+ }
+ return Arrays.equals(this.md5hash, compareToMd5);
+ }
+
+ /**
+ * Check to see if the class implements the Function interface. If so, it will be registered with
+ * FunctionService. Also, if the functions's class was originally declared in a cache.xml file
+ * then any properties specified at that time will be reused when re-registering the function.
+ *
+ * @param clazz Class to check for implementation of the Function class
+ * @return A collection of Objects that implement the Function interface.
+ */
+ private Collection<Function> getRegisterableFunctionsFromClass(Class<?> clazz) {
+ final List<Function> registerableFunctions = new ArrayList<Function>();
+
+ try {
+ if (Function.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
+ boolean registerUninitializedFunction = true;
+ if (Declarable.class.isAssignableFrom(clazz)) {
+ try {
+ final List<Properties> propertiesList =
+ ((GemFireCacheImpl) CacheFactory.getAnyInstance())
+ .getDeclarableProperties(clazz.getName());
+
+ if (!propertiesList.isEmpty()) {
+ registerUninitializedFunction = false;
+ // It's possible that the same function was declared multiple times in cache.xml
+ // with different properties. So, register the function using each set of
+ // properties.
+ for (Properties properties : propertiesList) {
+ @SuppressWarnings("unchecked")
+ Function function = newFunction((Class<Function>) clazz, true);
+ if (function != null) {
+ ((Declarable) function).init(properties);
+ if (function.getId() != null) {
+ registerableFunctions.add(function);
+ }
+ }
+ }
+ }
+ } catch (CacheClosedException ccex) {
+ // That's okay, it just means there were no properties to init the function with
+ }
+ }
+
+ if (registerUninitializedFunction) {
+ @SuppressWarnings("unchecked")
+ Function function = newFunction((Class<Function>) clazz, false);
+ if (function != null && function.getId() != null) {
+ registerableFunctions.add(function);
+ }
+ }
+ }
+ } catch (Exception ex) {
+ logger.error("Attempting to register function from JAR file: " + this.file.getAbsolutePath(),
+ ex);
+ }
+
+ return registerableFunctions;
+ }
+
+ private Function newFunction(final Class<Function> clazz, final boolean errorOnNoSuchMethod) {
+ try {
+ final Constructor<Function> constructor = clazz.getConstructor();
+ return constructor.newInstance();
+ } catch (NoSuchMethodException nsmex) {
+ if (errorOnNoSuchMethod) {
+ logger.error("Zero-arg constructor is required, but not found for class: {}",
+ clazz.getName(), nsmex);
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "Not registering function because it doesn't have a zero-arg constructor: {}",
+ clazz.getName());
+ }
+ }
+ } catch (SecurityException sex) {
+ logger.error("Zero-arg constructor of function not accessible for class: {}", clazz.getName(),
+ sex);
+ } catch (IllegalAccessException iae) {
+ logger.error("Zero-arg constructor of function not accessible for class: {}", clazz.getName(),
+ iae);
+ } catch (InvocationTargetException ite) {
+ logger.error("Error when attempting constructor for function for class: {}", clazz.getName(),
+ ite);
+ } catch (InstantiationException ie) {
+ logger.error("Unable to instantiate function for class: {}", clazz.getName(), ie);
+ } catch (ExceptionInInitializerError eiiex) {
+ logger.error("Error during function initialization for class: {}", clazz.getName(), eiiex);
+ }
+ return null;
+ }
+
+ private byte[] getJarContent() {
+ InputStream channelInputStream = null;
+ try {
+ channelInputStream = new FileInputStream(this.file);
+
+ final ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
+ final byte[] bytes = new byte[4096];
+
+ int bytesRead;
+ while (((bytesRead = channelInputStream.read(bytes)) != -1)) {
+ byteOutStream.write(bytes, 0, bytesRead);
+ }
+ channelInputStream.close();
+ return byteOutStream.toByteArray();
+ } catch (IOException e) {
+ logger.error("Error when attempting to read jar contents: ", e);
+ }
+
+ return new byte[0];
+ }
+
+ public String getJarName() {
+ return this.jarName;
+ }
+
+ public String getFileName() {
+ return this.file.getName();
+ }
+
+ public String getFileCanonicalPath() throws IOException {
+ return this.file.getCanonicalPath();
+ }
+
+ public URL getFileURL() {
+ try {
+ return this.file.toURL();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((this.jarName == null) ? 0 : this.jarName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ DeployedJar other = (DeployedJar) obj;
+ if (this.jarName == null) {
+ if (other.jarName != null) {
+ return false;
+ }
+ } else if (!this.jarName.equals(other.jarName)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(getClass().getName());
+ sb.append("@").append(System.identityHashCode(this)).append("{");
+ sb.append("jarName=").append(this.jarName);
+ sb.append(",file=").append(this.file.getAbsolutePath());
+ sb.append(",md5hash=").append(Arrays.toString(this.md5hash));
+ sb.append(",version=").append(this.getVersion());
+ sb.append("}");
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
index f4f4069..51212c6 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
@@ -4033,7 +4033,7 @@ public abstract class InternalDataSerializer extends DataSerializer implements D
public static void flushClassCache() {
if (classCache != null) {
- // Not locking classCache during clear as doing so causes a deadlock in the JarClassLoader
+ // Not locking classCache during clear as doing so causes a deadlock in the DeployedJar
classCache.clear();
}
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/JarClassLoader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/JarClassLoader.java b/geode-core/src/main/java/org/apache/geode/internal/JarClassLoader.java
deleted file mode 100644
index 9cd0589..0000000
--- a/geode-core/src/main/java/org/apache/geode/internal/JarClassLoader.java
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * 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.geode.internal;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Properties;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-
-import org.apache.logging.log4j.Logger;
-
-import org.apache.geode.cache.CacheClosedException;
-import org.apache.geode.cache.CacheFactory;
-import org.apache.geode.cache.Declarable;
-import org.apache.geode.cache.execute.Function;
-import org.apache.geode.cache.execute.FunctionService;
-import org.apache.geode.internal.cache.GemFireCacheImpl;
-import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.pdx.internal.TypeRegistry;
-
-/**
- * ClassLoader for a single JAR file.
- *
- * @since GemFire 7.0
- */
-public class JarClassLoader extends ClassLoader {
- private final static Logger logger = LogService.getLogger();
- private final static MessageDigest messageDigest;
-
- private final String jarName;
- private final File file;
- private final byte[] md5hash;
- private FileLock fileLock;
- private final Collection<Function> registeredFunctions = new ArrayList<Function>();
-
- private final ThreadLocal<Boolean> alreadyScanned = new ThreadLocal<Boolean>();
-
- // Lock used by ChannelInputStream (inner class) to prevent multiple threads from
- // trying to use the channel simultaneously.
- static final ReentrantLock channelLock = new ReentrantLock();
-
- private byte[] jarByteContent;
-
- static {
- MessageDigest md = null;
- try {
- md = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException nsaex) {
- // Failure just means we can't do a simple compare for content equality
- }
- messageDigest = md;
- }
-
- public JarClassLoader(final File file, final String jarName, byte[] jarBytes) throws IOException {
- Assert.assertTrue(file != null, "file cannot be null");
- Assert.assertTrue(jarName != null, "jarName cannot be null");
-
- final boolean isDebugEnabled = logger.isDebugEnabled();
- try {
- @SuppressWarnings("resource")
- FileInputStream fileInputStream = new FileInputStream(file);
- this.fileLock = fileInputStream.getChannel().lock(0, file.length(), true);
-
- if (isDebugEnabled) {
- logger.debug("Acquired shared file lock w/ channel: {}, for JAR: {}",
- this.fileLock.channel(), file.getAbsolutePath());
- }
-
- if (file.length() == 0) {
- throw new FileNotFoundException(
- "JAR file was truncated prior to obtaining a lock: " + jarName);
- }
-
- final byte[] fileContent = getJarContent();
- if (!Arrays.equals(fileContent, jarBytes)) {
- throw new FileNotFoundException("JAR file: " + file.getAbsolutePath()
- + ", was modified prior to obtaining a lock: " + jarName);
- }
-
- if (!isValidJarContent(jarBytes)) {
- if (this.fileLock != null) {
- this.fileLock.release();
- this.fileLock.channel().close();
- if (isDebugEnabled) {
- logger.debug(
- "Prematurely releasing shared file lock due to bad content for JAR file: {}, w/ channel: {}",
- file.getAbsolutePath(), this.fileLock.channel());
- }
- }
- throw new IllegalArgumentException(
- "File does not contain valid JAR content: " + file.getAbsolutePath());
- }
-
- Assert.assertTrue(jarBytes != null, "jarBytes cannot be null");
-
- // Temporarily save the contents of the JAR file until they can be processed by the
- // loadClassesandRegisterFunctions() method.
- this.jarByteContent = jarBytes;
-
- if (messageDigest != null) {
- this.md5hash = messageDigest.digest(this.jarByteContent);
- } else {
- this.md5hash = null;
- }
-
- this.file = file;
- this.jarName = jarName;
-
- } catch (FileNotFoundException fnfex) {
- if (this.fileLock != null) {
- this.fileLock.release();
- this.fileLock.channel().close();
- if (isDebugEnabled) {
- logger.debug(
- "Prematurely releasing shared file lock due to file not found for JAR file: {}, w/ channel: {}",
- file.getAbsolutePath(), this.fileLock.channel());
- }
- }
- throw fnfex;
- }
- }
-
- /**
- * Peek into the JAR data and make sure that it is valid JAR content.
- *
- * @param inputStream InputStream containing data to be validated.
- *
- * @return True if the data has JAR content, false otherwise
- */
- private static boolean hasValidJarContent(final InputStream inputStream) {
- JarInputStream jarInputStream = null;
- boolean valid = false;
-
- try {
- jarInputStream = new JarInputStream(inputStream);
- valid = (jarInputStream.getNextJarEntry() != null);
- } catch (IOException ignore) {
- // Ignore this exception and just return false
- } finally {
- try {
- jarInputStream.close();
- } catch (IOException ioex) {
- // Ignore this exception and just return result
- }
- }
-
- return valid;
- }
-
- /**
- * Peek into the JAR data and make sure that it is valid JAR content.
- *
- * @param jarBytes Bytes of data to be validated.
- *
- * @return True if the data has JAR content, false otherwise
- */
- public static boolean isValidJarContent(final byte[] jarBytes) {
- return hasValidJarContent(new ByteArrayInputStream(jarBytes));
- }
-
- /**
- * Peek into the JAR data and make sure that it is valid JAR content.
- *
- * @param jarFile File whose contents should be validated.
- *
- * @return True if the data has JAR content, false otherwise
- */
- public static boolean hasValidJarContent(final File jarFile) {
- try {
- return hasValidJarContent(new FileInputStream(jarFile));
- } catch (IOException ioex) {
- return false;
- }
- }
-
- /**
- * Scan the JAR file and attempt to load all classes and register any function classes found.
- */
- // This method will process the contents of the JAR file as stored in this.jarByteContent
- // instead of reading from the original JAR file. This is done because we can't open up
- // the original file and then close it without releasing the shared lock that was obtained
- // in the constructor. Once this method is finished, all classes will have been loaded and
- // there will no longer be a need to hang on to the original contents so they will be
- // discarded.
- public synchronized void loadClassesAndRegisterFunctions() throws ClassNotFoundException {
- final boolean isDebugEnabled = logger.isDebugEnabled();
- if (isDebugEnabled) {
- logger.debug("Registering functions with JarClassLoader: {}", this);
- }
-
- ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.jarByteContent);
-
- JarInputStream jarInputStream = null;
- try {
- jarInputStream = new JarInputStream(byteArrayInputStream);
- JarEntry jarEntry = jarInputStream.getNextJarEntry();
-
- while (jarEntry != null) {
- if (jarEntry.getName().endsWith(".class")) {
- if (isDebugEnabled) {
- logger.debug("Attempting to load class: {}, from JAR file: {}", jarEntry.getName(),
- this.file.getAbsolutePath());
- }
-
- final String className = jarEntry.getName().replaceAll("/", "\\.").substring(0,
- (jarEntry.getName().length() - 6));
- try {
- Class<?> clazz = loadClass(className, true, false);
- Collection<Function> registerableFunctions = getRegisterableFunctionsFromClass(clazz);
- for (Function function : registerableFunctions) {
- FunctionService.registerFunction(function);
- if (isDebugEnabled) {
- logger.debug("Registering function class: {}, from JAR file: {}", className,
- this.file.getAbsolutePath());
- }
- this.registeredFunctions.add(function);
- }
- } catch (ClassNotFoundException cnfex) {
- logger.error("Unable to load all classes from JAR file: {}",
- this.file.getAbsolutePath(), cnfex);
- throw cnfex;
- } catch (NoClassDefFoundError ncdfex) {
- logger.error("Unable to load all classes from JAR file: {}",
- this.file.getAbsolutePath(), ncdfex);
- throw ncdfex;
- }
- }
- jarEntry = jarInputStream.getNextJarEntry();
- }
- } catch (IOException ioex) {
- logger.error("Exception when trying to read class from ByteArrayInputStream", ioex);
- } finally {
- if (jarInputStream != null) {
- try {
- jarInputStream.close();
- } catch (IOException ioex) {
- logger.error("Exception attempting to close JAR input stream", ioex);
- }
- }
- }
- this.jarByteContent = new byte[0];
- }
-
- synchronized void cleanUp() {
- for (Function function : this.registeredFunctions) {
- FunctionService.unregisterFunction(function.getId());
- }
- this.registeredFunctions.clear();
-
- try {
- TypeRegistry typeRegistry =
- ((GemFireCacheImpl) CacheFactory.getAnyInstance()).getPdxRegistry();
- if (typeRegistry != null) {
- typeRegistry.flushCache();
- }
- } catch (CacheClosedException ccex) {
- // That's okay, it just means there was nothing to flush to begin with
- }
-
- try {
- this.fileLock.release();
- this.fileLock.channel().close();
- if (logger.isDebugEnabled()) {
- logger.debug("Released shared file lock on JAR file: {}, w/ channel: {}",
- this.file.getAbsolutePath(), this.fileLock.channel());
- }
- } catch (IOException ioex) {
- logger.error("Could not release the shared lock for JAR file: {}",
- this.file.getAbsolutePath(), ioex);
- }
- }
-
- /**
- * Uses MD5 hashes to determine if the original byte content of this JarClassLoader is the same as
- * that past in.
- *
- * @param compareToBytes Bytes to compare the original content to
- * @return True of the MD5 hash is the same o
- */
- public boolean hasSameContent(final byte[] compareToBytes) {
- // If the MD5 hash can't be calculated then silently return no match
- if (messageDigest == null || this.md5hash == null) {
- return false;
- }
-
- byte[] compareToMd5 = messageDigest.digest(compareToBytes);
- if (logger.isDebugEnabled()) {
- logger.debug("For JAR file: {}, Comparing MD5 hash {} to {}", this.file.getAbsolutePath(),
- new String(this.md5hash), new String(compareToMd5));
- }
- return Arrays.equals(this.md5hash, compareToMd5);
- }
-
- private boolean alreadyScanned() {
- if (this.alreadyScanned.get() == null) {
- this.alreadyScanned.set(Boolean.FALSE);
- }
- return this.alreadyScanned.get();
- }
-
- @Override
- protected URL findResource(String resourceName) {
- URL returnURL = null;
- JarInputStream jarInputStream = null;
-
- try {
- ChannelInputStream channelInputStream = new ChannelInputStream(this.fileLock.channel());
- jarInputStream = new JarInputStream(channelInputStream);
-
- JarEntry jarEntry = jarInputStream.getNextJarEntry();
- while (jarEntry != null && !jarEntry.getName().equals(resourceName)) {
- jarEntry = jarInputStream.getNextJarEntry();
- }
- if (jarEntry != null) {
- try {
- returnURL = new URL("jar", "", this.file.toURI().toURL() + "!/" + jarEntry.getName());
- } catch (MalformedURLException muex) {
- logger.error("Could not create resource URL from file URL", muex);
- }
- }
- } catch (IOException ioex) {
- logger.error("Exception when trying to read class from ByteArrayInputStream", ioex);
- } finally {
- if (jarInputStream != null) {
- try {
- jarInputStream.close();
- } catch (IOException ioex) {
- logger.error("Unable to close JAR input stream when finding resource", ioex);
- }
- }
- }
-
- return returnURL;
- }
-
- @Override
- protected Enumeration<URL> findResources(final String resourceName) {
- return new Enumeration<URL>() {
- private URL element = findResource(resourceName);
-
- @Override
- public boolean hasMoreElements() {
- return this.element != null;
- }
-
- @Override
- public URL nextElement() {
- if (this.element != null) {
- URL element = this.element;
- this.element = null;
- return element;
- }
- throw new NoSuchElementException();
- }
- };
- }
-
- @Override
- public Class<?> loadClass(final String className) throws ClassNotFoundException {
- return (loadClass(className, true));
- }
-
- @Override
- public Class<?> loadClass(final String className, final boolean resolveIt)
- throws ClassNotFoundException {
- return loadClass(className, resolveIt, true);
- }
-
- Class<?> loadClass(final String className, final boolean resolveIt,
- final boolean useClassPathLoader) throws ClassNotFoundException {
- Class<?> clazz = findLoadedClass(className);
- if (clazz != null) {
- return clazz;
- }
-
- try {
- clazz = findClass(className);
- if (resolveIt) {
- resolveClass(clazz);
- }
- } catch (ClassNotFoundException cnfex) {
- if (!useClassPathLoader) {
- throw cnfex;
- }
- }
-
- if (clazz == null) {
- try {
- this.alreadyScanned.set(true);
- return forName(className, ClassPathLoader.getLatest().getClassLoaders());
- } finally {
- this.alreadyScanned.set(false);
- }
- }
-
- return clazz;
- }
-
- // When loadClassesAndRegisterFunctions() is called and it starts to load classes, this method
- // may be called multiple times to resolve dependencies on other classes in the same or
- // another JAR file. During this stage, this.jarByteContent will contain the complete contents of
- // the JAR file and will be used when attempting to resolve these dependencies. Once
- // loadClassesAndRegisterFunctions() is complete it discards the data in this.jarByteContent.
- // However, at that point all of the classes available in the JAR file will already have been
- // loaded. Future calls to loadClass(...) will return the cached Class object for any
- // classes available in this JAR and findClass(...) will no longer be needed to find them.
- @Override
- protected Class<?> findClass(String className) throws ClassNotFoundException {
- String formattedClassName = className.replaceAll("\\.", "/") + ".class";
-
- JarInputStream jarInputStream = null;
- if (this.jarByteContent.length == 0) {
- throw new ClassNotFoundException(className);
- }
-
- try {
- jarInputStream = new JarInputStream(new ByteArrayInputStream(this.jarByteContent));
- JarEntry jarEntry = jarInputStream.getNextJarEntry();
-
- while (jarEntry != null && !jarEntry.getName().equals(formattedClassName)) {
- jarEntry = jarInputStream.getNextJarEntry();
- }
-
- if (jarEntry != null) {
- byte[] buffer = new byte[1024];
- ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(buffer.length);
-
- int bytesRead = -1;
- while ((bytesRead = jarInputStream.read(buffer)) != -1) {
- byteOutStream.write(buffer, 0, bytesRead);
- }
-
- // Add the package first if it doesn't already exist
- int lastDotIndex = className.lastIndexOf('.');
- if (lastDotIndex != -1) {
- String pkgName = className.substring(0, lastDotIndex);
- Package pkg = getPackage(pkgName);
- if (pkg == null) {
- definePackage(pkgName, null, null, null, null, null, null, null);
- }
- }
-
- byte[] classBytes = byteOutStream.toByteArray();
-
- synchronized (this.file) {
- Class<?> clazz = findLoadedClass(className);
- if (clazz == null) {
- clazz = defineClass(className, classBytes, 0, classBytes.length, null);
- }
- return clazz;
- }
- }
- } catch (IOException ioex) {
- logger.error("Exception when trying to read class from ByteArrayInputStream", ioex);
- } finally {
- if (jarInputStream != null) {
- try {
- jarInputStream.close();
- } catch (IOException ioex) {
- logger.error("Exception attempting to close JAR input stream", ioex);
- }
- }
- }
-
- throw new ClassNotFoundException(className);
- }
-
- /**
- * Check to see if the class implements the Function interface. If so, it will be registered with
- * FunctionService. Also, if the functions's class was originally declared in a cache.xml file
- * then any properties specified at that time will be reused when re-registering the function.
- *
- * @param clazz Class to check for implementation of the Function class
- * @return A collection of Objects that implement the Function interface.
- */
- private Collection<Function> getRegisterableFunctionsFromClass(Class<?> clazz) {
- final List<Function> registerableFunctions = new ArrayList<Function>();
-
- try {
- if (Function.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
- boolean registerUninitializedFunction = true;
- if (Declarable.class.isAssignableFrom(clazz)) {
- try {
- final List<Properties> propertiesList =
- ((GemFireCacheImpl) CacheFactory.getAnyInstance())
- .getDeclarableProperties(clazz.getName());
-
- if (!propertiesList.isEmpty()) {
- registerUninitializedFunction = false;
- // It's possible that the same function was declared multiple times in cache.xml
- // with different properties. So, register the function using each set of
- // properties.
- for (Properties properties : propertiesList) {
- @SuppressWarnings("unchecked")
- Function function = newFunction((Class<Function>) clazz, true);
- if (function != null) {
- ((Declarable) function).init(properties);
- if (function.getId() != null) {
- registerableFunctions.add(function);
- }
- }
- }
- }
- } catch (CacheClosedException ccex) {
- // That's okay, it just means there were no properties to init the function with
- }
- }
-
- if (registerUninitializedFunction) {
- @SuppressWarnings("unchecked")
- Function function = newFunction((Class<Function>) clazz, false);
- if (function != null && function.getId() != null) {
- registerableFunctions.add(function);
- }
- }
- }
- } catch (Exception ex) {
- logger.error("Attempting to register function from JAR file: " + this.file.getAbsolutePath(),
- ex);
- }
-
- return registerableFunctions;
- }
-
- private Class<?> forName(final String className, final Collection<ClassLoader> classLoaders)
- throws ClassNotFoundException {
- Class<?> clazz = null;
-
- for (ClassLoader classLoader : classLoaders) {
- try {
- if (classLoader instanceof JarClassLoader) {
- if (!((JarClassLoader) classLoader).alreadyScanned()) {
- clazz = ((JarClassLoader) classLoader).loadClass(className, true, false);
- }
- } else {
- clazz = Class.forName(className, true, classLoader);
- }
- if (clazz != null) {
- return clazz;
- }
- } catch (SecurityException sex) {
- // Continue to next ClassLoader
- } catch (ClassNotFoundException cnfex) {
- // Continue to next ClassLoader
- }
- }
- throw new ClassNotFoundException(className);
- }
-
- private Function newFunction(final Class<Function> clazz, final boolean errorOnNoSuchMethod) {
- try {
- final Constructor<Function> constructor = clazz.getConstructor();
- return constructor.newInstance();
- } catch (NoSuchMethodException nsmex) {
- if (errorOnNoSuchMethod) {
- logger.error("Zero-arg constructor is required, but not found for class: {}",
- clazz.getName(), nsmex);
- } else {
- if (logger.isDebugEnabled()) {
- logger.debug(
- "Not registering function because it doesn't have a zero-arg constructor: {}",
- clazz.getName());
- }
- }
- } catch (SecurityException sex) {
- logger.error("Zero-arg constructor of function not accessible for class: {}", clazz.getName(),
- sex);
- } catch (IllegalAccessException iae) {
- logger.error("Zero-arg constructor of function not accessible for class: {}", clazz.getName(),
- iae);
- } catch (InvocationTargetException ite) {
- logger.error("Error when attempting constructor for function for class: {}", clazz.getName(),
- ite);
- } catch (InstantiationException ie) {
- logger.error("Unable to instantiate function for class: {}", clazz.getName(), ie);
- } catch (ExceptionInInitializerError eiiex) {
- logger.error("Error during function initialization for class: {}", clazz.getName(), eiiex);
- }
- return null;
- }
-
- private byte[] getJarContent() throws IOException {
- ChannelInputStream channelInputStream = new ChannelInputStream(this.fileLock.channel());
- final ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
- final byte[] bytes = new byte[4096];
-
- int bytesRead;
- while (((bytesRead = channelInputStream.read(bytes)) != -1)) {
- byteOutStream.write(bytes, 0, bytesRead);
- }
- channelInputStream.close();
- return byteOutStream.toByteArray();
- }
-
- public String getJarName() {
- return this.jarName;
- }
-
- public String getFileName() {
- return this.file.getName();
- }
-
- public String getFileCanonicalPath() throws IOException {
- return this.file.getCanonicalPath();
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((this.jarName == null) ? 0 : this.jarName.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- JarClassLoader other = (JarClassLoader) obj;
- if (this.jarName == null) {
- if (other.jarName != null)
- return false;
- } else if (!this.jarName.equals(other.jarName))
- return false;
- return true;
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder(getClass().getName());
- sb.append("@").append(System.identityHashCode(this)).append("{");
- sb.append("jarName=").append(this.jarName);
- sb.append(",file=").append(this.file.getAbsolutePath());
- sb.append(",md5hash=").append(Arrays.toString(this.md5hash));
- sb.append(",fileLock=").append(this.fileLock);
- sb.append("}");
- return sb.toString();
- }
-
- /**
- * When a lock is acquired it is done so through an open file (FileInputStream, etc.). If for any
- * reason that same file is used to open another input stream, when the second input stream is
- * closed the file lock will not be held (although an OverlappingFileLock exception will be thrown
- * if an attempt is made to acquire the lock again). To get around this problem, this class is
- * used to wrap the original file channel used by the lock with an InputStream. When this class is
- * instantiated a lock is obtained to prevent other threads from attempting to use the file
- * channel at the same time. The file channel can then be read as with any other InputStream. When
- * the input stream is closed, instead of closing the file channel, the lock is released instead.
- *
- * This class is thread safe. However, multiple instances cannot be created by the same thread.
- * The reason for this is that the lock will be obtained in all cases (it's reentrant), and then
- * the channel position will be modified by both instances causing arbitrary values being returned
- * from the read() method.
- *
- * @since GemFire 7.0
- */
- private class ChannelInputStream extends InputStream {
- private final FileChannel fileChannel;
- private final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1);
-
- ChannelInputStream(final FileChannel fileChannel) throws IOException {
- channelLock.lock();
- this.fileChannel = fileChannel;
- this.fileChannel.position(0);
- }
-
- @Override
- public int read() throws IOException {
- this.byteBuffer.rewind();
- if (this.fileChannel.read(this.byteBuffer) <= 0) {
- return -1;
- }
- this.byteBuffer.rewind();
- return (this.byteBuffer.get() & 255);
- }
-
- @Override
- public void close() {
- channelLock.unlock();
- }
- }
-}
[8/8] geode git commit: GEODE-2290: Limit scanning of deployed jars
Posted by js...@apache.org.
GEODE-2290: Limit scanning of deployed jars
- Uses fast-classpath-scanner to scan jars for classes containing Functions without eagerly loading all classes in the jar.
Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/6f7f9439
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/6f7f9439
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/6f7f9439
Branch: refs/heads/develop
Commit: 6f7f943998153de1f00b1446eb80fa6d304ac40f
Parents: 8f9624d
Author: Jared Stewart <js...@pivotal.io>
Authored: Wed Apr 12 10:53:13 2017 -0700
Committer: Jared Stewart <js...@pivotal.io>
Committed: Sun Apr 16 09:10:02 2017 -0700
----------------------------------------------------------------------
geode-assembly/build.gradle | 1 +
.../src/test/resources/expected_jars.txt | 1 +
geode-core/build.gradle | 15 +-
.../org/apache/geode/internal/DeployedJar.java | 97 +++---
.../org/apache/geode/internal/JarDeployer.java | 7 +-
.../ClassPathLoaderIntegrationTest.java | 4 -
.../geode/internal/DeployedJarJUnitTest.java | 310 ++++++-------------
.../internal/JarDeployerIntegrationTest.java | 18 +-
.../cache/IncrementalBackupDUnitTest.java | 6 +-
.../geode/management/DeployJarTestSuite.java | 3 +
.../DeployCommandRedeployDUnitTest.java | 95 +++---
.../cli/commands/DeployCommandsDUnitTest.java | 40 +--
.../configuration/ClusterConfigBaseTest.java | 127 --------
.../ClusterConfigDeployJarDUnitTest.java | 10 +-
.../ClusterConfigImportDUnitTest.java | 3 +-
.../ClusterConfigStartMemberDUnitTest.java | 3 +-
.../configuration/ClusterConfigTestBase.java | 128 ++++++++
.../dunit/rules/LocatorServerStartupRule.java | 12 +
...oyCommandRedeployDUnitTest_FunctionATemplate | 30 ++
...oyCommandRedeployDUnitTest_FunctionBTemplate | 26 ++
gradle/dependency-versions.properties | 1 +
21 files changed, 439 insertions(+), 498 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-assembly/build.gradle
----------------------------------------------------------------------
diff --git a/geode-assembly/build.gradle b/geode-assembly/build.gradle
index 304a1c4..a4f0c69 100755
--- a/geode-assembly/build.gradle
+++ b/geode-assembly/build.gradle
@@ -139,6 +139,7 @@ def cp = {
it.contains('commons-io') ||
it.contains('commons-lang') ||
it.contains('commons-logging') ||
+ it.contains('fast-classpath-scanner') ||
it.contains('fastutil') ||
it.contains('jackson-annotations') ||
it.contains('jackson-core') ||
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-assembly/src/test/resources/expected_jars.txt
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/resources/expected_jars.txt b/geode-assembly/src/test/resources/expected_jars.txt
index b7d1dc2..6260167 100644
--- a/geode-assembly/src/test/resources/expected_jars.txt
+++ b/geode-assembly/src/test/resources/expected_jars.txt
@@ -10,6 +10,7 @@ commons-io
commons-lang
commons-logging
commons-modeler
+fast-classpath-scanner
fastutil
findbugs-annotations
gfsh-dependencies.jar
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/build.gradle
----------------------------------------------------------------------
diff --git a/geode-core/build.gradle b/geode-core/build.gradle
index 757599a..f07444a 100755
--- a/geode-core/build.gradle
+++ b/geode-core/build.gradle
@@ -32,7 +32,7 @@ configurations {
dependencies {
// Source Dependencies
- // External
+ // External
provided files("${System.getProperty('java.home')}/../lib/tools.jar")
compile 'com.github.stephenc.findbugs:findbugs-annotations:' + project.'stephenc-findbugs.version'
compile 'org.jgroups:jgroups:' + project.'jgroups.version'
@@ -104,17 +104,22 @@ dependencies {
}
compile ('org.iq80.snappy:snappy:' + project.'snappy-java.version') {
ext.optional = true
- }
+ }
compile 'org.apache.shiro:shiro-core:' + project.'shiro.version'
// This is only added since shiro is using an old version of beanutils and we want
// to use a standard version. Once shiro deps are updated, remove this explicit dependency
// in favor of a transitive dependency on beanutils.
compile 'commons-beanutils:commons-beanutils:' + project.'commons-beanutils.version'
-
+
+ // https://mvnrepository.com/artifact/io.github.lukehutch/fast-classpath-scanner
+ compile 'io.github.lukehutch:fast-classpath-scanner:' + project.'fast-classpath-scanner.version'
+
+
+
compile project(':geode-common')
compile project(':geode-json')
-
+
jcaCompile sourceSets.main.output
testCompile project(':geode-junit')
@@ -181,7 +186,7 @@ jar {
from sourceSets.main.output
from sourceSets.jca.output
-
+
exclude 'org/apache/geode/management/internal/web/**'
exclude 'org/apache/geode/internal/i18n/StringIdResourceBundle_ja.txt'
exclude 'org/apache/geode/admin/doc-files/ds4_0.dtd'
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java b/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
index 8adec1f..f96863f 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/DeployedJar.java
@@ -14,6 +14,9 @@
*/
package org.apache.geode.internal;
+import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;
+import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -25,7 +28,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.URL;
-import java.nio.channels.FileLock;
+import java.net.URLClassLoader;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -37,7 +40,6 @@ import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
-import org.apache.geode.cache.Cache;
import org.apache.logging.log4j.Logger;
import org.apache.geode.cache.CacheClosedException;
@@ -48,7 +50,6 @@ import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.pdx.internal.TypeRegistry;
-import sun.nio.ch.ChannelInputStream;
/**
* ClassLoader for a single JAR file.
@@ -103,7 +104,7 @@ public class DeployedJar {
+ ", was modified prior to obtaining a lock: " + jarName);
}
- if (!isValidJarContent(getJarContent())) {
+ if (!hasValidJarContent(getJarContent())) {
throw new IllegalArgumentException(
"File does not contain valid JAR content: " + versionedJarFile.getAbsolutePath());
}
@@ -147,23 +148,10 @@ public class DeployedJar {
* @param jarBytes Bytes of data to be validated.
* @return True if the data has JAR content, false otherwise
*/
- public static boolean isValidJarContent(final byte[] jarBytes) {
+ public static boolean hasValidJarContent(final byte[] jarBytes) {
return hasValidJarContent(new ByteArrayInputStream(jarBytes));
}
- /**
- * Peek into the JAR data and make sure that it is valid JAR content.
- *
- * @param jarFile File whose contents should be validated.
- * @return True if the data has JAR content, false otherwise
- */
- public static boolean hasValidJarContent(final File jarFile) {
- try {
- return hasValidJarContent(new FileInputStream(jarFile));
- } catch (IOException ioex) {
- return false;
- }
- }
/**
* Scan the JAR file and attempt to load all classes and register any function classes found.
@@ -184,37 +172,42 @@ public class DeployedJar {
JarInputStream jarInputStream = null;
try {
+ List<String> functionClasses = findFunctionsInThisJar();
+
jarInputStream = new JarInputStream(byteArrayInputStream);
JarEntry jarEntry = jarInputStream.getNextJarEntry();
while (jarEntry != null) {
if (jarEntry.getName().endsWith(".class")) {
- if (isDebugEnabled) {
- logger.debug("Attempting to load class: {}, from JAR file: {}", jarEntry.getName(),
- this.file.getAbsolutePath());
- }
-
final String className = jarEntry.getName().replaceAll("/", "\\.").substring(0,
(jarEntry.getName().length() - 6));
- try {
- Class<?> clazz = ClassPathLoader.getLatest().forName(className);
- Collection<Function> registerableFunctions = getRegisterableFunctionsFromClass(clazz);
- for (Function function : registerableFunctions) {
- FunctionService.registerFunction(function);
- if (isDebugEnabled) {
- logger.debug("Registering function class: {}, from JAR file: {}", className,
- this.file.getAbsolutePath());
+
+ if (functionClasses.contains(className)) {
+ if (isDebugEnabled) {
+ logger.debug("Attempting to load class: {}, from JAR file: {}", jarEntry.getName(),
+ this.file.getAbsolutePath());
+ }
+ try {
+ Class<?> clazz = ClassPathLoader.getLatest().forName(className);
+ Collection<Function> registerableFunctions = getRegisterableFunctionsFromClass(clazz);
+ for (Function function : registerableFunctions) {
+ FunctionService.registerFunction(function);
+ if (isDebugEnabled) {
+ logger.debug("Registering function class: {}, from JAR file: {}", className,
+ this.file.getAbsolutePath());
+ }
+ this.registeredFunctions.add(function);
}
- this.registeredFunctions.add(function);
+ } catch (ClassNotFoundException | NoClassDefFoundError cnfex) {
+ logger.error("Unable to load all classes from JAR file: {}",
+ this.file.getAbsolutePath(), cnfex);
+ throw cnfex;
+ }
+ } else {
+ if (isDebugEnabled) {
+ logger.debug("No functions found in class: {}, from JAR file: {}", jarEntry.getName(),
+ this.file.getAbsolutePath());
}
- } catch (ClassNotFoundException cnfex) {
- logger.error("Unable to load all classes from JAR file: {}",
- this.file.getAbsolutePath(), cnfex);
- throw cnfex;
- } catch (NoClassDefFoundError ncdfex) {
- logger.error("Unable to load all classes from JAR file: {}",
- this.file.getAbsolutePath(), ncdfex);
- throw ncdfex;
}
}
jarEntry = jarInputStream.getNextJarEntry();
@@ -327,6 +320,15 @@ public class DeployedJar {
return registerableFunctions;
}
+ private List<String> findFunctionsInThisJar() throws IOException {
+ URLClassLoader urlClassLoader =
+ new URLClassLoader(new URL[] {this.getFile().getCanonicalFile().toURL()});
+ FastClasspathScanner fastClasspathScanner = new FastClasspathScanner()
+ .removeTemporaryFilesAfterScan(true).overrideClassLoaders(urlClassLoader);
+ ScanResult scanResult = fastClasspathScanner.scan();
+ return scanResult.getNamesOfClassesImplementing(Function.class);
+ }
+
private Function newFunction(final Class<Function> clazz, final boolean errorOnNoSuchMethod) {
try {
final Constructor<Function> constructor = clazz.getConstructor();
@@ -342,20 +344,11 @@ public class DeployedJar {
clazz.getName());
}
}
- } catch (SecurityException sex) {
- logger.error("Zero-arg constructor of function not accessible for class: {}", clazz.getName(),
- sex);
- } catch (IllegalAccessException iae) {
- logger.error("Zero-arg constructor of function not accessible for class: {}", clazz.getName(),
- iae);
- } catch (InvocationTargetException ite) {
+ } catch (Exception ex) {
logger.error("Error when attempting constructor for function for class: {}", clazz.getName(),
- ite);
- } catch (InstantiationException ie) {
- logger.error("Unable to instantiate function for class: {}", clazz.getName(), ie);
- } catch (ExceptionInInitializerError eiiex) {
- logger.error("Error during function initialization for class: {}", clazz.getName(), eiiex);
+ ex);
}
+
return null;
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
index da4c136..a65cd0f 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
@@ -26,7 +26,6 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
@@ -35,7 +34,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -51,7 +49,6 @@ import java.util.stream.Stream;
public class JarDeployer implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = LogService.getLogger();
- public static final String JAR_PREFIX = "";
public static final String JAR_PREFIX_FOR_REGEX = "";
private static final Lock lock = new ReentrantLock();
@@ -438,7 +435,7 @@ public class JarDeployer implements Serializable {
Optional<File> latestValidDeployedJarOptional =
Arrays.stream(jarFiles).filter(Objects::nonNull).filter(jarFile -> {
try {
- return DeployedJar.isValidJarContent(FileUtils.readFileToByteArray(jarFile));
+ return DeployedJar.hasValidJarContent(FileUtils.readFileToByteArray(jarFile));
} catch (IOException e) {
return false;
}
@@ -501,7 +498,7 @@ public class JarDeployer implements Serializable {
DeployedJar[] deployedJars = new DeployedJar[jarNames.length];
for (int i = 0; i < jarNames.length; i++) {
- if (!DeployedJar.isValidJarContent(jarBytes[i])) {
+ if (!DeployedJar.hasValidJarContent(jarBytes[i])) {
throw new IllegalArgumentException(
"File does not contain valid JAR content: " + jarNames[i]);
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
index 14108c7..c783318 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
@@ -66,7 +66,6 @@ public class ClassPathLoaderIntegrationTest {
private File tempFile;
private File tempFile2;
- private File extLibsDir;
@Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
@@ -78,9 +77,6 @@ public class ClassPathLoaderIntegrationTest {
public void setUp() throws Exception {
System.setProperty(ClassPathLoader.EXCLUDE_TCCL_PROPERTY, "false");
- extLibsDir = new File(this.temporaryFolder.getRoot(), "ext");
- extLibsDir.mkdirs();
-
this.tempFile = this.temporaryFolder.newFile("tempFile1.tmp");
FileOutputStream fos = new FileOutputStream(this.tempFile);
fos.write(new byte[TEMP_FILE_BYTES_COUNT]);
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java
index 7216463..5e7c40f 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java
@@ -14,12 +14,9 @@
*/
package org.apache.geode.internal;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionContext;
@@ -27,6 +24,7 @@ import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.execute.ResultSender;
import org.apache.geode.internal.cache.execute.FunctionContextImpl;
import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.awaitility.Awaitility;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -43,17 +41,12 @@ import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Random;
-import java.util.concurrent.BrokenBarrierException;
-import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-/**
- * TODO: Need to fix this testDeclarableFunctionsWithParms and testClassOnClasspath on Windows:
- */
@Category(IntegrationTest.class)
public class DeployedJarJUnitTest {
@Rule
@@ -62,13 +55,13 @@ public class DeployedJarJUnitTest {
@Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
- private final ClassBuilder classBuilder = new ClassBuilder();
+ private ClassBuilder classBuilder;
@Before
public void setup() throws Exception {
File workingDir = temporaryFolder.newFolder();
-
ClassPathLoader.setLatestToDefault(workingDir);
+ classBuilder = new ClassBuilder();
}
@After
@@ -82,13 +75,14 @@ public class DeployedJarJUnitTest {
@Test
public void testIsValidJarContent() throws IOException {
- assertTrue(
- DeployedJar.isValidJarContent(this.classBuilder.createJarFromName("JarClassLoaderJUnitA")));
+ assertThat(
+ DeployedJar.hasValidJarContent(this.classBuilder.createJarFromName("JarClassLoaderJUnitA")))
+ .isTrue();
}
@Test
public void testIsInvalidJarContent() {
- assertFalse(DeployedJar.isValidJarContent("INVALID JAR CONTENT".getBytes()));
+ assertThat(DeployedJar.hasValidJarContent("INVALID JAR CONTENT".getBytes())).isFalse();
}
@Test
@@ -99,11 +93,7 @@ public class DeployedJarJUnitTest {
"package com.jcljunit; public class JarClassLoaderJUnitA {}");
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
- try {
- ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
+ ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA");
// Update the JAR file and make sure the first class is no longer on the Classpath
// and the second one is.
@@ -111,54 +101,36 @@ public class DeployedJarJUnitTest {
"package com.jcljunit; public class JarClassLoaderJUnitB {}");
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
- try {
- ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitB");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- try {
- ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA");
- fail("Class should not be found on Classpath");
- } catch (ClassNotFoundException expected) { // expected
- }
-
+ ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitB");
+ assertThatThrownBy(
+ () -> ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA"))
+ .isInstanceOf(ClassNotFoundException.class);
}
@Test
public void testFailingCompilation() throws Exception {
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer.append("public class JarClassLoaderJUnitFunction implements Function {}");
- String functionString = stringBuffer.toString();
-
- try {
- this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
- fail("This code should have failed to compile and thrown an exception");
- } catch (Exception ex) {
- // All good
- }
+ String functionString = "import org.apache.geode.cache.Declarable;"
+ + "import org.apache.geode.cache.execute.Function;"
+ + "import org.apache.geode.cache.execute.FunctionContext;"
+ + "public class JarClassLoaderJUnitFunction implements Function {}";
+
+ assertThatThrownBy(() -> this.classBuilder
+ .createJarFromClassContent("JarClassLoaderJUnitFunction", functionString)).isNotNull();
}
@Test
- public void testFunctions() throws IOException, ClassNotFoundException {
+ public void testFunctions() throws Exception {
// Test creating a JAR file with a function
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import java.util.Properties;");
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer.append("public class JarClassLoaderJUnitFunction implements Function {");
- stringBuffer.append("public void init(Properties props) {}");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"GOODv1\");}");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
- String functionString = stringBuffer.toString();
+ String functionString =
+ "import java.util.Properties;" + "import org.apache.geode.cache.Declarable;"
+ + "import org.apache.geode.cache.execute.Function;"
+ + "import org.apache.geode.cache.execute.FunctionContext;"
+ + "public class JarClassLoaderJUnitFunction implements Function {"
+ + "public void init(Properties props) {}" + "public boolean hasResult() {return true;}"
+ + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"GOODv1\");}"
+ + "public String getId() {return \"JarClassLoaderJUnitFunction\";}"
+ + "public boolean optimizeForWrite() {return false;}"
+ + "public boolean isHA() {return false;}}";
byte[] jarBytes =
this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
@@ -166,11 +138,11 @@ public class DeployedJarJUnitTest {
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
+ assertThat(function).isNotNull();
TestResultSender resultSender = new TestResultSender();
FunctionContext functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
function.execute(functionContext);
- assertEquals("GOODv1", (String) resultSender.getResults());
+ assertThat(resultSender.getResults()).isEqualTo("GOODv1");
// Test updating the function with a new JAR file
functionString = functionString.replace("v1", "v2");
@@ -179,11 +151,11 @@ public class DeployedJarJUnitTest {
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
+ assertThat(function).isNotNull();
resultSender = new TestResultSender();
functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
function.execute(functionContext);
- assertEquals("GOODv2", (String) resultSender.getResults());
+ assertThat(resultSender.getResults()).isEqualTo("GOODv2");
// Test returning null for the Id
String functionNullIdString =
@@ -192,88 +164,71 @@ public class DeployedJarJUnitTest {
functionNullIdString);
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes);
- assertNull(FunctionService.getFunction("JarClassLoaderJUnitFunction"));
+ assertThat(FunctionService.getFunction("JarClassLoaderJUnitFunction")).isNull();
// Test removing the JAR
ClassPathLoader.getLatest().getJarDeployer().undeploy("JarClassLoaderJUnit.jar");
- assertNull(FunctionService.getFunction("JarClassLoaderJUnitFunction"));
+ assertThat(FunctionService.getFunction("JarClassLoaderJUnitFunction")).isNull();
}
/**
* Ensure that abstract functions aren't added to the Function Service.
*/
@Test
- public void testAbstractFunction() throws IOException, ClassNotFoundException {
+ public void testAbstractFunction() throws Exception {
// Add an abstract Function to the Classpath
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("public abstract class JarClassLoaderJUnitFunction implements Function {");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}}");
- String functionString = stringBuffer.toString();
+ String functionString = "import org.apache.geode.cache.execute.Function;"
+ + "public abstract class JarClassLoaderJUnitFunction implements Function {"
+ + "public String getId() {return \"JarClassLoaderJUnitFunction\";}}";
byte[] jarBytes =
this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString);
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitFunction.jar",
jarBytes);
- try {
- ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunction");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
+ ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunction");
Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNull(function);
+ assertThat(function).isNull();
}
@Test
public void testDeclarableFunctionsWithNoCacheXml() throws Exception {
-
final String jarName = "JarClassLoaderJUnitNoXml.jar";
// Add a Declarable Function without parameters for the class to the Classpath
- StringBuffer stringBuffer = new StringBuffer();
- stringBuffer.append("import java.util.Properties;");
- stringBuffer.append("import org.apache.geode.cache.Declarable;");
- stringBuffer.append("import org.apache.geode.cache.execute.Function;");
- stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
- stringBuffer
- .append("public class JarClassLoaderJUnitFunctionNoXml implements Function, Declarable {");
- stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunctionNoXml\";}");
- stringBuffer.append("public void init(Properties props) {}");
- stringBuffer.append(
- "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"NOPARMSv1\");}");
- stringBuffer.append("public boolean hasResult() {return true;}");
- stringBuffer.append("public boolean optimizeForWrite() {return false;}");
- stringBuffer.append("public boolean isHA() {return false;}}");
- String functionString = stringBuffer.toString();
+ String functionString =
+ "import java.util.Properties;" + "import org.apache.geode.cache.Declarable;"
+ + "import org.apache.geode.cache.execute.Function;"
+ + "import org.apache.geode.cache.execute.FunctionContext;"
+ + "public class JarClassLoaderJUnitFunctionNoXml implements Function, Declarable {"
+ + "public String getId() {return \"JarClassLoaderJUnitFunctionNoXml\";}"
+ + "public void init(Properties props) {}"
+ + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"NOPARMSv1\");}"
+ + "public boolean hasResult() {return true;}"
+ + "public boolean optimizeForWrite() {return false;}"
+ + "public boolean isHA() {return false;}}";
byte[] jarBytes = this.classBuilder
.createJarFromClassContent("JarClassLoaderJUnitFunctionNoXml", functionString);
ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, jarBytes);
- try {
- ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunctionNoXml");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
+ ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunctionNoXml");
// Check to see if the function without parameters executes correctly
Function function = FunctionService.getFunction("JarClassLoaderJUnitFunctionNoXml");
- assertNotNull(function);
+ assertThat(function).isNotNull();
TestResultSender resultSender = new TestResultSender();
function.execute(new FunctionContextImpl(function.getId(), null, resultSender));
- assertEquals("NOPARMSv1", (String) resultSender.getResults());
+ assertThat((String) resultSender.getResults()).isEqualTo("NOPARMSv1");
}
@Test
- public void testDependencyBetweenJars() throws IOException, ClassNotFoundException {
+ public void testDependencyBetweenJars() throws Exception {
final File parentJarFile = temporaryFolder.newFile("JarClassLoaderJUnitParent.jar");
final File usesJarFile = temporaryFolder.newFile("JarClassLoaderJUnitUses.jar");
- JarDeployer jarDeployer = ClassPathLoader.getLatest().getJarDeployer();
-
// Write out a JAR files.
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("package jcljunit.parent;");
@@ -319,17 +274,15 @@ public class DeployedJarJUnitTest {
jarBytes = functionClassBuilder.createJarFromClassContent(
"jcljunit/function/JarClassLoaderJUnitFunction", stringBuffer.toString());
-
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitFunction.jar",
jarBytes);
-
Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction");
- assertNotNull(function);
+ assertThat(function).isNotNull();
TestResultSender resultSender = new TestResultSender();
FunctionContext functionContext = new FunctionContextImpl(function.getId(), null, resultSender);
function.execute(functionContext);
- assertEquals("PARENT:USES", (String) resultSender.getResults());
+ assertThat((String) resultSender.getResults()).isEqualTo("PARENT:USES");
}
@Test
@@ -342,39 +295,26 @@ public class DeployedJarJUnitTest {
jarBytes);
InputStream inputStream = ClassPathLoader.getLatest().getResourceAsStream(fileName);
- assertNotNull(inputStream);
+ assertThat(inputStream).isNotNull();
final byte[] fileBytes = new byte[fileContent.length()];
inputStream.read(fileBytes);
inputStream.close();
- assertTrue(fileContent.equals(new String(fileBytes)));
+ assertThat(fileContent).isEqualTo(new String(fileBytes));
}
@Test
- public void testUpdateClassInJar() throws IOException, ClassNotFoundException {
+ public void testUpdateClassInJar() throws Exception {
// First use of the JAR file
byte[] jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass",
"public class JarClassLoaderJUnitTestClass { public Integer getValue5() { return new Integer(5); } }");
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes);
- try {
- Class<?> clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass");
- Object object = clazz.newInstance();
- Method getValue5Method = clazz.getMethod("getValue5", new Class[] {});
- Integer value = (Integer) getValue5Method.invoke(object, new Object[] {});
- assertEquals(value.intValue(), 5);
-
- } catch (InvocationTargetException itex) {
- fail("JAR file not correctly added to Classpath" + itex);
- } catch (NoSuchMethodException nsmex) {
- fail("JAR file not correctly added to Classpath" + nsmex);
- } catch (InstantiationException iex) {
- fail("JAR file not correctly added to Classpath" + iex);
- } catch (IllegalAccessException iaex) {
- fail("JAR file not correctly added to Classpath" + iaex);
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath" + cnfex);
- }
+ Class<?> clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass");
+ Object object = clazz.newInstance();
+ Method getValue5Method = clazz.getMethod("getValue5");
+ Integer value = (Integer) getValue5Method.invoke(object);
+ assertThat(value).isEqualTo(5);
// Now create an updated JAR file and make sure that the method from the new
// class is available.
@@ -382,29 +322,15 @@ public class DeployedJarJUnitTest {
"public class JarClassLoaderJUnitTestClass { public Integer getValue10() { return new Integer(10); } }");
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes);
-
- try {
- Class<?> clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass");
- Object object = clazz.newInstance();
- Method getValue10Method = clazz.getMethod("getValue10", new Class[] {});
- Integer value = (Integer) getValue10Method.invoke(object, new Object[] {});
- assertEquals(value.intValue(), 10);
-
- } catch (InvocationTargetException itex) {
- fail("JAR file not correctly added to Classpath" + itex);
- } catch (NoSuchMethodException nsmex) {
- fail("JAR file not correctly added to Classpath" + nsmex);
- } catch (InstantiationException iex) {
- fail("JAR file not correctly added to Classpath" + iex);
- } catch (IllegalAccessException iaex) {
- fail("JAR file not correctly added to Classpath" + iaex);
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath" + cnfex);
- }
+ clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass");
+ object = clazz.newInstance();
+ Method getValue10Method = clazz.getMethod("getValue10");
+ value = (Integer) getValue10Method.invoke(object);
+ assertThat(value).isEqualTo(10);
}
@Test
- public void testMultiThread() throws IOException, ClassNotFoundException {
+ public void testMultiThreadingDoesNotCauseDeadlock() throws Exception {
// Add two JARs to the classpath
byte[] jarBytes = this.classBuilder.createJarFromName("JarClassLoaderJUnitA");
ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitA.jar", jarBytes);
@@ -416,54 +342,32 @@ public class DeployedJarJUnitTest {
String[] classNames = new String[] {"JarClassLoaderJUnitA", "com.jcljunit.JarClassLoaderJUnitB",
"NON-EXISTENT CLASS"};
- // Spawn some threads which try to instantiate these classes
final int threadCount = 10;
- final int numLoops = 1000;
- final CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount + 1);
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
for (int i = 0; i < threadCount; i++) {
- new ForNameExerciser(cyclicBarrier, numLoops, classNames).start();
+ executorService.submit(new ForNameExerciser(classNames));
}
- // Wait for all of the threads to be ready
- try {
- cyclicBarrier.await();
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for barrier");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
- }
+ executorService.shutdown();
+ Awaitility.await().atMost(60, TimeUnit.SECONDS).until(executorService::isTerminated);
- // Loop while each thread tries N times to instantiate a non-existent class
- for (int i = 0; i < numLoops; i++) {
- try {
- cyclicBarrier.await(5, TimeUnit.SECONDS);
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for barrier");
- } catch (TimeoutException tex) {
- ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
- long[] threadIds = threadMXBean.findDeadlockedThreads();
-
- if (threadIds != null) {
- StringBuffer deadLockTrace = new StringBuffer();
- for (long threadId : threadIds) {
- ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId, 100);
- deadLockTrace.append(threadInfo.getThreadName()).append("\n");
- for (StackTraceElement stackTraceElem : threadInfo.getStackTrace()) {
- deadLockTrace.append("\t").append(stackTraceElem).append("\n");
- }
- }
-
- fail("Deadlock with trace:\n" + deadLockTrace.toString());
- }
+ ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+ long[] threadIds = threadMXBean.findDeadlockedThreads();
- fail("Timeout while waiting for barrier - no deadlock detected");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
+ if (threadIds != null) {
+ StringBuilder deadLockTrace = new StringBuilder();
+ for (long threadId : threadIds) {
+ ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId, 100);
+ deadLockTrace.append(threadInfo.getThreadName()).append("\n");
+ for (StackTraceElement stackTraceElem : threadInfo.getStackTrace()) {
+ deadLockTrace.append("\t").append(stackTraceElem).append("\n");
+ }
}
+ System.out.println(deadLockTrace);
}
+ assertThat(threadIds).isNull();
}
-
private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException {
final OutputStream outStream = new FileOutputStream(jarFile);
outStream.write(jarBytes);
@@ -497,40 +401,24 @@ public class DeployedJarJUnitTest {
static final Random random = new Random();
- private class ForNameExerciser extends Thread {
- private final CyclicBarrier cyclicBarrier;
- private final int numLoops;
+ private class ForNameExerciser implements Runnable {
+ private final int numLoops = 1000;
private final String[] classNames;
- ForNameExerciser(final CyclicBarrier cyclicBarrier, final int numLoops,
- final String[] classNames) {
- this.cyclicBarrier = cyclicBarrier;
- this.numLoops = numLoops;
+ ForNameExerciser(final String[] classNames) {
this.classNames = classNames;
}
@Override
public void run() {
- try {
- this.cyclicBarrier.await();
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for latch");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
- }
for (int i = 0; i < this.numLoops; i++) {
try {
// Random select a name from the list of class names and try to load it
String className = this.classNames[random.nextInt(this.classNames.length)];
ClassPathLoader.getLatest().forName(className);
} catch (ClassNotFoundException expected) { // expected
- }
- try {
- this.cyclicBarrier.await();
- } catch (InterruptedException iex) {
- fail("Interrupted while waiting for barrrier");
- } catch (BrokenBarrierException bbex) {
- fail("Broken barrier while waiting");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
}
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
index e9af0e7..b81e3e9 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerIntegrationTest.java
@@ -21,6 +21,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.awaitility.Awaitility;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,6 +35,7 @@ import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -94,8 +96,6 @@ public class JarDeployerIntegrationTest {
alternateDir.delete();
final JarDeployer jarDeployer = new JarDeployer(alternateDir);
-
- final CyclicBarrier barrier = new CyclicBarrier(2);
final byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDTID");
// Test to verify that deployment fails if the directory doesn't exist.
@@ -106,16 +106,20 @@ public class JarDeployerIntegrationTest {
// Test to verify that deployment succeeds if the directory doesn't
// initially exist, but is then created while the JarDeployer is looping
// looking for a valid directory.
- Future<Boolean> done = Executors.newSingleThreadExecutor().submit(() -> {
+ final AtomicBoolean isDeployed = new AtomicBoolean(false);
+ final CyclicBarrier barrier = new CyclicBarrier(2);
+
+ Executors.newSingleThreadExecutor().submit(() -> {
barrier.await();
jarDeployer.deployWithoutRegistering("JarDeployerIntegrationTest.jar", jarBytes);
+ isDeployed.set(true);
return true;
});
barrier.await();
- Thread.sleep(500);
- alternateDir.mkdir();
- assertThat(done.get(2, TimeUnit.MINUTES)).isTrue();
+ alternateDir.mkdirs();
+ Awaitility.await().atMost(1, TimeUnit.MINUTES)
+ .until(() -> assertThat(isDeployed.get()).isTrue());
}
@Test
@@ -137,7 +141,7 @@ public class JarDeployerIntegrationTest {
@Test
public void testVersionNumberMatcher() throws IOException {
int version =
- jarDeployer.extractVersionFromFilename(temporaryFolder.newFile("MyJar.v1.jar").getName());
+ JarDeployer.extractVersionFromFilename(temporaryFolder.newFile("MyJar.v1.jar").getName());
assertThat(version).isEqualTo(1);
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
index dcbbeb0..0dbe75f 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/IncrementalBackupDUnitTest.java
@@ -1103,7 +1103,7 @@ public class IncrementalBackupDUnitTest extends JUnit4CacheTestCase {
}
});
- assert (deployedJarFile.exists());
+ assertTrue(deployedJarFile.exists());
/*
* Perform backup. Make sure it is successful.
*/
@@ -1138,7 +1138,7 @@ public class IncrementalBackupDUnitTest extends JUnit4CacheTestCase {
/*
* Cleanup "dummy" jar from file system.
*/
- Pattern pattern = Pattern.compile("^" + JarDeployer.JAR_PREFIX + jarName + ".*#\\d++$");
+ Pattern pattern = Pattern.compile("^" + jarName + ".*#\\d++$");
deleteMatching(new File("."), pattern);
// Execute the restore
@@ -1179,7 +1179,7 @@ public class IncrementalBackupDUnitTest extends JUnit4CacheTestCase {
/*
* Cleanup "dummy" jar from file system.
*/
- pattern = Pattern.compile("^" + JarDeployer.JAR_PREFIX + jarName + ".*#\\d++$");
+ pattern = Pattern.compile("^" + jarName + ".*#\\d++$");
deleteMatching(new File(vmDir), pattern);
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
index ee46cbf..6dfab66 100644
--- a/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
+++ b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java
@@ -21,9 +21,12 @@ import org.apache.geode.internal.JarDeployerIntegrationTest;
import org.apache.geode.management.internal.cli.commands.DeployCommandRedeployDUnitTest;
import org.apache.geode.management.internal.cli.commands.DeployCommandsDUnitTest;
import org.apache.geode.management.internal.configuration.ClusterConfigDeployJarDUnitTest;
+import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
+
+@Ignore
@RunWith(Suite.class)
@Suite.SuiteClasses({DeployedJarJUnitTest.class, DeployCommandsDUnitTest.class,
JarDeployerIntegrationTest.class, ClassPathLoaderIntegrationTest.class,
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java
index 8280f5d..7780c0e 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest.java
@@ -16,6 +16,7 @@ package org.apache.geode.management.internal.cli.commands;
import static org.assertj.core.api.Assertions.assertThat;
+import org.apache.commons.io.FileUtils;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.distributed.DistributedSystem;
@@ -23,10 +24,8 @@ import org.apache.geode.internal.ClassBuilder;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
-import org.apache.geode.test.dunit.rules.Locator;
import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
import org.apache.geode.test.dunit.rules.MemberVM;
-import org.apache.geode.test.dunit.rules.Server;
import org.apache.geode.test.junit.categories.DistributedTest;
import org.junit.Before;
import org.junit.Rule;
@@ -34,8 +33,8 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.File;
-import java.io.IOException;
import java.io.Serializable;
+import java.net.URL;
import java.util.List;
@Category(DistributedTest.class)
@@ -43,15 +42,15 @@ public class DeployCommandRedeployDUnitTest implements Serializable {
private static final String VERSION1 = "Version1";
private static final String VERSION2 = "Version2";
- private static final String jarNameA = "DeployCommandRedeployDUnitTestA.jar";
- private static final String functionA = "DeployCommandRedeployDUnitFunctionA";
+ private static final String JAR_NAME_A = "DeployCommandRedeployDUnitTestA.jar";
+ private static final String FUNCTION_A = "DeployCommandRedeployDUnitFunctionA";
private File jarAVersion1;
private File jarAVersion2;
- private static final String jarNameB = "DeployCommandRedeployDUnitTestB.jar";
- private static final String functionB = "DeployCommandRedeployDUnitFunctionB";
- private static final String packageB = "jddunit.function";
- private static final String fullyQualifiedFunctionB = packageB + "." + functionB;
+ private static final String JAR_NAME_B = "DeployCommandRedeployDUnitTestB.jar";
+ private static final String FUNCTION_B = "DeployCommandRedeployDUnitFunctionB";
+ private static final String PACKAGE_B = "jddunit.function";
+ private static final String FULLY_QUALIFIED_FUNCTION_B = PACKAGE_B + "." + FUNCTION_B;
private File jarBVersion1;
private File jarBVersion2;
@@ -59,7 +58,7 @@ public class DeployCommandRedeployDUnitTest implements Serializable {
private MemberVM server;
@Rule
- public LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
+ public LocatorServerStartupRule lsRule = new LocatorServerStartupRule(true);
@Rule
public transient GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
@@ -81,64 +80,60 @@ public class DeployCommandRedeployDUnitTest implements Serializable {
@Test
public void redeployJarsWithNewVersionsOfFunctions() throws Exception {
gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarAVersion1.getCanonicalPath());
- server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
- server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION1));
-
+ server.invoke(() -> assertThatCanLoad(JAR_NAME_A, FUNCTION_A));
+ server.invoke(() -> assertThatFunctionHasVersion(FUNCTION_A, VERSION1));
gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarBVersion1.getCanonicalPath());
- server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
- server.invoke(() -> assertThatCanLoad(jarNameB, fullyQualifiedFunctionB));
- server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION1));
- server.invoke(() -> assertThatFunctionHasVersion(functionB, VERSION1));
+ server.invoke(() -> assertThatCanLoad(JAR_NAME_A, FUNCTION_A));
+ server.invoke(() -> assertThatCanLoad(JAR_NAME_B, FULLY_QUALIFIED_FUNCTION_B));
+ server.invoke(() -> assertThatFunctionHasVersion(FUNCTION_A, VERSION1));
+ server.invoke(() -> assertThatFunctionHasVersion(FUNCTION_B, VERSION1));
gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarBVersion2.getCanonicalPath());
- server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
- server.invoke(() -> assertThatCanLoad(jarNameB, fullyQualifiedFunctionB));
- server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION1));
- server.invoke(() -> assertThatFunctionHasVersion(functionB, VERSION2));
+ server.invoke(() -> assertThatCanLoad(JAR_NAME_A, FUNCTION_A));
+ server.invoke(() -> assertThatCanLoad(JAR_NAME_B, FULLY_QUALIFIED_FUNCTION_B));
+ server.invoke(() -> assertThatFunctionHasVersion(FUNCTION_A, VERSION1));
+ server.invoke(() -> assertThatFunctionHasVersion(FUNCTION_B, VERSION2));
gfshConnector.executeAndVerifyCommand("deploy --jar=" + jarAVersion2.getCanonicalPath());
- server.invoke(() -> assertThatCanLoad(jarNameA, functionA));
- server.invoke(() -> assertThatCanLoad(jarNameB, fullyQualifiedFunctionB));
- server.invoke(() -> assertThatFunctionHasVersion(functionA, VERSION2));
- server.invoke(() -> assertThatFunctionHasVersion(functionB, VERSION2));
+ server.invoke(() -> assertThatCanLoad(JAR_NAME_A, FUNCTION_A));
+ server.invoke(() -> assertThatCanLoad(JAR_NAME_B, FULLY_QUALIFIED_FUNCTION_B));
+ server.invoke(() -> assertThatFunctionHasVersion(FUNCTION_A, VERSION2));
+ server.invoke(() -> assertThatFunctionHasVersion(FUNCTION_B, VERSION2));
}
// Note that jar A is a Declarable Function, while jar B is only a Function.
// Also, the function for jar A resides in the default package, whereas jar B specifies a package.
// This ensures that this test has identical coverage to some tests that it replaced.
private File createJarWithFunctionA(String version) throws Exception {
- String classContents =
- "import java.util.Properties;" + "import org.apache.geode.cache.Declarable;"
- + "import org.apache.geode.cache.execute.Function;"
- + "import org.apache.geode.cache.execute.FunctionContext;" + "public class " + functionA
- + " implements Function, Declarable {" + "public String getId() {return \"" + functionA
- + "\";}" + "public void init(Properties props) {}"
- + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\""
- + version + "\");}" + "public boolean hasResult() {return true;}"
- + "public boolean optimizeForWrite() {return false;}"
- + "public boolean isHA() {return false;}}";
-
- File jar = new File(lsRule.getTempFolder().newFolder(jarNameA + version), this.jarNameA);
+ URL classTemplateUrl = DeployCommandRedeployDUnitTest.class
+ .getResource("DeployCommandRedeployDUnitTest_FunctionATemplate");
+ assertThat(classTemplateUrl).isNotNull();
+
+ String classContents = FileUtils.readFileToString(new File(classTemplateUrl.toURI()), "UTF-8");
+ classContents = classContents.replaceAll("FUNCTION_A", FUNCTION_A);
+ classContents = classContents.replaceAll("VERSION", version);
+
+ File jar = new File(lsRule.getTempFolder().newFolder(JAR_NAME_A + version), this.JAR_NAME_A);
ClassBuilder functionClassBuilder = new ClassBuilder();
- functionClassBuilder.writeJarFromContent(functionA, classContents, jar);
+ functionClassBuilder.writeJarFromContent(FUNCTION_A, classContents, jar);
return jar;
}
- private File createJarWithFunctionB(String version) throws IOException {
- String classContents =
- "package " + packageB + ";" + "import org.apache.geode.cache.execute.Function;"
- + "import org.apache.geode.cache.execute.FunctionContext;" + "public class " + functionB
- + " implements Function {" + "public boolean hasResult() {return true;}"
- + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\""
- + version + "\");}" + "public String getId() {return \"" + functionB + "\";}"
- + "public boolean optimizeForWrite() {return false;}"
- + "public boolean isHA() {return false;}}";
-
- File jar = new File(lsRule.getTempFolder().newFolder(jarNameB + version), this.jarNameB);
+ private File createJarWithFunctionB(String version) throws Exception {
+ URL classTemplateUrl = DeployCommandRedeployDUnitTest.class
+ .getResource("DeployCommandRedeployDUnitTest_FunctionATemplate");
+ assertThat(classTemplateUrl).isNotNull();
+
+ String classContents = FileUtils.readFileToString(new File(classTemplateUrl.toURI()), "UTF-8");
+ classContents = classContents.replaceAll("PACKAGE_B", PACKAGE_B);
+ classContents = classContents.replaceAll("FUNCTION_B", FUNCTION_B);
+ classContents = classContents.replaceAll("VERSION", version);
+
+ File jar = new File(lsRule.getTempFolder().newFolder(JAR_NAME_B + version), this.JAR_NAME_B);
ClassBuilder functionClassBuilder = new ClassBuilder();
- functionClassBuilder.writeJarFromContent("jddunit/function/" + functionB, classContents, jar);
+ functionClassBuilder.writeJarFromContent("jddunit/function/" + FUNCTION_B, classContents, jar);
return jar;
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
index 6df2572..9ed5bed 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java
@@ -15,6 +15,7 @@
package org.apache.geode.management.internal.cli.commands;
import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
+import static org.apache.geode.test.dunit.Host.getHost;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertNotNull;
@@ -39,7 +40,7 @@ import java.util.Properties;
/**
* Unit tests for the DeployCommands class
- *
+ *
* @since GemFire 7.0
*/
@SuppressWarnings("serial")
@@ -76,6 +77,9 @@ public class DeployCommandsDUnitTest implements Serializable {
@Before
public void setup() throws Exception {
+ getHost(0).getVM(1).bounce();
+ getHost(0).getVM(2).bounce();
+
ClassBuilder classBuilder = new ClassBuilder();
File jarsDir = lsRule.getTempFolder().newFolder();
jar1 = new File(jarsDir, jarName1);
@@ -108,7 +112,7 @@ public class DeployCommandsDUnitTest implements Serializable {
// Deploy a jar to a single group
CommandResult cmdResult =
gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar2 + " --group=" + GROUP1);
- String resultString = commandResultToString(cmdResult);
+ String resultString = gfshConnector.getGfshOutput();
assertThat(resultString).contains(server1.getName());
assertThat(resultString).doesNotContain(server2.getName());
@@ -121,9 +125,9 @@ public class DeployCommandsDUnitTest implements Serializable {
@Test
public void deployMultipleJarsToOneGroup() throws Exception {
// Deploy of multiple JARs to a single group
- CommandResult cmdResult = gfshConnector.executeAndVerifyCommand(
+ gfshConnector.executeAndVerifyCommand(
"deploy --group=" + GROUP1 + " --dir=" + subdirWithJars3and4.getCanonicalPath());
- String resultString = commandResultToString(cmdResult);
+ String resultString = gfshConnector.getGfshOutput();
assertThat(resultString).describedAs(resultString).contains(server1.getName());
assertThat(resultString).doesNotContain(server2.getName());
@@ -139,7 +143,6 @@ public class DeployCommandsDUnitTest implements Serializable {
assertThatCannotLoad(jarName4, class4);
});
-
// Undeploy of multiple jars by specifying group
gfshConnector.executeAndVerifyCommand("undeploy --group=" + GROUP1);
server1.invoke(() -> {
@@ -155,9 +158,9 @@ public class DeployCommandsDUnitTest implements Serializable {
@Test
public void deployJarToAllServers() throws Exception {
// Deploy a jar to all servers
- CommandResult cmdResult = gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar1);
+ gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar1);
+ String resultString = gfshConnector.getGfshOutput();
- String resultString = commandResultToString(cmdResult);
assertThat(resultString).contains(server1.getName());
assertThat(resultString).contains(server2.getName());
assertThat(resultString).contains(jarName1);
@@ -242,16 +245,16 @@ public class DeployCommandsDUnitTest implements Serializable {
"deploy jar --group=" + GROUP2 + " --jar=" + jar2.getCanonicalPath());
// List for all members
- CommandResult commandResult = gfshConnector.executeAndVerifyCommand("list deployed");
- String resultString = commandResultToString(commandResult);
+ gfshConnector.executeAndVerifyCommand("list deployed");
+ String resultString = gfshConnector.getGfshOutput();
assertThat(resultString).contains(server1.getName());
assertThat(resultString).contains(server2.getName());
assertThat(resultString).contains(jarName1);
assertThat(resultString).contains(jarName2);
// List for members in Group1
- commandResult = gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP1);
- resultString = commandResultToString(commandResult);
+ gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP1);
+ resultString = gfshConnector.getGfshOutput();
assertThat(resultString).contains(server1.getName());
assertThat(resultString).doesNotContain(server2.getName());
@@ -259,23 +262,12 @@ public class DeployCommandsDUnitTest implements Serializable {
assertThat(resultString).doesNotContain(jarName2);
// List for members in Group2
- commandResult = gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP2);
- resultString = commandResultToString(commandResult);
+ gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP2);
+ resultString = gfshConnector.getGfshOutput();
assertThat(resultString).doesNotContain(server1.getName());
assertThat(resultString).contains(server2.getName());
assertThat(resultString).doesNotContain(jarName1);
assertThat(resultString).contains(jarName2);
}
-
- protected static String commandResultToString(final CommandResult commandResult) {
- assertNotNull(commandResult);
- commandResult.resetToFirstLine();
- StringBuilder buffer = new StringBuilder(commandResult.getHeader());
- while (commandResult.hasNextLine()) {
- buffer.append(commandResult.nextLine());
- }
- buffer.append(commandResult.getFooter());
- return buffer.toString();
- }
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigBaseTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigBaseTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigBaseTest.java
deleted file mode 100644
index cecc8cf..0000000
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigBaseTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.geode.management.internal.configuration;
-
-import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
-import static org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.geode.internal.ClassBuilder;
-import org.apache.geode.management.internal.configuration.utils.ZipUtils;
-import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
-import org.junit.Before;
-import org.junit.Rule;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Properties;
-
-public class ClusterConfigBaseTest {
- public String clusterConfigZipPath;
-
- public static final ConfigGroup CLUSTER = new ConfigGroup("cluster").regions("regionForCluster")
- .jars("cluster.jar").maxLogFileSize("5000").configFiles("cluster.properties", "cluster.xml");
- public static final ConfigGroup GROUP1 = new ConfigGroup("group1").regions("regionForGroup1")
- .jars("group1.jar").maxLogFileSize("6000").configFiles("group1.properties", "group1.xml");
- public static final ConfigGroup GROUP2 = new ConfigGroup("group2").regions("regionForGroup2")
- .jars("group2.jar").maxLogFileSize("7000").configFiles("group2.properties", "group2.xml");
-
- public static final ClusterConfig CONFIG_FROM_ZIP = new ClusterConfig(CLUSTER, GROUP1, GROUP2);
-
- public static final ClusterConfig REPLICATED_CONFIG_FROM_ZIP = new ClusterConfig(
- new ConfigGroup("cluster").maxLogFileSize("5000").jars("cluster.jar")
- .regions("regionForCluster"),
- new ConfigGroup("group1").maxLogFileSize("6000").jars("group1.jar")
- .regions("regionForGroup1"),
- new ConfigGroup("group2").maxLogFileSize("7000").jars("group2.jar")
- .regions("regionForGroup2"));
-
- @Rule
- public LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
-
- protected Properties locatorProps;
- protected Properties serverProps;
-
- @Before
- public void before() throws Exception {
- clusterConfigZipPath = buildClusterZipFile();
- locatorProps = new Properties();
- serverProps = new Properties();
-
- // the following are default values, we don't need to set them. We do it for clarity purpose
- locatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
- serverProps.setProperty(USE_CLUSTER_CONFIGURATION, "true");
- }
-
- private String buildClusterZipFile() throws Exception {
- ClassBuilder classBuilder = new ClassBuilder();
- File clusterConfigDir = this.lsRule.getTempFolder().newFolder("cluster_config");
-
- File clusterDir = new File(clusterConfigDir, "cluster");
- String clusterXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
- + "<cache xmlns=\"http://geode.apache.org/schema/cache\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" copy-on-read=\"false\" is-server=\"false\" lock-lease=\"120\" lock-timeout=\"60\" search-timeout=\"300\" version=\"1.0\" xsi:schemaLocation=\"http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd\">\n"
- + "<region name=\"regionForCluster\">\n"
- + " <region-attributes data-policy=\"replicate\" scope=\"distributed-ack\"/>\n"
- + " </region>\n" + "</cache>\n";
- writeFile(clusterDir, "cluster.xml", clusterXml);
- writeFile(clusterDir, "cluster.properties", "log-file-size-limit=5000");
- createJarFileWithClass("Cluster", "cluster.jar", clusterDir);
-
- File group1Dir = new File(clusterConfigDir, "group1");
- String group1Xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
- + "<cache xmlns=\"http://geode.apache.org/schema/cache\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" copy-on-read=\"false\" is-server=\"false\" lock-lease=\"120\" lock-timeout=\"60\" search-timeout=\"300\" version=\"1.0\" xsi:schemaLocation=\"http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd\">\n"
- + "<region name=\"regionForGroup1\">\n"
- + " <region-attributes data-policy=\"replicate\" scope=\"distributed-ack\"/>\n"
- + " </region>\n" + "</cache>\n";
- writeFile(group1Dir, "group1.xml", group1Xml);
- writeFile(group1Dir, "group1.properties", "log-file-size-limit=6000");
- createJarFileWithClass("Group1", "group1.jar", group1Dir);
-
-
- File group2Dir = new File(clusterConfigDir, "group2");
- String group2Xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
- + "<cache xmlns=\"http://geode.apache.org/schema/cache\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" copy-on-read=\"false\" is-server=\"false\" lock-lease=\"120\" lock-timeout=\"60\" search-timeout=\"300\" version=\"1.0\" xsi:schemaLocation=\"http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd\">\n"
- + "<region name=\"regionForGroup2\">\n"
- + " <region-attributes data-policy=\"replicate\" scope=\"distributed-ack\"/>\n"
- + " </region>\n" + "</cache>\n";
- writeFile(group2Dir, "group2.xml", group2Xml);
- writeFile(group2Dir, "group2.properties", "log-file-size-limit=7000");
- createJarFileWithClass("Group2", "group2.jar", group2Dir);
-
-
- File clusterConfigZip = new File(lsRule.getTempFolder().newFolder(), "cluster_config.zip");
- ZipUtils.zipDirectory(clusterConfigDir.getCanonicalPath(), clusterConfigZip.getCanonicalPath());
-
- FileUtils.deleteDirectory(clusterConfigDir);
- return clusterConfigZip.getCanonicalPath();
- }
-
- private File writeFile(File dir, String fileName, String content) throws IOException {
- dir.mkdirs();
- File file = new File(dir, fileName);
- FileUtils.writeStringToFile(file, content);
-
- return file;
- }
-
- protected String createJarFileWithClass(String className, String jarName, File dir)
- throws IOException {
- File jarFile = new File(dir, jarName);
- new ClassBuilder().writeJarFromName(className, jarFile);
- return jarFile.getCanonicalPath();
- }
-}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
index 980f81f..3781c98 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
@@ -18,6 +18,7 @@ package org.apache.geode.management.internal.configuration;
import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.test.dunit.Host.getHost;
import static org.assertj.core.api.Assertions.assertThat;
import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
@@ -29,7 +30,7 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(DistributedTest.class)
-public class ClusterConfigDeployJarDUnitTest extends ClusterConfigBaseTest {
+public class ClusterConfigDeployJarDUnitTest extends ClusterConfigTestBase {
@Rule
public GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
@@ -37,7 +38,6 @@ public class ClusterConfigDeployJarDUnitTest extends ClusterConfigBaseTest {
@Before
public void before() throws Exception {
- super.before();
clusterJar = createJarFileWithClass("Cluster", "cluster.jar", lsRule.getTempFolder().getRoot());
group1Jar = createJarFileWithClass("Group1", "group1.jar", lsRule.getTempFolder().getRoot());
group2Jar = createJarFileWithClass("Group2", "group2.jar", lsRule.getTempFolder().getRoot());
@@ -180,7 +180,6 @@ public class ClusterConfigDeployJarDUnitTest extends ClusterConfigBaseTest {
// test undeploy cluster
gfshConnector.executeAndVerifyCommand("undeploy --jar=cluster.jar");
-
cluster = cluster.removeJar("cluster.jar");
server3Config.verify(locator);
server1Config.verify(server1);
@@ -253,7 +252,6 @@ public class ClusterConfigDeployJarDUnitTest extends ClusterConfigBaseTest {
gfshConnector.executeAndVerifyCommand("undeploy --jar=cluster.jar");
server3 = lsRule.startServerVM(3, serverProps, locator.getPort());
-
cluster = cluster.removeJar("cluster.jar");
server3Config.verify(locator);
server1Config.verify(server1);
@@ -264,8 +262,8 @@ public class ClusterConfigDeployJarDUnitTest extends ClusterConfigBaseTest {
group1 = group1.removeJar("group1.jar");
/*
- * TODO: This is the current (weird) behavior If you started server4 with group1,group2 after
- * this undeploy command, it would have group1.jar (brought from
+ * TODO: GEODE-2779 This is the current (weird) behavior If you started server4 with
+ * group1,group2 after this undeploy command, it would have group1.jar (brought from
* cluster_config/group2/group1.jar on locator) whereas server3 (also in group1,group2) does not
* have this jar.
*/
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java
index 696d22c..521e084 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java
@@ -42,7 +42,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@Category(DistributedTest.class)
-public class ClusterConfigImportDUnitTest extends ClusterConfigBaseTest {
+public class ClusterConfigImportDUnitTest extends ClusterConfigTestBase {
@Rule
public GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
@@ -52,7 +52,6 @@ public class ClusterConfigImportDUnitTest extends ClusterConfigBaseTest {
@Before
public void before() throws Exception {
- super.before();
locatorVM = lsRule.startLocatorVM(0, locatorProps);
INITIAL_CONFIG.verify(locatorVM);
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java
index 652ec60..1cdda4c 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java
@@ -33,12 +33,11 @@ import java.io.File;
import java.util.Properties;
@Category(DistributedTest.class)
-public class ClusterConfigStartMemberDUnitTest extends ClusterConfigBaseTest {
+public class ClusterConfigStartMemberDUnitTest extends ClusterConfigTestBase {
protected MemberVM locator;
@Before
public void before() throws Exception {
- super.before();
locator = startLocatorWithLoadCCFromDir();
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java
new file mode 100644
index 0000000..c5aaa74
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java
@@ -0,0 +1,128 @@
+/*
+ * 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.geode.management.internal.configuration;
+
+import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.test.dunit.Host.getHost;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.geode.internal.ClassBuilder;
+import org.apache.geode.management.internal.configuration.utils.ZipUtils;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.junit.Before;
+import org.junit.Rule;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+public abstract class ClusterConfigTestBase {
+ public String clusterConfigZipPath;
+
+ public static final ConfigGroup CLUSTER = new ConfigGroup("cluster").regions("regionForCluster")
+ .jars("cluster.jar").maxLogFileSize("5000").configFiles("cluster.properties", "cluster.xml");
+ public static final ConfigGroup GROUP1 = new ConfigGroup("group1").regions("regionForGroup1")
+ .jars("group1.jar").maxLogFileSize("6000").configFiles("group1.properties", "group1.xml");
+ public static final ConfigGroup GROUP2 = new ConfigGroup("group2").regions("regionForGroup2")
+ .jars("group2.jar").maxLogFileSize("7000").configFiles("group2.properties", "group2.xml");
+
+ public static final ClusterConfig CONFIG_FROM_ZIP = new ClusterConfig(CLUSTER, GROUP1, GROUP2);
+
+ public static final ClusterConfig REPLICATED_CONFIG_FROM_ZIP = new ClusterConfig(
+ new ConfigGroup("cluster").maxLogFileSize("5000").jars("cluster.jar")
+ .regions("regionForCluster"),
+ new ConfigGroup("group1").maxLogFileSize("6000").jars("group1.jar")
+ .regions("regionForGroup1"),
+ new ConfigGroup("group2").maxLogFileSize("7000").jars("group2.jar")
+ .regions("regionForGroup2"));
+
+ @Rule
+ public LocatorServerStartupRule lsRule = new LocatorServerStartupRule(true);
+
+ protected Properties locatorProps;
+ protected Properties serverProps;
+
+ @Before
+ public void beforeClusterConfigTestBase() throws Exception {
+ clusterConfigZipPath = buildClusterZipFile();
+ locatorProps = new Properties();
+ serverProps = new Properties();
+
+ // the following are default values, we don't need to set them. We do it for clarity purpose
+ locatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
+ serverProps.setProperty(USE_CLUSTER_CONFIGURATION, "true");
+ }
+
+ private String buildClusterZipFile() throws Exception {
+ File clusterConfigDir = this.lsRule.getTempFolder().newFolder("cluster_config");
+
+ File clusterDir = new File(clusterConfigDir, "cluster");
+ String clusterXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ + "<cache xmlns=\"http://geode.apache.org/schema/cache\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" copy-on-read=\"false\" is-server=\"false\" lock-lease=\"120\" lock-timeout=\"60\" search-timeout=\"300\" version=\"1.0\" xsi:schemaLocation=\"http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd\">\n"
+ + "<region name=\"regionForCluster\">\n"
+ + " <region-attributes data-policy=\"replicate\" scope=\"distributed-ack\"/>\n"
+ + " </region>\n" + "</cache>\n";
+ writeFile(clusterDir, "cluster.xml", clusterXml);
+ writeFile(clusterDir, "cluster.properties", "log-file-size-limit=5000");
+ createJarFileWithClass("Cluster", "cluster.jar", clusterDir);
+
+ File group1Dir = new File(clusterConfigDir, "group1");
+ String group1Xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ + "<cache xmlns=\"http://geode.apache.org/schema/cache\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" copy-on-read=\"false\" is-server=\"false\" lock-lease=\"120\" lock-timeout=\"60\" search-timeout=\"300\" version=\"1.0\" xsi:schemaLocation=\"http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd\">\n"
+ + "<region name=\"regionForGroup1\">\n"
+ + " <region-attributes data-policy=\"replicate\" scope=\"distributed-ack\"/>\n"
+ + " </region>\n" + "</cache>\n";
+ writeFile(group1Dir, "group1.xml", group1Xml);
+ writeFile(group1Dir, "group1.properties", "log-file-size-limit=6000");
+ createJarFileWithClass("Group1", "group1.jar", group1Dir);
+
+
+ File group2Dir = new File(clusterConfigDir, "group2");
+ String group2Xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ + "<cache xmlns=\"http://geode.apache.org/schema/cache\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" copy-on-read=\"false\" is-server=\"false\" lock-lease=\"120\" lock-timeout=\"60\" search-timeout=\"300\" version=\"1.0\" xsi:schemaLocation=\"http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd\">\n"
+ + "<region name=\"regionForGroup2\">\n"
+ + " <region-attributes data-policy=\"replicate\" scope=\"distributed-ack\"/>\n"
+ + " </region>\n" + "</cache>\n";
+ writeFile(group2Dir, "group2.xml", group2Xml);
+ writeFile(group2Dir, "group2.properties", "log-file-size-limit=7000");
+ createJarFileWithClass("Group2", "group2.jar", group2Dir);
+
+
+ File clusterConfigZip = new File(lsRule.getTempFolder().newFolder(), "cluster_config.zip");
+ ZipUtils.zipDirectory(clusterConfigDir.getCanonicalPath(), clusterConfigZip.getCanonicalPath());
+
+ FileUtils.deleteDirectory(clusterConfigDir);
+ return clusterConfigZip.getCanonicalPath();
+ }
+
+ private File writeFile(File dir, String fileName, String content) throws IOException {
+ dir.mkdirs();
+ File file = new File(dir, fileName);
+ FileUtils.writeStringToFile(file, content);
+
+ return file;
+ }
+
+ protected String createJarFileWithClass(String className, String jarName, File dir)
+ throws IOException {
+ File jarFile = new File(dir, jarName);
+ new ClassBuilder().writeJarFromName(className, jarFile);
+ return jarFile.getCanonicalPath();
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
index 97c636b..34506c4 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
@@ -57,9 +57,18 @@ public class LocatorServerStartupRule extends ExternalResource implements Serial
private TemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
private MemberVM[] members;
+ private final boolean bounceVms;
public LocatorServerStartupRule() {
+ this(false);
+ }
+
+ /**
+ * If your DUnit tests fail due to insufficient cleanup, try setting bounceVms=true.
+ */
+ public LocatorServerStartupRule(boolean bounceVms) {
DUnitLauncher.launchIfNeeded();
+ this.bounceVms = bounceVms;
}
@Override
@@ -67,6 +76,9 @@ public class LocatorServerStartupRule extends ExternalResource implements Serial
restoreSystemProperties.before();
temporaryFolder.create();
Invoke.invokeInEveryVM("Stop each VM", this::cleanupVm);
+ if (bounceVms) {
+ getHost(0).getAllVMs().forEach(VM::bounce);
+ }
members = new MemberVM[4];
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionATemplate
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionATemplate b/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionATemplate
new file mode 100644
index 0000000..766963a
--- /dev/null
+++ b/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionATemplate
@@ -0,0 +1,30 @@
+import java.util.Properties;
+
+import org.apache.geode.cache.Declarable;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+
+public class FUNCTION_A implements Function, Declarable {
+ public String getId() {
+ return "FUNCTION_A";
+ }
+
+ public void init(Properties props) {
+ }
+
+ public void execute(FunctionContext context) {
+ context.getResultSender().lastResult("VERSION");
+ }
+
+ public boolean hasResult() {
+ return true;
+ }
+
+ public boolean optimizeForWrite() {
+ return false;
+ }
+
+ public boolean isHA() {
+ return false;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionBTemplate
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionBTemplate b/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionBTemplate
new file mode 100644
index 0000000..b37a6cf
--- /dev/null
+++ b/geode-core/src/test/resources/org/apache/geode/management/internal/cli/commands/DeployCommandRedeployDUnitTest_FunctionBTemplate
@@ -0,0 +1,26 @@
+package PACKAGE_B;
+
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+
+public class FUNCTION_B implements Function {
+ public boolean hasResult() {
+ return true;
+ }
+
+ public void execute(FunctionContext context) {
+ context.getResultSender().lastResult("VERSION");
+ }
+
+ public String getId() {
+ return "FUNCTION_B";
+ }
+
+ public boolean optimizeForWrite() {
+ return false;
+ }
+
+ public boolean isHA() {
+ return false;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/geode/blob/6f7f9439/gradle/dependency-versions.properties
----------------------------------------------------------------------
diff --git a/gradle/dependency-versions.properties b/gradle/dependency-versions.properties
index da8bdf2..a9e3fdf 100644
--- a/gradle/dependency-versions.properties
+++ b/gradle/dependency-versions.properties
@@ -33,6 +33,7 @@ commons-digester.version=2.1
commons-exec.version=1.3
derby.version = 10.13.1.1
dom4j.version = 1.6.1
+fast-classpath-scanner.version=2.0.11
fastutil.version = 7.1.0
google-gson.version=2.8.0
guava.version = 21.0
[4/8] geode git commit: GEODE-2686: Remove JarClassLoader
Posted by js...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
index 18d4b42..ad5c435 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
@@ -14,44 +14,60 @@
*/
package org.apache.geode.internal;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.geode.GemFireException;
+import org.apache.geode.GemFireIOException;
import org.apache.geode.SystemFailure;
import org.apache.geode.internal.logging.LogService;
import org.apache.logging.log4j.Logger;
import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
-import java.io.RandomAccessFile;
import java.io.Serializable;
-import java.nio.channels.FileLock;
+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.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
public class JarDeployer implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = LogService.getLogger();
- public static final String JAR_PREFIX = "vf.gf#";
- public static final String JAR_PREFIX_FOR_REGEX = "^vf\\.gf#";
+ public static final String JAR_PREFIX = "";
+ public static final String JAR_PREFIX_FOR_REGEX = "";
private static final Lock lock = new ReentrantLock();
+ private final Map<String, DeployedJar> deployedJars = new ConcurrentHashMap<>();
+
+
// Split a versioned filename into its name and version
public static final Pattern versionedPattern =
- Pattern.compile(JAR_PREFIX_FOR_REGEX + "(.*)#(\\d++)$");
+ Pattern.compile(JAR_PREFIX_FOR_REGEX + "(.*)\\.v(\\d++).jar$");
private final File deployDirectory;
@@ -63,262 +79,36 @@ public class JarDeployer implements Serializable {
this.deployDirectory = deployDirectory;
}
- /**
- * Re-deploy all previously deployed JAR files.
- */
- public void loadPreviouslyDeployedJars() {
- List<JarClassLoader> jarClassLoaders = new ArrayList<JarClassLoader>();
-
- lock.lock();
- try {
- try {
- verifyWritableDeployDirectory();
- final Set<String> jarNames = findDistinctDeployedJars();
- if (!jarNames.isEmpty()) {
- for (String jarName : jarNames) {
- final File[] jarFiles = findSortedOldVersionsOfJar(jarName);
-
- // It's possible the JARs were deleted by another process
- if (jarFiles.length != 0) {
- JarClassLoader jarClassLoader = findJarClassLoader(jarName);
-
- try {
- final byte[] jarBytes = getJarContent(jarFiles[0]);
- if (!JarClassLoader.isValidJarContent(jarBytes)) {
- logger.warn("Invalid JAR file found and deleted: {}",
- jarFiles[0].getAbsolutePath());
- jarFiles[0].delete();
- } else {
- // Test to see if the exact same file is already in use
- if (jarClassLoader == null
- || !jarClassLoader.getFileName().equals(jarFiles[0].getName())) {
- jarClassLoader = new JarClassLoader(jarFiles[0], jarName, jarBytes);
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(jarClassLoader);
- jarClassLoaders.add(jarClassLoader);
- }
- }
- } catch (IOException ioex) {
- // Another process deleted the file so don't bother doing anything else with it
- if (logger.isDebugEnabled()) {
- logger.debug("Failed attempt to use JAR to create JarClassLoader for: {}",
- jarName);
- }
- }
-
- // Remove any old left-behind versions of this JAR file
- for (File jarFile : jarFiles) {
- if (jarFile.exists() && (jarClassLoader == null
- || !jarClassLoader.getFileName().equals(jarFile.getName()))) {
- attemptFileLockAndDelete(jarFile);
- }
- }
- }
- }
- }
-
- for (JarClassLoader jarClassLoader : jarClassLoaders) {
- jarClassLoader.loadClassesAndRegisterFunctions();
- }
- } catch (VirtualMachineError e) {
- SystemFailure.initiateFailure(e);
- throw e;
- } catch (Throwable th) {
- SystemFailure.checkFailure();
- logger.error("Error when attempting to deploy JAR files on load.", th);
- }
- } finally {
- lock.unlock();
- }
+ public File getDeployDirectory() {
+ return this.deployDirectory;
}
- /**
- * Deploy the given JAR files.
- *
- * @param jarNames Array of names of the JAR files to deploy.
- * @param jarBytes Array of contents of the JAR files to deploy.
- * @return An array of newly created JAR class loaders. Entries will be null for an JARs that were
- * already deployed.
- * @throws IOException When there's an error saving the JAR file to disk
- */
- public JarClassLoader[] deploy(final String jarNames[], final byte[][] jarBytes)
- throws IOException, ClassNotFoundException {
- JarClassLoader[] jarClassLoaders = new JarClassLoader[jarNames.length];
- verifyWritableDeployDirectory();
-
+ public DeployedJar deployWithoutRegistering(final String jarName, final byte[] jarBytes)
+ throws IOException {
lock.lock();
+
try {
- for (int i = 0; i < jarNames.length; i++) {
- if (!JarClassLoader.isValidJarContent(jarBytes[i])) {
- throw new IllegalArgumentException(
- "File does not contain valid JAR content: " + jarNames[i]);
- }
- }
+ verifyWritableDeployDirectory();
- for (int i = 0; i < jarNames.length; i++) {
- jarClassLoaders[i] = deployWithoutRegistering(jarNames[i], jarBytes[i]);
- }
+ File newVersionedJarFile = getNextVersionedJarFile(jarName);
+ writeJarBytesToFile(newVersionedJarFile, jarBytes);
- for (JarClassLoader jarClassLoader : jarClassLoaders) {
- if (jarClassLoader != null) {
- jarClassLoader.loadClassesAndRegisterFunctions();
- }
- }
+ return new DeployedJar(newVersionedJarFile, jarName, jarBytes);
} finally {
lock.unlock();
}
- return jarClassLoaders;
}
- /**
- * Deploy the given JAR file without registering functions.
- *
- * @param jarName Name of the JAR file to deploy.
- * @param jarBytes Contents of the JAR file to deploy.
- * @return The newly created JarClassLoader or null if the JAR was already deployed
- * @throws IOException When there's an error saving the JAR file to disk
- */
- private JarClassLoader deployWithoutRegistering(final String jarName, final byte[] jarBytes)
- throws IOException {
- JarClassLoader oldJarClassLoader = findJarClassLoader(jarName);
-
- final boolean isDebugEnabled = logger.isDebugEnabled();
- if (isDebugEnabled) {
- logger.debug("Deploying {}: {}", jarName, (oldJarClassLoader == null ? ": not yet deployed"
- : ": already deployed as " + oldJarClassLoader.getFileCanonicalPath()));
- }
-
- // Test to see if the exact same file is being deployed
- if (oldJarClassLoader != null && oldJarClassLoader.hasSameContent(jarBytes)) {
- return null;
- }
-
- JarClassLoader newJarClassLoader = null;
-
- do {
- File[] oldJarFiles = findSortedOldVersionsOfJar(jarName);
-
- try {
- // If this is the first version of this JAR file we've seen ...
- if (oldJarFiles.length == 0) {
- if (isDebugEnabled) {
- logger.debug("There were no pre-existing versions for JAR: {}", jarName);
- }
- File nextVersionJarFile = getNextVersionJarFile(jarName);
- if (writeJarBytesToFile(nextVersionJarFile, jarBytes)) {
- newJarClassLoader = new JarClassLoader(nextVersionJarFile, jarName, jarBytes);
- if (isDebugEnabled) {
- logger.debug("Successfully created initial JarClassLoader at file: {}",
- nextVersionJarFile.getAbsolutePath());
- }
- } else {
- if (isDebugEnabled) {
- logger.debug("Unable to write contents for first version of JAR to file: {}",
- nextVersionJarFile.getAbsolutePath());
- }
- }
-
- } else {
- // Most recent is at the beginning of the list, see if this JAR matches what's
- // already on disk.
- if (doesFileMatchBytes(oldJarFiles[0], jarBytes)) {
- if (isDebugEnabled) {
- logger.debug("A version on disk was an exact match for the JAR being deployed: {}",
- oldJarFiles[0].getAbsolutePath());
- }
- newJarClassLoader = new JarClassLoader(oldJarFiles[0], jarName, jarBytes);
- if (isDebugEnabled) {
- logger.debug("Successfully reused JAR to create JarClassLoader from file: {}",
- oldJarFiles[0].getAbsolutePath());
- }
- } else {
- // This JAR isn't on disk
- if (isDebugEnabled) {
- logger.debug("Need to create a new version for JAR: {}", jarName);
- }
- File nextVersionJarFile = getNextVersionJarFile(oldJarFiles[0].getName());
- if (writeJarBytesToFile(nextVersionJarFile, jarBytes)) {
- newJarClassLoader = new JarClassLoader(nextVersionJarFile, jarName, jarBytes);
- if (isDebugEnabled) {
- logger.debug("Successfully created next JarClassLoader at file: {}",
- nextVersionJarFile.getAbsolutePath());
- }
- } else {
- if (isDebugEnabled) {
- logger.debug("Unable to write contents for next version of JAR to file: {}",
- nextVersionJarFile.getAbsolutePath());
- }
- }
- }
- }
- } catch (IOException ioex) {
- // Another process deleted the file before we could get to it, just start again
- logger.info("Failed attempt to use JAR to create JarClassLoader for: {} : {}", jarName,
- ioex.getMessage());
- }
-
- if (isDebugEnabled) {
- if (newJarClassLoader == null) {
- logger.debug("Unable to determine a JAR file location, will loop and try again: {}",
- jarName);
- } else {
- logger.debug("Exiting loop for JarClassLoader creation using file: {}",
- newJarClassLoader.getFileName());
- }
- }
- } while (newJarClassLoader == null);
-
- ClassPathLoader.getLatest().addOrReplaceAndSetLatest(newJarClassLoader);
-
- // Remove the JAR file that was undeployed as part of this redeploy
- if (oldJarClassLoader != null) {
- attemptFileLockAndDelete(new File(this.deployDirectory, oldJarClassLoader.getFileName()));
- }
-
- return newJarClassLoader;
- }
/**
- * Undeploy the given JAR file.
+ * Get a list of all currently deployed jars.
*
- * @param jarName The name of the JAR file to undeploy
- * @return The path to the location on disk where the JAR file had been deployed
- * @throws IOException If there's a problem deleting the file
+ * @return The list of DeployedJars
*/
- public String undeploy(final String jarName) throws IOException {
- JarClassLoader jarClassLoader = null;
- verifyWritableDeployDirectory();
-
- lock.lock();
- try {
- jarClassLoader = findJarClassLoader(jarName);
- if (jarClassLoader == null) {
- throw new IllegalArgumentException("JAR not deployed");
- }
-
- ClassPathLoader.getLatest().removeAndSetLatest(jarClassLoader);
- attemptFileLockAndDelete(new File(this.deployDirectory, jarClassLoader.getFileName()));
- return jarClassLoader.getFileCanonicalPath();
- } finally {
- lock.unlock();
- }
+ public List<DeployedJar> findDeployedJars() {
+ return getDeployedJars().values().stream().collect(toList());
}
- /**
- * Get a list of all currently deployed JarClassLoaders.
- *
- * @return The list of JarClassLoaders
- */
- public List<JarClassLoader> findJarClassLoaders() {
- List<JarClassLoader> returnList = new ArrayList<JarClassLoader>();
- Collection<ClassLoader> classLoaders = ClassPathLoader.getLatest().getClassLoaders();
- for (ClassLoader classLoader : classLoaders) {
- if (classLoader instanceof JarClassLoader) {
- returnList.add((JarClassLoader) classLoader);
- }
- }
-
- return returnList;
- }
/**
* Suspend all deploy and undeploy operations. This is done by acquiring and holding the lock
@@ -339,26 +129,19 @@ public class JarDeployer implements Serializable {
lock.unlock();
}
- /**
- * Figure out the next version of a JAR file
- *
- * @param latestVersionedJarName The previous most recent version of the JAR file or original name
- * if there wasn't one
- * @return The file that represents the next version
- */
- protected File getNextVersionJarFile(final String latestVersionedJarName) {
- String newFileName;
- final Matcher matcher = versionedPattern.matcher(latestVersionedJarName);
- if (matcher.find()) {
- newFileName = JAR_PREFIX + matcher.group(1) + "#" + (Integer.parseInt(matcher.group(2)) + 1);
+ protected File getNextVersionedJarFile(String unversionedJarName) {
+ File[] oldVersions = findSortedOldVersionsOfJar(unversionedJarName);
+
+ String nextVersionedJarName;
+ if (oldVersions == null || oldVersions.length == 0) {
+ nextVersionedJarName = removeJarExtension(unversionedJarName) + ".v1.jar";
} else {
- newFileName = JAR_PREFIX + latestVersionedJarName + "#1";
+ String latestVersionedJarName = oldVersions[0].getName();
+ int nextVersion = extractVersionFromFilename(latestVersionedJarName) + 1;
+ nextVersionedJarName = removeJarExtension(unversionedJarName) + ".v" + nextVersion + ".jar";
}
- if (logger.isDebugEnabled()) {
- logger.debug("Next version file name will be: {}", newFileName);
- }
- return new File(this.deployDirectory, newFileName);
+ return new File(deployDirectory, nextVersionedJarName);
}
/**
@@ -370,27 +153,18 @@ public class JarDeployer implements Serializable {
* @param jarBytes Contents of the JAR file to deploy.
* @return True if the file was successfully written, false otherwise
*/
- private boolean writeJarBytesToFile(final File file, final byte[] jarBytes) {
+ private boolean writeJarBytesToFile(final File file, final byte[] jarBytes) throws IOException {
final boolean isDebugEnabled = logger.isDebugEnabled();
- try {
- if (file.createNewFile()) {
- if (isDebugEnabled) {
- logger.debug("Successfully created new JAR file: {}", file.getAbsolutePath());
- }
- final OutputStream outStream = new FileOutputStream(file);
- outStream.write(jarBytes);
- outStream.close();
- return true;
- }
- return doesFileMatchBytes(file, jarBytes);
-
- } catch (IOException ioex) {
- // Another VM clobbered what was happening here, try again
+ if (file.createNewFile()) {
if (isDebugEnabled) {
- logger.debug("IOException while trying to write JAR content to file: {}", ioex);
+ logger.debug("Successfully created new JAR file: {}", file.getAbsolutePath());
}
- return false;
+ final OutputStream outStream = new FileOutputStream(file);
+ outStream.write(jarBytes);
+ outStream.close();
+ return true;
}
+ return doesFileMatchBytes(file, jarBytes);
}
/**
@@ -457,86 +231,22 @@ public class JarDeployer implements Serializable {
return true;
}
- private void attemptFileLockAndDelete(final File file) throws IOException {
- final String absolutePath = file.getAbsolutePath();
- FileOutputStream fileOutputStream = new FileOutputStream(file, true);
- final boolean isDebugEnabled = logger.isDebugEnabled();
- try {
- FileLock fileLock = null;
- try {
- fileLock = fileOutputStream.getChannel().tryLock();
-
- if (fileLock != null) {
- if (isDebugEnabled) {
- logger.debug("Tried and acquired exclusive lock for file: {}, w/ channel {}",
- absolutePath, fileLock.channel());
- }
-
- if (file.delete()) {
- if (isDebugEnabled) {
- logger.debug("Deleted file with name: {}", absolutePath);
- }
- } else {
- if (isDebugEnabled) {
- logger.debug("Could not delete file, will truncate instead and delete on exit: {}",
- absolutePath);
- }
- file.deleteOnExit();
-
- RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
- try {
- randomAccessFile.setLength(0);
- } finally {
- try {
- randomAccessFile.close();
- } catch (IOException ioex) {
- logger.error("Could not close file when attempting to set zero length", ioex);
- }
- }
- }
- } else {
- if (isDebugEnabled) {
- logger.debug("Will not delete file since exclusive lock unavailable: {}", absolutePath);
- }
- }
-
- } finally {
- if (fileLock != null) {
- try {
- fileLock.release();
- fileLock.channel().close();
- if (isDebugEnabled) {
- logger.debug("Released file lock for file: {}, w/ channel: {}", absolutePath,
- fileLock.channel());
- }
- } catch (IOException ioex) {
- logger.error("Could not close channel on JAR lock file", ioex);
- }
- }
- }
- } finally {
- try {
- fileOutputStream.close();
- } catch (IOException ioex) {
- logger.error("Could not close output stream on JAR file", ioex);
- }
- }
- }
-
/**
* Find the version number that's embedded in the name of this file
*
- * @param file File to get the version number from
+ * @param filename Filename to get the version number from
* @return The version number embedded in the filename
*/
- int extractVersionFromFilename(final File file) {
- final Matcher matcher = versionedPattern.matcher(file.getName());
- matcher.find();
- return Integer.parseInt(matcher.group(2));
+ public static int extractVersionFromFilename(final String filename) {
+ final Matcher matcher = versionedPattern.matcher(filename);
+ if (matcher.find()) {
+ return Integer.parseInt(matcher.group(2));
+ } else {
+ return 0;
+ }
}
protected Set<String> findDistinctDeployedJars() {
-
// Find all deployed JAR files
final File[] oldFiles = this.deployDirectory.listFiles(new FilenameFilter() {
@Override
@@ -559,41 +269,32 @@ public class JarDeployer implements Serializable {
* Find all versions of the JAR file that are currently on disk and return them sorted from newest
* (highest version) to oldest
*
- * @param jarFilename Name of the JAR file that we want old versions of
+ * @param unversionedJarName Name of the JAR file that we want old versions of
* @return Sorted array of files that are older versions of the given JAR
*/
- protected File[] findSortedOldVersionsOfJar(final String jarFilename) {
+ protected File[] findSortedOldVersionsOfJar(final String unversionedJarName) {
// Find all matching files
- final Pattern pattern = Pattern.compile(JAR_PREFIX_FOR_REGEX + jarFilename + "#\\d++$");
- final File[] oldJarFiles = this.deployDirectory.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(final File file, final String name) {
- return (pattern.matcher(name).matches());
- }
- });
+ final Pattern pattern = Pattern.compile(
+ JAR_PREFIX_FOR_REGEX + removeJarExtension(unversionedJarName) + "\\.v\\d++\\.jar$");
+ final File[] oldJarFiles =
+ this.deployDirectory.listFiles((file, name) -> (pattern.matcher(name).matches()));
// Sort them in order from newest (highest version) to oldest
- Arrays.sort(oldJarFiles, new Comparator<File>() {
- @Override
- public int compare(final File file1, final File file2) {
- int file1Version = extractVersionFromFilename(file1);
- int file2Version = extractVersionFromFilename(file2);
- return file2Version - file1Version;
- }
+ Arrays.sort(oldJarFiles, (file1, file2) -> {
+ int file1Version = extractVersionFromFilename(file1.getName());
+ int file2Version = extractVersionFromFilename(file2.getName());
+ return file2Version - file1Version;
});
return oldJarFiles;
}
- private JarClassLoader findJarClassLoader(final String jarName) {
- Collection<ClassLoader> classLoaders = ClassPathLoader.getLatest().getClassLoaders();
- for (ClassLoader classLoader : classLoaders) {
- if (classLoader instanceof JarClassLoader
- && ((JarClassLoader) classLoader).getJarName().equals(jarName)) {
- return (JarClassLoader) classLoader;
- }
+ protected String removeJarExtension(String jarName) {
+ if (jarName != null && jarName.endsWith(".jar")) {
+ return jarName.replaceAll("\\.jar$", "");
+ } else {
+ return jarName;
}
- return null;
}
/**
@@ -601,7 +302,7 @@ public class JarDeployer implements Serializable {
*
* @throws IOException If the directory isn't writable
*/
- private void verifyWritableDeployDirectory() throws IOException {
+ public void verifyWritableDeployDirectory() throws IOException {
Exception exception = null;
int tryCount = 0;
do {
@@ -627,20 +328,246 @@ public class JarDeployer implements Serializable {
"Unable to write to deploy directory: " + this.deployDirectory.getCanonicalPath());
}
- private byte[] getJarContent(File jarFile) throws IOException {
- InputStream inputStream = new FileInputStream(jarFile);
+ final Pattern oldNamingPattern = Pattern.compile("^vf\\.gf#(.*)\\.jar#(\\d+)$");
+
+ /*
+ * In Geode 1.1.0, the deployed version of 'myjar.jar' would be named 'vf.gf#myjar.jar#1'. Now it
+ * is be named 'myjar.v1.jar'. We need to rename all existing deployed jars to the new convention
+ * if this is the first time starting up with the new naming format.
+ */
+ protected void renameJarsWithOldNamingConvention() throws IOException {
+ Set<File> jarsWithOldNamingConvention = findJarsWithOldNamingConvention();
+
+ if (jarsWithOldNamingConvention.isEmpty()) {
+ return;
+ }
+
+ for (File jar : jarsWithOldNamingConvention) {
+ renameJarWithOldNamingConvention(jar);
+ }
+ }
+
+ protected Set<File> findJarsWithOldNamingConvention() {
+ return Stream.of(this.deployDirectory.listFiles())
+ .filter((File file) -> isOldNamingConvention(file.getName())).collect(toSet());
+ }
+
+ protected boolean isOldNamingConvention(String fileName) {
+ return oldNamingPattern.matcher(fileName).matches();
+ }
+
+ private void renameJarWithOldNamingConvention(File oldJar) throws IOException {
+ Matcher matcher = oldNamingPattern.matcher(oldJar.getName());
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("The given jar " + oldJar.getCanonicalPath()
+ + " does not match the old naming convention");
+ }
+
+ String unversionedJarNameWithoutExtension = matcher.group(1);
+ String jarVersion = matcher.group(2);
+ String newJarName = unversionedJarNameWithoutExtension + ".v" + jarVersion + ".jar";
+
+ File newJar = new File(this.deployDirectory, newJarName);
+ logger.debug("Renaming deployed jar from " + oldJar.getCanonicalPath() + " to "
+ + newJar.getCanonicalPath());
+
+ FileUtils.moveFile(oldJar, newJar);
+ FileUtils.deleteQuietly(oldJar);
+ }
+
+ /**
+ * Re-deploy all previously deployed JAR files.
+ */
+ public void loadPreviouslyDeployedJars() {
+ lock.lock();
+ try {
+ verifyWritableDeployDirectory();
+ renameJarsWithOldNamingConvention();
+
+ final Set<String> jarNames = findDistinctDeployedJars();
+ if (jarNames.isEmpty()) {
+ return;
+ }
+
+ Map<String, DeployedJar> latestVersionOfEachJar = new LinkedHashMap<>();
+
+ for (String jarName : jarNames) {
+ final File[] jarFiles = findSortedOldVersionsOfJar(jarName);
+
+ Optional<File> latestValidDeployedJarOptional =
+ Arrays.stream(jarFiles).filter(Objects::nonNull).filter(jarFile -> {
+ try {
+ return DeployedJar.isValidJarContent(FileUtils.readFileToByteArray(jarFile));
+ } catch (IOException e) {
+ return false;
+ }
+ }).findFirst();
+
+ if (!latestValidDeployedJarOptional.isPresent()) {
+ // No valid version of this jar
+ continue;
+ }
+
+ File latestValidDeployedJar = latestValidDeployedJarOptional.get();
+ latestVersionOfEachJar.put(jarName, new DeployedJar(latestValidDeployedJar, jarName));
+
+ // Remove any old left-behind versions of this JAR file
+ for (File jarFile : jarFiles) {
+ if (!latestValidDeployedJar.equals(jarFile)) {
+ FileUtils.deleteQuietly(jarFile);
+ }
+ }
+ }
+
+ registerNewVersions(latestVersionOfEachJar.values().stream().collect(toList()));
+ // ClassPathLoader.getLatest().deploy(latestVersionOfEachJar.keySet().toArray(),
+ // latestVersionOfEachJar.values().toArray())
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+
+ public URL[] getDeployedJarURLs() {
+ return this.deployedJars.values().stream().map(DeployedJar::getFileURL).toArray(URL[]::new);
+
+ }
+
+ public List<DeployedJar> registerNewVersions(List<DeployedJar> deployedJars)
+ throws ClassNotFoundException {
+ lock.lock();
+ try {
+ for (DeployedJar deployedJar : deployedJars) {
+ if (deployedJar != null) {
+ DeployedJar oldJar = this.deployedJars.put(deployedJar.getJarName(), deployedJar);
+ if (oldJar != null) {
+ oldJar.cleanUp();
+ }
+ }
+ }
+
+ ClassPathLoader.getLatest().rebuildClassLoaderForDeployedJars();
+
+ for (DeployedJar deployedJar : deployedJars) {
+ if (deployedJar != null) {
+ deployedJar.loadClassesAndRegisterFunctions();
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ return deployedJars;
+ }
+
+ /**
+ * Deploy the given JAR files.
+ *
+ * @param jarNames Array of names of the JAR files to deploy.
+ * @param jarBytes Array of contents of the JAR files to deploy.
+ * @return An array of newly created JAR class loaders. Entries will be null for an JARs that were
+ * already deployed.
+ * @throws IOException When there's an error saving the JAR file to disk
+ */
+ public List<DeployedJar> deploy(final String jarNames[], final byte[][] jarBytes)
+ throws IOException, ClassNotFoundException {
+ DeployedJar[] deployedJars = new DeployedJar[jarNames.length];
+
+ for (int i = 0; i < jarNames.length; i++) {
+ if (!DeployedJar.isValidJarContent(jarBytes[i])) {
+ throw new IllegalArgumentException(
+ "File does not contain valid JAR content: " + jarNames[i]);
+ }
+ }
+
+ lock.lock();
+ try {
+ for (int i = 0; i < jarNames.length; i++) {
+ String jarName = jarNames[i];
+ byte[] newJarBytes = jarBytes[i];
+
+ boolean shouldDeployNewVersion = shouldDeployNewVersion(jarName, newJarBytes);
+
+ if (shouldDeployNewVersion) {
+ deployedJars[i] = deployWithoutRegistering(jarName, newJarBytes);
+ } else {
+ deployedJars[i] = null;
+ }
+ }
+
+ return registerNewVersions(Arrays.asList(deployedJars));
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private boolean shouldDeployNewVersion(String jarName, byte[] newJarBytes) throws IOException {
+ DeployedJar oldDeployedJar = this.deployedJars.get(jarName);
+
+ if (oldDeployedJar == null) {
+ return true;
+ }
+
+ if (oldDeployedJar.hasSameContentAs(newJarBytes)) {
+ logger.warn("Jar is identical to the latest deployed version: ",
+ oldDeployedJar.getFileCanonicalPath());
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public DeployedJar findDeployedJar(String jarName) {
+ return this.deployedJars.get(jarName);
+ }
+
+ public DeployedJar deploy(final String jarName, final byte[] jarBytes)
+ throws IOException, ClassNotFoundException {
+ lock.lock();
+
try {
- final ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
- final byte[] bytes = new byte[4096];
+ List<DeployedJar> deployedJars = deploy(new String[] {jarName}, new byte[][] {jarBytes});
+ if (deployedJars == null || deployedJars.size() == 0) {
+ return null;
+ }
+
+ return deployedJars.get(0);
+ } finally {
+ lock.unlock();
+ }
+
+ }
- int bytesRead;
- while (((bytesRead = inputStream.read(bytes)) != -1)) {
- byteOutStream.write(bytes, 0, bytesRead);
+ public Map<String, DeployedJar> getDeployedJars() {
+ return Collections.unmodifiableMap(this.deployedJars);
+ }
+
+ /**
+ * Undeploy the given JAR file.
+ *
+ * @param jarName The name of the JAR file to undeploy
+ * @return The path to the location on disk where the JAR file had been deployed
+ * @throws IOException If there's a problem deleting the file
+ */
+ public String undeploy(final String jarName) throws IOException {
+ lock.lock();
+
+ try {
+ DeployedJar deployedJar = deployedJars.remove(jarName);
+ if (deployedJar == null) {
+ throw new IllegalArgumentException("JAR not deployed");
}
- return byteOutStream.toByteArray();
+ ClassPathLoader.getLatest().rebuildClassLoaderForDeployedJars();
+
+ deployedJar.cleanUp();
+
+ return deployedJar.getFileCanonicalPath();
} finally {
- inputStream.close();
+ lock.unlock();
}
}
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
index f904af1..2b627b2 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
@@ -24,9 +24,11 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Properties;
import java.util.Set;
+import org.apache.geode.internal.ClassPathLoader;
import org.apache.logging.log4j.Logger;
import org.apache.geode.UnmodifiableException;
@@ -35,7 +37,7 @@ import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.ClusterConfigurationService;
import org.apache.geode.distributed.internal.tcpserver.TcpClient;
import org.apache.geode.internal.ConfigSource;
-import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.internal.DeployedJar;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.admin.remote.DistributionLocatorId;
import org.apache.geode.internal.i18n.LocalizedStrings;
@@ -56,45 +58,38 @@ public class ClusterConfigurationLoader {
*
* @param cache Cache of this member
* @param response {@link ConfigurationResponse} received from the locators
- * @throws IOException
- * @throws ClassNotFoundException
*/
public static void deployJarsReceivedFromClusterConfiguration(Cache cache,
ConfigurationResponse response) throws IOException, ClassNotFoundException {
- if (response == null)
+ if (response == null) {
return;
+ }
String[] jarFileNames = response.getJarNames();
byte[][] jarBytes = response.getJars();
- final JarDeployer jarDeployer = new JarDeployer(
- ((GemFireCacheImpl) cache).getDistributedSystem().getConfig().getDeployWorkingDir());
-
- /******
- * Un-deploy the existing jars, deployed during cache creation, do not delete anything
- */
-
if (jarFileNames != null && jarBytes != null) {
- JarClassLoader[] jarClassLoaders = jarDeployer.deploy(jarFileNames, jarBytes);
- for (int i = 0; i < jarFileNames.length; i++) {
- if (jarClassLoaders[i] != null) {
- logger.info("Deployed " + (jarClassLoaders[i].getFileCanonicalPath()));
- }
- }
+ List<DeployedJar> deployedJars =
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarFileNames, jarBytes);
+
+ deployedJars.stream().filter(Objects::nonNull)
+ .forEach((jar) -> logger.info("Deployed " + (jar.getFile().getAbsolutePath())));
}
+ // TODO: Jared - Does this need to actually undeploy extra jars like the javadoc says?
}
/***
* Apply the cache-xml cluster configuration on this member
- *
+ *
* @param cache Cache created for this member
* @param response {@link ConfigurationResponse} containing the requested {@link Configuration}
* @param config this member's config.
*/
public static void applyClusterXmlConfiguration(Cache cache, ConfigurationResponse response,
DistributionConfig config) {
- if (response == null || response.getRequestedConfiguration().isEmpty())
+ if (response == null || response.getRequestedConfiguration().isEmpty()) {
return;
+ }
List<String> groups = getGroups(config);
Map<String, Configuration> requestedConfiguration = response.getRequestedConfiguration();
@@ -138,15 +133,16 @@ public class ClusterConfigurationLoader {
/***
* Apply the gemfire properties cluster configuration on this member
- *
+ *
* @param cache Cache created for this member
* @param response {@link ConfigurationResponse} containing the requested {@link Configuration}
* @param config this member's config
*/
public static void applyClusterPropertiesConfiguration(Cache cache,
ConfigurationResponse response, DistributionConfig config) {
- if (response == null || response.getRequestedConfiguration().isEmpty())
+ if (response == null || response.getRequestedConfiguration().isEmpty()) {
return;
+ }
List<String> groups = getGroups(config);
Map<String, Configuration> requestedConfiguration = response.getRequestedConfiguration();
@@ -189,8 +185,6 @@ public class ClusterConfigurationLoader {
*
* @param config this member's configuration.
* @return {@link ConfigurationResponse}
- * @throws ClusterConfigurationNotAvailableException
- * @throws UnknownHostException
*/
public static ConfigurationResponse requestConfigurationFromLocators(DistributionConfig config,
List<String> locatorList)
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
index 08f916b..fb311e7 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
@@ -1192,7 +1192,7 @@ public class GemFireCacheImpl
listener.cacheCreated(this);
}
- ClassPathLoader.setLatestToDefault();
+ ClassPathLoader.setLatestToDefault(this.system.getConfig().getDeployWorkingDir());
// request and check cluster configuration
ConfigurationResponse configurationResponse = requestSharedConfiguration();
@@ -1239,7 +1239,7 @@ public class GemFireCacheImpl
try {
// Deploy all the jars from the deploy working dir.
- new JarDeployer(this.system.getConfig().getDeployWorkingDir()).loadPreviouslyDeployedJars();
+ ClassPathLoader.getLatest().getJarDeployer().loadPreviouslyDeployedJars();
ClusterConfigurationLoader.applyClusterXmlConfiguration(this, configurationResponse,
system.getConfig());
initializeDeclarativeCache();
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/internal/cache/persistence/BackupManager.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/persistence/BackupManager.java b/geode-core/src/main/java/org/apache/geode/internal/cache/persistence/BackupManager.java
index d052551..deb53cb 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/persistence/BackupManager.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/persistence/BackupManager.java
@@ -22,7 +22,8 @@ import org.apache.geode.distributed.internal.DM;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.MembershipListener;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
-import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.DeployedJar;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.cache.DiskStoreImpl;
import org.apache.geode.internal.cache.GemFireCacheImpl;
@@ -290,21 +291,20 @@ public class BackupManager implements MembershipListener {
JarDeployer deployer = null;
try {
- deployer = new JarDeployer();
-
/*
* Suspend any user deployed jar file updates during this backup.
*/
+ deployer = ClassPathLoader.getLatest().getJarDeployer();
deployer.suspendAll();
- List<JarClassLoader> jarList = deployer.findJarClassLoaders();
+ List<DeployedJar> jarList = deployer.findDeployedJars();
if (!jarList.isEmpty()) {
File userBackupDir = new File(backupDir, USER_FILES);
if (!userBackupDir.exists()) {
userBackupDir.mkdir();
}
- for (JarClassLoader loader : jarList) {
+ for (DeployedJar loader : jarList) {
File source = new File(loader.getFileCanonicalPath());
File dest = new File(userBackupDir, source.getName());
if (source.isDirectory()) {
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DeployFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DeployFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DeployFunction.java
index 5f1f161..148aa5f 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DeployFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DeployFunction.java
@@ -15,8 +15,10 @@
package org.apache.geode.management.internal.cli.functions;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import org.apache.geode.internal.ClassPathLoader;
import org.apache.logging.log4j.Logger;
import org.apache.geode.SystemFailure;
@@ -27,7 +29,7 @@ import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.internal.InternalEntity;
-import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.internal.DeployedJar;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.logging.LogService;
@@ -62,11 +64,12 @@ public class DeployFunction implements Function, InternalEntity {
}
List<String> deployedList = new ArrayList<String>();
- JarClassLoader[] jarClassLoaders = jarDeployer.deploy(jarFilenames, jarBytes);
+ List<DeployedJar> jarClassLoaders =
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarFilenames, jarBytes);
for (int i = 0; i < jarFilenames.length; i++) {
deployedList.add(jarFilenames[i]);
- if (jarClassLoaders[i] != null) {
- deployedList.add(jarClassLoaders[i].getFileCanonicalPath());
+ if (jarClassLoaders.get(i) != null) {
+ deployedList.add(jarClassLoaders.get(i).getFileCanonicalPath());
} else {
deployedList.add("Already deployed");
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListDeployedFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListDeployedFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListDeployedFunction.java
index 8df24db..3d6a321 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListDeployedFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListDeployedFunction.java
@@ -16,6 +16,8 @@ package org.apache.geode.management.internal.cli.functions;
import java.util.List;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.DeployedJar;
import org.apache.logging.log4j.Logger;
import org.apache.geode.SystemFailure;
@@ -26,7 +28,6 @@ import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.internal.InternalEntity;
-import org.apache.geode.internal.JarClassLoader;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.logging.LogService;
@@ -45,8 +46,7 @@ public class ListDeployedFunction implements Function, InternalEntity {
try {
Cache cache = CacheFactory.getAnyInstance();
- final JarDeployer jarDeployer = new JarDeployer(
- ((GemFireCacheImpl) cache).getDistributedSystem().getConfig().getDeployWorkingDir());
+ final JarDeployer jarDeployer = ClassPathLoader.getLatest().getJarDeployer();
DistributedMember member = cache.getDistributedSystem().getDistributedMember();
@@ -56,10 +56,10 @@ public class ListDeployedFunction implements Function, InternalEntity {
memberId = member.getName();
}
- final List<JarClassLoader> jarClassLoaders = jarDeployer.findJarClassLoaders();
+ final List<DeployedJar> jarClassLoaders = jarDeployer.findDeployedJars();
final String[] jars = new String[jarClassLoaders.size() * 2];
int index = 0;
- for (JarClassLoader jarClassLoader : jarClassLoaders) {
+ for (DeployedJar jarClassLoader : jarClassLoaders) {
jars[index++] = jarClassLoader.getJarName();
jars[index++] = jarClassLoader.getFileCanonicalPath();
}
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/UndeployFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/UndeployFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/UndeployFunction.java
index 3f05082..14d875e 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/UndeployFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/UndeployFunction.java
@@ -18,6 +18,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
+import org.apache.geode.internal.ClassPathLoader;
import org.apache.logging.log4j.Logger;
import org.apache.geode.SystemFailure;
@@ -28,7 +29,7 @@ import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.internal.InternalEntity;
-import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.internal.DeployedJar;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.logging.LogService;
@@ -50,8 +51,7 @@ public class UndeployFunction implements Function, InternalEntity {
final String jarFilenameList = (String) args[0]; // Comma separated
Cache cache = CacheFactory.getAnyInstance();
- final JarDeployer jarDeployer = new JarDeployer(
- ((GemFireCacheImpl) cache).getDistributedSystem().getConfig().getDeployWorkingDir());
+ final JarDeployer jarDeployer = ClassPathLoader.getLatest().getJarDeployer();
DistributedMember member = cache.getDistributedSystem().getDistributedMember();
@@ -63,13 +63,14 @@ public class UndeployFunction implements Function, InternalEntity {
String[] undeployedJars = new String[0];
if (jarFilenameList == null || jarFilenameList.equals("")) {
- final List<JarClassLoader> jarClassLoaders = jarDeployer.findJarClassLoaders();
+ final List<DeployedJar> jarClassLoaders = jarDeployer.findDeployedJars();
undeployedJars = new String[jarClassLoaders.size() * 2];
int index = 0;
- for (JarClassLoader jarClassLoader : jarClassLoaders) {
+ for (DeployedJar jarClassLoader : jarClassLoaders) {
undeployedJars[index++] = jarClassLoader.getJarName();
try {
- undeployedJars[index++] = jarDeployer.undeploy(jarClassLoader.getJarName());
+ undeployedJars[index++] =
+ ClassPathLoader.getLatest().getJarDeployer().undeploy(jarClassLoader.getJarName());
} catch (IllegalArgumentException iaex) {
// It's okay for it to have have been uneployed from this server
undeployedJars[index++] = iaex.getMessage();
@@ -82,7 +83,7 @@ public class UndeployFunction implements Function, InternalEntity {
String jarFilename = jarTokenizer.nextToken().trim();
try {
undeployedList.add(jarFilename);
- undeployedList.add(jarDeployer.undeploy(jarFilename));
+ undeployedList.add(ClassPathLoader.getLatest().getJarDeployer().undeploy(jarFilename));
} catch (IllegalArgumentException iaex) {
// It's okay for it to not have been deployed to this server
undeployedList.add(iaex.getMessage());
http://git-wip-us.apache.org/repos/asf/geode/blob/6fd2d123/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
index c52d575..d30feb6 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java
@@ -14,6 +14,8 @@
*/
package org.apache.geode.internal;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.*;
import java.io.BufferedInputStream;
@@ -24,11 +26,20 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
import java.util.Vector;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;
+import org.apache.commons.io.FileUtils;
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.distributed.DistributedSystem;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.test.dunit.rules.ServerStarterRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -53,8 +64,9 @@ public class ClassPathLoaderIntegrationTest {
private static final int TEMP_FILE_BYTES_COUNT = 256;
- private volatile File tempFile;
- private volatile File tempFile2;
+ private File tempFile;
+ private File tempFile2;
+ private File extLibsDir;
@Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
@@ -65,8 +77,9 @@ public class ClassPathLoaderIntegrationTest {
@Before
public void setUp() throws Exception {
System.setProperty(ClassPathLoader.EXCLUDE_TCCL_PROPERTY, "false");
- System.setProperty(ClassPathLoader.EXT_LIB_DIR_PARENT_PROPERTY,
- this.temporaryFolder.getRoot().getAbsolutePath());
+
+ extLibsDir = new File(this.temporaryFolder.getRoot(), "ext");
+ extLibsDir.mkdirs();
this.tempFile = this.temporaryFolder.newFile("tempFile1.tmp");
FileOutputStream fos = new FileOutputStream(this.tempFile);
@@ -77,98 +90,248 @@ public class ClassPathLoaderIntegrationTest {
fos = new FileOutputStream(this.tempFile2);
fos.write(new byte[TEMP_FILE_BYTES_COUNT]);
fos.close();
+
+ System.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
+ ClassPathLoader.setLatestToDefault(temporaryFolder.getRoot());
}
- /**
- * Verifies that <tt>getResource</tt> works with custom loader from {@link ClassPathLoader}.
- */
+
@Test
- public void testGetResourceWithCustomLoader() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testGetResourceWithCustomLoader");
+ public void testDeployFileAndChange() throws IOException, ClassNotFoundException {
+ String jarName = "JarDeployerIntegrationTest.jar";
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
+ String classAResource = "integration/parent/ClassA.class";
+ String classBResource = "integration/parent/ClassB.class";
- String resourceToGet = "com/nowhere/testGetResourceWithCustomLoader.rsc";
- URL url = dcl.getResource(resourceToGet);
- assertNotNull(url);
+ String classAName = "integration.parent.ClassA";
+ String classBName = "integration.parent.ClassB";
- InputStream is = url != null ? url.openStream() : null;
- assertNotNull(is);
+ byte[] firstJarBytes = createJarWithClass("ClassA");
- int totalBytesRead = 0;
- byte[] input = new byte[128];
+ // First deploy of the JAR file
+ File firstDeployedJarFile =
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, firstJarBytes).getFile();
- BufferedInputStream bis = new BufferedInputStream(is);
- for (int bytesRead = bis.read(input); bytesRead > -1;) {
- totalBytesRead += bytesRead;
- bytesRead = bis.read(input);
- }
- bis.close();
+ assertThat(firstDeployedJarFile).exists().hasBinaryContent(firstJarBytes);
+ assertThat(firstDeployedJarFile.getName()).contains(".v1.").doesNotContain(".v2.");
+
+ assertThatClassCanBeLoaded(classAName);
+ assertThatClassCannotBeLoaded(classBName);
+
+ assertThatResourceCanBeLoaded(classAResource);
+ assertThatResourceCannotBeLoaded(classBResource);
- assertEquals(TEMP_FILE_BYTES_COUNT, totalBytesRead);
+ // Now deploy an updated JAR file and make sure that the next version of the JAR file
+ // was created and the first one is no longer used
+ byte[] secondJarBytes = createJarWithClass("ClassB");
+
+ File secondDeployedJarFile =
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, secondJarBytes).getFile();
+
+ assertThat(secondDeployedJarFile).exists().hasBinaryContent(secondJarBytes);
+ assertThat(secondDeployedJarFile.getName()).contains(".v2.").doesNotContain(".v1.");
+
+ assertThatClassCanBeLoaded(classBName);
+ assertThatClassCannotBeLoaded(classAName);
+
+ assertThatResourceCanBeLoaded(classBResource);
+ assertThatResourceCannotBeLoaded(classAResource);
+
+ // Now undeploy JAR and make sure it gets cleaned up
+ ClassPathLoader.getLatest().getJarDeployer().undeploy(jarName);
+ assertThatClassCannotBeLoaded(classBName);
+ assertThatClassCannotBeLoaded(classAName);
+
+ assertThatResourceCannotBeLoaded(classBResource);
+ assertThatResourceCannotBeLoaded(classAResource);
}
- /**
- * Verifies that <tt>getResources</tt> works with custom loader from {@link ClassPathLoader}.
- */
@Test
- public void testGetResourcesWithCustomLoader() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testGetResourceWithCustomLoader");
+ public void testDeployNoUpdateWhenNoChange() throws IOException, ClassNotFoundException {
+ String jarName = "JarDeployerIntegrationTest.jar";
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
+ // First deploy of the JAR file
+ byte[] jarBytes = new ClassBuilder().createJarFromName("JarDeployerDUnitDNUWNC");
+ DeployedJar jarClassLoader =
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, jarBytes);
+ File deployedJar = new File(jarClassLoader.getFileCanonicalPath());
- String resourceToGet = "com/nowhere/testGetResourceWithCustomLoader.rsc";
- Enumeration<URL> urls = dcl.getResources(resourceToGet);
- assertNotNull(urls);
- assertTrue(urls.hasMoreElements());
+ assertThat(deployedJar).exists();
+ assertThat(deployedJar.getName()).contains(".v1.");
- URL url = urls.nextElement();
- InputStream is = url != null ? url.openStream() : null;
- assertNotNull(is);
+ // Re-deploy of the same JAR should do nothing
+ DeployedJar newJarClassLoader =
+ ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, jarBytes);
+ assertThat(newJarClassLoader).isNull();
+ assertThat(deployedJar).exists();
- int totalBytesRead = 0;
- byte[] input = new byte[128];
+ }
- BufferedInputStream bis = new BufferedInputStream(is);
- for (int bytesRead = bis.read(input); bytesRead > -1;) {
- totalBytesRead += bytesRead;
- bytesRead = bis.read(input);
- }
- bis.close();
+ @Test
+ public void testDeployWithExistingDependentJars() throws Exception {
+ ClassBuilder classBuilder = new ClassBuilder();
+ final File parentJarFile =
+ new File(temporaryFolder.getRoot(), "JarDeployerDUnitAParent.v1.jar");
+ final File usesJarFile = new File(temporaryFolder.getRoot(), "JarDeployerDUnitUses.v1.jar");
+ final File functionJarFile =
+ new File(temporaryFolder.getRoot(), "JarDeployerDUnitFunction.v1.jar");
+
+ // Write out a JAR files.
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("package jddunit.parent;");
+ stringBuffer.append("public class JarDeployerDUnitParent {");
+ stringBuffer.append("public String getValueParent() {");
+ stringBuffer.append("return \"PARENT\";}}");
+
+ byte[] jarBytes = classBuilder.createJarFromClassContent(
+ "jddunit/parent/JarDeployerDUnitParent", stringBuffer.toString());
+ FileOutputStream outStream = new FileOutputStream(parentJarFile);
+ outStream.write(jarBytes);
+ outStream.close();
+
+ stringBuffer = new StringBuffer();
+ stringBuffer.append("package jddunit.uses;");
+ stringBuffer.append("public class JarDeployerDUnitUses {");
+ stringBuffer.append("public String getValueUses() {");
+ stringBuffer.append("return \"USES\";}}");
- assertEquals(TEMP_FILE_BYTES_COUNT, totalBytesRead);
+ jarBytes = classBuilder.createJarFromClassContent("jddunit/uses/JarDeployerDUnitUses",
+ stringBuffer.toString());
+ outStream = new FileOutputStream(usesJarFile);
+ outStream.write(jarBytes);
+ outStream.close();
+
+ stringBuffer = new StringBuffer();
+ stringBuffer.append("package jddunit.function;");
+ stringBuffer.append("import jddunit.parent.JarDeployerDUnitParent;");
+ stringBuffer.append("import jddunit.uses.JarDeployerDUnitUses;");
+ stringBuffer.append("import org.apache.geode.cache.execute.Function;");
+ stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;");
+ stringBuffer.append(
+ "public class JarDeployerDUnitFunction extends JarDeployerDUnitParent implements Function {");
+ stringBuffer.append("private JarDeployerDUnitUses uses = new JarDeployerDUnitUses();");
+ stringBuffer.append("public boolean hasResult() {return true;}");
+ stringBuffer.append(
+ "public void execute(FunctionContext context) {context.getResultSender().lastResult(getValueParent() + \":\" + uses.getValueUses());}");
+ stringBuffer.append("public String getId() {return \"JarDeployerDUnitFunction\";}");
+ stringBuffer.append("public boolean optimizeForWrite() {return false;}");
+ stringBuffer.append("public boolean isHA() {return false;}}");
+
+ ClassBuilder functionClassBuilder = new ClassBuilder();
+ functionClassBuilder.addToClassPath(parentJarFile.getAbsolutePath());
+ functionClassBuilder.addToClassPath(usesJarFile.getAbsolutePath());
+ jarBytes = functionClassBuilder.createJarFromClassContent(
+ "jddunit/function/JarDeployerDUnitFunction", stringBuffer.toString());
+ outStream = new FileOutputStream(functionJarFile);
+ outStream.write(jarBytes);
+ outStream.close();
+
+ Properties properties = new Properties();
+ properties.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
+ ServerStarterRule serverStarterRule = new ServerStarterRule();
+ serverStarterRule.startServer();
+
+ GemFireCacheImpl gemFireCache = GemFireCacheImpl.getInstance();
+ DistributedSystem distributedSystem = gemFireCache.getDistributedSystem();
+ Execution execution =
+ FunctionService.onMember(distributedSystem, distributedSystem.getDistributedMember());
+ ResultCollector resultCollector = execution.execute("JarDeployerDUnitFunction");
+ @SuppressWarnings("unchecked")
+ List<String> result = (List<String>) resultCollector.getResult();
+ assertEquals("PARENT:USES", result.get(0));
+
+ serverStarterRule.after();
}
- /**
- * Verifies that <tt>getResourceAsStream</tt> works with custom loader from
- * {@link ClassPathLoader}.
- */
@Test
- public void testGetResourceAsStreamWithCustomLoader() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testGetResourceAsStreamWithCustomLoader");
+ public void deployNewVersionOfFunctionOverOldVersion() throws Exception {
+ File jarVersion1 = createVersionOfJar("Version1", "MyFunction", "MyJar.jar");
+ File jarVersion2 = createVersionOfJar("Version2", "MyFunction", "MyJar.jar");
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
+ Properties properties = new Properties();
+ properties.setProperty("user.dir", temporaryFolder.getRoot().getAbsolutePath());
+ ServerStarterRule serverStarterRule = new ServerStarterRule();
+ serverStarterRule.startServer();
- String resourceToGet = "com/nowhere/testGetResourceAsStreamWithCustomLoader.rsc";
- InputStream is = dcl.getResourceAsStream(resourceToGet);
- assertNotNull(is);
+ GemFireCacheImpl gemFireCache = GemFireCacheImpl.getInstance();
+ DistributedSystem distributedSystem = gemFireCache.getDistributedSystem();
- int totalBytesRead = 0;
- byte[] input = new byte[128];
+ ClassPathLoader.getLatest().getJarDeployer().deploy("MyJar.jar",
+ FileUtils.readFileToByteArray(jarVersion1));
- BufferedInputStream bis = new BufferedInputStream(is);
- for (int bytesRead = bis.read(input); bytesRead > -1;) {
- totalBytesRead += bytesRead;
- bytesRead = bis.read(input);
- }
- bis.close();
+ assertThatClassCanBeLoaded("jddunit.function.MyFunction");
+ Execution execution =
+ FunctionService.onMember(distributedSystem, distributedSystem.getDistributedMember());
+
+ List<String> result = (List<String>) execution.execute("MyFunction").getResult();
+ assertThat(result.get(0)).isEqualTo("Version1");
+
+
+ ClassPathLoader.getLatest().getJarDeployer().deploy("MyJar.jar",
+ FileUtils.readFileToByteArray(jarVersion2));
+ result = (List<String>) execution.execute("MyFunction").getResult();
+ assertThat(result.get(0)).isEqualTo("Version2");
- assertEquals(TEMP_FILE_BYTES_COUNT, totalBytesRead);
+
+ serverStarterRule.after();
}
+
+ private File createVersionOfJar(String version, String functionName, String jarName)
+ throws IOException {
+ String classContents =
+ "package jddunit.function;" + "import org.apache.geode.cache.execute.Function;"
+ + "import org.apache.geode.cache.execute.FunctionContext;" + "public class "
+ + functionName + " implements Function {" + "public boolean hasResult() {return true;}"
+ + "public String getId() {return \"" + functionName + "\";}"
+ + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\""
+ + version + "\");}}";
+
+ File jar = new File(this.temporaryFolder.newFolder(version), jarName);
+ ClassBuilder functionClassBuilder = new ClassBuilder();
+ functionClassBuilder.writeJarFromContent("jddunit/function/" + functionName, classContents,
+ jar);
+
+ return jar;
+ }
+
+ private void assertThatClassCanBeLoaded(String className) throws ClassNotFoundException {
+ assertThat(ClassPathLoader.getLatest().forName(className)).isNotNull();
+ }
+
+ private void assertThatClassCannotBeLoaded(String className) throws ClassNotFoundException {
+ assertThatThrownBy(() -> ClassPathLoader.getLatest().forName(className))
+ .isExactlyInstanceOf(ClassNotFoundException.class);
+ }
+
+ private void assertThatResourceCanBeLoaded(String resourceName) throws IOException {
+ // ClassPathLoader.getResource
+ assertThat(ClassPathLoader.getLatest().getResource(resourceName)).isNotNull();
+
+ // ClassPathLoader.getResources
+ Enumeration<URL> urls = ClassPathLoader.getLatest().getResources(resourceName);
+ assertThat(urls).isNotNull();
+ assertThat(urls.hasMoreElements()).isTrue();
+
+ // ClassPathLoader.getResourceAsStream
+ InputStream is = ClassPathLoader.getLatest().getResourceAsStream(resourceName);
+ assertThat(is).isNotNull();
+ }
+
+ private void assertThatResourceCannotBeLoaded(String resourceName) throws IOException {
+ // ClassPathLoader.getResource
+ assertThat(ClassPathLoader.getLatest().getResource(resourceName)).isNull();
+
+ // ClassPathLoader.getResources
+ Enumeration<URL> urls = ClassPathLoader.getLatest().getResources(resourceName);
+ assertThat(urls.hasMoreElements()).isFalse();
+
+ // ClassPathLoader.getResourceAsStream
+ InputStream is = ClassPathLoader.getLatest().getResourceAsStream(resourceName);
+ assertThat(is).isNull();
+ }
+
+
/**
* Verifies that <tt>getResource</tt> works with TCCL from {@link ClassPathLoader}.
*/
@@ -281,154 +444,6 @@ public class ClassPathLoaderIntegrationTest {
}
}
- /**
- * Verifies that JAR files found in the extlib directory will be correctly added to the
- * {@link ClassPathLoader}.
- */
- @Test
- public void testJarsInExtLib() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testJarsInExtLib");
-
- File EXT_LIB_DIR = ClassPathLoader.defineEXT_LIB_DIR();
- EXT_LIB_DIR.mkdir();
-
- File subdir = new File(EXT_LIB_DIR, "cplju");
- subdir.mkdir();
-
- final ClassBuilder classBuilder = new ClassBuilder();
-
- writeJarBytesToFile(new File(EXT_LIB_DIR, "ClassPathLoaderJUnit1.jar"),
- classBuilder.createJarFromClassContent("com/cpljunit1/ClassPathLoaderJUnit1",
- "package com.cpljunit1; public class ClassPathLoaderJUnit1 {}"));
- writeJarBytesToFile(new File(subdir, "ClassPathLoaderJUnit2.jar"),
- classBuilder.createJarFromClassContent("com/cpljunit2/ClassPathLoaderJUnit2",
- "package com.cpljunit2; public class ClassPathLoaderJUnit2 {}"));
-
- ClassPathLoader classPathLoader = ClassPathLoader.createWithDefaults(false);
- try {
- classPathLoader.forName("com.cpljunit1.ClassPathLoaderJUnit1");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- try {
- classPathLoader.forName("com.cpljunit2.ClassPathLoaderJUnit2");
- } catch (ClassNotFoundException cnfex) {
- fail("JAR file not correctly added to Classpath");
- }
-
- assertNotNull(classPathLoader.getResource("com/cpljunit2/ClassPathLoaderJUnit2.class"));
-
- Enumeration<URL> urls = classPathLoader.getResources("com/cpljunit1");
- if (!urls.hasMoreElements()) {
- fail("Resources should return one element");
- }
- }
-
- /**
- * Verifies that the 3rd custom loader will get the resource. Parent cannot find it and TCCL is
- * broken. This verifies that all custom loaders are checked and that the custom loaders are all
- * checked before TCCL.
- */
- @Test
- public void testGetResourceAsStreamWithMultipleCustomLoaders() throws Exception {
- System.out
- .println("\nStarting ClassPathLoaderTest#testGetResourceAsStreamWithMultipleCustomLoaders");
-
- // create DCL such that the 3rd loader should find the resource
- // first custom loader becomes parent which won't find anything
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
- dcl = dcl.addOrReplace(new SimpleClassLoader(getClass().getClassLoader()));
- dcl = dcl.addOrReplace(new NullClassLoader());
-
- String resourceToGet = "com/nowhere/testGetResourceAsStreamWithMultipleCustomLoaders.rsc";
-
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- try {
- // set TCCL to throw errors which makes sure we find before checking TCCL
- Thread.currentThread().setContextClassLoader(new BrokenClassLoader());
-
- InputStream is = dcl.getResourceAsStream(resourceToGet);
- assertNotNull(is);
- is.close();
- } finally {
- Thread.currentThread().setContextClassLoader(cl);
- }
- }
-
- /**
- * Verifies that the 3rd custom loader will get the resource. Parent cannot find it and TCCL is
- * broken. This verifies that all custom loaders are checked and that the custom loaders are all
- * checked before TCCL.
- */
- @Test
- public void testGetResourceWithMultipleCustomLoaders() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testGetResourceWithMultipleCustomLoaders");
-
- // create DCL such that the 3rd loader should find the resource
- // first custom loader becomes parent which won't find anything
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
- dcl = dcl.addOrReplace(new SimpleClassLoader(getClass().getClassLoader()));
- dcl = dcl.addOrReplace(new NullClassLoader());
-
- String resourceToGet = "com/nowhere/testGetResourceWithMultipleCustomLoaders.rsc";
-
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- try {
- // set TCCL to throw errors which makes sure we find before checking TCCL
- Thread.currentThread().setContextClassLoader(new BrokenClassLoader());
-
- URL url = dcl.getResource(resourceToGet);
- assertNotNull(url);
- } finally {
- Thread.currentThread().setContextClassLoader(cl);
- }
- }
-
- /**
- * Verifies that the 3rd custom loader will get the resources. Parent cannot find it and TCCL is
- * broken. This verifies that all custom loaders are checked and that the custom loaders are all
- * checked before TCCL.
- */
- @Test
- public void testGetResourcesWithMultipleCustomLoaders() throws Exception {
- System.out.println("\nStarting ClassPathLoaderTest#testGetResourceWithMultipleCustomLoaders");
-
- // create DCL such that the 3rd loader should find the resource
- // first custom loader becomes parent which won't find anything
- ClassPathLoader dcl = ClassPathLoader.createWithDefaults(false);
- dcl = dcl.addOrReplace(new GeneratingClassLoader());
- dcl = dcl.addOrReplace(new GeneratingClassLoader2());
- dcl = dcl.addOrReplace(new SimpleClassLoader(getClass().getClassLoader()));
- dcl = dcl.addOrReplace(new NullClassLoader());
-
- String resourceToGet = "com/nowhere/testGetResourceWithMultipleCustomLoaders.rsc";
-
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- try {
- // set TCCL to throw errors which makes sure we find before checking TCCL
- Thread.currentThread().setContextClassLoader(new BrokenClassLoader());
-
- Enumeration<URL> urls = dcl.getResources(resourceToGet);
- assertNotNull(urls);
- assertTrue(urls.hasMoreElements());
-
- URL url = urls.nextElement();
- assertNotNull(url);
-
- // Should find two with unique URLs
- assertTrue("Did not find all resources.", urls.hasMoreElements());
- URL url2 = urls.nextElement();
- assertNotNull(url2);
- assertTrue("Resource URLs should be unique.", !url.equals(url2));
-
- } finally {
- Thread.currentThread().setContextClassLoader(cl);
- }
- }
-
private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException {
final OutputStream outStream = new FileOutputStream(jarFile);
outStream.write(jarBytes);
@@ -508,4 +523,11 @@ public class ClassPathLoaderIntegrationTest {
return tempFile2;
}
}
+
+ private byte[] createJarWithClass(String className) throws IOException {
+ String stringBuilder = "package integration.parent;" + "public class " + className + " {}";
+
+ return new ClassBuilder().createJarFromClassContent("integration/parent/" + className,
+ stringBuilder);
+ }
}
[7/8] geode git commit: GEODE-2686: Add more logging to JarDeployer
Posted by js...@apache.org.
GEODE-2686: Add more logging to JarDeployer
Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/8f9624d0
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/8f9624d0
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/8f9624d0
Branch: refs/heads/develop
Commit: 8f9624d05abf6a9dea20a9cf7aee2b6a0b7ccb8b
Parents: ee11b0a
Author: Jared Stewart <js...@pivotal.io>
Authored: Mon Apr 10 14:49:09 2017 -0700
Committer: Jared Stewart <js...@pivotal.io>
Committed: Sun Apr 16 09:10:01 2017 -0700
----------------------------------------------------------------------
.../main/java/org/apache/geode/internal/JarDeployer.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/geode/blob/8f9624d0/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
index 669802c..da4c136 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
@@ -14,6 +14,7 @@
*/
package org.apache.geode.internal;
+import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
@@ -89,6 +90,7 @@ public class JarDeployer implements Serializable {
try {
boolean shouldDeployNewVersion = shouldDeployNewVersion(jarName, jarBytes);
if (!shouldDeployNewVersion) {
+ logger.debug("No need to deploy a new version of {}", jarName);
return null;
}
@@ -146,6 +148,8 @@ public class JarDeployer implements Serializable {
nextVersionedJarName = removeJarExtension(unversionedJarName) + ".v" + nextVersion + ".jar";
}
+ logger.debug("Next versioned jar name for {} is {}", unversionedJarName, nextVersionedJarName);
+
return new File(deployDirectory, nextVersionedJarName);
}
@@ -274,6 +278,7 @@ public class JarDeployer implements Serializable {
* @return Sorted array of files that are older versions of the given JAR
*/
protected File[] findSortedOldVersionsOfJar(final String unversionedJarName) {
+ logger.debug("Finding sorted old versions of {}", unversionedJarName);
// Find all matching files
final Pattern pattern = Pattern.compile(
JAR_PREFIX_FOR_REGEX + removeJarExtension(unversionedJarName) + "\\.v\\d++\\.jar$");
@@ -287,6 +292,8 @@ public class JarDeployer implements Serializable {
return file2Version - file1Version;
});
+ logger.debug("Found [{}]",
+ Arrays.stream(oldJarFiles).map(File::getAbsolutePath).collect(joining(",")));
return oldJarFiles;
}
@@ -458,7 +465,7 @@ public class JarDeployer implements Serializable {
try {
for (DeployedJar deployedJar : deployedJars) {
if (deployedJar != null) {
- logger.info("Registering new version of jar: {}", deployedJar.toString());
+ logger.info("Registering new version of jar: {}", deployedJar);
DeployedJar oldJar = this.deployedJars.put(deployedJar.getJarName(), deployedJar);
if (oldJar != null) {
oldJar.cleanUp();