Author: rmannibucau
Date: Fri Jan 6 19:10:10 2012
New Revision: 1228352
URL: http://svn.apache.org/viewvc?rev=1228352&view=rev
Log:
adding CheckClassLoading (in progress)
Added:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckClassLoading.java
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppValidator.java
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ValidateModules.java
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppValidator.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppValidator.java?rev=1228352&r1=1228351&r2=1228352&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppValidator.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppValidator.java
Fri Jan 6 19:10:10 2012
@@ -37,6 +37,7 @@ import org.apache.openejb.config.rules.C
import org.apache.openejb.config.rules.CheckMethods;
import org.apache.openejb.config.rules.CheckPersistenceRefs;
import org.apache.openejb.config.rules.CheckUserTransactionRefs;
+import org.apache.openejb.config.rules.ValidationBase;
import org.apache.openejb.util.Messages;
import org.apache.openejb.util.OpenEjbVersion;
@@ -57,6 +58,7 @@ public class AppValidator {
boolean PRINT_COUNT = false;
private List<ValidationResults> sets = new ArrayList<ValidationResults>();
+ private ValidationBase[] additionalValidators;
/*------------------------------------------------------*/
/* Constructors */
@@ -71,6 +73,10 @@ public class AppValidator {
this.PRINT_COUNT = PRINT_COUNT;
}
+ public AppValidator(final ValidationBase... additionalValidator) {
+ additionalValidators = additionalValidator;
+ }
+
public void addValidationResults(ValidationResults set) {
sets.add(set);
}
@@ -100,7 +106,8 @@ public class AppValidator {
// END SNIPPET : code2
// START SNIPPET : code1
protected ValidationRule[] getValidationRules() {
- ValidationRule[] rules = new ValidationRule[]{
+ // we don't want CheckClassLoading in standalone mode since it doesn't
mean anything
+ final ValidationRule[] defaultRules = new ValidationRule[]{
new CheckClasses(),
new CheckMethods(),
new CheckCallbacks(),
@@ -113,6 +120,17 @@ public class AppValidator {
new CheckAsynchronous(),
new CheckDescriptorLocation()
};
+ if (additionalValidators == null || additionalValidators.length == 0) {
+ return defaultRules;
+ }
+
+ final ValidationRule[] rules = new
ValidationRule[additionalValidators.length + 11];
+ for (int i = 0; i < additionalValidators.length; i++) {
+ rules[i] = additionalValidators[i];
+ }
+ for (int i = 0; i < defaultRules.length; i++) {
+ rules[i + additionalValidators.length] = defaultRules[i];
+ }
return rules;
}
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ValidateModules.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ValidateModules.java?rev=1228352&r1=1228351&r2=1228352&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ValidateModules.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ValidateModules.java
Fri Jan 6 19:10:10 2012
@@ -17,6 +17,7 @@
package org.apache.openejb.config;
import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.config.rules.CheckClassLoading;
/**
* @version $Rev$ $Date$
@@ -25,7 +26,12 @@ import org.apache.openejb.OpenEJBExcepti
public class ValidateModules implements DynamicDeployer {
public AppModule deploy(AppModule appModule) throws OpenEJBException {
- AppValidator validator = new AppValidator();
+ final AppValidator validator;
+ if (!Boolean.getBoolean("openejb.check.classloader")) {
+ validator = new AppValidator();
+ } else {
+ validator = new AppValidator(new CheckClassLoading());
+ }
return validator.validate(appModule);
}
Added:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckClassLoading.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckClassLoading.java?rev=1228352&view=auto
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckClassLoading.java
(added)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckClassLoading.java
Fri Jan 6 19:10:10 2012
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.openejb.config.rules;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.openejb.config.AppModule;
+import org.apache.openejb.config.ClientModule;
+import org.apache.openejb.config.EjbModule;
+import org.apache.openejb.config.ValidationWarning;
+import org.apache.openejb.config.WebModule;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class CheckClassLoading extends ValidationBase {
+ protected AppModule appModule;
+
+ @Override public void validate(AppModule appModule) {
+ this.appModule = appModule;
+ module = appModule;
+ // validate appmodule first
+ check(appModule.getClassLoader(),
appModule.getClassLoader().getParent());
+
+ // nothing more for now till i'm not sure nested validation can be
useful
+ for (WebModule webModule : appModule.getWebModules()) {
+ module = webModule;
+ validate(webModule);
+ }
+ super.validate(appModule);
+ }
+
+ private void check(final ClassLoader classLoader, final ClassLoader
parent) {
+ final URLClassLoader parentUrlClassLoader;
+ if (parent instanceof URLClassLoader) {
+ parentUrlClassLoader = (URLClassLoader) parent;
+ } else {
+ parentUrlClassLoader = null;
+ }
+
+ final URLClassLoader currentUrlClassLoader;
+ if (classLoader instanceof URLClassLoader) {
+ currentUrlClassLoader = (URLClassLoader) classLoader;
+ } else {
+ currentUrlClassLoader = null;
+ }
+
+ if (parentUrlClassLoader == null || currentUrlClassLoader == null) {
+ module.getValidation().addWarning(new ValidationWarning("was not
able to compare application classloader and its parent"));
+ return; // we don't know (at least for now), xbean scanning from
classloader can be wrong for this purpose
+ }
+
+ final URL[] parentUrls = parentUrlClassLoader.getURLs();
+ final URL[] currentUrls = currentUrlClassLoader.getURLs();
+
+ final Classes fcl = new Classes(currentUrls);
+ final Classes scl = new Classes(parentUrls);
+ final Collection<DiffItem> diffs = Classes.intersection(fcl, scl);
+ for (DiffItem diff : diffs) {
+ warn(module.getModuleId() + " application", diff.toString());
+ }
+ }
+
+ private void validate(WebModule webModule) {
+ // no-op: appmodule should be enough
+ }
+
+ @Override public void validate(ClientModule appModule) {
+ // no-op: appmodule should be enough
+ }
+
+ @Override public void validate(EjbModule appModule) {
+ // no-op: appmodule should be enough
+ }
+
+ public static class Classes {
+ private static final String[] EXTENSIONS = new String[] { "jar", "zip"
};
+ private static final String[] CLASS_EXTENSION = new String[] {
".class" };
+
+ private final Map<String, Collection<String>> fileByArchive = new
TreeMap<String, Collection<String>>();
+
+ public Classes(final URL[] urls) {
+ list(urls);
+ }
+
+ public void list(final URL[] urls) {
+ fileByArchive.clear();
+
+ // for all archives list all files
+ // all is sorted by the natural String order
+ for (URL archive : urls) {
+ try {
+ final File file = new File(archive.toURI());
+ List<String> files = JarUtil.listFiles(file,
CLASS_EXTENSION);
+ Collections.sort(files);
+ fileByArchive.put(file.getName(), files);
+ } catch (Exception e) {
+ // ignored
+ }
+ }
+ }
+
+ public Map<String, Collection<String>> getFileByArchive() {
+ return fileByArchive;
+ }
+
+ public static Collection<DiffItem> intersection(Classes cl1, Classes
cl2) {
+ final List<DiffItem> diff = new ArrayList<DiffItem>();
+ for (Map.Entry<String, Collection<String>> entry1 :
cl1.fileByArchive.entrySet()) {
+ for (Map.Entry<String, Collection<String>> entry2 :
cl2.fileByArchive.entrySet()) {
+ Collection<String> v1 = entry1.getValue();
+ Collection<String> v2 = entry2.getValue();
+ Collection<String> inter =
CollectionUtils.intersection(v1, v2);
+
+ if (inter.size() == 0) {
+ continue;
+ }
+
+ if (inter.size() == v1.size() && v1.size() == v2.size()) {
+ diff.add(new SameItem(inter, entry1.getKey(),
entry2.getKey()));
+ } else if (inter.size() == v1.size()) {
+ diff.add(new IncludedItem(inter, entry1.getKey(),
entry2.getKey()));
+ } else if (inter.size() == v2.size()) {
+ diff.add(new ContainingItem(inter, entry1.getKey(),
entry2.getKey()));
+ } else {
+ diff.add(new DiffItem(inter, entry1.getKey(),
entry2.getKey()));
+ }
+ }
+ }
+
+ Collections.sort(diff, DiffItemComparator.getInstance());
+ return diff;
+ }
+ }
+
+ public final static class JarUtil {
+
+ public static final String CLASS_EXT = ".class";
+
+ private JarUtil() {
+ // no-op
+ }
+
+ public static List<String> listFiles(File archive, String[]
extensions) throws IOException {
+ if (!archive.exists() || !archive.isFile()) {
+ throw new IllegalArgumentException(archive.getPath() + " is
not a file");
+ }
+
+ List<String> files = new ArrayList<String>();
+
+ JarFile file = new JarFile(archive);
+ Enumeration<JarEntry> entries = file.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String name = entry.getName();
+ for (String ext : extensions) {
+ if (name.endsWith(ext)) {
+ if (CLASS_EXT.equals(ext)) {
+ files.add(name.replace("/", "."));
+ } else {
+ files.add(name);
+ }
+ break;
+ }
+ }
+ }
+
+ return files;
+ }
+ }
+
+ public static class ContainingItem extends DiffItem {
+ public ContainingItem(Collection<String> inter, String dir1, String
dir2) {
+ super(inter, dir1, dir2);
+ }
+
+ @Override public String toString() {
+ return "ContainingItem{" + getFile1() + " contains " + getFile2()
+ "}";
+ }
+ }
+
+ public static class DiffItem {
+ private Collection<String> files = new ArrayList<String>();
+ private String file1;
+ private String file2;
+
+ public DiffItem(Collection<String> files, String file1, String file2) {
+ this.files = files;
+ this.file1 = file1;
+ this.file2 = file2;
+ }
+
+ public Collection<String> getFiles() {
+ return files;
+ }
+
+ public String getFile1() {
+ return file1;
+ }
+
+ public String getFile2() {
+ return file2;
+ }
+
+ @Override public String toString() {
+ return "DiffItem{"
+ + "both files " + file1 + '\''
+ + " and " + file2 + '\''
+ + "contains files=" + files
+ + '}';
+ }
+ }
+
+ public static class DiffItemComparator implements Comparator<DiffItem> {
+ private static final DiffItemComparator INSTANCE = new
DiffItemComparator();
+ private static final Map<Class<?>, Integer> ORDER = new
HashMap<Class<?>, Integer>();
+ static {
+ ORDER.put(SameItem.class, 0);
+ ORDER.put(IncludedItem.class, 1);
+ ORDER.put(ContainingItem.class, 2);
+ ORDER.put(DiffItem.class, 3);
+ }
+
+
+ public static DiffItemComparator getInstance() {
+ return INSTANCE;
+ }
+
+ @Override public int compare(DiffItem o1, DiffItem o2) {
+ int index1 = ORDER.get(o1.getClass());
+ int index2 = ORDER.get(o2.getClass());
+ if (index1 == index2) {
+ return o1.getFile1().compareTo(o1.getFile1());
+ }
+ return index1 - index2;
+ }
+ }
+
+ public static class IncludedItem extends DiffItem {
+ public IncludedItem(Collection<String> files, String file1, String
file2) {
+ super(files, file1, file2);
+ }
+
+ @Override public String toString() {
+ return "IncludedItem{" + getFile1() + " is included inside " +
getFile2() + "}";
+ }
+ }
+
+ public static class SameItem extends DiffItem {
+ public SameItem(Collection<String> files, String file1, String file2) {
+ super(files, file1, file2);
+ }
+
+ @Override public String toString() {
+ return "SameItem{" + getFile1() + ", " + getFile2() + "}";
+ }
+ }
+}