From 3a3274df26933d879099636fff3488bc4259390b Mon Sep 17 00:00:00 2001 From: Ioannis Canellos Date: Fri, 1 Jun 2018 10:59:56 +0300 Subject: [PATCH 1/3] feat: KubernetesDeserializer can now lookup for resource mappings via ServiceLoader. --- .../KubernetesResourceMappingProvider.java | 26 ++++++ .../InternalResourceMappingProvider.java | 38 ++++++++ .../internal/KubernetesDeserializer.java | 92 ++++++++++++++----- ...etes.api.KubernetesResourceMappingProvider | 1 + 4 files changed, 134 insertions(+), 23 deletions(-) create mode 100644 kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java create mode 100644 kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/InternalResourceMappingProvider.java create mode 100644 kubernetes-model/src/main/resources/META-INF/services/io.fabric8.kubernetes.api.KubernetesResourceMappingProvider diff --git a/kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java b/kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java new file mode 100644 index 000000000..f371af7bd --- /dev/null +++ b/kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2018 Red Hat inc. + * + * Licensed 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 io.fabric8.kubernetes.api; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.KubernetesResource; + +public interface KubernetesResourceMappingProvider { + + Map> getMappings(); +} diff --git a/kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/InternalResourceMappingProvider.java b/kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/InternalResourceMappingProvider.java new file mode 100644 index 000000000..dcd41fec8 --- /dev/null +++ b/kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/InternalResourceMappingProvider.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2011 Red Hat, Inc. + * + * Licensed 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 io.fabric8.kubernetes.internal; + +import io.fabric8.kubernetes.api.KubernetesResourceMappingProvider; +import io.fabric8.kubernetes.api.model.KubernetesList; +import io.fabric8.kubernetes.api.model.KubernetesResource; + +import java.util.HashMap; +import java.util.Map; + +public class InternalResourceMappingProvider implements KubernetesResourceMappingProvider { + + private final Map> mappings = new HashMap<>(); + + public InternalResourceMappingProvider() { + mappings.put("List", KubernetesList.class); + mappings.put("v1#List", KubernetesList.class); + } + + @Override + public Map> getMappings() { + return mappings; + } +} diff --git a/kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java b/kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java index f883d6168..459317cca 100644 --- a/kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java +++ b/kubernetes-model/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java @@ -15,22 +15,27 @@ */ package io.fabric8.kubernetes.internal; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; + import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; + import com.fasterxml.jackson.databind.node.ObjectNode; import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.api.model.KubernetesResource; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; +import io.fabric8.kubernetes.api.KubernetesResourceMappingProvider; public class KubernetesDeserializer extends JsonDeserializer { private static final String KIND = "kind"; + private static final String API_VERSION = "apiVersion"; + private static final String KEY_SEPARATOR = "#"; private static final String KUBERNETES_PACKAGE_PREFIX = "io.fabric8.kubernetes.api.model."; private static final String KUBERNETES_EXTENSIONS_PACKAGE_PREFIX = "io.fabric8.kubernetes.api.model.extensions."; @@ -39,21 +44,21 @@ public class KubernetesDeserializer extends JsonDeserializer private static final Map> MAP = new HashMap<>(); - static { - // Exceptions (not just package prefix + class name) can be added here. - MAP.put("List", KubernetesList.class); + //Use service loader to load extension types. + for (KubernetesResourceMappingProvider provider : ServiceLoader.load(KubernetesResourceMappingProvider.class)) { + MAP.putAll(provider.getMappings()); + } } @Override public KubernetesResource deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { ObjectNode node = jp.readValueAsTree(); - JsonNode kind = node.get(KIND); - if (kind != null) { - String value = kind.textValue(); - Class resourceType = getTypeForName(value); + String key = getKey(node); + if (key != null) { + Class resourceType = getTypeForKey(key); if (resourceType == null) { - throw ctxt.mappingException("No resource type found for kind:" + value); + throw ctxt.mappingException("No resource type found for:" + key); } else { return jp.getCodec().treeToValue(node, resourceType); } @@ -61,17 +66,63 @@ public KubernetesResource deserialize(JsonParser jp, DeserializationContext ctxt return null; } + /** + * Return a string representation of the key of the type: #. + */ + private static final String getKey(ObjectNode node) { + JsonNode apiVersion = node.get(API_VERSION); + JsonNode kind = node.get(KIND); + + return getKey(apiVersion != null ? apiVersion.textValue() : null, + kind != null ? kind.textValue() : null); + } + + /** + * Returns a composite key for apiVersion and kind. + */ + private static final String getKey(String apiVersion, String kind) { + if (kind == null) { + return null; + } else if (apiVersion == null) { + return kind; + } else { + return String.format("%s#%s", apiVersion, kind); + } + } + /** * Registers a Custom Resource Definition Kind */ public static void registerCustomKind(String kind, Class clazz) { - MAP.put(kind, clazz); + registerCustomKind(null, kind, clazz); } - private static Class getTypeForName(String name) { - Class result = MAP.get(name); + /** + * Registers a Custom Resource Definition Kind + */ + public static void registerCustomKind(String apiVersion, String kind, Class clazz) { + MAP.put(getKey(apiVersion, kind), clazz); + } + + static Class getTypeForKey(String key) { + Class result = MAP.get(key); if (result == null) { - result = loadClassIfExists(KUBERNETES_PACKAGE_PREFIX + name); + String name = key != null && key.contains(KEY_SEPARATOR) ? + key.substring(key.indexOf(KEY_SEPARATOR) + 1) : + key; + + System.out.println("Trying internal type for name:"+name); + result = getInternalTypeForName(name); + } + + if (result != null) { + MAP.put(key, result); + } + return result; + } + + private static Class getInternalTypeForName(String name) { + Class result = loadClassIfExists(KUBERNETES_PACKAGE_PREFIX + name); if (result == null) { result = loadClassIfExists(KUBERNETES_EXTENSIONS_PACKAGE_PREFIX + name); if (result == null) { @@ -81,13 +132,8 @@ private static Class getTypeForName(String name) { } } } - } - - if (result != null) { - MAP.put(name, result); - } - return result; - } + return result; + } private static Class loadClassIfExists(String className) { try { diff --git a/kubernetes-model/src/main/resources/META-INF/services/io.fabric8.kubernetes.api.KubernetesResourceMappingProvider b/kubernetes-model/src/main/resources/META-INF/services/io.fabric8.kubernetes.api.KubernetesResourceMappingProvider new file mode 100644 index 000000000..ee2125c68 --- /dev/null +++ b/kubernetes-model/src/main/resources/META-INF/services/io.fabric8.kubernetes.api.KubernetesResourceMappingProvider @@ -0,0 +1 @@ +io.fabric8.kubernetes.internal.InternalResourceMappingProvider \ No newline at end of file From 3f107494e3eec86cc3fa753f903c06d2155651fa Mon Sep 17 00:00:00 2001 From: Ioannis Canellos Date: Fri, 1 Jun 2018 11:04:36 +0300 Subject: [PATCH 2/3] chore: bump minor version. --- kubernetes-model-annotator/pom.xml | 2 +- kubernetes-model/pom.xml | 2 +- model-generator-app/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kubernetes-model-annotator/pom.xml b/kubernetes-model-annotator/pom.xml index bc929c009..1ebb387c8 100644 --- a/kubernetes-model-annotator/pom.xml +++ b/kubernetes-model-annotator/pom.xml @@ -21,7 +21,7 @@ io.fabric8 kubernetes-model-generator - 2.0-SNAPSHOT + 2.1-SNAPSHOT 4.0.0 diff --git a/kubernetes-model/pom.xml b/kubernetes-model/pom.xml index 2126e2146..98b1c2ea7 100644 --- a/kubernetes-model/pom.xml +++ b/kubernetes-model/pom.xml @@ -22,7 +22,7 @@ io.fabric8 kubernetes-model-generator - 2.0-SNAPSHOT + 2.1-SNAPSHOT kubernetes-model diff --git a/model-generator-app/pom.xml b/model-generator-app/pom.xml index f1b785070..ff1fcfce0 100644 --- a/model-generator-app/pom.xml +++ b/model-generator-app/pom.xml @@ -22,7 +22,7 @@ io.fabric8 kubernetes-model-generator - 2.0-SNAPSHOT + 2.1-SNAPSHOT model-generator-app diff --git a/pom.xml b/pom.xml index fa0af36c8..3933db2ff 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ io.fabric8 - 2.0-SNAPSHOT + 2.1-SNAPSHOT kubernetes-model-generator pom From 6965c1d20dc8756d33ebbab4df91fe321e3d49ba Mon Sep 17 00:00:00 2001 From: Ioannis Canellos Date: Fri, 1 Jun 2018 11:07:43 +0300 Subject: [PATCH 3/3] fix: ill formatted license header. --- .../KubernetesResourceMappingProvider.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java b/kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java index f371af7bd..d6917cb0d 100644 --- a/kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java +++ b/kubernetes-model/src/main/java/io/fabric8/kubernetes/api/KubernetesResourceMappingProvider.java @@ -1,19 +1,18 @@ /** - * Copyright (C) 2018 Red Hat inc. - * - * Licensed 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. - * -**/ + * Copyright (C) 2011 Red Hat, Inc. + * + * Licensed 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 io.fabric8.kubernetes.api; import java.util.Map;