diff --git a/api/pom.xml b/api/pom.xml index e2a66bb3..235e1d5b 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -341,6 +341,8 @@ Jakarta JSON Processing API ${spec.version} ${vendor.name} ${buildNumber} + + osgi.extender;filter:="(osgi.extender=osgi.serviceloader.processor)", osgi.serviceloader; filter:="(osgi.serviceloader=jakarta.json.spi.JsonProvider)"; cardinality:=multiple diff --git a/demos/jsonpointer-osgi/pom.xml b/demos/jsonpointer-osgi/pom.xml new file mode 100644 index 00000000..f994f6ff --- /dev/null +++ b/demos/jsonpointer-osgi/pom.xml @@ -0,0 +1,233 @@ + + + + + 4.0.0 + + + org.eclipse.jsonp + demos + 2.0.2-SNAPSHOT + ../pom.xml + + + jsondemos-jsonpointer-osgi + bundle + + + JsonpointerOsgiDemo + ${project.build.directory}/modules + 2.0 + 2.0.1-SNAPSHOT + ${project.version} + + + + + jakarta.json + jakarta.json-api + ${json.api.version} + provided + + + org.eclipse.jsonp + jsonp + ${jsonp.impl.version} + provided + + + org.osgi + osgi.core + provided + + + + org.apache.felix + org.apache.felix.framework + test + + + org.apache.felix + org.apache.felix.eventadmin + test + + + + org.ops4j.pax.exam + pax-exam + test + + + org.ops4j.pax.exam + pax-exam-junit4 + test + + + org.ops4j.pax.exam + pax-exam-container-forked + test + + + org.ops4j.pax.exam + pax-exam-link-mvn + test + + + org.ops4j.pax.url + pax-url-aether + test + + + + junit + junit + test + + + + org.slf4j + slf4j-log4j12 + test + + + + + org.apache.aries.spifly + org.apache.aries.spifly.dynamic.bundle + provided + + + org.ow2.asm + asm-all + provided + + + org.apache.aries + org.apache.aries.util + provided + + + + + + + org.ops4j.pax.exam + maven-paxexam-plugin + + + generate-config + + generate-depends-file + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + test-compile + test-compile + + testCompile + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-tests + verify + + test + + + + **/*IT.java + + + + + + + org.glassfish.build + spec-version-maven-plugin + + + ${non.final} + api + ${spec.version} + ${project.version} + ${project.artifactId} + + + + + + set-spec-properties + + + + + + org.apache.felix + maven-bundle-plugin + true + + + main-artifact-module + + bundle + + + + org.eclipse.jsondemos.osgi.jsonpointer.JsonpointerOsgiDemo + + ${spec.bundle.version} + ${spec.bundle.symbolic-name} + {maven-resources},target/classes/module-info.class + + + + + + + org.apache.karaf.tooling + karaf-maven-plugin + true + + 80 + false + true + ${karaf.feature.name} + + + + generate-features-file + package + + features-generate-descriptor + + + + + + + + diff --git a/demos/jsonpointer-osgi/src/main/feature/feature.xml b/demos/jsonpointer-osgi/src/main/feature/feature.xml new file mode 100644 index 00000000..4099bcc6 --- /dev/null +++ b/demos/jsonpointer-osgi/src/main/feature/feature.xml @@ -0,0 +1,25 @@ + + + + + + + mvn:jakarta.json/jakarta.json-api/${project.version} + mvn:org.eclipse.jsonp/jsonp/${project.version} + + mvn:org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle/${spifly.version} + + mvn:org.ow2.asm/asm-all/${asm.all.version} + mvn:org.apache.aries/org.apache.aries.util/${aries.util.version} + + diff --git a/demos/jsonpointer-osgi/src/main/java/module-info.java b/demos/jsonpointer-osgi/src/main/java/module-info.java new file mode 100644 index 00000000..f89a2a49 --- /dev/null +++ b/demos/jsonpointer-osgi/src/main/java/module-info.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0, which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +module org.eclipse.jsondemos.osgi.jsonpointer { + requires jakarta.json; + requires osgi.core; +} diff --git a/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonPointerService.java b/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonPointerService.java new file mode 100644 index 00000000..08732e62 --- /dev/null +++ b/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonPointerService.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0, which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jsondemos.osgi.jsonpointer; + +import jakarta.json.JsonObject; + +/** + * Implementation of this interface will be registered in OSGI container as a service. + */ +public interface JsonPointerService { + + JsonObject read(String pathToResource); +} diff --git a/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonPointerServiceImpl.java b/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonPointerServiceImpl.java new file mode 100644 index 00000000..da134aa8 --- /dev/null +++ b/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonPointerServiceImpl.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0, which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jsondemos.osgi.jsonpointer; + +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; + +import java.io.IOException; +import java.io.InputStream; + +/** + * This class will be registered as a service inside an OSGI container and will be available for other bundles. + */ +public class JsonPointerServiceImpl implements JsonPointerService { + @Override + public JsonObject read(String pathToResource) { + try ( + InputStream is = JsonpointerOsgiDemo.class.getResourceAsStream("/wiki.json"); + JsonReader rdr = Json.createReader(is) + ) { + return rdr.readObject(); + } catch (IOException e) { + return null; + } + } +} diff --git a/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonpointerOsgiDemo.java b/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonpointerOsgiDemo.java new file mode 100644 index 00000000..959e8352 --- /dev/null +++ b/demos/jsonpointer-osgi/src/main/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonpointerOsgiDemo.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0, which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jsondemos.osgi.jsonpointer; + +import java.io.IOException; +import java.io.InputStream; + +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * JsonPointer demo with object model API to run inside an OSGI container + */ +public class JsonpointerOsgiDemo implements BundleActivator { + + @Override + public void start(BundleContext context) throws Exception { + testWiki(); + testPointer(); + System.out.println("Both tests PASSED !!!"); + registerService(context); + } + + @Override + public void stop(BundleContext context) throws Exception { + System.out.println("OSGI bundle stopped"); + } + + private void registerService(BundleContext context) { + context.registerService(JsonPointerService.class, new JsonPointerServiceImpl(), null); + } + + private void testWiki() throws IOException { + try ( + InputStream is = JsonpointerOsgiDemo.class.getResourceAsStream("/wiki.json"); + JsonReader rdr = Json.createReader(is) + ) { + JsonObject person = rdr.readObject(); + + assertEquals("NY", getString(person, "/address/state")); + assertEquals("212 555-1234", getString(person, "/phoneNumber/0/number")); + } + } + + private void testPointer() throws IOException { + try (InputStream is = JsonpointerOsgiDemo.class.getResourceAsStream("/jsonpointer.json"); + JsonReader rdr = Json.createReader(is)) { + JsonObject root = rdr.readObject(); + + assertEquals(root, get(root, "")); + assertEquals(root.get("foo"), get(root, "/foo")); + assertEquals(root.getJsonArray("foo").get(0), get(root, "/foo/0")); + assertEquals(root.get(""), get(root, "/")); + assertEquals(root.get("a/b"), get(root, "/a~1b")); + assertEquals(root.get("c%d"), get(root, "/c%d")); + assertEquals(root.get("e^f"), get(root, "/e^f")); + assertEquals(root.get("k\"l"), get(root, "/k\"l")); + assertEquals(root.get("i\\j"), get(root, "/i\\j")); + assertEquals(root.get(" "), get(root, "/ ")); + assertEquals(root.get("m~n"), get(root, "/m~0n")); + + // Adding a parent to current root and try with it + JsonObject doc = Json.createObjectBuilder().add("doc", root).build(); + root = doc.getJsonObject("doc"); + assertEquals(doc, get(doc, "")); + assertEquals(root.get("foo"), get(doc, "/doc/foo")); + assertEquals(root.getJsonArray("foo").get(0), get(doc, "/doc/foo/0")); + assertEquals(root.get(""), get(doc, "/doc/")); + assertEquals(root.get("a/b"), get(doc, "/doc/a~1b")); + assertEquals(root.get("c%d"), get(doc, "/doc/c%d")); + assertEquals(root.get("e^f"), get(doc, "/doc/e^f")); + assertEquals(root.get("k\"l"), get(doc, "/doc/k\"l")); + assertEquals(root.get("i\\j"), get(doc, "/doc/i\\j")); + assertEquals(root.get(" "), get(doc, "/doc/ ")); + assertEquals(root.get("m~n"), get(doc, "/doc/m~0n")); + } + } + + private String getString(JsonValue root, String pointer) { + return ((JsonString) get(root, pointer)).getString(); + } + + private JsonValue get(JsonValue root, String pointer) { + if (pointer.isEmpty()) { + return root; + } + if (pointer.charAt(0) != '/') { + throw new IllegalArgumentException( + "JsonPointer " + pointer + " doesn't start with /"); + } + + StringBuilder referenceToken = new StringBuilder(); + for (int i = 1; i < pointer.length(); i++) { // 1 to skip first / + char ch = pointer.charAt(i); + if (ch == '/') { + return get(newRoot(root, referenceToken.toString()), pointer.substring(i)); + } else if (ch == '~') { + // handle escaping ~0, ~1 + if (i + 1 == pointer.length()) { + throw new IllegalArgumentException("Illegal escaping: expected ~0 or ~1, but got only ~ in pointer=" + pointer); + } + ch = pointer.charAt(++i); + if (ch == '0') { + referenceToken.append('~'); + } else if (ch == '1') { + referenceToken.append('/'); + } else { + throw new IllegalArgumentException("Illegal escaping: expected ~0 or ~1, but got ~" + ch + " in pointer=" + pointer); + } + } else { + referenceToken.append(ch); + } + } + return newRoot(root, referenceToken.toString()); + } + + private JsonValue newRoot(JsonValue root, String referenceToken) { + if (root instanceof JsonObject) { + return ((JsonObject) root).get(referenceToken); + } else if (root instanceof JsonArray) { + return ((JsonArray) root).get(Integer.parseInt(referenceToken)); + } + throw new IllegalArgumentException("Illegal reference token=" + referenceToken + " for value=" + root); + } + + private void assertEquals(JsonValue exp, JsonValue got) { + if (exp != got) { + throw new RuntimeException("Expected = " + exp + " but got = " + got); + } + } + + private void assertEquals(String exp, String got) { + if (!exp.equals(got)) { + throw new RuntimeException("Expected = " + exp + " but got = " + got); + } + } +} diff --git a/demos/jsonpointer-osgi/src/main/resources/jsonpointer.json b/demos/jsonpointer-osgi/src/main/resources/jsonpointer.json new file mode 100644 index 00000000..937a098c --- /dev/null +++ b/demos/jsonpointer-osgi/src/main/resources/jsonpointer.json @@ -0,0 +1,12 @@ +{ + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 +} diff --git a/demos/jsonpointer-osgi/src/main/resources/wiki.json b/demos/jsonpointer-osgi/src/main/resources/wiki.json new file mode 100644 index 00000000..17bb1932 --- /dev/null +++ b/demos/jsonpointer-osgi/src/main/resources/wiki.json @@ -0,0 +1,21 @@ +{ + "firstName": "John", + "lastName": "Smith", + "age": 25, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021" + }, + "phoneNumber": [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "fax", + "number": "646 555-4567" + } + ] +} diff --git a/demos/jsonpointer-osgi/src/test/java/org/eclipse/jsondemos/osgi/jsonpointer/AbstractJsonpOsgiTest.java b/demos/jsonpointer-osgi/src/test/java/org/eclipse/jsondemos/osgi/jsonpointer/AbstractJsonpOsgiTest.java new file mode 100644 index 00000000..f7a46504 --- /dev/null +++ b/demos/jsonpointer-osgi/src/test/java/org/eclipse/jsondemos/osgi/jsonpointer/AbstractJsonpOsgiTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0, which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jsondemos.osgi.jsonpointer; + +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.osgi.framework.BundleContext; + +import javax.inject.Inject; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; + +import static org.ops4j.pax.exam.CoreOptions.bundle; +import static org.ops4j.pax.exam.CoreOptions.cleanCaches; +import static org.ops4j.pax.exam.CoreOptions.junitBundles; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.options; + +public class AbstractJsonpOsgiTest { + + @Inject + protected BundleContext bundleContext; + + @Configuration + public Option[] configuration() { + final Option[] base = options( + cleanCaches(true), + junitBundles(), + mavenBundle() + .groupId("org.apache.aries.spifly") + .artifactId("org.apache.aries.spifly.dynamic.bundle") + .versionAsInProject(), + mavenBundle().groupId("org.ow2.asm").artifactId("asm-all").versionAsInProject(), + mavenBundle().groupId("org.apache.aries").artifactId("org.apache.aries.util").versionAsInProject(), + mavenBundle().groupId("jakarta.json").artifactId("jakarta.json-api").versionAsInProject(), + mavenBundle().groupId("org.eclipse.jsonp").artifactId("jsonp").versionAsInProject(), + bundle(getCurrentProjectArtifactUrl().toString()) + ); + return base; + } + + private URL getCurrentProjectArtifactUrl() { + URL artifactUrl=null; + String targetClassDirPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); + File artifact = new File(targetClassDirPath) + .getParentFile() + .listFiles((dir, name) -> + name.startsWith("jsondemos-jsonpointer-osgi") + && name.endsWith(".jar") + && !name.contains("sources"))[0]; + try { + artifactUrl = artifact.toURI().toURL(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return artifactUrl; + } +} diff --git a/demos/jsonpointer-osgi/src/test/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonpointerOsgiDemoTestIT.java b/demos/jsonpointer-osgi/src/test/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonpointerOsgiDemoTestIT.java new file mode 100644 index 00000000..ad795890 --- /dev/null +++ b/demos/jsonpointer-osgi/src/test/java/org/eclipse/jsondemos/osgi/jsonpointer/JsonpointerOsgiDemoTestIT.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0, which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jsondemos.osgi.jsonpointer; + +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(PaxExam.class) +public class JsonpointerOsgiDemoTestIT extends AbstractJsonpOsgiTest { + + @Test + public void testJsonPointerOsgiBundle() { + int expectedBundleStatus = 32; //Bundle.ACTIVE + String expectedJsonFieldValue = "John"; + List bundles = Arrays.asList(bundleContext.getBundles()); + + ServiceReference reference = bundleContext.getServiceReference(JsonPointerService.class.getName()); + JsonPointerService jsonPointerService = (JsonPointerService) bundleContext.getService(reference); + JsonObject jsonObject = jsonPointerService.read("/wiki.json"); + + assertEquals(expectedBundleStatus, getBundleState(bundles, "jakarta.json-api")); + assertEquals(expectedBundleStatus, getBundleState(bundles, "org.eclipse.jsonp")); + assertEquals(expectedBundleStatus, getBundleState(bundles, "jsondemos-jsonpointer-osgi-api")); + assertEquals(expectedJsonFieldValue, ((JsonString)jsonObject.get("firstName")).getString()); + } + + private int getBundleState(List bundles, String bundleSymbolicName) { + return bundles + .stream() + .filter(bundle -> bundle.getSymbolicName().equals(bundleSymbolicName)) + .findFirst().get() + .getState(); + } +} diff --git a/demos/jsonpointer-osgi/src/test/resources/wiki.json b/demos/jsonpointer-osgi/src/test/resources/wiki.json new file mode 100644 index 00000000..17bb1932 --- /dev/null +++ b/demos/jsonpointer-osgi/src/test/resources/wiki.json @@ -0,0 +1,21 @@ +{ + "firstName": "John", + "lastName": "Smith", + "age": 25, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021" + }, + "phoneNumber": [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "fax", + "number": "646 555-4567" + } + ] +} diff --git a/demos/pom.xml b/demos/pom.xml index 9ec70d49..82d4f538 100644 --- a/demos/pom.xml +++ b/demos/pom.xml @@ -36,6 +36,7 @@ jsonpointer servlet customprovider-jdk9 + jsonpointer-osgi diff --git a/impl/pom.xml b/impl/pom.xml index 4306dc14..da27ec0b 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -53,6 +53,8 @@ ${project.groupId}:${project.artifactId} ${project.version} - ${buildNumber} org.eclipse.jsonp.api + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)" + osgi.serviceloader; osgi.serviceloader=jakarta.json.spi.JsonProvider diff --git a/pom.xml b/pom.xml index 4a2131c4..e2b787fc 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,19 @@ 2.0.0 3.0.1 3.0.0 + + ${project.artifactId} + 4.3.2 + 7.0.0 + 6.0.3 + 1.5.0 + 4.13.1 + 1.5.0 + 1.6.4 + 1.2.4 + 1.1 + 5.2 + 1.1.3 @@ -369,6 +382,16 @@ maven-assembly-plugin 3.3.0 + + org.apache.karaf.tooling + karaf-maven-plugin + ${karaf.version} + + + org.ops4j.pax.exam + maven-paxexam-plugin + ${paxexam.plugin.version} + @@ -421,6 +444,66 @@ 1.3 test + + org.osgi + osgi.core + ${osgi.core.version} + + + org.apache.felix + org.apache.felix.framework + ${felix.framework.version} + + + org.apache.felix + org.apache.felix.eventadmin + ${felix.eventadmin.version} + + + org.ops4j.pax.exam + pax-exam + ${pax.exam.version} + + + org.ops4j.pax.exam + pax-exam-junit4 + ${pax.exam.version} + + + org.ops4j.pax.exam + pax-exam-container-forked + ${pax.exam.version} + + + org.ops4j.pax.exam + pax-exam-link-mvn + ${pax.exam.version} + + + org.ops4j.pax.url + pax-url-aether + ${pax.url.aether.version} + + + org.slf4j + slf4j-log4j12 + ${slf.version} + + + org.apache.aries.spifly + org.apache.aries.spifly.dynamic.bundle + ${spifly.version} + + + org.ow2.asm + asm-all + ${asm.all.version} + + + org.apache.aries + org.apache.aries.util + ${aries.util.version} +