### Eclipse Workspace Patch 1.0 #P dso-l1 Index: tests.unit.resources/com/tc/object/config/tc-config-includeexclude.xml =================================================================== --- tests.unit.resources/com/tc/object/config/tc-config-includeexclude.xml (revision 0) +++ tests.unit.resources/com/tc/object/config/tc-config-includeexclude.xml (revision 0) @@ -0,0 +1,39 @@ + + + + + development + + + %d/client-logs-%h + + + + + + + + + + + p.* + + p.q.* + + p.q.C + + + p.q.r.* + + p.q.r.D + + + + + + Index: src/com/tc/object/config/ConfigLoader.java =================================================================== --- src/com/tc/object/config/ConfigLoader.java (revision 9740) +++ src/com/tc/object/config/ConfigLoader.java (working copy) @@ -19,6 +19,7 @@ import com.tc.util.ClassUtils.ClassSpec; import com.terracottatech.config.AdditionalBootJarClasses; import com.terracottatech.config.Autolock; +import com.terracottatech.config.ClassExpression; import com.terracottatech.config.DistributedMethods; import com.terracottatech.config.DsoApplication; import com.terracottatech.config.Include; @@ -289,27 +290,35 @@ } } - private void loadInstrumentedClasses(InstrumentedClasses instrumentedClasses) { + private void loadInstrumentedClasses(InstrumentedClasses instrumentedClasses) throws ConfigurationSetupException { if (instrumentedClasses != null) { - Include[] includes = instrumentedClasses.getIncludeArray(); - for (int i = 0; includes != null && i < includes.length; i++) { - Include include = includes[i]; - IncludeOnLoad includeOnLoad = new IncludeOnLoad(); - OnLoad onLoad = include.getOnLoad(); - if (onLoad != null) { - if (onLoad.getExecute() != null) { - includeOnLoad = new IncludeOnLoad(IncludeOnLoad.EXECUTE, onLoad.getExecute()); - } else if (onLoad.getMethod() != null) { - includeOnLoad = new IncludeOnLoad(IncludeOnLoad.METHOD, onLoad.getMethod()); + // Call selectPath() rather than using getIncludeArray and getExcludeArray(), + // because we need to preserve the relative order of includes and excludes. + XmlObject[] elements = instrumentedClasses.selectPath("*"); + for (int i = 0; elements != null && i < elements.length; ++i) { + if (elements[i] instanceof Include) { + Include include = (Include) elements[i]; + IncludeOnLoad includeOnLoad = new IncludeOnLoad(); + OnLoad onLoad = include.getOnLoad(); + if (onLoad != null) { + if (onLoad.getExecute() != null) { + includeOnLoad = new IncludeOnLoad(IncludeOnLoad.EXECUTE, onLoad.getExecute()); + } else if (onLoad.getMethod() != null) { + includeOnLoad = new IncludeOnLoad(IncludeOnLoad.METHOD, onLoad.getMethod()); + } } + config.addInstrumentationDescriptor(new IncludedInstrumentedClass(include.getClassExpression(), include + .getHonorTransient(), false, includeOnLoad)); } - config.addInstrumentationDescriptor(new IncludedInstrumentedClass(include.getClassExpression(), include - .getHonorTransient(), false, includeOnLoad)); - } - - String[] excludeArray = instrumentedClasses.getExcludeArray(); - for (int i = 0; excludeArray != null && i < excludeArray.length; i++) { - config.addInstrumentationDescriptor(new ExcludedInstrumentedClass(excludeArray[i])); + else if (elements[i] instanceof ClassExpression) { + String expr = ((ClassExpression)elements[i]).getStringValue(); + config.addInstrumentationDescriptor(new ExcludedInstrumentedClass(expr)); + } + else { + throw new ConfigurationSetupException( + "The following element was unexpected within an element:" + + elements[i]); + } } } } Index: tests.unit.resources/com/tc/object/config/tc-config-includeexclude2.xml =================================================================== --- tests.unit.resources/com/tc/object/config/tc-config-includeexclude2.xml (revision 0) +++ tests.unit.resources/com/tc/object/config/tc-config-includeexclude2.xml (revision 0) @@ -0,0 +1,41 @@ + + + + + development + + + %d/client-logs-%h + + + + + + + + + + + A* + + ABC + + + AB* + + + ZY + + + Z* + + + + + + Index: tests.unit/com/tc/object/config/IncludeExcludeOrderingTest.java =================================================================== --- tests.unit/com/tc/object/config/IncludeExcludeOrderingTest.java (revision 0) +++ tests.unit/com/tc/object/config/IncludeExcludeOrderingTest.java (revision 0) @@ -0,0 +1,97 @@ +/* + * All content copyright (c) 2008 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All + * rights reserved. + */ +package com.tc.object.config; + +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlOptions; +import org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException; + +import com.tc.aspectwerkz.reflect.ClassInfo; +import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo; +import com.tc.config.Loader; +import com.tc.config.schema.setup.ConfigurationSetupException; +import com.tc.logging.NullTCLogger; +import com.tc.logging.TCLogger; +import com.tc.object.BaseDSOTestCase; +import com.terracottatech.config.Application; +import com.terracottatech.config.TcConfigDocument; +import com.terracottatech.config.TcConfigDocument.TcConfig; + +import java.io.IOException; +import java.io.InputStream; + +public class IncludeExcludeOrderingTest extends BaseDSOTestCase { + + /** + * Verify that relative order of includes and excludes is preserved: a specific include placed after a more general + * exclude will win, and similarly a specific exclude will win after a general include. + */ + public void testMoreSpecificOrdering() throws XmlException, IOException, ConfigurationSetupException { + DSOClientConfigHelper config = loadConfigFile("tc-config-includeexclude.xml"); + + System.out.println("The following warnings about unloadable classes [p/A*] are expected."); + ClassInfo classInfoA = AsmClassInfo.getClassInfo("p.A", getClass().getClassLoader()); + assertTrue(config.shouldBeAdapted(classInfoA)); + + ClassInfo classInfoB = AsmClassInfo.getClassInfo("p.q.B", getClass().getClassLoader()); + assertFalse(config.shouldBeAdapted(classInfoB)); + + ClassInfo classInfoC = AsmClassInfo.getClassInfo("p.q.C", getClass().getClassLoader()); + assertTrue(config.shouldBeAdapted(classInfoC)); + + ClassInfo classInfoD = AsmClassInfo.getClassInfo("p.q.r.D", getClass().getClassLoader()); + assertFalse(config.shouldBeAdapted(classInfoD)); + + ClassInfo classInfoE = AsmClassInfo.getClassInfo("p.q.r.E", getClass().getClassLoader()); + assertTrue(config.shouldBeAdapted(classInfoE)); + } + + /** + * Verify that relative order of includes and excludes is preserved: a more general include placed after a more + * specific exclude will win, and similarly a more general exclude after a specific include. Note that this sort of + * content in a tc-config.xml is not very useful, and indeed at some point we might want to issue warnings. + */ + public void testMoreGeneralOrdering() throws XmlException, IOException, ConfigurationSetupException { + DSOClientConfigHelper config = loadConfigFile("tc-config-includeexclude2.xml"); + + System.out.println("The following warnings about unloadable classes [A*] and [Z*] are expected."); + ClassInfo classInfoA = AsmClassInfo.getClassInfo("A", getClass().getClassLoader()); + assertTrue(config.shouldBeAdapted(classInfoA)); + + ClassInfo classInfoC = AsmClassInfo.getClassInfo("ABC", getClass().getClassLoader()); + assertTrue(config.shouldBeAdapted(classInfoC)); + + ClassInfo classInfoZ = AsmClassInfo.getClassInfo("Z", getClass().getClassLoader()); + assertFalse(config.shouldBeAdapted(classInfoZ)); + + ClassInfo classInfoY = AsmClassInfo.getClassInfo("ZY", getClass().getClassLoader()); + assertFalse(config.shouldBeAdapted(classInfoY)); + } + + /** + * Load a config file in the same way that normal instrumention is done. + * @see com.tc.ModulesLoader#loadConfiguration() + */ + private DSOClientConfigHelper loadConfigFile(String fileName) throws IOException, XmlException, + ConfigurationSetupException { + InputStream configFile = getClass().getResourceAsStream(fileName); + TcConfigDocument tcConfigDocument = new Loader().parse(configFile, new XmlOptions().setLoadLineNumbers() + .setValidateOnSet()); + TcConfig tcConfig = tcConfigDocument.getTcConfig(); + Application application = tcConfig.getApplication(); + assertNotNull(" tag not found - check file " + fileName, application); + TCLogger logger = new NullTCLogger(); + DSOClientConfigHelper config = createClientConfigHelper(); + + ConfigLoader loader = new ConfigLoader(config, logger); + try { + loader.loadDsoConfig(application.getDso()); + } catch (XmlValueOutOfRangeException e) { + fail(e.getMessage()); + } + return config; + } + +}