This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-bnd-models.git
commit 363730ffdf705645d55327b16497b9779660900b Author: Stefan Seifert <[email protected]> AuthorDate: Fri Nov 11 21:55:19 2016 +0000 SLING-6048 add parameter to generate Sling-Model-Packages instead of Sling-Model-Classes header, and a check for maxlength of header value git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1769351 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 22 ++++++ .../sling/bnd/models/ModelsScannerPlugin.java | 79 +++++++++++++++++-- src/test/java/dummy/example/pkg1/Model1.java | 26 +++++++ src/test/java/dummy/example/pkg1/Model2.java | 26 +++++++ src/test/java/dummy/example/pkg1/sub1/Model3.java | 26 +++++++ src/test/java/dummy/example/pkg2/Model4.java | 26 +++++++ src/test/java/dummy/example/pkg2/Model5.java | 26 +++++++ .../models/AbstractModelsScannerPluginTest.java | 89 ++++++++++++++++++++++ .../bnd/models/GenerateClassesHeaderTest.java | 44 +++++++++++ .../bnd/models/GeneratePackagesHeaderTest.java | 53 +++++++++++++ 10 files changed, 411 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index a949d52..c608037 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,28 @@ <version>3.3.2</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>2.2.15</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.models.api</artifactId> + <version>1.3.0</version> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/src/main/java/org/apache/sling/bnd/models/ModelsScannerPlugin.java b/src/main/java/org/apache/sling/bnd/models/ModelsScannerPlugin.java index 29fe4f5..e53047c 100644 --- a/src/main/java/org/apache/sling/bnd/models/ModelsScannerPlugin.java +++ b/src/main/java/org/apache/sling/bnd/models/ModelsScannerPlugin.java @@ -18,11 +18,14 @@ */ package org.apache.sling.bnd.models; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.HashSet; import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import aQute.bnd.osgi.Analyzer; @@ -44,11 +47,18 @@ public class ModelsScannerPlugin implements AnalyzerPlugin, Plugin { static final String MODELS_PACKAGES_HEADER = "Sling-Model-Packages"; static final String MODELS_CLASSES_HEADER = "Sling-Model-Classes"; + // max length of manifest header value 65535 bytes (see http://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html) + // fall back to packages header when class names string gets too long + static final int MODELS_CLASSES_HEADER_MAXLENGTH = 60000; + + static final String PROPERTY_GENERATE_PACKAGES_HEADER = "generatePackagesHeader"; + private Reporter reporter; + private Map<String,String> properties; @Override public void setProperties(Map<String, String> map) throws Exception { - // ignore + properties = map; } @Override @@ -67,7 +77,12 @@ public class ModelsScannerPlugin implements AnalyzerPlugin, Plugin { // set bundle header containing all class names found if (!classNames.isEmpty()) { - analyzer.set(MODELS_CLASSES_HEADER, StringUtils.join(classNames, ",")); + if (getBooleanProperty(PROPERTY_GENERATE_PACKAGES_HEADER)) { + generatePackagesHeader(analyzer, classNames); + } + else { + generateClassesHeader(analyzer, classNames); + } } } @@ -76,6 +91,53 @@ public class ModelsScannerPlugin implements AnalyzerPlugin, Plugin { return false; } + private void generateClassesHeader(Analyzer analyzer, Collection<String> classNames) { + String classNameHeader = StringUtils.join(classNames, ","); + if (classNameHeader.length() <= MODELS_CLASSES_HEADER_MAXLENGTH) { + analyzer.set(MODELS_CLASSES_HEADER, classNameHeader); + } + else { + generatePackagesHeader(analyzer, classNames); + } + } + + private void generatePackagesHeader(Analyzer analyzer, Collection<String> classNames) { + + // get all package names + SortedSet<String> packages = new TreeSet<>(); + for (String className : classNames) { + if (StringUtils.contains(className, ".")) { + packages.add(StringUtils.substringBeforeLast(className, ".")); + } + } + + // eliminate package names for which parent packages exist (they are included automatically) + Set<String> packagesToRemove = new HashSet<>(); + for (String packageName : packages) { + if (includesParentPackage(packages, packageName)) { + packagesToRemove.add(packageName); + } + } + packages.removeAll(packagesToRemove); + + analyzer.set(MODELS_PACKAGES_HEADER, StringUtils.join(packages, ",")); + } + + private boolean includesParentPackage(Set<String> packages, String packageName) { + if (StringUtils.contains(packageName, ".")) { + String parentPackageName = StringUtils.substringBeforeLast(packageName, "."); + if (packages.contains(parentPackageName)) { + return true; + } + else { + return includesParentPackage(packages, parentPackageName); + } + } + else { + return false; + } + } + /** * Get all classes that implement the given annotation via bnd Analyzer. * @param analyzer Analyzer @@ -83,12 +145,12 @@ public class ModelsScannerPlugin implements AnalyzerPlugin, Plugin { * @return Class names */ private Collection<String> getClassesWithAnnotation(String annotationClassName, Analyzer analyzer) { - List<String> classNames = new ArrayList<>(); + SortedSet<String> classNames = new TreeSet<>(); Collection<Clazz> clazzes = analyzer.getClassspace().values(); Instruction instruction = new Instruction(annotationClassName); try { for (Clazz clazz : clazzes) { - if (clazz.isAnnotation() && clazz.is(QUERY.ANNOTATED, instruction, analyzer)) { + if (clazz.is(QUERY.ANNOTATED, instruction, analyzer)) { classNames.add(clazz.getClassName().getFQN()); } } @@ -99,4 +161,9 @@ public class ModelsScannerPlugin implements AnalyzerPlugin, Plugin { return classNames; } + private boolean getBooleanProperty(String propertyName) { + String value = properties != null ? properties.get(propertyName) : null; + return BooleanUtils.toBoolean(value); + } + } diff --git a/src/test/java/dummy/example/pkg1/Model1.java b/src/test/java/dummy/example/pkg1/Model1.java new file mode 100644 index 0000000..4cd8f9b --- /dev/null +++ b/src/test/java/dummy/example/pkg1/Model1.java @@ -0,0 +1,26 @@ +/* + * 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 dummy.example.pkg1; + +import org.apache.sling.models.annotations.Model; + +@Model(adaptables=Object.class) +public class Model1 { + +} diff --git a/src/test/java/dummy/example/pkg1/Model2.java b/src/test/java/dummy/example/pkg1/Model2.java new file mode 100644 index 0000000..3e8ae03 --- /dev/null +++ b/src/test/java/dummy/example/pkg1/Model2.java @@ -0,0 +1,26 @@ +/* + * 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 dummy.example.pkg1; + +import org.apache.sling.models.annotations.Model; + +@Model(adaptables=Object.class) +public class Model2 { + +} diff --git a/src/test/java/dummy/example/pkg1/sub1/Model3.java b/src/test/java/dummy/example/pkg1/sub1/Model3.java new file mode 100644 index 0000000..7accb4c --- /dev/null +++ b/src/test/java/dummy/example/pkg1/sub1/Model3.java @@ -0,0 +1,26 @@ +/* + * 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 dummy.example.pkg1.sub1; + +import org.apache.sling.models.annotations.Model; + +@Model(adaptables=Object.class) +public class Model3 { + +} diff --git a/src/test/java/dummy/example/pkg2/Model4.java b/src/test/java/dummy/example/pkg2/Model4.java new file mode 100644 index 0000000..5bdb120 --- /dev/null +++ b/src/test/java/dummy/example/pkg2/Model4.java @@ -0,0 +1,26 @@ +/* + * 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 dummy.example.pkg2; + +import org.apache.sling.models.annotations.Model; + +@Model(adaptables=Object.class) +public class Model4 { + +} diff --git a/src/test/java/dummy/example/pkg2/Model5.java b/src/test/java/dummy/example/pkg2/Model5.java new file mode 100644 index 0000000..a160d99 --- /dev/null +++ b/src/test/java/dummy/example/pkg2/Model5.java @@ -0,0 +1,26 @@ +/* + * 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 dummy.example.pkg2; + +import org.apache.sling.models.annotations.Model; + +@Model(adaptables=Object.class) +public class Model5 { + +} diff --git a/src/test/java/org/apache/sling/bnd/models/AbstractModelsScannerPluginTest.java b/src/test/java/org/apache/sling/bnd/models/AbstractModelsScannerPluginTest.java new file mode 100644 index 0000000..ab1db08 --- /dev/null +++ b/src/test/java/org/apache/sling/bnd/models/AbstractModelsScannerPluginTest.java @@ -0,0 +1,89 @@ +/* + * 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.sling.bnd.models; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.jar.Manifest; + +import org.apache.commons.lang3.StringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import aQute.bnd.osgi.Builder; +import aQute.bnd.osgi.Jar; +import aQute.bnd.service.Plugin; +import aQute.service.reporter.Reporter; + +@RunWith(MockitoJUnitRunner.class) +public abstract class AbstractModelsScannerPluginTest { + + protected Builder builder; + + @Before + public final void setUp() throws Exception { + builder = new Builder(); + + Jar classesDirJar = new Jar("test.jar", new File("target/test-classes")); + classesDirJar.setManifest(new Manifest()); + builder.setJar(classesDirJar); + + builder.setSourcepath(new File[] { new File("src/test/java") } ); + + Plugin plugin = new ModelsScannerPlugin(); + plugin.setReporter(mock(Reporter.class)); + plugin.setProperties(getProperties()); + builder.addBasicPlugin(plugin); + } + + @After + public final void tearDown() throws Exception { + if (!builder.getErrors().isEmpty()) { + fail(StringUtils.join(builder.getErrors(), "\n")); + } + builder.close(); + } + + protected Map<String,String> getProperties() { + return new HashMap<>(); + } + + protected final void assertHeaderMissing(Jar jar, String headerName) throws Exception { + assertNull(jar.getManifest().getMainAttributes().getValue(headerName)); + } + + protected final void assertHeader(Jar jar, String headerName, String... headerValues) throws Exception { + Set<String> expectedValues = new HashSet<>(Arrays.asList(headerValues)); + String[] actual = StringUtils.split(jar.getManifest().getMainAttributes().getValue(headerName), ","); + Set<String> actualValues = new HashSet<>(Arrays.asList(actual)); + assertEquals(expectedValues, actualValues); + } + +} diff --git a/src/test/java/org/apache/sling/bnd/models/GenerateClassesHeaderTest.java b/src/test/java/org/apache/sling/bnd/models/GenerateClassesHeaderTest.java new file mode 100644 index 0000000..52076a9 --- /dev/null +++ b/src/test/java/org/apache/sling/bnd/models/GenerateClassesHeaderTest.java @@ -0,0 +1,44 @@ +/* + * 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.sling.bnd.models; + +import static org.apache.sling.bnd.models.ModelsScannerPlugin.MODELS_CLASSES_HEADER; +import static org.apache.sling.bnd.models.ModelsScannerPlugin.*; + +import org.junit.Test; + +import aQute.bnd.osgi.Jar; + +public class GenerateClassesHeaderTest extends AbstractModelsScannerPluginTest { + + @Test + public void testBuild() throws Exception { + Jar jar = builder.build(); + + assertHeaderMissing(jar, MODELS_PACKAGES_HEADER); + + assertHeader(jar, MODELS_CLASSES_HEADER, + "dummy.example.pkg1.Model1", + "dummy.example.pkg1.Model2", + "dummy.example.pkg1.sub1.Model3", + "dummy.example.pkg2.Model4", + "dummy.example.pkg2.Model5"); + } + +} diff --git a/src/test/java/org/apache/sling/bnd/models/GeneratePackagesHeaderTest.java b/src/test/java/org/apache/sling/bnd/models/GeneratePackagesHeaderTest.java new file mode 100644 index 0000000..72e59d1 --- /dev/null +++ b/src/test/java/org/apache/sling/bnd/models/GeneratePackagesHeaderTest.java @@ -0,0 +1,53 @@ +/* + * 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.sling.bnd.models; + +import static org.apache.sling.bnd.models.ModelsScannerPlugin.MODELS_CLASSES_HEADER; +import static org.apache.sling.bnd.models.ModelsScannerPlugin.MODELS_PACKAGES_HEADER; +import static org.apache.sling.bnd.models.ModelsScannerPlugin.PROPERTY_GENERATE_PACKAGES_HEADER; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import aQute.bnd.osgi.Jar; + +public class GeneratePackagesHeaderTest extends AbstractModelsScannerPluginTest { + + @Override + protected Map<String, String> getProperties() { + Map<String,String> props = new HashMap<>(); + props.put(PROPERTY_GENERATE_PACKAGES_HEADER, "true"); + return props; + } + + @Test + public void testBuild() throws Exception { + Jar jar = builder.build(); + + assertHeader(jar, MODELS_PACKAGES_HEADER, + "dummy.example.pkg1", + "dummy.example.pkg2"); + + assertHeaderMissing(jar, MODELS_CLASSES_HEADER); + + } + +} -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
