Created
May 9, 2011 10:26
-
-
Save aslakknutsen/962338 to your computer and use it in GitHub Desktop.
JOops Test Impl, Auto discover dependencies (based on examples-domain from Arquillian-Core)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, Home of Professional Open Source | |
* Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors | |
* as indicated by the @authors tag. All rights reserved. | |
* See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* Licensed 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 com.acme.deps; | |
import java.util.HashSet; | |
import java.util.Set; | |
import junit.framework.Assert; | |
import oops.Analyzer; | |
import oops.DependencyVisitor; | |
import org.jboss.shrinkwrap.impl.base.URLPackageScanner; | |
import org.jboss.shrinkwrap.impl.base.URLPackageScanner.Callback; | |
import org.junit.Test; | |
import com.acme.cdi.translate.NorwegianTranslator; | |
import com.acme.cdi.translate.SentenceParser; | |
import com.acme.cdi.translate.TextTranslator; | |
import com.acme.cdi.translate.TranslateController; | |
import com.acme.cdi.translate.Translator; | |
import com.acme.ejb.GreetingManager; | |
import com.acme.ejb.GreetingManagerBean; | |
/** | |
* Simple test case to demonstrate auto dependency resolving issues | |
* | |
* @author <a href="mailto:aslak@redhat.com">Aslak Knutsen</a> | |
* @version $Revision: $ | |
*/ | |
public class OppsTestCase | |
{ | |
/* | |
* A EJB Interface does not depend on it's implementation | |
*/ | |
@Test | |
public void ejb_shouldFindImplementationBasedOnInterface() throws Exception | |
{ | |
Set<String> result = scan( | |
new String[]{GreetingManager.class.getName()}); | |
Assert.assertTrue(result.contains(GreetingManager.class.getName())); | |
// not found when scanning the interface, No EJB deployed | |
Assert.assertTrue(result.contains(GreetingManagerBean.class.getName())); | |
} | |
/* | |
* Can't resolve Bean implementations or Observers based on interfaces | |
*/ | |
@Test | |
public void cdi_shouldFindImplementationBasedOnInterface() throws Exception | |
{ | |
Set<String> result = scan( | |
new String[]{TranslateController.class.getName()}); | |
Assert.assertTrue(result.contains(Translator.class.getName())); | |
Assert.assertTrue(result.contains(TranslateController.class.getName())); | |
Assert.assertTrue(result.contains(TextTranslator.class.getName())); | |
Assert.assertTrue(result.contains(SentenceParser.class.getName())); | |
// not found, no one directly depend on it, UnResolvedBeanException | |
Assert.assertTrue(result.contains(NorwegianTranslator.class.getName())); | |
} | |
/* | |
* Scanning the whole package works in this case(so does archive.addPackage()), but it will most likely depend on another package | |
* based on interfaces, and we'll have the same issue as above. | |
*/ | |
@Test | |
public void cdi_scanPackage_shouldFindImplementationBasedOnInterface() throws Exception | |
{ | |
Set<String> result = scan( | |
scanPackage(TranslateController.class.getPackage().getName())); | |
Assert.assertTrue(result.contains(Translator.class.getName())); | |
Assert.assertTrue(result.contains(TranslateController.class.getName())); | |
Assert.assertTrue(result.contains(TextTranslator.class.getName())); | |
Assert.assertTrue(result.contains(SentenceParser.class.getName())); | |
Assert.assertTrue(result.contains(NorwegianTranslator.class.getName())); | |
} | |
private Set<String> scan(String[] classesToScan) | |
{ | |
final Set<String> foundClasses = new HashSet<String>(); | |
final long start = System.currentTimeMillis(); | |
Analyzer.analyze(new DependencyVisitor() | |
{ | |
@Override | |
public void success(String className) | |
{ | |
if(!className.matches("(java|javax|sun|com\\.sun|org\\.xml|org\\.w3c)\\..*")) | |
{ | |
System.out.println("Found: " + className); | |
foundClasses.add(className); | |
} | |
} | |
@Override | |
public void fail(String className) | |
{ | |
System.out.println("Not found: " + className); | |
} | |
@Override | |
public void end() | |
{ | |
System.out.println("End Scan in " + (System.currentTimeMillis() - start) + " ms"); | |
} | |
}, | |
classesToScan); | |
return foundClasses; | |
} | |
private String[] scanPackage(String packageName) | |
{ | |
final Set<String> found = new HashSet<String>(); | |
URLPackageScanner scanner = URLPackageScanner.newInstance(true, OppsTestCase.class.getClassLoader(), new Callback() | |
{ | |
public void classFound(String name) | |
{ | |
found.add(name); | |
} | |
}, | |
packageName); | |
scanner.scanPackage(); | |
return found.toArray(new String[]{}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output:
Found: com.acme.ejb.GreetingManager
End Scan in 2643 ms
Found: com.acme.cdi.translate.TranslateController
Found: com.acme.cdi.translate.SentenceParser
Found: com.acme.cdi.translate.Translator
Found: com.acme.cdi.translate.TextTranslator
End Scan in 1662 ms
Found: com.acme.cdi.translate.SentenceParser
Found: com.acme.cdi.translate.TranslateController
Found: com.acme.cdi.translate.NorwegianTranslator
Found: com.acme.cdi.translate.TextTranslator
Found: com.acme.cdi.translate.Translator
End Scan in 1612 ms
The two main problems:
Interface not depending on implementation
We could probably fix the 80% case by using a very simple hack:
** Include anything that depends on the given class or it's dependencies
Example:
acme.Interface
acme.Impl extends Interface
Speed
Adding another 2 sec pr @deployment is a bit much, but a very simple performance gain would be to move the filter up to the scanner, instead of Filtering the scanner result. JOops is not optimized for the kind of scanning we need, it finds EVERYTHING,
hench the regexp "(java|javax|sun|com.sun|org.xml|org.w3c)..*" in success.
But if we can stop scanning the class hierarchy when we hit the Filter, we should in most cases only scan a couple of classes deep.
Of course another issue is, what should the filter be?