This is an automated email from the ASF dual-hosted git repository. nfilotto pushed a commit to branch camel-karaf-4.8.x in repository https://gitbox.apache.org/repos/asf/camel-karaf.git
The following commit(s) were added to refs/heads/camel-karaf-4.8.x by this push: new 3e8a241bb Ref #590 Add Bundle-Name and Bundle-SymbolicName to wrapped bundles (#591) 3e8a241bb is described below commit 3e8a241bbb60c64b26b6110bc327bc03d7a3cb19 Author: François de Parscau <116000379+f2p...@users.noreply.github.com> AuthorDate: Thu Jan 30 14:15:52 2025 +0100 Ref #590 Add Bundle-Name and Bundle-SymbolicName to wrapped bundles (#591) Motivation Very long names in karaf console when listing bundles by names or symbolic names Modifications: Add Bundle-Name= and Bundle-SymbolicName= to the wrapped bundles --- features/pom.xml | 1 + features/src/main/feature/camel-features.xml | 2 +- .../feature/maven/EnsureWrapBundleNameMojo.java | 142 +++++++++++++++++++++ .../maven/EnsureWrapBundleNameMojoTest.java | 77 +++++++++++ 4 files changed, 221 insertions(+), 1 deletion(-) diff --git a/features/pom.xml b/features/pom.xml index c1a926148..0d947d994 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -76,6 +76,7 @@ <goals> <goal>auto-detect-version</goal> <goal>ensure-wrap-bundle-version</goal> + <goal>ensure-wrap-bundle-name</goal> <goal>configure-wrap-spi-provider</goal> </goals> <configuration> diff --git a/features/src/main/feature/camel-features.xml b/features/src/main/feature/camel-features.xml index 362aa0117..b05258290 100644 --- a/features/src/main/feature/camel-features.xml +++ b/features/src/main/feature/camel-features.xml @@ -1128,7 +1128,7 @@ <feature version='${camel-osgi-version-range}'>camel-core</feature> <bundle dependency='true'>wrap:mvn:com.alibaba/fastjson/${fastjson-version}</bundle> <bundle dependency='true'>wrap:mvn:com.alibaba.fastjson2/fastjson2/${auto-detect-version}</bundle> - <bundle dependency='true'>wrap:mvn:com.alibaba.fastjson2/fastjson2-extension/${auto-detect-version}</bundle> + <bundle dependency='true'>wrap:mvn:com.alibaba.fastjson2/fastjson2-extension/${auto-detect-version}$Fragment-Host=wrap_com.alibaba.fastjson2.fastjson2</bundle> <bundle>mvn:org.apache.camel.karaf/camel-fastjson/${project.version}</bundle> </feature> <feature name='camel-fhir' version='${project.version}' start-level='50'> diff --git a/tooling/camel-karaf-feature-maven-plugin/src/main/java/org/apache/camel/karaf/feature/maven/EnsureWrapBundleNameMojo.java b/tooling/camel-karaf-feature-maven-plugin/src/main/java/org/apache/camel/karaf/feature/maven/EnsureWrapBundleNameMojo.java new file mode 100644 index 000000000..714e42d21 --- /dev/null +++ b/tooling/camel-karaf-feature-maven-plugin/src/main/java/org/apache/camel/karaf/feature/maven/EnsureWrapBundleNameMojo.java @@ -0,0 +1,142 @@ +/* + * 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.camel.karaf.feature.maven; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.karaf.features.internal.model.Bundle; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; + +@Mojo(name = "ensure-wrap-bundle-name", defaultPhase = LifecyclePhase.PROCESS_RESOURCES) +public class EnsureWrapBundleNameMojo extends AbstractWrapBundleMojo { + + private static final List<String> HEADERS_AFTER_BUNDLE_NAME = Arrays.asList( + "Bundle-Version", + "DynamicImport-Package", + "Export-Package", + "Export-Service", + "Fragment-Host", + "Import-Package", + "Import-Service", + "Provide-Capability", + "Require-Bundle", + "Require-Capability"); + + private static final String BUNDLE_NAME = "Bundle-Name"; + private static final String BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName"; + + private static String toPascalCase(String kebabCase) { + // Handle null or empty string + if (kebabCase == null || kebabCase.isEmpty()) { + return kebabCase; + } + + // Split by hyphen + String[] words = kebabCase.split("-"); + StringBuilder result = new StringBuilder(); + + // Capitalize first letter of each word + for (int i = 0; i < words.length; i++) { + String word = words[i]; + if (word.isEmpty()) { + continue; + } + result.append(Character.toUpperCase(word.charAt(0))); + if (word.length() > 1) { + result.append(word.substring(1).toLowerCase()); + } + // Only add %20 if it's not the last word + if (i < words.length - 1) { + result.append("%20"); + } + } + return result.toString(); + } + + @Override + protected boolean processWrappedBundle(WrappedBundle wrappedBundle) { + Bundle bundle = wrappedBundle.getBundle(); + String location = bundle.getLocation(); + try { + bundle.setLocation(processLocation(wrappedBundle)); + } catch (Exception e) { + getLog().error("Could not process the Bundle location '%s': %s".formatted(location, e.getMessage()), e); + } + return false; + } + + String processLocation(WrappedBundle wrappedBundle) throws Exception { + String location = wrappedBundle.getBundle().getLocation(); + String instructions = wrappedBundle.getInstructions(); + boolean dollarNeeded = instructions == null || !instructions.contains("$"); + + String bundleNameHeader = "%s=Wrap%%20of%%20%s".formatted(BUNDLE_NAME, toPascalCase(wrappedBundle.getArtifactId())); + String bundleSymbolicNameHeader = "%s=wrap_%s.%s".formatted(BUNDLE_SYMBOLIC_NAME, wrappedBundle.getGroupId(), wrappedBundle.getArtifactId()); + Map<String, String> headers = new TreeMap<>(); //sorted by key + headers.put(BUNDLE_NAME, bundleNameHeader); + headers.put(BUNDLE_SYMBOLIC_NAME, bundleSymbolicNameHeader); + + return insertHeaderIfNeeded(dollarNeeded, location, headers); + } + + + private String insertHeaderIfNeeded(boolean dollarNeeded, String location, Map<String, String> headers) { + + StringBuilder sb = new StringBuilder(location); + for (Map.Entry<String, String> entry : headers.entrySet()) { + if (location.contains(entry.getKey())) { + continue; + } + boolean hasChanged = false; + // insert before existing headers header + for (String header : HEADERS_AFTER_BUNDLE_NAME) { + // add Bundle-Version before + if (location.contains(header)) { + int versionHeaderStartIndex = location.indexOf(header); + if (dollarNeeded) { + // "amp;" is automatically added + dollarNeeded = false; + location = sb.insert(versionHeaderStartIndex, "$%s&".formatted(entry.getValue())).toString(); + } else { + // "amp;" is automatically added + location = sb.insert(versionHeaderStartIndex, "%s&".formatted(entry.getValue())).toString(); + } + hasChanged = true; + break; + } + } + if (hasChanged) { + //header already handled, go to next + continue; + } + + // insert at the end + if (dollarNeeded) { + dollarNeeded = false; + location = sb.insert(location.length(), "$%s".formatted(entry.getValue())).toString(); + } else { + // "amp;" is automatically added + location = sb.insert(location.length(), "&%s".formatted(entry.getValue())).toString(); + } + } + return location; + } +} \ No newline at end of file diff --git a/tooling/camel-karaf-feature-maven-plugin/src/test/java/org/apache/camel/karaf/feature/maven/EnsureWrapBundleNameMojoTest.java b/tooling/camel-karaf-feature-maven-plugin/src/test/java/org/apache/camel/karaf/feature/maven/EnsureWrapBundleNameMojoTest.java new file mode 100644 index 000000000..2e9730af3 --- /dev/null +++ b/tooling/camel-karaf-feature-maven-plugin/src/test/java/org/apache/camel/karaf/feature/maven/EnsureWrapBundleNameMojoTest.java @@ -0,0 +1,77 @@ +/* + * 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.camel.karaf.feature.maven; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.apache.karaf.features.internal.model.Bundle; +import org.junit.jupiter.api.Test; + +public class EnsureWrapBundleNameMojoTest { + + private final EnsureWrapBundleNameMojo ensureNameMojo = new EnsureWrapBundleNameMojo(); + + @Test + void modifyLocationTest() throws Exception { + Bundle bundle = new Bundle(); + // add bundle name at the end as first wrap protocol option + bundle.setLocation("wrap:mvn:org.apache.olingo/odata-server-core/5.0.0"); + String expected = "wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$Bundle-Name=Wrap%20of%20Odata%20Server%20Core&Bundle-SymbolicName=wrap_org.apache.olingo.odata-server-core"; + WrappedBundle wrappedBundle = WrappedBundle.fromBundle(bundle); + assertNotNull(wrappedBundle); + assertEquals(expected, ensureNameMojo.processLocation(wrappedBundle)); + + // add bundle name at the end but not as first wrap protocol option + bundle.setLocation("wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$overwrite=merge"); + expected = "wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$overwrite=merge&Bundle-Name=Wrap%20of%20Odata%20Server%20Core&Bundle-SymbolicName=wrap_org.apache.olingo.odata-server-core"; + wrappedBundle = WrappedBundle.fromBundle(bundle); + assertNotNull(wrappedBundle); + assertEquals(expected, ensureNameMojo.processLocation(wrappedBundle)); + + // add bundle name before existing wrap protocol header that should be declared after + bundle.setLocation("wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$overwrite=merge&Export-Package=org.apache.olingo.*;version=5.0.0"); + expected = "wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$overwrite=merge&Bundle-Name=Wrap%20of%20Odata%20Server%20Core&Bundle-SymbolicName=wrap_org.apache.olingo.odata-server-core&Export-Package=org.apache.olingo.*;version=5.0.0"; + wrappedBundle = WrappedBundle.fromBundle(bundle); + assertNotNull(wrappedBundle); + assertEquals(expected, ensureNameMojo.processLocation(wrappedBundle)); + + // add bundle name before existing wrap protocol header that should be declared after + bundle.setLocation("wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$overwrite=merge&Bundle-Version=5.0.0&Export-Package=org.apache.olingo.*;version=5.0.0"); + expected = "wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$overwrite=merge&Bundle-Name=Wrap%20of%20Odata%20Server%20Core&Bundle-SymbolicName=wrap_org.apache.olingo.odata-server-core&Bundle-Version=5.0.0&Export-Package=org.apache.olingo.*;version=5.0.0"; + wrappedBundle = WrappedBundle.fromBundle(bundle); + assertNotNull(wrappedBundle); + assertEquals(expected, ensureNameMojo.processLocation(wrappedBundle)); + + // don't override the Bundle-Name if present + bundle.setLocation("wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$Bundle-Name=MyName"); + expected = "wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$Bundle-Name=MyName&Bundle-SymbolicName=wrap_org.apache.olingo.odata-server-core"; + wrappedBundle = WrappedBundle.fromBundle(bundle); + assertNotNull(wrappedBundle); + assertEquals(expected, ensureNameMojo.processLocation(wrappedBundle)); + + // don't override the Bundle-SymbolicName if present + bundle.setLocation("wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$Bundle-SymbolicName=MyName"); + expected = "wrap:mvn:org.apache.olingo/odata-server-core/5.0.0$Bundle-SymbolicName=MyName&Bundle-Name=Wrap%20of%20Odata%20Server%20Core"; + wrappedBundle = WrappedBundle.fromBundle(bundle); + assertNotNull(wrappedBundle); + assertEquals(expected, ensureNameMojo.processLocation(wrappedBundle)); + + } + + +} \ No newline at end of file