Prevent registration of duplicate CommandInfo instances.
diff --git a/activation-api-1.1/pom.xml b/activation-api-1.1/pom.xml
index 25a79a3..77794fb 100644
--- a/activation-api-1.1/pom.xml
+++ b/activation-api-1.1/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.servicemix.specs</groupId>
<artifactId>specs-pom</artifactId>
- <version>1-SNAPSHOT</version>
+ <version>2</version>
<relativePath>../specs-pom/pom.xml</relativePath>
</parent>
@@ -38,14 +38,13 @@
<connection>scm:git:https://gitbox.apache.org/repos/asf/servicemix-specs.git</connection>
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/servicemix-specs.git</developerConnection>
<url>https://gitbox.apache.org/repos/asf?p=servicemix-specs.git</url>
- <tag>HEAD</tag>
</scm>
<dependencies>
<dependency>
<groupId>org.apache.servicemix.specs</groupId>
<artifactId>org.apache.servicemix.specs.locator</artifactId>
- <version>2.10-SNAPSHOT</version>
+ <version>2.10</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
@@ -58,6 +57,18 @@
<version>1.4.0</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.13</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>3.3.3</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -131,6 +142,22 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>3.0.0-M4</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <argLine>-Djava.endorsed.dirs=${project.build.directory},${maven.dependency.org.osgi.core.jar.path}</argLine>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
diff --git a/activation-api-1.1/src/main/java/javax/activation/MailcapCommandMap.java b/activation-api-1.1/src/main/java/javax/activation/MailcapCommandMap.java
index a028635..492cbb0 100644
--- a/activation-api-1.1/src/main/java/javax/activation/MailcapCommandMap.java
+++ b/activation-api-1.1/src/main/java/javax/activation/MailcapCommandMap.java
@@ -28,7 +28,6 @@
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
-import java.security.Security;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -277,11 +276,21 @@
cmdList = new ArrayList();
allCommands.put(mimeType, cmdList);
}
- cmdList.add(info);
+ addUnique(cmdList, info);
}
}
}
+ private void addUnique(List commands, CommandInfo newCommand) {
+ for (Iterator i = commands.iterator(); i.hasNext();) {
+ CommandInfo info = (CommandInfo)i.next();
+ if (info.getCommandName().equals(newCommand.getCommandName())
+ && info.getCommandClass().equals(newCommand.getCommandClass())) {
+ return;
+ }
+ }
+ commands.add(newCommand);
+ }
/**
* Add a command to a target command list (preferred or fallback).
diff --git a/activation-api-1.1/src/main/java/org/apache/servicemix/specs/activation/Activator.java b/activation-api-1.1/src/main/java/org/apache/servicemix/specs/activation/Activator.java
index fc2643f..30ff5df 100644
--- a/activation-api-1.1/src/main/java/org/apache/servicemix/specs/activation/Activator.java
+++ b/activation-api-1.1/src/main/java/org/apache/servicemix/specs/activation/Activator.java
@@ -99,6 +99,7 @@
commandMap.addMailcap(line, mailcap.bundle);
}
}
+ commandMap.addMailcap("", null);
CommandMap.setDefaultCommandMap(commandMap);
} finally {
Thread.currentThread().setContextClassLoader(tccl);
diff --git a/activation-api-1.1/src/test/java/javax/activation/ITBugDuplicatedMaincapRegistrations.java b/activation-api-1.1/src/test/java/javax/activation/ITBugDuplicatedMaincapRegistrations.java
new file mode 100644
index 0000000..4bb4749
--- /dev/null
+++ b/activation-api-1.1/src/test/java/javax/activation/ITBugDuplicatedMaincapRegistrations.java
@@ -0,0 +1,49 @@
+/*
+ * 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 javax.activation;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+
+/**
+ * SM-4383. Filter out duplicate registrations of a command.
+ */
+public class ITBugDuplicatedMaincapRegistrations {
+
+ private static final String MIMETYPE = "example/sm-4383";
+
+ private static final String MAILCAP = MIMETYPE+";; x-java-content-handler=some.value";
+
+ @Test
+ public void testFilterDuplicates() {
+ MailcapCommandMap mc = new MailcapCommandMap();
+
+ assertEquals(0, mc.getAllCommands(MIMETYPE).length);
+
+ mc.addMailcap(MAILCAP);
+ mc.addMailcap(MAILCAP);
+ assertEquals(1, mc.getAllCommands(MIMETYPE).length);
+
+ mc.addMailcap(MAILCAP+".alt");
+ assertEquals(2, mc.getAllCommands(MIMETYPE).length);
+ }
+
+}
diff --git a/activation-api-1.1/src/test/java/org/apache/servicemix/specs/activation/ITClearCurrentBundle.java b/activation-api-1.1/src/test/java/org/apache/servicemix/specs/activation/ITClearCurrentBundle.java
new file mode 100644
index 0000000..7cf6f49
--- /dev/null
+++ b/activation-api-1.1/src/test/java/org/apache/servicemix/specs/activation/ITClearCurrentBundle.java
@@ -0,0 +1,75 @@
+/*
+ * 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.servicemix.specs.activation;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Field;
+import java.net.URL;
+
+import javax.activation.CommandMap;
+import javax.activation.DataContentHandler;
+
+import org.junit.After;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+
+/**
+ * After Activator.rebuildCommandMap the currentBundle of OsgiMailcapCommandMap should be null, so that calls
+ * to addMailcap do not register with the last started bundle.
+ */
+public class ITClearCurrentBundle {
+
+ @After
+ public void tearDown() {
+ CommandMap.setDefaultCommandMap(null);
+ }
+
+ @Test
+ public void testClearCurrentBundle() throws Exception {
+ Activator activator = new Activator();
+ Bundle bundle = createBundle(ITClearCurrentBundle.class.getResource("/mailcap.example"));
+
+ activator.register(bundle);
+
+ assertTrue(CommandMap.getDefaultCommandMap() instanceof OsgiMailcapCommandMap);
+ assertNullCurrentBundle((OsgiMailcapCommandMap) CommandMap.getDefaultCommandMap());
+ }
+
+ private void assertNullCurrentBundle(OsgiMailcapCommandMap commandMap) throws Exception {
+ Field field = OsgiMailcapCommandMap.class.getDeclaredField("currentBundle");
+ boolean oldAccessible = field.isAccessible();
+ try {
+ field.setAccessible(true);
+ assertNull(field.get(commandMap));
+ }
+ finally {
+ field.setAccessible(oldAccessible);
+ }
+ }
+
+ private Bundle createBundle(URL mailcapResource) throws Exception {
+ Bundle result = Mockito.mock(Bundle.class);
+ Mockito.when(result.loadClass("javax.activation.DataContentHandler")).thenReturn(DataContentHandler.class);
+ Mockito.when(result.getResource("/META-INF/mailcap")).thenReturn(mailcapResource);
+ return result;
+ }
+}
diff --git a/activation-api-1.1/src/test/resources/mailcap.example b/activation-api-1.1/src/test/resources/mailcap.example
new file mode 100644
index 0000000..3ec1b0d
--- /dev/null
+++ b/activation-api-1.1/src/test/resources/mailcap.example
@@ -0,0 +1,2 @@
+# Example mailcap
+example/sm-4383;; x-java-content-handler=some.value